changelog for RT#99102 fix
[p5sagit/Devel-Declare.git] / t / method-no-semi.t
CommitLineData
8343b16e 1use strict;
2use warnings;
ce7f7bf0 3use Devel::Declare ();
ce7f7bf0 4
5{
6 package MethodHandlers;
7
8 use strict;
9 use warnings;
b9a35c84 10 use B::Hooks::EndOfScope;
ce7f7bf0 11
12 our ($Declarator, $Offset);
13
14 sub skip_declarator {
15 $Offset += Devel::Declare::toke_move_past_token($Offset);
16 }
17
18 sub skipspace {
19 $Offset += Devel::Declare::toke_skipspace($Offset);
20 }
21
22 sub strip_name {
23 skipspace;
24 if (my $len = Devel::Declare::toke_scan_word($Offset, 1)) {
25 my $linestr = Devel::Declare::get_linestr();
26 my $name = substr($linestr, $Offset, $len);
27 substr($linestr, $Offset, $len) = '';
28 Devel::Declare::set_linestr($linestr);
29 return $name;
30 }
31 return;
32 }
33
34 sub strip_proto {
35 skipspace;
36
37 my $linestr = Devel::Declare::get_linestr();
38 if (substr($linestr, $Offset, 1) eq '(') {
39 my $length = Devel::Declare::toke_scan_str($Offset);
40 my $proto = Devel::Declare::get_lex_stuff();
41 Devel::Declare::clear_lex_stuff();
42 $linestr = Devel::Declare::get_linestr();
43 substr($linestr, $Offset, $length) = '';
44 Devel::Declare::set_linestr($linestr);
45 return $proto;
46 }
47 return;
48 }
49
50 sub shadow {
51 my $pack = Devel::Declare::get_curstash_name;
52 Devel::Declare::shadow_sub("${pack}::${Declarator}", $_[0]);
53 }
54
55 # undef -> my ($self) = shift;
56 # '' -> my ($self) = @_;
57 # '$foo' -> my ($self, $foo) = @_;
58
59 sub make_proto_unwrap {
60 my ($proto) = @_;
61 my $inject = 'my ($self';
62 if (defined $proto) {
63 $inject .= ", $proto" if length($proto);
64 $inject .= ') = @_; ';
65 } else {
66 $inject .= ') = shift;';
67 }
68 return $inject;
69 }
70
71 sub inject_if_block {
72 my $inject = shift;
73 skipspace;
74 my $linestr = Devel::Declare::get_linestr;
75 if (substr($linestr, $Offset, 1) eq '{') {
76 substr($linestr, $Offset+1, 0) = $inject;
77 Devel::Declare::set_linestr($linestr);
78 }
79 }
80
81 sub scope_injector_call {
82 return ' BEGIN { MethodHandlers::inject_scope }; ';
83 }
84
85 sub parser {
86 local ($Declarator, $Offset) = @_;
87 skip_declarator;
88 my $name = strip_name;
89 my $proto = strip_proto;
90 my $inject = make_proto_unwrap($proto);
91 if (defined $name) {
92 $inject = scope_injector_call().$inject;
93 }
94 inject_if_block($inject);
95 if (defined $name) {
96 $name = join('::', Devel::Declare::get_curstash_name(), $name)
97 unless ($name =~ /::/);
98 shadow(sub (&) { no strict 'refs'; *{$name} = shift; });
99 } else {
100 shadow(sub (&) { shift });
101 }
102 }
103
104 sub inject_scope {
b9a35c84 105 on_scope_end {
ce7f7bf0 106 my $linestr = Devel::Declare::get_linestr;
107 my $offset = Devel::Declare::get_linestr_offset;
108 substr($linestr, $offset, 0) = ';';
109 Devel::Declare::set_linestr($linestr);
b9a35c84 110 };
ce7f7bf0 111 }
112}
113
114my ($test_method1, $test_method2, @test_list);
115
116{
117 package DeclareTest;
118
119 sub method (&);
120
121 BEGIN {
122 Devel::Declare->setup_for(
123 __PACKAGE__,
124 { method => { const => \&MethodHandlers::parser } }
125 );
126 }
127
128 method new {
129 my $class = ref $self || $self;
130 return bless({ @_ }, $class);
131 }
132
133 method foo ($foo) {
134 return (ref $self).': Foo: '.$foo;
135 }
136
137 method upgrade(){ # no spaces to make case pathological
138 bless($self, 'DeclareTest2');
139 }
140
141 method DeclareTest2::bar () {
142 return 'DeclareTest2: bar';
143 }
144
145 $test_method1 = method {
146 return join(', ', $self->{attr}, $_[1]);
147 };
148
149 $test_method2 = method ($what) {
150 return join(', ', ref $self, $what);
151 };
152
153 method main () { return "main"; }
154
155 @test_list = (method { 1 }, sub { 2 }, method () { 3 }, sub { 4 });
156
157}
158
b52072dc 159use Test::More;
ce7f7bf0 160
161my $o = DeclareTest->new(attr => "value");
162
163isa_ok($o, 'DeclareTest');
164
165is($o->{attr}, 'value', '@_ args ok');
166
167is($o->foo('yay'), 'DeclareTest: Foo: yay', 'method with argument ok');
168
169is($o->main, 'main', 'declaration of package named method ok');
170
171$o->upgrade;
172
173isa_ok($o, 'DeclareTest2');
174
175is($o->bar, 'DeclareTest2: bar', 'absolute method declaration ok');
176
177is($o->$test_method1('no', 'yes'), 'value, yes', 'anon method with @_ ok');
178
179is($o->$test_method2('this'), 'DeclareTest2, this', 'anon method with proto ok');
180
181is_deeply([ map { $_->() } @test_list ], [ 1, 2, 3, 4], 'binding ok');
b52072dc 182
183done_testing;