Object-Realize-Later-3.00/0000755000175000001440000000000015107407353016023 5ustar00markovusers00000000000000Object-Realize-Later-3.00/Makefile.PL0000644000175000001440000000313215107407352017773 0ustar00markovusers00000000000000use ExtUtils::MakeMaker; require 5.016; # Use command 'oodist' to produce your whole software release. my $version = '3.00'; my $git = "https://github.com/markov2/perl5-Object-Realize-Later"; my $publish = "../public_html/object-realize-later"; my $homepage = "http://perl.overmeer.net/CPAN/"; my %oodist = ( oodoc_version => 3.05, first_year => 2001, email => "markov\@cpan.org", include => [ ], use => [ ], parser => { syntax => 'markov', skip_links => [ ], pmhead => undef, }, tests => { }, release => { publish => "$publish/source", }, raw => { publish => "$publish/raw", }, generate => [ { format => 'pod3', podtail => undef, }, ], ); my %requires = ( 'Scalar::Util' => 0, ); WriteMakefile NAME => 'Object::Realize::Later', VERSION => $version, AUTHOR => 'Mark Overmeer ', ABSTRACT => 'Delayed realization of objects', LICENSE => 'perl_5', META_MERGE => { 'meta-spec' => { version => 2 }, resources => { repository => { type => 'git', url => "$git.git", web => $git, }, bugtracker => { web => "$git/issues", }, homepage => $homepage, license => [ 'http//dev.perl.org/licenses/' ], }, prereqs => { runtime => { requires => \%requires, }, develop => { requires => { 'OODoc' => '3.00', }, }, test => { requires => { 'Test::More' => 1.00, 'Test::Pod' => 1.00, }, }, }, # You may use multiple set-ups, see "oodist --make" x_oodist => \%oodist, }; Object-Realize-Later-3.00/t/0000755000175000001440000000000015107407353016266 5ustar00markovusers00000000000000Object-Realize-Later-3.00/t/41autoload.t0000644000175000001440000000241415062004410020414 0ustar00markovusers00000000000000#!/usr/bin/env perl # # Test the autoloading() where becomes => CODE # use strict; use warnings; use Test; use lib 't', '.', 't/testmods', 'testmods'; use C::G::H; BEGIN { plan tests => 17 } my $warntxt; sub catchwarn {$warntxt = "@_"}; # Autoload via C::G because of request from A::B my $obj = C::G->new; ok($obj->c_g eq 'c_g'); ok($obj->c eq 'c' ); { local $SIG{__WARN__} = \&catchwarn; ok($obj->a_b eq 'a_b'); # triggers autoload } ok($warntxt, qr/^Realization of C::G /); ok(ref $obj eq 'A::B'); # Autoload via C::G::H because of request from A::B $obj = C::G::H->new; ok($obj->c_g_h eq 'c_g_h'); ok($obj->c_g eq 'c_g'); ok($obj->c eq 'c' ); { local $SIG{__WARN__} = \&catchwarn; ok($obj->a_b eq 'a_b'); # triggers autoload } ok($warntxt, qr/^Realization of C::G::H /); ok(ref $obj eq 'A::B'); # Autoload via C::G because of request from A $obj = C::G->new; { local $SIG{__WARN__} = \&catchwarn; ok($obj->a eq 'a'); # triggers autoload } ok($warntxt, qr/^Realization of C::G /); ok(ref $obj eq 'A::B'); # Autoload via C::G::H because of request from A $obj = C::G::H->new; { local $SIG{__WARN__} = \&catchwarn; ok($obj->a eq 'a'); # triggers autoload } ok($warntxt, qr/^Realization of C::G::H /); ok(ref $obj eq 'A::B'); Object-Realize-Later-3.00/t/40autoload.t0000644000175000001440000000241615062004410020415 0ustar00markovusers00000000000000#!/usr/bin/env perl # # Test the autoloading() where becomes => STRING # use strict; use warnings; use Test; use lib 't', '.', 't/testmods', 'testmods'; use C::D::E; BEGIN { plan tests => 17 } my $warntxt; sub catchwarn {$warntxt = "@_"}; # Autoload via C::D because of request from A::B my $obj = C::D->new; ok($obj->c_d eq 'c_d'); ok($obj->c eq 'c' ); { local $SIG{__WARN__} = \&catchwarn; ok($obj->a_b eq 'a_b'); # triggers autoload } ok($warntxt, qr/^Realization of C::D /); ok(ref $obj eq 'A::B'); # Autoload via C::D::E because of request from A::B $obj = C::D::E->new; ok($obj->c_d_e eq 'c_d_e'); ok($obj->c_d eq 'c_d'); ok($obj->c eq 'c' ); { local $SIG{__WARN__} = \&catchwarn; ok($obj->a_b eq 'a_b'); # triggers autoload } ok($warntxt, qr/^Realization of C::D::E /); ok(ref $obj eq 'A::B'); # Autoload via C::D because of request from A $obj = C::D->new; { local $SIG{__WARN__} = \&catchwarn; ok($obj->a eq 'a'); # triggers autoload } ok($warntxt, qr/^Realization of C::D /); ok(ref $obj eq 'A::B'); # Autoload via C::D::E because of request from A $obj = C::D::E->new; { local $SIG{__WARN__} = \&catchwarn; ok($obj->a eq 'a'); # triggers autoload } ok($warntxt, qr/^Realization of C::D::E /); ok(ref $obj eq 'A::B'); Object-Realize-Later-3.00/t/testmods/0000755000175000001440000000000015107407353020130 5ustar00markovusers00000000000000Object-Realize-Later-3.00/t/testmods/C/0000755000175000001440000000000015107407353020312 5ustar00markovusers00000000000000Object-Realize-Later-3.00/t/testmods/C/G.pm0000644000175000001440000000035015062004410021017 0ustar00markovusers00000000000000package C::G; use base 'C'; use Object::Realize::Later ( becomes => 'A::B' , realize => sub { bless(shift, 'A::B') } , warn_realization => 1 , warn_realize_again => 1 ); sub c_g() {'c_g'} 1; Object-Realize-Later-3.00/t/testmods/C/D.pm0000644000175000001440000000035715062004410021023 0ustar00markovusers00000000000000package C::D; use base 'C'; use Object::Realize::Later ( becomes => 'A::B' , realize => 'load' , warn_realization => 1 , warn_realize_again => 1 ); sub load() { bless {}, 'A::B' } sub c_d() {'c_d'} 1; Object-Realize-Later-3.00/t/testmods/C/D/0000755000175000001440000000000015107407353020475 5ustar00markovusers00000000000000Object-Realize-Later-3.00/t/testmods/C/D/E.pm0000644000175000001440000000013115062004410021175 0ustar00markovusers00000000000000 use warnings; use strict; package C::D::E; use base 'C::D'; sub c_d_e() {'c_d_e'} 1; Object-Realize-Later-3.00/t/testmods/C/G/0000755000175000001440000000000015107407353020500 5ustar00markovusers00000000000000Object-Realize-Later-3.00/t/testmods/C/G/H.pm0000644000175000001440000000013115062004410021203 0ustar00markovusers00000000000000 use warnings; use strict; package C::G::H; use base 'C::G'; sub c_g_h() {'c_g_h'} 1; Object-Realize-Later-3.00/t/testmods/I.pm0000644000175000001440000000030215062004410020634 0ustar00markovusers00000000000000package I; use Object::Realize::Later realize => sub { bless {}, 'Another::Class' }, becomes => 'Another::Class', source_module => 'J'; sub new { bless {}, shift } 1; Object-Realize-Later-3.00/t/testmods/A.pm0000644000175000001440000000007115062004410020627 0ustar00markovusers00000000000000 use strict; use warnings; package A; sub a() {'a'} 1; Object-Realize-Later-3.00/t/testmods/J.pm0000644000175000001440000000007615062004410020645 0ustar00markovusers00000000000000package J; package Another::Class; sub a_method { 42 } 1; Object-Realize-Later-3.00/t/testmods/A/0000755000175000001440000000000015107407353020310 5ustar00markovusers00000000000000Object-Realize-Later-3.00/t/testmods/A/B.pm0000644000175000001440000000011715062004410021011 0ustar00markovusers00000000000000 use strict; use warnings; package A::B; use base 'A'; sub a_b() {'a_b'} 1; Object-Realize-Later-3.00/t/testmods/C.pm0000644000175000001440000000020515062004410020630 0ustar00markovusers00000000000000 use strict; use warnings; package C; use overload '""' => sub { ref(shift) }; sub new() { bless {}, shift } sub c() { 'c' } 1; Object-Realize-Later-3.00/t/30realize.t0000644000175000001440000000156515062004410020243 0ustar00markovusers00000000000000#!/usr/bin/env perl # # Test the realize() # use strict; use warnings; use Test; use lib 't', '.', 't/testmods', 'testmods'; use C::D::E; BEGIN { plan tests => 15 } my $warntxt; sub catchwarn {$warntxt = "@_"}; my $obj = C::D->new; ok($obj); ok(ref $obj eq 'C::D'); ok(not defined $warntxt); my $new; { local $SIG{__WARN__} = \&catchwarn; $new = $obj->forceRealize; } ok($new); ok($warntxt, qr/^Realization of C::D /); ok(ref $obj eq 'A::B'); # passed new ref back? $obj = C::D::E->new; ok($obj); undef $warntxt; { local $SIG{__WARN__} = \&catchwarn; $new = $obj->forceRealize; } ok($new); ok($warntxt, qr/^Realization of C::D::E /); ok(ref $obj eq 'A::B'); ok(not defined $obj->can('C::D::E')); ok(not defined $obj->can('C::D')); ok(not defined $obj->can('C')); # test class methods (simple and proxied) ok( C::D->c_d eq 'c_d' ); ok( C::D->a_b eq 'a_b' ); Object-Realize-Later-3.00/t/50again.t0000644000175000001440000000136115062004410017663 0ustar00markovusers00000000000000#!/usr/bin/env perl # # Test re-realization # use strict; use warnings; use Test; use lib 't', '.', 't/testmods', 'testmods'; use C::D::E; BEGIN { plan tests => 8 } my $warntxt; sub catchwarn {$warntxt = "@_"}; # Autoload via C::D because of request from A::B my $obj = C::D->new; my $copy = $obj; { local $SIG{__WARN__} = \&catchwarn; ok($obj->a_b eq 'a_b'); # triggers autoload } ok($warntxt, qr/^Realization of C::D /); ok(ref $obj eq 'A::B'); ok(ref $copy eq 'C::D'); { local $SIG{__WARN__} = \&catchwarn; ok($copy->a_b eq 'a_b'); # triggers autoload for the second time } #warn "$warntxt\n"; ok($warntxt =~ /^Attempt to realize object again: old reference caught at/); ok(ref $copy eq 'A::B'); ok($copy eq $obj); Object-Realize-Later-3.00/t/10isa.t0000644000175000001440000000135615062004410017360 0ustar00markovusers00000000000000#!/usr/bin/env perl # # Test the isa() relations # use strict; use warnings; use Test; use lib 't', '.', 't/testmods', 'testmods'; use C::D::E; BEGIN { plan tests => 23 } my $obj = C::D->new; ok($obj); ok($obj->isa('C')); ok(not $obj->isa('C::D::E')); ok($obj->isa('A::B')); ok($obj->isa('A')); ok(not $obj->isa('GarbleBlaster')); ok(C::D::E->isa('C::D::E')); ok(C::D::E->isa('C::D')); ok(C::D::E->isa('C')); ok(C::D->isa('C::D')); ok(C::D->isa('C')); ok(C->isa('C')); ok(not C::D->isa('GarbleBlaster')); ok(C::D::E->isa('A::B')); ok(C::D::E->isa('A')); ok(C::D->isa('A::B')); ok(C::D->isa('A')); ok(not C->isa('A::B')); ok(not C->isa('A')); ok(not A::B->isa('C::D')); ok(not A::B->isa('C')); ok(not A->isa('C::D')); ok(not A->isa('C')); Object-Realize-Later-3.00/t/60module.t0000644000175000001440000000043115062004410020067 0ustar00markovusers00000000000000#!/usr/bin/env perl # -*- perl -*- # By Slavan Rezic 2003-07-29 use strict; use warnings; use Test; use lib "t/testmods"; use I; BEGIN { plan tests => 3 } my $i_obj = I->new; ok(ref $i_obj, "I"); ok($i_obj->a_method, 42); ok(ref $i_obj, "Another::Class"); Object-Realize-Later-3.00/t/20can.t0000644000175000001440000000175115062004410017345 0ustar00markovusers00000000000000#!/usr/bin/env perl # # Test the can() relations # use strict; use warnings; use Test; use lib 't', '.', 't/testmods', 'testmods'; use C::D::E; BEGIN { plan tests => 26 } my $obj = C::D->new; ok($obj); ok(defined $obj->can('c')); ok(not $obj->can('c_d_e')); ok(defined $obj->can('a_b')); ok(defined $obj->can('a')); ok(defined C::D::E->can('c_d_e')); ok(defined C::D::E->can('c_d')); ok(defined C::D::E->can('c')); ok(defined C::D->can('c_d')); ok(defined C::D->can('c')); ok(defined C->can('c')); ok(defined C::D::E->can('a_b')); ok(defined C::D::E->can('a')); ok(defined C::D->can('a_b')); ok(defined C::D->can('a')); ok(not defined C->can('a_b')); ok(not defined C->can('a')); ok(not defined A::B->can('c_d')); ok(not defined A::B->can('c')); ok(not defined A->can('c_d')); ok(not defined A->can('c')); ok(defined C::D->can('willRealize')); ok(defined C::D::E->can('willRealize')); ok(!defined C->can('willRealize')); ok(C::D->willRealize eq 'A::B'); ok(C::D::E->willRealize eq 'A::B'); Object-Realize-Later-3.00/ChangeLog0000644000175000001440000000662115107407254017602 0ustar00markovusers00000000000000== Revision history for Perl extension Object::Realize::Later. All changes are made by Mark Overmeer unless explicitly stated differently. version 3.00: Wed 19 Nov 19:38:18 CET 2025 Improvements: - add bugtracker to meta - bump version number to refect it depends on Mail-Box 3 version 0.22: Mon 15 Sep 14:43:11 CEST 2025 Changes: - require 5.016 (2012) Fixes: - fix metadata [Mohammad S Anwar] Improvements: - convert to OODoc 3.04 - add .gitignore version 0.21: Wed 24 Jan 09:54:03 CET 2018 Something went wrong with the release upload the GitHUB. Releases of this module are so rare, that I correct it in a no-change release version 0.20: Wed 24 Jan 09:35:33 CET 2018 Improvements: - convert to GIT - publish via GitHUB version 0.19: Fri Jan 24 11:09:06 CET 2014 Improvements: - mv t/99pod.t to xt/ and removed dependency to Test::Pod - changed documentation syntax - minor spell fixes, via Debian rt.cpan.org#92458 [Salvatore Bonaccorso] version 0.18: Fri Jun 8 16:12:16 CEST 2007 - add Test::Pod to pre-requisits. version 0.17: Fri Jun 8 16:09:52 CEST 2007 - added t/pod.t - use oodist to generate documentation version 0.16: Sun Mar 25 17:10:24 CEST 2007 - generate pod with OODoc 0.99 - removed need for version, mkdist, mkdoc - removed README.oodoc version 0.15: Fri Jan 9 11:39:54 CET 2004 - [Renat Araslanow] found many mistakes in the docs. - [Daniel Axelrod] Realized class which can AUTOLOAD should not die on 'unknown method'. version 0.14: Tue Jul 29 2003 - [Slaven Rezic] spotted another buglet which was caused by a missed escape in generated code. version 0.13: Tue Jul 29 16:11:18 CEST 2003 - Module moved to lib/ - Documentation now uses OODoc - [Slaven Rezic] added the feature to specify a class which has a different name than its module. See new(source_module). tests in t/60module.t - forgot to include t/50again.t in the distribution version 0.12 Mon Jul 7 16:20:32 CEST 2003 - [Bjoern Kriews] found a bug in $class->isa($otherclass) version 0.11 Tue Jun 10 11:42:01 CEST 2003 - [Bjoern Kriews] made proxying of class methods work as well, without realization. - [Bjoern Kriews] showed that the method name can be stripped using substr/rindex much faster than by using a regex version 0.10: Thu Dec 12 13:20:33 CET 2002 - Multi-Level laziness now works as well! Problem discover by [Mark Fowler] version 0.09: Sat Nov 16 15:05:04 CET 2002 - Removed reference to (non-existent) Object::Realize::Proxy in man-page. [Liz Mattijsen] - Added location to warn_realization warnings [Slavan Rezic] version 0.08: Wed Nov 14 10:35:18 CET 2001 - Added option `believe_caller' version 0.07: Thu Sep 20 17:44:19 CEST 2001 - Added requirement for Scalar::Util to Makefile.PL spotted by [Andreas Marcel Riechert] - Added README requested by [Andreas Marcel Riechert] version 0.06: Thu Sep 20 16:54:47 CEST 2001 - Fixed serious bug in AUTOLOAD: forgot to consume one arg. version 0.05: Wed Sep 19 14:22:15 CEST 2001 - Removed need for Memoize version 0.02: Mon Sep 10 14:59:22 CEST 2001 - Added willRealize() to question what an object will become. - option `warn' now called `warn_realization'. - When 'becomes' specifies code, the reference was stringified. Fixed and tests added. version 0.01: Sun Aug 12 12:00:46 2001 - original version; created by h2xs 1.20 with options -AX Object::Realize::Later Object-Realize-Later-3.00/xt/0000755000175000001440000000000015107407353016456 5ustar00markovusers00000000000000Object-Realize-Later-3.00/xt/99pod.t0000644000175000001440000000041215062004410017567 0ustar00markovusers00000000000000#!/usr/bin/perl use warnings; use strict; use Test::More; BEGIN { eval "use Test::Pod 1.00"; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; plan skip_all => "devel home uses OODoc" if $ENV{MARKOV_DEVEL}; } all_pod_files_ok(); Object-Realize-Later-3.00/MANIFEST0000644000175000001440000000101415107407353017150 0ustar00markovusers00000000000000ChangeLog MANIFEST Makefile.PL README.md lib/Object/Realize/Later.pm lib/Object/Realize/Later.pod t/10isa.t t/20can.t t/30realize.t t/40autoload.t t/41autoload.t t/50again.t t/60module.t t/testmods/A.pm t/testmods/A/B.pm t/testmods/C.pm t/testmods/C/D.pm t/testmods/C/D/E.pm t/testmods/C/G.pm t/testmods/C/G/H.pm t/testmods/I.pm t/testmods/J.pm xt/99pod.t META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Object-Realize-Later-3.00/lib/0000755000175000001440000000000015107407353016571 5ustar00markovusers00000000000000Object-Realize-Later-3.00/lib/Object/0000755000175000001440000000000015107407353017777 5ustar00markovusers00000000000000Object-Realize-Later-3.00/lib/Object/Realize/0000755000175000001440000000000015107407353021372 5ustar00markovusers00000000000000Object-Realize-Later-3.00/lib/Object/Realize/Later.pod0000644000175000001440000003136715107407352023156 0ustar00markovusers00000000000000=encoding utf8 =head1 NAME Object::Realize::Later - Delayed creation of objects =head1 SYNOPSIS package MyLazyObject; use Object::Realize::Later becomes => 'MyRealObject', realize => 'load'; =head1 DESCRIPTION The C class helps with implementing transparent on demand realization of object data. This is related to the tricks on autoloading of data, the lesser known cousin of autoloading of functionality. On demand realization is all about performance gain. Why should you spent costly time on realizing an object, when the data on the object is never (or not yet) used? In interactive programs, postponed realization may boost start-up: the realization of objects is triggered by the use, so spread over time. =head1 METHODS =head2 Construction =over 4 =item B(Object::Realize::Later %options) When you invoke (C) the C package, it will add a set of methods to your package (see section L). -Option --Default becomes believe_caller false realize source_module warn_realization false warn_realize_again false =over 2 =item becomes => $class Which type will this object become after realization. =item believe_caller => BOOLEAN When a method is called on the un-realized object, the AUTOLOAD checks whether this resolves the need. If not, the realization is not done. However, when realization may result in an object that extends the functionality of the class specified with C, this check must be disabled. In that case, specify C for this option. =item realize => $method|CODE How will transform. If you specify a CODE reference, then this will be called with the lazy-object as first argument, and the requested C<$method> as second. After realization, you may still have your hands on the lazy object on various places. Be sure that your realization method is coping with that, for instance by using L. See examples below. =item source_module => $class if the C<$class> (a package) is included in a file (module) with a different name, then use this argument to specify the file name. The name is expected to be the same as in the C call which would load it. =item warn_realization => BOOLEAN Print a warning message when the realization starts. This is for debugging purposes. =item warn_realize_again => BOOLEAN When an object is realized, the original object -which functioned as a stub- is reconstructed to work as proxy to the realized object. This option will issue a warning when that proxy is used, which means that somewhere in your program there is a variable still holding a reference to the stub. This latter is not problematic at all, although it slows-down each method call. =back =back =head2 Added to YOUR class =over 4 =item $obj-EB() When a method is called which is not available for the lazy object, the AUTOLOAD is called. =item $any-EB($method) Is the specified C<$method> available for the lazy or the realized version of this object? It will return the reference to the code. » example: MyLazyObject->can('lazyWork') # true MyLazyObject->can('realWork') # true my $lazy = MyLazyObject->new; $lazy->can('lazyWork'); # true $lazy->can('realWork'); # true =item $obj-EB() You can force the load by calling this method on your object. It returns the realized object. =item $class-EB($class) Is this object a (sub-)class of the specified C<$class> or can it become a (sub-)class of C<$class>. » example: MyLazyObject->isa('MyRealObject') # true MyLazyObject->isa('SuperClassOfLazy'); # true MyLazyObject->isa('SuperClassOfReal'); # true my $lazy = MyLazyObject->new; $lazy->isa('MyRealObject'); # true $lazy->isa('SuperClassOfLazy'); # true $lazy->isa('SuperClassOfReal'); # true =item $obj-EB() Returns which class will be the realized to follow-up this class. =back =head2 Object::Realize::Later internals The next methods are not exported to the class where the `use' took place. These methods implement the actual realization. =over 4 =item $class-EB(%options) The C<%options> used for C are the values after the class name with C. So this routine implements the actual option parsing. It generates code dynamically, which is then evaluated in the callers name-space. =item $class-EB( $object, [$realized] ) Returns the C<$realized> version of C<$object>, optionally after setting it first. When the method returns C, the realization has not yet taken place or the realized object has already been removed again. =item $class-EB(%options) This method is called when a C<$object->forceRealize()> takes place. It checks whether the realization has been done already (is which case the realized object is returned) =back =head1 DETAILS =head2 About lazy loading There are two ways to implement lazy behaviour: you may choose to check whether you have realized the data in each method which accesses the data, or use the autoloading of data trick. An implementation of the first solution is: sub realize { my $self = shift; return $self unless $self->{_is_realized}; # read the data from file, or whatever $self->{data} = ....; $self->{_is_realized} = 1; $self; } sub getData() { my $self = shift; return $self->realize->{data}; } The above implementation is error-prone, where you can easily forget to call L. The tests cannot cover all ordenings of method-calls to detect the mistakes. The I uses autoloading, and is supported by this package. First we create a stub-object, which will be transformable into a realized object later. This transformation is triggered by AUTOLOAD. This stub-object may contain some methods from the realized object, to reduce the need for realization. The stub will also contain some information which is required for the creation of the real object. C solves the inheritance problems (especially the L and L methods) and supplies the AUTOLOAD method. Class methods which are not defined in the stub object are forwarded as class methods without realization. =head2 Traps Be aware of dangerous traps in the current implementation. These problems appear by having multiple references to the same delayed object. Depending on how the realization is implemented, terrible things can happen. The two versions of realization: =over 4 =item * by reblessing This is the safe version. The realized object is the same object as the delayed one, but reblessed in a different package. When multiple references to the delayed object exists, they will all be updated at the same, because the bless information is stored within the refered variable. =item * by new instance This is the nicest way of realization, but also quite more dangerous. Consider this: package Delayed; use Object::Realize::Later becomes => 'Realized', realize => 'load'; sub new($) {my($class,$v)=@_; bless {label=>$v}, $class} sub setLabel($) {my $self = shift; $self->{label} = shift} sub load() {$_[0] = Realized->new($_[0]->{label}) } package Realized; # file Realized.pm or use use(source_module) sub new($) {my($class,$v)=@_; bless {label=>$v}, $class} sub setLabel($) {my $self = shift; $self->{label} = shift} sub getLabel() {my $self = shift; $self->{label}} package main; my $original = Delayed->new('original'); my $copy = $original; print $original->getLabel; # prints 'original' print ref $original; # prints 'Realized' print ref $copy; # prints 'Delayed' $original->setLabel('changed'); print $original->getLabel; # prints 'changed' print $copy->getLabel; # prints 'original' =back =head2 Examples =head3 Example 1 In the first example, we delay-load a message. On the moment the message is defined, we only take the location. When the data of the message is taken (header or body), the data is autoloaded. package Mail::Message::Delayed; use Object::Realize::Later( becomes => 'Mail::Message::Real', realize => 'loadMessage' ); sub new($) { my ($class, $file) = @_; bless { filename => $file }, $class; } sub loadMessage() { my $self = shift; Mail::Message::Real->new($self->{filename}); } In the main program: package main; use Mail::Message::Delayed; my $msg = Mail::Message::Delayed->new('/home/user/mh/1'); $msg->body->print; # this will trigger autoload. =head3 Example 2 Your realization may also be done by reblessing. In that case to change the type of your object into a different type which stores the same information. Is that right? Are you sure? For simple cases, this may be possible: package Alive; use Object::Realize::Later becomes => 'Dead', realize => 'kill'; sub new() {my $class = shift; bless {@_}, $class} sub jump() {print "Jump!\n"} sub showAntlers() {print "Fight!\n"} sub kill() {bless(shift, 'Dead')} package Dead; sub takeAntlers() {...} In the main program: my $deer = Alive->new(Animal => 'deer'); my $trophy = $deer->takeAntlers(); In this situation, the object (reference) is not changed but is I. There is no danger that the un-realized version of the object is kept somewhere: all variable which know about this partical I see the change. =head3 Example 3 This module is especially useful for larger projects, which there is a need for speed or memory reduction. In this case, you may have an extra overview on which objects have been realized (transformed), and which not. This example is taken from the MailBox modules: The L module tries to boost the access-time to a folder. If you only need the messages of the last day, why shall all be read? So, MailBox only creates an invertory of messages at first. It takes the headers of all messages, but leaves the body (content) of the message in the file. In MailBox' case, the L-object has the choice between a number of L's, one of which has only be prepared to read the body when needed. A code snippet: package Mail::Message; sub new($$) { my ($class, $head, $body) = @_; my $self = bless +{ head => $head, body => $body }, $class; $body->message($self); # tell body about the message } sub head() { $_[0]->{head} } sub body() { $_[0]->{body} } sub loadBody() { my $self = shift; my $body = $self->body; # Catch re-invocations of the loading. If anywhere was still # a reference to the old (unrealized) body of this message, we # return the new-one directly. $body->can('forceRealize') or return $body; # Load the body (change it to anything which really is of # the promised type, or a sub-class of it. my ($lines, $size) = .......; # get the data $self->{body} = Mail::Message::Body::Lines->new($lines, $size, $self); # Return the realized object. return $self->{body}; } package Mail::Message::Body::Lines; use base 'Mail::Message::Body'; sub new($$$) { my ($class, $lines, $size, $message) = @_; bless { lines => $lines, size => $size, message => $message }, $class; } sub size() { $_[0]->{size} } sub lines() { $_[0]->{lines} } sub message() { $_[0]->{message} }; package Mail::Message::Body::Delayed; use Object::Realize::Later becomes => 'Mail::Message::Body', realize => sub {shift->message->loadBody}; sub new($) { my ($class, $size) = @_; bless +{ size => $size }, $class; } sub size() { $_[0]->{size} } sub message(;$) { my $self = shift; @_ ? ($self->{message} = shift) : $self->{messages}; } package main; use Mail::Message (); use Mail::Message::Body::Delayed (); my $body = Mail::Message::Body::Delayed->new(42); my $message = Mail::Message->new($head, $body); print $message->size; # will not trigger realization! print $message->can('lines'); # true, but no realization yet. print $message->lines; # realizes automatically. =head1 SEE ALSO This module is part of Object-Realize-Later version 3.00, built on November 19, 2025. Website: F =head1 LICENSE For contributors see file ChangeLog. This software is copyright (c) 2001-2025 by Mark Overmeer. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Object-Realize-Later-3.00/lib/Object/Realize/Later.pm0000644000175000001440000001067515107407352023007 0ustar00markovusers00000000000000# This code is part of Perl distribution Object-Realize-Later version 3.00. # The POD got stripped from this file by OODoc version 3.05. # For contributors see file ChangeLog. # This software is copyright (c) 2001-2025 by Mark Overmeer. # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later package Object::Realize::Later;{ our $VERSION = '3.00'; } use Carp; use Scalar::Util 'weaken'; use warnings; use strict; no strict 'refs'; #-------------------- #------------ my $named = 'ORL_realization_method'; my $helper = 'ORL_fake_realized'; sub init_code($) { my $args = shift; <{class}; require $args->{source_module}; my \$$helper = bless {}, '$args->{becomes}'; INIT_CODE } sub isa_code($) { my $args = shift; <SUPER::isa(\$what); # real dependency? \$$helper\->isa(\$what); } ISA_CODE } sub can_code($) { my $args = shift; my $becomes = $args->{becomes}; <SUPER::can(\$method) and return \$func; \$func = \$$helper\->can(\$method) or return; # wrap func() to trigger load if needed. sub { ref \$thing ? \$func->(\$thing->forceRealize, \@_) : \$func->(\$thing, \@_) }; } CAN_CODE } sub AUTOLOAD_code($) { my $args = shift; <<'CODE1' . ($args->{believe_caller} ? '' : <can(\$call) || \$$helper->can('AUTOLOAD')) { use Carp; croak "Unknown method \$call called"; } NOT_BELIEVE # forward as class method if required shift and return $args->{becomes}->\$call( \@_ ) unless ref \$_[0]; \$_[0]->forceRealize; my \$made = shift; \$made->\$call(\@_); } CODE2 } sub realize_code($) { my $args = shift; my $pkg = __PACKAGE__; my $argspck = join "'\n , '", %$args; <{warn_realization} ? <<'WARN' : '') . <realize( ref_object => \\\${_[0]}, caller => [ caller 1 ], '$argspck' ); } REALIZE_CODE } sub will_realize_code($) { my $args = shift; my $becomes = $args->{becomes}; <realizationOf($object); if(defined $already && ref $already ne ref $object) { if($args{warn_realize_again}) { my (undef, $filename, $line) = @{$args{caller}}; warn "Attempt to realize object again: old reference caught at $filename line $line.\n" } return ${$args{ref_object}} = $already; } my $loaded = ref $realize ? $realize->($object) : $object->$realize; $loaded->isa($args{becomes}) or warn "Load produces a ".ref($loaded) . " where a $args{becomes} is expected.\n"; ${$args{ref_object}} = $loaded; $class->realizationOf($object, $loaded); } my %realization; sub realizationOf($;$) { my ($class, $object) = (shift, shift); my $unique = "$object"; if(@_) { $realization{$unique} = shift; weaken $realization{$unique}; } $realization{$unique}; } sub import(@) { my ($class, %args) = @_; confess "Require 'becomes'" unless $args{becomes}; confess "Require 'realize'" unless $args{realize}; $args{class} = caller; $args{warn_realization} ||= 0; $args{warn_realize_again} ||= 0; $args{source_module} ||= $args{becomes}; # A reference to code will stringify at the eval below. To solve # this, it is tranformed into a call to a named subroutine. if(ref $args{realize} eq 'CODE') { my $named_method = "$args{class}::$named"; *{$named_method} = $args{realize}; $args{realize} = $named_method; } # Produce the code my $args = \%args; my $eval = init_code($args) . isa_code($args) . can_code($args) . AUTOLOAD_code($args) . realize_code($args) . will_realize_code($args); #warn $eval; # Install the code eval $eval; die $@ if $@; 1; } #-------------------- 1; Object-Realize-Later-3.00/README.md0000644000175000001440000000514015107407254017302 0ustar00markovusers00000000000000# distribution Object-Realize-Later * My extended documentation: * Development via GitHub: * Sponsor me: * Download from CPAN: * Indexed from CPAN: The "Object::Realize::Later" class helps with implementing transparent on demand realization of object data. This is related to the tricks on autoloading of data, the lesser known cousin of autoloading of functionality. On demand realization is all about performance gain. Why should you spent costly time on realizing an object, when the data on the object is never (or not yet) used? In interactive programs, postponed realization may boost start-up: the realization of objects is triggered by the use, so spread over time. It is part of the MailBox collection of modules, and nowhere else, as far as I know. ## Installing On github, you can find the processed version for each release. But the better source is CPAN; to get it installed simply run: ```sh cpan -i Object::Realize::Later ``` ## Development → Release Important to know, is that I use an extension on POD to write the manuals. The "raw" unprocessed version is visible on GitHub. It will run without problems, but does not contain manual-pages. Releases to CPAN are different: "raw" documentation gets removed from the code and translated into real POD and clean HTML. This reformatting is implemented with the OODoc distribution (A name I chose before OpenOffice existed, sorry for the confusion) Clone from github for the "raw" version. For instance, when you want to contribute a new feature. ## Contributing When you want to contribute to this module, you do not need to provide a perfect patch... actually: it is nearly impossible to create a patch which I will merge without modification. Usually, I need to adapt the style of code and documentation to my own strict rules. When you submit an extension, please contribute a set with 1. code 2. code documentation 3. regression tests in t/ **Please note:** When you contribute in any way, you agree to transfer the copyrights to Mark Overmeer (you will get the honors in the code and/or ChangeLog). You also automatically agree that your contribution is released under the same license as this project: licensed as perl itself. ## Copyright and License This project is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See Object-Realize-Later-3.00/META.yml0000644000175000001440000000220615107407353017274 0ustar00markovusers00000000000000--- abstract: 'Delayed realization of objects' author: - 'Mark Overmeer ' build_requires: ExtUtils::MakeMaker: '0' Test::More: '1' Test::Pod: '1' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Object-Realize-Later no_index: directory: - t - inc requires: Scalar::Util: '0' resources: bugtracker: https://github.com/markov2/perl5-Object-Realize-Later/issues homepage: http://perl.overmeer.net/CPAN/ repository: https://github.com/markov2/perl5-Object-Realize-Later.git version: '3.00' x_oodist: email: markov@cpan.org first_year: 2001 generate: - format: pod3 podtail: ~ include: [] oodoc_version: 3.05 parser: pmhead: ~ skip_links: [] syntax: markov raw: publish: ../public_html/object-realize-later/raw release: publish: ../public_html/object-realize-later/source tests: {} use: [] x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Object-Realize-Later-3.00/META.json0000644000175000001440000000412715107407353017450 0ustar00markovusers00000000000000{ "abstract" : "Delayed realization of objects", "author" : [ "Mark Overmeer " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Object-Realize-Later", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "develop" : { "requires" : { "OODoc" : "3.00" } }, "runtime" : { "requires" : { "Scalar::Util" : "0" } }, "test" : { "requires" : { "Test::More" : "1", "Test::Pod" : "1" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/markov2/perl5-Object-Realize-Later/issues" }, "homepage" : "http://perl.overmeer.net/CPAN/", "repository" : { "type" : "git", "url" : "https://github.com/markov2/perl5-Object-Realize-Later.git", "web" : "https://github.com/markov2/perl5-Object-Realize-Later" } }, "version" : "3.00", "x_oodist" : { "email" : "markov@cpan.org", "first_year" : 2001, "generate" : [ { "format" : "pod3", "podtail" : null } ], "include" : [], "oodoc_version" : 3.05, "parser" : { "pmhead" : null, "skip_links" : [], "syntax" : "markov" }, "raw" : { "publish" : "../public_html/object-realize-later/raw" }, "release" : { "publish" : "../public_html/object-realize-later/source" }, "tests" : {}, "use" : [] }, "x_serialization_backend" : "JSON::PP version 4.16" }