From: Rhesa Rozendaal Date: Wed, 22 Oct 2008 22:09:49 +0000 (+0000) Subject: improvements from MX::MS and MX::Declare X-Git-Tag: 0.005000~47^2~1 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=b0a896321dc9c1d61dc59c4c1b32cb8f920123ca;p=p5sagit%2FDevel-Declare.git improvements from MX::MS and MX::Declare --- diff --git a/lib/Devel/Declare/Context/Simple.pm b/lib/Devel/Declare/Context/Simple.pm index 548aa45..7b0f740 100644 --- a/lib/Devel/Declare/Context/Simple.pm +++ b/lib/Devel/Declare/Context/Simple.pm @@ -1,10 +1,11 @@ package Devel::Declare::Context::Simple; use Devel::Declare (); -use Scope::Guard; +use B::Hooks::EndOfScope; use strict; use warnings; +sub DEBUG { warn "@_" } sub new { my $class = shift; bless {@_}, $class; @@ -39,6 +40,8 @@ sub strip_name { Devel::Declare::set_linestr($linestr); return $name; } + + $self->skipspace; return; } @@ -47,15 +50,16 @@ sub strip_proto { $self->skipspace; my $linestr = Devel::Declare::get_linestr(); - if (substr( $linestr, $self->offset, 1 ) eq '(') { - my $length = Devel::Declare::toke_scan_str( $self->offset ); + if (substr($linestr, $self->offset, 1) eq '(') { + my $length = Devel::Declare::toke_scan_str($self->offset); my $proto = Devel::Declare::get_lex_stuff(); Devel::Declare::clear_lex_stuff(); $linestr = Devel::Declare::get_linestr(); - substr( $linestr, $self->offset, $length ) = ''; + substr($linestr, $self->offset, $length) = ''; Devel::Declare::set_linestr($linestr); return $proto; } + return; } @@ -70,30 +74,37 @@ sub shadow { } sub inject_if_block { - my $self = shift; + my $self = shift; my $inject = shift; + my $before = shift || ''; + $self->skipspace; + my $linestr = Devel::Declare::get_linestr; - if (substr( $linestr, $self->offset, 1 ) eq '{') { - substr( $linestr, $self->offset + 1, 0 ) = $inject; + if (substr($linestr, $self->offset, 1) eq '{') { + substr($linestr, $self->offset + 1, 0) = $inject; + substr($linestr, $self->offset, 0) = $before; Devel::Declare::set_linestr($linestr); } } sub scope_injector_call { - return ' BEGIN { ' . __PACKAGE__ . '::inject_scope }; '; + my $self = shift; + my $inject = shift || ''; + return ' BEGIN { ' . ref($self) . "->inject_scope('${inject}') }; "; } sub inject_scope { - my $self = shift; - $^H |= 0x120000; - $^H{DD_METHODHANDLERS} = Scope::Guard->new(sub { + my $class = shift; + my $inject = shift; + on_scope_end { my $linestr = Devel::Declare::get_linestr; + return unless defined $linestr; my $offset = Devel::Declare::get_linestr_offset; - substr( $linestr, $offset, 0 ) = ';'; + substr( $linestr, $offset, 0 ) = ';' . $inject; Devel::Declare::set_linestr($linestr); - }); + }; } 1; - +# vi:sw=2 ts=2 diff --git a/lib/Devel/Declare/MethodInstaller/Simple.pm b/lib/Devel/Declare/MethodInstaller/Simple.pm index 4167116..96fa88c 100644 --- a/lib/Devel/Declare/MethodInstaller/Simple.pm +++ b/lib/Devel/Declare/MethodInstaller/Simple.pm @@ -22,6 +22,53 @@ sub install_methodhandler { ); } +sub strip_attrs { + my $self = shift; + $self->skipspace; + + my $Offset = $self->offset; + my $linestr = Devel::Declare::get_linestr; + my $attrs = ''; + + if (substr($linestr, $Offset, 1) eq ':') { + while (substr($linestr, $Offset, 1) ne '{') { + if (substr($linestr, $Offset, 1) eq ':') { + substr($linestr, $Offset, 1) = ''; + Devel::Declare::set_linestr($linestr); + + $attrs .= ':'; + } + + $self->skipspace; + $Offset = $self->offset; + $linestr = Devel::Declare::get_linestr(); + + if (my $len = Devel::Declare::toke_scan_word($Offset, 0)) { + my $name = substr($linestr, $Offset, $len); + substr($linestr, $Offset, $len) = ''; + Devel::Declare::set_linestr($linestr); + + $attrs .= " ${name}"; + + if (substr($linestr, $Offset, 1) eq '(') { + my $length = Devel::Declare::toke_scan_str($Offset); + my $arg = Devel::Declare::get_lex_stuff(); + Devel::Declare::clear_lex_stuff(); + $linestr = Devel::Declare::get_linestr(); + substr($linestr, $Offset, $length) = ''; + Devel::Declare::set_linestr($linestr); + + $attrs .= "(${arg})"; + } + } + } + + $linestr = Devel::Declare::get_linestr(); + } + + return $attrs; +} + sub parser { my $self = shift; $self->init(@_); @@ -29,12 +76,13 @@ sub parser { $self->skip_declarator; my $name = $self->strip_name; my $proto = $self->strip_proto; + my $attrs = $self->strip_attrs; my @decl = $self->parse_proto($proto); my $inject = $self->inject_parsed_proto(@decl); if (defined $name) { $inject = $self->scope_injector_call() . $inject; } - $self->inject_if_block($inject); + $self->inject_if_block($inject, $attrs ? "sub ${attrs} " : ''); if (defined $name) { my $pkg = $self->get_curstash_name; $name = join( '::', $pkg, $name ) diff --git a/t/methinstaller-simple.t b/t/methinstaller-simple.t index 11f4e47..c588bea 100644 --- a/t/methinstaller-simple.t +++ b/t/methinstaller-simple.t @@ -66,6 +66,7 @@ my ($test_method1, $test_method2, @test_list); @test_list = (method { 1 }, sub { 2 }, method () { 3 }, sub { 4 }); + method leftie :lvalue { $self->{attributes} }; } use Test::More 'no_plan'; @@ -80,6 +81,9 @@ is($o->foo('yay'), 'DeclareTest: Foo: yay', 'method with argument ok'); is($o->main, 'main', 'declaration of package named method ok'); +$o->leftie = 'attributes work'; +is($o->leftie, 'attributes work', 'code attributes intact'); + $o->upgrade; isa_ok($o, 'DeclareTest2'); @@ -92,19 +96,3 @@ is($o->$test_method2('this'), 'DeclareTest2, this', 'anon method with proto ok') is_deeply([ map { $_->() } @test_list ], [ 1, 2, 3, 4], 'binding ok'); -__END__ -/home/rhesa/perl/t/methinstaller-simple.... -ok 1 - The object isa DeclareTest -ok 2 - @_ args ok -ok 3 - method with argument ok -ok 4 - declaration of package named method ok -ok 5 - The object isa DeclareTest2 -ok 6 - absolute method declaration ok -ok 7 - anon method with @_ ok -ok 8 - anon method with proto ok -ok 9 - binding ok -1..9 -ok -All tests successful. -Files=1, Tests=9, 0 wallclock secs ( 0.04 usr 0.00 sys + 0.05 cusr 0.00 csys = 0.09 CPU) -Result: PASS