File Coverage

blib/lib/Rubyish/Attribute.pm
Criterion Covered Total %
statement 77 81 95.0
branch 10 12 83.3
condition n/a
subroutine 21 21 100.0
pod 3 7 42.8
total 111 121 91.7


line stmt bran cond sub pod time code
1             package Rubyish::Attribute;
2 5     5   115674 use 5.010;
  5         21  
  5         231  
3              
4             =head1 NAME
5              
6             Rubyish::Attribute - ruby-like accessor builder: attr_accessor, attr_writer and attr_reader.
7              
8             =cut
9              
10 5     5   10478 use Want;
  5         10570  
  5         1223  
11              
12             sub import {
13 5     5   40 my $caller = caller;
14 5         14 for (qw(attr_accessor attr_reader attr_writer)) {
15 15         21 *{$caller . "::" . $_} = *{$_};
  15         134  
  15         28  
16             }
17 5     5   4087 eval qq{package $caller; use PadWalker qw(peek_my);};
  5         4219  
  5         459  
  5         364  
18             }
19              
20              
21             =head1 VERSION
22              
23             This document is for version 1.2
24              
25             =cut
26              
27             our $VERSION = "1.2";
28              
29             =head1 SYNOPSIS
30              
31             #!/usr/bin/env perl
32            
33             use 5.010;
34              
35             use strict;
36             use warnings;
37              
38             {
39             package Animal;
40            
41             use Rubyish::Attribute;
42             # import attr_accessor, attr_writer and attr_reader
43              
44             BEGIN {
45             attr_accessor "name", "color", "type";
46             }
47             # pass a list as the only one parameter
48             # invoke it in compile time to avoid using parenthesis when using instance variable as below
49              
50             # then create a constructer based on hashref
51             sub new {
52             $class = shift;
53             bless {}, $class;
54             }
55              
56             sub rename_as {
57             my ($self, $new_name) = @_;
58             __name__ = $new_name;
59              
60             # __name__ is accurately a lvalue subroutine &__name__() which refer to $self->{name}
61             # now it looks like a instance variable.
62             }
63              
64             1;
65             }
66            
67             $dogy = Animal->new()->name("rock")
68             ->color("black")->type("unknown");
69             # new Animal with three attribute
70              
71             say $dogy->name; #=> rock
72             say $dogy->color; #=> black
73             say $dogy->type; #=> unknown
74              
75             =head1 FUNCTIONS
76              
77             =head2 attr_accessor(@list)
78              
79             attr_accessor provides getters double as setters.
80             Because all setter return instance itself, now we can manipulate object in ruby way more than ruby.
81              
82             attr_accessor qw(name color type master)
83             $dogy = Animal->new()->name("lucky")->color("white")
84             ->type("unknown")->master("shelling");
85              
86             Each attribute could be read by getter as showing in synopsis.
87              
88             =cut
89              
90              
91             sub make_accessor {
92 4     4 0 8 my $field = shift;
93             return sub {
94 2     2   449 my ($self, $arg) = @_;
95 2 100       7 if ($arg) {
96 1         6 $self->{$field} = $arg;
97 1         4 $self;
98             }
99             else {
100 1         8 $self->{$field};
101             }
102             }
103 4         22 }
104              
105             sub attr_accessor {
106 5     5   52 no strict;
  5         15  
  5         979  
107 4     4 1 17 my $package = caller;
108 4         12 for my $field (@_) {
109 4         13 *{"${package}::${field}"} = make_accessor($field);
  4         23  
110 4         18 make_instance_vars_accessor($package, $field);
111             }
112             }
113              
114             =head2 attr_reader(@list)
115              
116             attr_reader create only getter for the class you call it
117              
118             attr_reader qw(name) # pass a list
119             $dogy = Animal->new({name => "rock"}) # if we write initialize function in constructor
120             $dogy->name() #=> rock
121             $dogy->name("jack") #=> undef (with warn msg)
122              
123             =cut
124              
125             sub make_reader {
126 4     4 0 8 my $field = shift;
127             return sub {
128 2     2   1197 my ($self, $arg) = @_;
129 2 100       6 if ($arg) {
130 1         91 warn "error - $field is only reader\n";
131 1         5 return; # because no writer
132             }
133             else {
134 1         10 $self->{$field};
135             }
136             }
137 4         16 };
138              
139             sub attr_reader {
140 5     5   26 no strict;
  5         9  
  5         914  
141 4     4 1 17 my $package = caller;
142 4         10 for my $field (@_) {
143 4         12 *{"${package}::${field}"} = make_reader($field);
  4         25  
144 4         12 make_instance_vars_accessor($package, $field);
145             }
146             }
147              
148             =head2 attr_writer(@list)
149              
150             attr_writer create only setter for the class you call it.
151              
152             attr_writer qw(name) # pass a list
153             $dogy = Animal->new()->name("lucky") # initialize and set and get instance itself
154             $dogy->name("jack") #=> instance itself
155             $dogy->name #=> undef (with warn msg)
156              
157             =cut
158              
159             sub make_writer {
160 4     4 0 9 my $field = shift;
161             return sub {
162 2     2   1086 my ($self, $arg) = @_;
163 2 100       7 if ($arg) {
164 1         3 $self->{$field} = $arg;
165 1         8 $self;
166             }
167             else {
168 1         73 warn "error - $field is only writer\n";
169 1         24 return; # because no reader
170             }
171             }
172 4         18 }
173              
174             sub attr_writer {
175 5     5   25 no strict;
  5         7  
  5         459  
176 4     4 1 17 my $package = caller;
177 4         7 for my $field (@_) {
178 4         10 *{"${package}::${field}"} = make_writer($field);
  4         18  
179 4         11 make_instance_vars_accessor($package, $field);
180             }
181             }
182              
183             sub make_instance_vars_accessor {
184 5     5   23 no strict;
  5         9  
  5         455  
185 12     12 0 19 my ($package, $field) = @_;
186 12 50   1   1842 eval qq|package $package;
  1 100   3   39  
  0 50   1   0  
  0         0  
  1         3  
  1         30  
  3         1344  
  1         11  
  1         171  
  2         3  
  2         34  
  1         41  
  0         0  
  0         0  
  1         2  
  1         11  
187             sub __${field}__ : lvalue {
188             unless ( caller eq $package ) {
189             require Carp;
190             Carp::croak "__${field}__ is a protected method of $package!";
191             }
192             \${ peek_my(1)->{\'\$self\'} }->{$field};
193             }
194             |;
195             }
196              
197             =head1 DEPENDENCE
198              
199             L
200              
201             =head1 SEE ALSO
202              
203             L, L, L, L
204              
205             L
206              
207             L chinese introduction
208              
209             =head1 AUTHOR
210              
211             shelling
212              
213             gugod
214              
215             =head2 acknowledgement
216              
217             Thanks to gugod providing testing script and leading me on the way of perl
218              
219             =head1 REPOSITORY
220              
221             host: L
222              
223             checkout: git clone git://github.com/shelling/rubyish-attribute.git
224              
225             =head1 BUGS
226              
227             please report bugs to or
228              
229             =head1 COPYRIGHT & LICENCE
230              
231             Copyright (C) 2008 shelling, gugod, all rights reserved.
232              
233             Release under MIT (X11) Lincence.
234              
235             =cut
236              
237             1;
238