excluded blib
[urisagit/Stem.git] / Cookbook / World4.pm
1 package World4 ;
2
3 use strict;
4
5 my $attr_spec =
6 [
7         {
8                 'name'          => 'planet',
9                 'default'       => 'uranus',
10         },
11 ];
12
13 sub new {
14
15         my( $class ) = shift ;
16         my $self = Stem::Class::parse_args( $attr_spec, @_ ) ;
17
18         return ( $self );
19 }
20
21 # based on who was the receiver of the message
22 # we return with the appropriate response
23
24 sub hello_cmd {
25
26         my( $self ) = @_;
27
28         return "Hello world from $self->{'planet'}!\n";
29 }
30
31 sub name_cmd {
32
33         my ( $self, $msg ) = @_ ;
34
35         my $data = $msg->data() ;
36
37         return unless $data ;
38
39         $self->{'planet'} = ${$data} ;
40
41         return ;
42 }
43
44
45
46
47 =head1 Stem Cookbook - World3
48
49 =head1 NAME
50
51 World3 - Mixing class and object B<Stem> cells.
52
53 =head1 DESCRIPTION
54
55 This is an extension of the B<Stem Cookbook Part 1 & Stem Cookbook Part 2> where
56 we talked about the creation of B<Stem> class and object cells.  In
57 this example, we take the idea of a class cell and an object cell
58 and combine them into a single B<Stem> module.  We then have
59 the ability of creating multiple cells (registered objects)
60 with their own private data and at the same time have a
61 class cell to manage a global resource.
62
63 =head1 CREATING THE CELL
64
65 The following lists the requirements for creating a B<Stem>
66 object level cell:
67
68 =over 4
69
70 =item *
71
72 An attribute specification
73
74 =item *
75
76 An object constructor
77
78 =item *
79
80 A class registration
81
82 =back
83
84 =head2 CHANGES FROM PART 1 AND PART 2
85
86 Most of the code from Part 2 and Part 1 remain the same.  We keep
87 the same attribute specification as well as the same object cell
88 constructor (except for a slight modification, see below).
89 You remember from Part 1 that we created a class level
90 B<Stem> cell from the configuration file,
91
92 [
93         class   =>      'World1',
94         name    =>      'solar_system',
95
96 ]
97
98 Because we do not have an args field, it means we are creating a
99 class cell.  In this example, we want a class cell to be created
100 as a global resource only if an object cell is created.  If the
101 class cell is supposed to manage global information for object
102 cells there is no need to create one if an object cell does not
103 exist.  To get this type of behavior, we register the class cell
104 from within the B<Stem> module rather than from the configuration
105 file,
106
107     Stem::Route::register_class( __PACKAGE__, 'solar_system' );
108
109 This line (World3.pm, line 5) effectively registers the class cell
110 with the B<Stem> message routing system using the package name
111 and a name we wish to register the cell as.
112
113 We keep referring to the class cell as a global resource, so in
114 this example we create a global resource that the class cell will
115 manage,
116
117     my @objects = ();
118
119 On line 16 in World3.pm we create an array named objects that will
120 be used to hold a reference to each of the World3 cell objects that are
121 created from the configuration file (Note that this is not a
122 requirement for creating this module and is just used as an example.
123 It could have just as easily been a simple scalar, a hash, some
124 other kind of object, or even nothing!).
125
126 In order to populate this array of the objects that are created from
127 the configuration file, we simply add them to the array when they
128 are created in the object cell constructor,
129
130     push @objects, $self;
131
132 This simply pushes the reference to the newely created World3 object cell
133 onto the objects array.  The class cell can now be used to represent the
134 World3 object cells as a group.
135
136 The next modification exists in the hello_cmd subroutine.  We need a way
137 to distiguish whether or not a message is being sent to an object cell
138 as opposed to a class cell.  As you might recall, the perl I<ref> function
139 is used to determine if a scalar refers to a reference or a normal
140 scalar value.  If a subroutine is invoked from an object, the first
141 argument of the subroutine will be a reference to the object itself,
142 otherwise, it will be the string name of the class from which the subroutine
143 belongs.  The following code demonstrates a new hello_cmd subroutine
144 that makes this distinction and performs accordingly,
145
146 sub hello_cmd {
147
148     my ($class) = @_;
149
150     return "Hello world from $class->{'planet'}\n" if ref $class;
151
152     my $response_string = '';
153     foreach my $obj (@objects) {
154
155       $response_string .= "Hello world from $obj->{'planet'}\n";
156     }
157
158     return $response_string;
159 }
160
161 As you can see, we return the familiar "Hello world from $class->{'planet'}"
162 string, but this time we check to make sure $class is a reference before
163 returning the string.  If it is not, we know that the hello_cmd was invoked
164 from a message that was intended for the class cell.  If this is the case, we
165 concatenate a "Hello, World ..." string for each of the Hello3 object cells
166 that were stored in the objects array and send that string as a response
167 message to the sender.
168
169 =head1 SEE ALSO
170
171 F<Stem Cookbook Part 1>
172
173 F<Stem Cookbook Part 2>
174
175 F<Hello3 Module>
176
177 =cut
178
179 1;