Object-Realize-Later-0.21/0000755000175000001440000000000013232046045016015 5ustar00markovusers00000000000000Object-Realize-Later-0.21/t/0000755000175000001440000000000013232046045016260 5ustar00markovusers00000000000000Object-Realize-Later-0.21/t/60module.t0000644000175000001440000000043113232042365020077 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-0.21/t/40autoload.t0000644000175000001440000000241613232042365020425 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-0.21/t/testmods/0000755000175000001440000000000013232046045020122 5ustar00markovusers00000000000000Object-Realize-Later-0.21/t/testmods/J.pm0000644000175000001440000000051213232046044020646 0ustar00markovusers00000000000000# Copyrights 2001-2018 by [Mark Overmeer]. # For other contributors see ChangeLog. # See the manual pages for details on the licensing terms. # Pod stripped from pm file by OODoc 2.02. package J; use vars '$VERSION'; $VERSION = '0.21'; package Another::Class; use vars '$VERSION'; $VERSION = '0.21'; sub a_method { 42 } 1; Object-Realize-Later-0.21/t/testmods/A/0000755000175000001440000000000013232046045020302 5ustar00markovusers00000000000000Object-Realize-Later-0.21/t/testmods/A/B.pm0000644000175000001440000000046213232046044021022 0ustar00markovusers00000000000000# Copyrights 2001-2018 by [Mark Overmeer]. # For other contributors see ChangeLog. # See the manual pages for details on the licensing terms. # Pod stripped from pm file by OODoc 2.02. use strict; use warnings; package A::B; use vars '$VERSION'; $VERSION = '0.21'; use base 'A'; sub a_b() {'a_b'} 1; Object-Realize-Later-0.21/t/testmods/C/0000755000175000001440000000000013232046045020304 5ustar00markovusers00000000000000Object-Realize-Later-0.21/t/testmods/C/D.pm0000644000175000001440000000072213232046044021025 0ustar00markovusers00000000000000# Copyrights 2001-2018 by [Mark Overmeer]. # For other contributors see ChangeLog. # See the manual pages for details on the licensing terms. # Pod stripped from pm file by OODoc 2.02. package C::D; use vars '$VERSION'; $VERSION = '0.21'; 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-0.21/t/testmods/C/G/0000755000175000001440000000000013232046045020472 5ustar00markovusers00000000000000Object-Realize-Later-0.21/t/testmods/C/G/H.pm0000644000175000001440000000047413232046044021223 0ustar00markovusers00000000000000# Copyrights 2001-2018 by [Mark Overmeer]. # For other contributors see ChangeLog. # See the manual pages for details on the licensing terms. # Pod stripped from pm file by OODoc 2.02. use warnings; use strict; package C::G::H; use vars '$VERSION'; $VERSION = '0.21'; use base 'C::G'; sub c_g_h() {'c_g_h'} 1; Object-Realize-Later-0.21/t/testmods/C/D/0000755000175000001440000000000013232046045020467 5ustar00markovusers00000000000000Object-Realize-Later-0.21/t/testmods/C/D/E.pm0000644000175000001440000000047413232046044021215 0ustar00markovusers00000000000000# Copyrights 2001-2018 by [Mark Overmeer]. # For other contributors see ChangeLog. # See the manual pages for details on the licensing terms. # Pod stripped from pm file by OODoc 2.02. use warnings; use strict; package C::D::E; use vars '$VERSION'; $VERSION = '0.21'; use base 'C::D'; sub c_d_e() {'c_d_e'} 1; Object-Realize-Later-0.21/t/testmods/C/G.pm0000644000175000001440000000071313232046044021030 0ustar00markovusers00000000000000# Copyrights 2001-2018 by [Mark Overmeer]. # For other contributors see ChangeLog. # See the manual pages for details on the licensing terms. # Pod stripped from pm file by OODoc 2.02. package C::G; use vars '$VERSION'; $VERSION = '0.21'; 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-0.21/t/testmods/C.pm0000644000175000001440000000055013232046044020641 0ustar00markovusers00000000000000# Copyrights 2001-2018 by [Mark Overmeer]. # For other contributors see ChangeLog. # See the manual pages for details on the licensing terms. # Pod stripped from pm file by OODoc 2.02. use strict; use warnings; package C; use vars '$VERSION'; $VERSION = '0.21'; use overload '""' => sub { ref(shift) }; sub new() { bless {}, shift } sub c() { 'c' } 1; Object-Realize-Later-0.21/t/testmods/I.pm0000644000175000001440000000064513232046044020654 0ustar00markovusers00000000000000# Copyrights 2001-2018 by [Mark Overmeer]. # For other contributors see ChangeLog. # See the manual pages for details on the licensing terms. # Pod stripped from pm file by OODoc 2.02. package I; use vars '$VERSION'; $VERSION = '0.21'; use Object::Realize::Later realize => sub { bless {}, 'Another::Class' }, becomes => 'Another::Class', source_module => 'J'; sub new { bless {}, shift } 1; Object-Realize-Later-0.21/t/testmods/A.pm0000644000175000001440000000043413232046044020640 0ustar00markovusers00000000000000# Copyrights 2001-2018 by [Mark Overmeer]. # For other contributors see ChangeLog. # See the manual pages for details on the licensing terms. # Pod stripped from pm file by OODoc 2.02. use strict; use warnings; package A; use vars '$VERSION'; $VERSION = '0.21'; sub a() {'a'} 1; Object-Realize-Later-0.21/t/41autoload.t0000644000175000001440000000241413232042365020424 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-0.21/t/10isa.t0000644000175000001440000000135613232042365017370 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-0.21/t/30realize.t0000644000175000001440000000156513232042365020253 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-0.21/t/20can.t0000644000175000001440000000175113232042365017355 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-0.21/t/50again.t0000644000175000001440000000136113232042365017673 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-0.21/Changes0000644000175000001440000000541213232042365017313 0ustar00markovusers00000000000000Revision history for Perl extension Object::Realize::Later. version 0.20: Improvements: - share podtail with MailBox 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-0.21/MANIFEST0000644000175000001440000000103313232046045017143 0ustar00markovusers00000000000000ChangeLog Changes MANIFEST Makefile.PL README 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-0.21/xt/0000755000175000001440000000000013232046045016450 5ustar00markovusers00000000000000Object-Realize-Later-0.21/xt/99pod.t0000644000175000001440000000041213232042365017577 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-0.21/lib/0000755000175000001440000000000013232046045016563 5ustar00markovusers00000000000000Object-Realize-Later-0.21/lib/Object/0000755000175000001440000000000013232046045017771 5ustar00markovusers00000000000000Object-Realize-Later-0.21/lib/Object/Realize/0000755000175000001440000000000013232046045021364 5ustar00markovusers00000000000000Object-Realize-Later-0.21/lib/Object/Realize/Later.pm0000644000175000001440000001116613232046044022775 0ustar00markovusers00000000000000# Copyrights 2001-2018 by [Mark Overmeer]. # For other contributors see ChangeLog. # See the manual pages for details on the licensing terms. # Pod stripped from pm file by OODoc 2.02. # This code is part of distribution Object-Realize-Later. Meta-POD processed # with OODoc into POD and HTML manual-pages. See README.md # Copyright Mark Overmeer. Licensed under the same terms as Perl itself. package Object::Realize::Later; use vars '$VERSION'; $VERSION = '0.21'; 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; warn "Load produces a ".ref($loaded) . " where a $args{becomes} is expected.\n" unless $loaded->isa($args{becomes}); ${$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-0.21/lib/Object/Realize/Later.pod0000644000175000001440000003137113232046044023143 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 realize source_module warn_realization warn_realize_again =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 true 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 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 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 $obj-EB($method) =item Object::Realize::Later-EB($method) Is the specified $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 Object::Realize::Later-EB($class) Is this object a (sub-)class of the specified $class or can it become a (sub-)class of $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 Object::Realize::Later-EB(%options) The %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 Object::Realize::Later-EB( $object, [$realized] ) Returns the $realized version of $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 Object::Realize::Later-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() { shift->{head} } sub body() { shift->{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. return $body unless $body->can('forceRealize'); # 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() { shift->{size} } sub lines() { shift->{lines} } sub message() { shift->{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() { shift->{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 distribution version 0.21, built on January 24, 2018. Website: F =head1 LICENSE Copyrights 2001-2018 by [Mark Overmeer]. For other contributors see ChangeLog. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See F Object-Realize-Later-0.21/README.md0000644000175000001440000000511713232042365017301 0ustar00markovusers00000000000000# distribution Object-Realize-Later * My extended documentation: * Development via GitHub: * Download from CPAN: * Indexed from CPAN: and 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. ## 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. 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 ``` ## 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-0.21/ChangeLog0000644000175000001440000000611213232046044017566 0ustar00markovusers00000000000000== Revision history for Perl extension Object::Realize::Later. All changes are made by Mark Overmeer unless explicitly stated differently. 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-0.21/README0000644000175000001440000000152013232042365016674 0ustar00markovusers00000000000000=== README for Object-Realize-Later version 0.20 = Generated on Wed Jan 24 09:33:57 2018 by OODoc 2.02 There are various ways to install this module: (1) if you have a command-line, you can do: perl -MCPAN -e 'install ' (2) if you use Windows, have a look at http://ppm.activestate.com/ (3) if you have downloaded this module manually (as root/administrator) gzip -d Object-Realize-Later-0.20.tar.gz tar -xf Object-Realize-Later-0.20.tar cd Object-Realize-Later-0.20 perl Makefile.PL make # optional make test # optional make install For usage, see the included manual-pages or http://search.cpan.org/dist/Object-Realize-Later-0.20/ Please report problems to http://rt.cpan.org/Dist/Display.html?Queue=Object-Realize-Later Object-Realize-Later-0.21/Makefile.PL0000644000175000001440000000212313232046044017764 0ustar00markovusers00000000000000use ExtUtils::MakeMaker; require 5.008; WriteMakefile ( NAME => 'Object::Realize::Later' , VERSION => '0.21' , PREREQ_PM => { Scalar::Util => 0.0 } , AUTHOR => 'Mark Overmeer' , ABSTRACT => 'Delayed realization of objects' , LICENSE => 'perl' , META_MERGE => { 'meta-spec' => { version => 2 } , resources => { repository => { type => 'git' , url => 'https://github.com/markov2/perl5-Object-Realize-Later.git' , web => 'https://github.com/markov2/perl5-Object-Realize-Later' } } , homepage => 'http://perl.overmeer.net/CPAN/' , license => [ 'http://dev.perl.org/licenses/' ] } ); ### used by oodist during production of distribution sub MY::postamble { <<'__POSTAMBLE' } # for DIST RAWDIR = ../public_html/object-realize-later/raw DISTDIR = ../public_html/object-realize-later/source LICENSE = perl # for POD FIRST_YEAR = 2001 EMAIL = markov@cpan.org WEBSITE = http://perl.overmeer.net/CPAN/ __POSTAMBLE Object-Realize-Later-0.21/META.yml0000644000175000001440000000124513232046045017270 0ustar00markovusers00000000000000--- abstract: 'Delayed realization of objects' author: - 'Mark Overmeer' build_requires: ExtUtils::MakeMaker: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.3, CPAN::Meta::Converter version 2.150010' license: unknown 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: repository: https://github.com/markov2/perl5-Object-Realize-Later.git version: '0.21' x_homepage: http://perl.overmeer.net/CPAN/ x_serialization_backend: 'CPAN::Meta::YAML version 0.011' Object-Realize-Later-0.21/META.json0000644000175000001440000000230713232046045017440 0ustar00markovusers00000000000000{ "abstract" : "Delayed realization of objects", "author" : [ "Mark Overmeer" ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.3, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5", "unknown" ], "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" } }, "runtime" : { "requires" : { "Scalar::Util" : "0" } } }, "release_status" : "stable", "resources" : { "repository" : { "type" : "git", "url" : "https://github.com/markov2/perl5-Object-Realize-Later.git", "web" : "https://github.com/markov2/perl5-Object-Realize-Later" } }, "version" : "0.21", "x_homepage" : "http://perl.overmeer.net/CPAN/", "x_serialization_backend" : "JSON::PP version 2.94" }