Commit | Line | Data |
4536f655 |
1 | package World3 ; |
2 | |
3 | use strict; |
4 | |
5 | # This is the specification table that describes the attributes for |
6 | # this object. The only attribute is the name of the planet and it |
7 | # defaults to 'X' |
8 | |
9 | my $attr_spec = |
10 | [ |
11 | { |
12 | 'name' => 'planet', |
13 | 'default' => 'X', |
14 | }, |
15 | ]; |
16 | |
17 | # The new method constructs the object which is returned to the |
18 | # configuration system where it will be registered. |
19 | |
20 | sub new { |
21 | |
22 | my( $class ) = shift ; |
23 | |
24 | # The call to parse_args takes the attribute specification and the |
25 | # configuration arguments and creates a cell object |
26 | |
27 | my $self = Stem::Class::parse_args( $attr_spec, @_ ) ; |
28 | |
29 | return ( $self ); |
30 | } |
31 | |
32 | # This command method is similar to the one in World1 except we |
33 | # we use the object argument and return the name from that object. |
34 | |
35 | sub hello_cmd { |
36 | |
37 | my( $self ) = @_; |
38 | |
39 | return "Hello world from $self->{'planet'}!\n"; |
40 | } |
41 | |
42 | =head1 Stem Cookbook - World3 |
43 | |
44 | =head1 NAME |
45 | |
46 | World2 - A simple object level B<Stem> cell. |
47 | |
48 | =head1 DESCRIPTION |
49 | |
50 | This cell is an extension of the B<World1> cell. In this example, |
51 | instead of a single class cell with a fixed response value, we now can |
52 | create multiple cells (registered objects) each with their own private |
53 | data. The world_cmd method will return the planet's name stored in the |
54 | cell. |
55 | |
56 | =head1 CREATING THE CELL |
57 | |
58 | This cell illustrates the basic way to construct objects in Stem. |
59 | |
60 | =over 4 |
61 | |
62 | =item * |
63 | |
64 | A specification table is required to describe the allowed attributes |
65 | of the object. This is a list of hashes with each hash describing one |
66 | attribute. It is usually defined in a file lexical variable commonly |
67 | named $attr_spec which is assigned an anonymous list of attribute |
68 | descriptions. The fields that describe the attributes are defined in |
69 | the F<Stem::Class> module. |
70 | |
71 | =item * |
72 | |
73 | An object constructor is called and is passed a list of key value |
74 | arguments. This class method can be called via a configuration (which |
75 | uses default name of 'new') or from any Stem code. The constructor |
76 | passes its attribute specification table and the passed arguments to |
77 | the Stem::Class::parse_args routine which returns the new object The |
78 | constructor method checks if an error happened by seeing if that |
79 | returned value is an object (ref is true) or else it must be an error |
80 | string. Any error string is returned to the caller of this |
81 | constructor. This is the standard way Stem handles errors, references |
82 | are good values and scalars (error strings) are bad. This propogation |
83 | of error strings up the call stack is consistantly used in all Stem |
84 | modules. After a successful construction of an object, the constructor |
85 | method can do additional work and then it returns the object. The |
86 | caller of the constructor will also check for an object or error |
87 | string. The common case of a configuration file constructing a Stem |
88 | object cell with register a good cell or print the error string and |
89 | die. |
90 | |
91 | =back |
92 | |
93 | =head2 ATTRIBUTE SPECIFICATION |
94 | |
95 | Object cells require an attribute specification that describes |
96 | the information we want to exist independently in each object |
97 | cell when it is created. The following is the attribute specification |
98 | used in C<World2>: |
99 | |
100 | $attr_spec = |
101 | [ |
102 | { |
103 | 'name' => 'planet', |
104 | 'default' => 'X', |
105 | |
106 | }, |
107 | |
108 | ]; |
109 | |
110 | This specification indicates that this cell has an attribute |
111 | named I<planet>. It will default to the value of I<X> if |
112 | this attribute is not specified in the configuration arguments |
113 | for this cell. Some of the attribute specification tags are I<name>, |
114 | I<type>, I<default>, I<required>, I<class>, and I<help>. For more |
115 | information on cell configuration please see |
116 | B<Stem Object and Cell Creation and Configuration Design Notes> and |
117 | B<Stem Cell Design Notes>. |
118 | |
119 | =head2 OBJECT CONSTRUCTOR |
120 | |
121 | This is a minimal B<Stem> constructor with the usual name I<new>. you |
122 | can invoke any other method as a constructor from a configuration by |
123 | using the 'method' field: |
124 | |
125 | sub new { |
126 | |
127 | my ( $class ) = shift; |
128 | |
129 | my $self = Stem::Class::parse_args( $attr_spec, @_ ); |
130 | return $self unless ref $self ; |
131 | |
132 | return ( $self ); |
133 | |
134 | } |
135 | |
136 | To create a B<Stem> object cell we call the C<Stem::Class::parse_args> |
137 | routine and pass it the object cell attribute specification and the |
138 | rest of the arguments passed into this constructor. The rest of the |
139 | arguments come from the I<args> field in the configuration for this cell. |
140 | The parse_args function then returns the newly created object to the |
141 | caller, which is usually the configuration system but it could be any |
142 | other code as well. An important observation to make here is the |
143 | B<Stem> error handling technique. Errors, in B<Stem>, are propagated |
144 | up the call stack bu returning an error string rather than a |
145 | reference. This is the typical Stem way of determining whether of not |
146 | an error condition had occurred. Constructors or subroutines which |
147 | normally return objects or references will return a string value as |
148 | an error message. This is always checked by the caller and will usually |
149 | be passed up the call stack until a top level subroutine handles it. |
150 | |
151 | =head1 CREATING THE CONFIGURATION FILE |
152 | |
153 | The following B<Stem> configuration file is used to bring a |
154 | World2 object level cell into existance in the B<Stem> environment. |
155 | |
156 | [ |
157 | class => 'Console', |
158 | ], |
159 | |
160 | [ |
161 | class => 'World2', |
162 | name => 'first_planet', |
163 | args => [], |
164 | |
165 | ], |
166 | |
167 | [ |
168 | class => 'World2', |
169 | name => 'second_planet', |
170 | args => [ |
171 | planet => 'venus', |
172 | |
173 | ], |
174 | |
175 | ], |
176 | |
177 | |
178 | As explained in F<World1.pm>, we create a |
179 | C<Stem::Console> cell to allow for the creation of a Stem console |
180 | to manually send command messages and display their responses. |
181 | We also create two object level C<World2> cells. |
182 | The first, we name I<first_planet> and it defaults to having its planet |
183 | attribute set to 'first_planet'. The second, we name I<second_planet> and set its |
184 | planet attribute to 'venus'. |
185 | |
186 | Using the I<args> specifier in the cell configuration indicates |
187 | that we are creating an I<object> cell rather than a class cell. |
188 | It indicates to the B<Stem> cell creation environment that we |
189 | wish to execute the constructor of the specified class to |
190 | create an object of the class rather than using the B<Stem> |
191 | module as a class itself. Using object cells allow us to instantiate |
192 | multiple objects with unique values, addressed and subsequent |
193 | behavior. |
194 | |
195 | =head1 USAGE |
196 | |
197 | Execute C<run_stem world2> from the command line to run this |
198 | configuration. You will be greeted with the B<StemE<gt>> prompt. |
199 | It is now possible to send a message manually into the system. |
200 | |
201 | Type the following at the B<Stem> prompt: |
202 | |
203 | B<reg status> |
204 | |
205 | This will show the status of the local B<Stem> hub. You |
206 | will notice the two entries for the object cells created |
207 | by the configuration file under the object cell section. |
208 | |
209 | Now execute the same command as you did in F<World1>: |
210 | |
211 | B<first_planet hello> |
212 | |
213 | B<Hello, World! (from X)> |
214 | |
215 | B<second_planet hello> |
216 | |
217 | B<Hello, World! (from venus)> |
218 | |
219 | As in F<World1>, the above triggers the C<hello_cmd> method. However, |
220 | now we are triggering the C<hello_cmd> method on separate object cells |
221 | rather than a single class cell. |
222 | |
223 | |
224 | =head1 SEE ALSO |
225 | |
226 | F<Stem Cookbook Part 1> |
227 | |
228 | F<Stem Cookbook Part 3> |
229 | |
230 | F<World2 Module> |
231 | |
232 | =cut |
233 | |
234 | |
235 | 1; |