rumx 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.md +6 -0
- data/LICENSE.txt +201 -0
- data/README.md +107 -0
- data/Rakefile +23 -0
- data/examples/bean_list/README +2 -0
- data/examples/bean_list/config.ru +9 -0
- data/examples/bean_list/my_bean.rb +35 -0
- data/examples/embedded/README +2 -0
- data/examples/embedded/config.ru +9 -0
- data/examples/embedded/my_bean.rb +23 -0
- data/examples/embedded/my_embedded_bean.rb +22 -0
- data/examples/list/README +2 -0
- data/examples/list/config.ru +9 -0
- data/examples/list/my_bean.rb +28 -0
- data/examples/simple/README +2 -0
- data/examples/simple/config.ru +11 -0
- data/examples/simple/my_bean.rb +36 -0
- data/examples/timer/README +7 -0
- data/examples/timer/config.ru +9 -0
- data/examples/timer/my_bean.rb +28 -0
- data/lib/rumx/argument.rb +11 -0
- data/lib/rumx/attribute.rb +38 -0
- data/lib/rumx/bean.rb +484 -0
- data/lib/rumx/beans/folder.rb +9 -0
- data/lib/rumx/beans/message.rb +16 -0
- data/lib/rumx/beans/timer.rb +75 -0
- data/lib/rumx/beans.rb +3 -0
- data/lib/rumx/operation.rb +26 -0
- data/lib/rumx/server/public/_lib/jquery.cookie.js +96 -0
- data/lib/rumx/server/public/_lib/jquery.hotkeys.js +99 -0
- data/lib/rumx/server/public/_lib/jquery.js +18 -0
- data/lib/rumx/server/public/attribute_test.html +148 -0
- data/lib/rumx/server/public/jquery-ui-1.8.16.custom.min.js +132 -0
- data/lib/rumx/server/public/jquery.jstree.js +4551 -0
- data/lib/rumx/server/public/jquery.layout.min-1.2.0.js +80 -0
- data/lib/rumx/server/public/themes/apple/bg.jpg +0 -0
- data/lib/rumx/server/public/themes/apple/d.png +0 -0
- data/lib/rumx/server/public/themes/apple/dot_for_ie.gif +0 -0
- data/lib/rumx/server/public/themes/apple/style.css +61 -0
- data/lib/rumx/server/public/themes/apple/throbber.gif +0 -0
- data/lib/rumx/server/public/themes/classic/d.gif +0 -0
- data/lib/rumx/server/public/themes/classic/d.png +0 -0
- data/lib/rumx/server/public/themes/classic/dot_for_ie.gif +0 -0
- data/lib/rumx/server/public/themes/classic/style.css +77 -0
- data/lib/rumx/server/public/themes/classic/throbber.gif +0 -0
- data/lib/rumx/server/public/themes/default/d.gif +0 -0
- data/lib/rumx/server/public/themes/default/d.png +0 -0
- data/lib/rumx/server/public/themes/default/style.css +74 -0
- data/lib/rumx/server/public/themes/default/throbber.gif +0 -0
- data/lib/rumx/server/public/themes/default-rtl/d.gif +0 -0
- data/lib/rumx/server/public/themes/default-rtl/d.png +0 -0
- data/lib/rumx/server/public/themes/default-rtl/dots.gif +0 -0
- data/lib/rumx/server/public/themes/default-rtl/style.css +84 -0
- data/lib/rumx/server/public/themes/default-rtl/throbber.gif +0 -0
- data/lib/rumx/server/views/attribute_value_tag.haml +4 -0
- data/lib/rumx/server/views/content_attribute.haml +35 -0
- data/lib/rumx/server/views/content_attributes.haml +31 -0
- data/lib/rumx/server/views/content_operation.haml +39 -0
- data/lib/rumx/server/views/content_operations.haml +36 -0
- data/lib/rumx/server/views/index.haml +1 -0
- data/lib/rumx/server/views/layout.haml +18 -0
- data/lib/rumx/server/views/link_to_content.haml +1 -0
- data/lib/rumx/server/views/tree.haml +11 -0
- data/lib/rumx/server/views/tree_bean.haml +6 -0
- data/lib/rumx/server/views/tree_bean_attributes.haml +6 -0
- data/lib/rumx/server/views/tree_bean_operations.haml +6 -0
- data/lib/rumx/server.rb +185 -0
- data/lib/rumx/type.rb +36 -0
- data/lib/rumx.rb +7 -0
- metadata +123 -0
data/lib/rumx/bean.rb
ADDED
@@ -0,0 +1,484 @@
|
|
1
|
+
module Rumx
|
2
|
+
# Defines a Rumx bean that allows access to the defined attributes and operations.
|
3
|
+
# All public instance methods are prefixed with "bean_" to try to avoid collisions.
|
4
|
+
module Bean
|
5
|
+
module ClassMethods
|
6
|
+
|
7
|
+
def bean_reader(name, type, description, options={})
|
8
|
+
bean_add_attribute(Attribute.new(name, type, description, true, false, options))
|
9
|
+
end
|
10
|
+
|
11
|
+
# options
|
12
|
+
# max_size - the max size the list can be indexed for setting. Can be an integer or
|
13
|
+
# a symbol that represents an attribute or method of the bean. Defaults to the
|
14
|
+
# current size of the list.
|
15
|
+
def bean_list_reader(name, type, description, options={})
|
16
|
+
bean_add_list_attribute(Attribute.new(name, type, description, true, false, options))
|
17
|
+
end
|
18
|
+
|
19
|
+
def bean_attr_reader(name, type, description, options={})
|
20
|
+
attr_reader(name)
|
21
|
+
bean_reader(name, type, description, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def bean_list_attr_reader(name, type, description, options={})
|
25
|
+
attr_reader(name)
|
26
|
+
bean_list_reader(name, type, description, options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def bean_writer(name, type, description, options={})
|
30
|
+
bean_add_attribute(Attribute.new(name, type, description, false, true, options))
|
31
|
+
end
|
32
|
+
|
33
|
+
def bean_list_writer(name, type, description, options={})
|
34
|
+
bean_add_list_attribute(Attribute.new(name, type, description, false, true, options))
|
35
|
+
end
|
36
|
+
|
37
|
+
def bean_attr_writer(name, type, description, options={})
|
38
|
+
attr_writer(name)
|
39
|
+
bean_writer(name, type, description, options)
|
40
|
+
end
|
41
|
+
|
42
|
+
def bean_list_attr_writer(name, type, description, options={})
|
43
|
+
attr_writer(name)
|
44
|
+
bean_list_writer(name, type, description, options)
|
45
|
+
end
|
46
|
+
|
47
|
+
def bean_accessor(name, type, description, options={})
|
48
|
+
bean_add_attribute(Attribute.new(name, type, description, true, true, options))
|
49
|
+
end
|
50
|
+
|
51
|
+
def bean_list_accessor(name, type, description, options={})
|
52
|
+
bean_add_list_attribute(Attribute.new(name, type, description, true, true, options))
|
53
|
+
end
|
54
|
+
|
55
|
+
def bean_attr_accessor(name, type, description, options={})
|
56
|
+
attr_accessor(name)
|
57
|
+
bean_accessor(name, type, description, options)
|
58
|
+
end
|
59
|
+
|
60
|
+
def bean_list_attr_accessor(name, type, description, options={})
|
61
|
+
attr_accessor(name)
|
62
|
+
bean_list_accessor(name, type, description, options)
|
63
|
+
end
|
64
|
+
|
65
|
+
def bean_embed(name, description)
|
66
|
+
# We're going to ignore description (for now)
|
67
|
+
bean_embeds << name.to_sym
|
68
|
+
end
|
69
|
+
|
70
|
+
def bean_attr_embed(name, description)
|
71
|
+
attr_reader(name)
|
72
|
+
bean_embed(name, description)
|
73
|
+
end
|
74
|
+
|
75
|
+
def bean_embed_list(name, description)
|
76
|
+
# We're going to ignore description (for now)
|
77
|
+
bean_embed_lists << name.to_sym
|
78
|
+
end
|
79
|
+
|
80
|
+
def bean_attr_embed_list(name, description)
|
81
|
+
attr_reader(name)
|
82
|
+
bean_embed_list(name, description)
|
83
|
+
end
|
84
|
+
|
85
|
+
#bean_operation :my_operation, :string, 'My operation', [
|
86
|
+
# [ :arg_int, :int, 'An int argument' ],
|
87
|
+
# [ :arg_float, :float, 'A float argument' ],
|
88
|
+
# [ :arg_string, :string, 'A string argument' ]
|
89
|
+
#]
|
90
|
+
def bean_operation(name, type, description, args)
|
91
|
+
arguments = args.map do |arg|
|
92
|
+
raise 'Invalid bean_operation format' unless arg.kind_of?(Array) && arg.size == 3
|
93
|
+
Argument.new(*arg)
|
94
|
+
end
|
95
|
+
@operations ||= []
|
96
|
+
@operations << Operation.new(name, type, description, arguments)
|
97
|
+
end
|
98
|
+
|
99
|
+
#######
|
100
|
+
# private - TODO: Local helper methods, how should I designate them as private or just nodoc them?
|
101
|
+
#######
|
102
|
+
|
103
|
+
def bean_add_attribute(attribute)
|
104
|
+
@attributes ||= []
|
105
|
+
@attributes << attribute
|
106
|
+
end
|
107
|
+
|
108
|
+
def bean_add_list_attribute(attribute)
|
109
|
+
@list_attributes ||= []
|
110
|
+
@list_attributes << attribute
|
111
|
+
end
|
112
|
+
|
113
|
+
def bean_attributes
|
114
|
+
attributes = []
|
115
|
+
self.ancestors.reverse_each do |mod|
|
116
|
+
attributes += mod.bean_attributes_local if mod.include?(Rumx::Bean)
|
117
|
+
end
|
118
|
+
return attributes
|
119
|
+
end
|
120
|
+
|
121
|
+
def bean_list_attributes
|
122
|
+
attributes = []
|
123
|
+
self.ancestors.reverse_each do |mod|
|
124
|
+
attributes += mod.bean_list_attributes_local if mod.include?(Rumx::Bean)
|
125
|
+
end
|
126
|
+
return attributes
|
127
|
+
end
|
128
|
+
|
129
|
+
def bean_attributes_local
|
130
|
+
@attributes ||= []
|
131
|
+
end
|
132
|
+
|
133
|
+
def bean_list_attributes_local
|
134
|
+
@list_attributes ||= []
|
135
|
+
end
|
136
|
+
|
137
|
+
def bean_operations
|
138
|
+
operations = []
|
139
|
+
self.ancestors.reverse_each do |mod|
|
140
|
+
operations += mod.bean_operations_local if mod.include?(Rumx::Bean)
|
141
|
+
end
|
142
|
+
return operations
|
143
|
+
end
|
144
|
+
|
145
|
+
def bean_operations_local
|
146
|
+
@operations ||= []
|
147
|
+
end
|
148
|
+
|
149
|
+
def bean_embeds
|
150
|
+
@embeds ||= []
|
151
|
+
end
|
152
|
+
|
153
|
+
def bean_embed_lists
|
154
|
+
@embed_lists ||= []
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.included(base)
|
159
|
+
base.extend(ClassMethods)
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.root
|
163
|
+
@root ||= Beans::Folder.new
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.find(name_array)
|
167
|
+
bean = root
|
168
|
+
until name_array.empty?
|
169
|
+
name = name_array.shift.to_sym
|
170
|
+
child_bean = bean.bean_children[name]
|
171
|
+
if !child_bean && bean.class.bean_embeds.include?(name)
|
172
|
+
child_bean = bean.send(name)
|
173
|
+
end
|
174
|
+
if !child_bean && bean.class.bean_embed_lists.include?(name)
|
175
|
+
list = bean.send(name)
|
176
|
+
if list
|
177
|
+
index = name_array.shift
|
178
|
+
child_bean = list[index.to_i] if index && index.match(/\d+/)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
return nil unless child_bean
|
182
|
+
bean = child_bean
|
183
|
+
end
|
184
|
+
return bean
|
185
|
+
end
|
186
|
+
|
187
|
+
# Return [bean, attribute, param_name, value] list or nil if not found
|
188
|
+
def self.find_attribute(name_array)
|
189
|
+
name = name_array.pop
|
190
|
+
# If it's a list attribute
|
191
|
+
if name.match(/^\d+$/)
|
192
|
+
index = name.to_i
|
193
|
+
name = name_array.pop
|
194
|
+
bean = Bean.find(name_array)
|
195
|
+
return nil unless bean
|
196
|
+
name = name.to_sym
|
197
|
+
bean.class.bean_list_attributes.each do |attribute|
|
198
|
+
if name == attribute.name
|
199
|
+
obj = bean.send(attribute.name)
|
200
|
+
if obj
|
201
|
+
param_name = "#{attribute.name}[#{index}]"
|
202
|
+
return [bean, attribute, param_name, attribute.get_index_value(obj, index)]
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
# else just a regular attribute
|
207
|
+
else
|
208
|
+
bean = Bean.find(name_array)
|
209
|
+
return nil unless bean
|
210
|
+
name = name.to_sym
|
211
|
+
bean.class.bean_attributes.each do |attribute|
|
212
|
+
if name == attribute.name
|
213
|
+
return [bean, attribute, attribute.name, attribute.get_value(bean)]
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
return nil
|
218
|
+
end
|
219
|
+
|
220
|
+
# Return [bean, operation] pair or nil if not found
|
221
|
+
def self.find_operation(name_array)
|
222
|
+
name = name_array.pop
|
223
|
+
bean = Bean.find(name_array)
|
224
|
+
return nil unless bean
|
225
|
+
name = name.to_sym
|
226
|
+
bean.class.bean_operations.each do |operation|
|
227
|
+
return [bean, operation] if name == operation.name
|
228
|
+
end
|
229
|
+
return nil
|
230
|
+
end
|
231
|
+
|
232
|
+
# Mutex for synchronization of attributes/operations
|
233
|
+
def bean_mutex
|
234
|
+
# TBD: How to initialize this in a module and avoid race condition?
|
235
|
+
@mutex || Mutex.new
|
236
|
+
end
|
237
|
+
|
238
|
+
# Synchronize access to attributes and operations
|
239
|
+
def bean_synchronize
|
240
|
+
bean_mutex.synchronize do
|
241
|
+
yield
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def bean_children
|
246
|
+
@bean_children ||= {}
|
247
|
+
end
|
248
|
+
|
249
|
+
def bean_add_child(name, child_bean)
|
250
|
+
# TBD - Should I mutex protect this? All beans would normally be registered during the code initialization process
|
251
|
+
raise "Error trying to add #{name} to embedded bean" if @bean_is_embedded
|
252
|
+
bean_children[name.to_sym] = child_bean
|
253
|
+
end
|
254
|
+
|
255
|
+
def bean_remove_child(name)
|
256
|
+
bean_children.delete(name.to_sym)
|
257
|
+
end
|
258
|
+
|
259
|
+
def bean_has_attributes?
|
260
|
+
return true unless self.class.bean_attributes.empty? && self.class.bean_list_attributes.empty?
|
261
|
+
self.class.bean_embeds.each do |name|
|
262
|
+
bean = send(name)
|
263
|
+
return true if bean && bean.bean_has_attributes?
|
264
|
+
end
|
265
|
+
self.class.bean_embed_lists.each do |list_name|
|
266
|
+
list = send(list_name)
|
267
|
+
if list
|
268
|
+
list.each do |bean|
|
269
|
+
return true if bean.bean_has_attributes?
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
return false
|
274
|
+
end
|
275
|
+
|
276
|
+
def bean_get_attributes(rel_path=nil, param_name=nil, &block)
|
277
|
+
bean_synchronize do
|
278
|
+
do_bean_get_attributes(rel_path, param_name, &block)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def bean_set_attributes(params)
|
283
|
+
bean_synchronize do
|
284
|
+
do_bean_set_attributes(params)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def bean_get_and_set_attributes(params, rel_path=nil, param_name=nil, &block)
|
289
|
+
bean_synchronize do
|
290
|
+
val = do_bean_get_attributes(rel_path, param_name, &block)
|
291
|
+
do_bean_set_attributes(params)
|
292
|
+
val
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
def bean_set_and_get_attributes(params, rel_path=nil, param_name=nil, &block)
|
297
|
+
bean_synchronize do
|
298
|
+
do_bean_set_attributes(params)
|
299
|
+
do_bean_get_attributes(rel_path, param_name, &block)
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def bean_has_operations?
|
304
|
+
return true unless self.class.bean_operations.empty?
|
305
|
+
self.class.bean_embeds.each do |name|
|
306
|
+
bean = send(name)
|
307
|
+
return true if bean && bean.bean_has_operations?
|
308
|
+
end
|
309
|
+
self.class.bean_embed_lists.each do |list_name|
|
310
|
+
list = send(list_name)
|
311
|
+
if list
|
312
|
+
list.each do |bean|
|
313
|
+
return true if bean.bean_has_operations?
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
return false
|
318
|
+
end
|
319
|
+
|
320
|
+
def bean_each_operation(rel_path=nil, &block)
|
321
|
+
self.class.bean_operations.each do |operation|
|
322
|
+
yield operation, bean_join_rel_path(rel_path, operation.name.to_s)
|
323
|
+
end
|
324
|
+
self.class.bean_embeds.each do |name|
|
325
|
+
bean = send(name)
|
326
|
+
bean.bean_each_operation(bean_join_rel_path(rel_path, name), &block) if bean
|
327
|
+
end
|
328
|
+
self.class.bean_embed_lists.each do |name|
|
329
|
+
list = send(name)
|
330
|
+
if list
|
331
|
+
list_rel_path = bean_join_rel_path(rel_path, name)
|
332
|
+
list.each_with_index do |bean, i|
|
333
|
+
bean.bean_each_operation(bean_join_rel_path(list_rel_path, i.to_s), &block)
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
#########
|
340
|
+
protected
|
341
|
+
#########
|
342
|
+
|
343
|
+
# Allow extenders to save changes, etc. if attribute values change
|
344
|
+
def bean_attributes_changed
|
345
|
+
end
|
346
|
+
|
347
|
+
#######
|
348
|
+
private
|
349
|
+
#######
|
350
|
+
|
351
|
+
# Separate call in case we're already mutex locked
|
352
|
+
def do_bean_get_attributes(rel_path, param_name, &block)
|
353
|
+
return do_bean_get_attributes_json unless block_given?
|
354
|
+
self.class.bean_attributes.each do |attribute|
|
355
|
+
yield attribute, attribute.get_value(self), bean_join_rel_path(rel_path, attribute.name.to_s), bean_join_param_name(param_name, attribute.name.to_s)
|
356
|
+
end
|
357
|
+
self.class.bean_list_attributes.each do |attribute|
|
358
|
+
obj = send(attribute.name)
|
359
|
+
if obj
|
360
|
+
new_rel_path = bean_join_rel_path(rel_path, attribute.name.to_s)
|
361
|
+
new_param_name = bean_join_param_name(param_name, attribute.name.to_s)
|
362
|
+
obj.each_index do |i|
|
363
|
+
yield attribute, attribute.get_index_value(obj, i), "#{new_rel_path}/#{i}", "#{new_param_name}[#{i}]"
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
self.class.bean_embeds.each do |name|
|
368
|
+
bean = send(name)
|
369
|
+
bean.bean_get_attributes(bean_join_rel_path(rel_path, name), bean_join_param_name(param_name, name), &block) if bean
|
370
|
+
end
|
371
|
+
self.class.bean_embed_lists.each do |name|
|
372
|
+
list = send(name)
|
373
|
+
if list
|
374
|
+
list_rel_path = bean_join_rel_path(rel_path, name)
|
375
|
+
list_param_name = bean_join_param_name(param_name, name)
|
376
|
+
list.each_with_index do |bean, i|
|
377
|
+
bean.bean_get_attributes(bean_join_rel_path(list_rel_path, i.to_s), bean_join_param_name(list_param_name, i.to_s), &block)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
def do_bean_get_attributes_json
|
384
|
+
hash = {}
|
385
|
+
self.class.bean_attributes.each do |attribute|
|
386
|
+
hash[attribute.name] = attribute.get_value(self)
|
387
|
+
end
|
388
|
+
self.class.bean_list_attributes.each do |attribute|
|
389
|
+
hash[attribute.name] = attribute.get_value(self)
|
390
|
+
end
|
391
|
+
self.class.bean_embeds.each do |name|
|
392
|
+
bean = send(name)
|
393
|
+
hash[name] = bean.bean_get_attributes if bean
|
394
|
+
end
|
395
|
+
self.class.bean_embed_lists.each do |name|
|
396
|
+
list = send(name)
|
397
|
+
if list
|
398
|
+
hash[name] = list.map {|bean| bean.bean_get_attributes}
|
399
|
+
end
|
400
|
+
end
|
401
|
+
return hash
|
402
|
+
end
|
403
|
+
|
404
|
+
# Separate call in case we're already mutex locked
|
405
|
+
def do_bean_set_attributes(params)
|
406
|
+
return if !params || params.empty?
|
407
|
+
changed = false
|
408
|
+
self.class.bean_attributes.each do |attribute|
|
409
|
+
if attribute.allow_write
|
410
|
+
if params.has_key?(attribute.name)
|
411
|
+
attribute.set_value(self, params[attribute.name])
|
412
|
+
changed = true
|
413
|
+
elsif params.has_key?(attribute.name.to_s)
|
414
|
+
attribute.set_value(self, params[attribute.name.to_s])
|
415
|
+
changed = true
|
416
|
+
end
|
417
|
+
end
|
418
|
+
end
|
419
|
+
self.class.bean_list_attributes.each do |attribute|
|
420
|
+
if attribute.allow_write
|
421
|
+
obj = send(attribute.name)
|
422
|
+
sub_params = params[attribute.name] || params[attribute.name.to_s]
|
423
|
+
raise "Can't assign value for nil list attribute" if !obj && sub_params
|
424
|
+
if sub_params
|
425
|
+
# TODO: Allow array?
|
426
|
+
raise "Invalid param for #{attribute.name}" unless sub_params.kind_of?(Hash)
|
427
|
+
max_size = attribute[:max_size]
|
428
|
+
if max_size
|
429
|
+
if max_size.kind_of?(Symbol)
|
430
|
+
max_size = send(max_size)
|
431
|
+
end
|
432
|
+
else
|
433
|
+
# Default to current size of the list if unset
|
434
|
+
max_size = obj.size
|
435
|
+
end
|
436
|
+
sub_params.each do |index, value|
|
437
|
+
if index.to_i < max_size
|
438
|
+
attribute.set_index_value(obj, index.to_i, value)
|
439
|
+
changed = true
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
443
|
+
end
|
444
|
+
end
|
445
|
+
self.class.bean_embeds.each do |name|
|
446
|
+
bean = send(name)
|
447
|
+
if bean
|
448
|
+
embedded_params = params[name]
|
449
|
+
bean.bean_set_attributes(embedded_params)
|
450
|
+
changed = true
|
451
|
+
end
|
452
|
+
end
|
453
|
+
self.class.bean_embed_lists.each do |name|
|
454
|
+
list = send(name)
|
455
|
+
if list
|
456
|
+
list_params = params[name]
|
457
|
+
if list_params
|
458
|
+
list.each_with_index do |bean, i|
|
459
|
+
bean.bean_set_attributes(list_params[i] || list_params[i.to_s])
|
460
|
+
end
|
461
|
+
changed = true
|
462
|
+
end
|
463
|
+
end
|
464
|
+
end
|
465
|
+
bean_attributes_changed if changed
|
466
|
+
end
|
467
|
+
|
468
|
+
def bean_join_rel_path(parent_rel_path, name)
|
469
|
+
if parent_rel_path
|
470
|
+
"#{parent_rel_path}/#{name}"
|
471
|
+
else
|
472
|
+
name.to_s
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
def bean_join_param_name(parent_param_name, name)
|
477
|
+
if parent_param_name
|
478
|
+
"#{parent_param_name}[#{name}]"
|
479
|
+
else
|
480
|
+
name.to_s
|
481
|
+
end
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Rumx
|
2
|
+
module Beans
|
3
|
+
class Message
|
4
|
+
include ::Rumx::Bean
|
5
|
+
|
6
|
+
bean_attr_reader :message, :string, 'Message'
|
7
|
+
# TODO: create time and date types
|
8
|
+
bean_attr_reader :time, :string, 'Time that the message occurred'
|
9
|
+
|
10
|
+
def initialize(message, time=nil)
|
11
|
+
@message = message
|
12
|
+
@time = (time || Time.now).to_s
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Rumx
|
2
|
+
module Beans
|
3
|
+
class Timer
|
4
|
+
include Bean
|
5
|
+
|
6
|
+
bean_attr_reader :total_count, :integer, 'Number of times the measured block has run'
|
7
|
+
bean_attr_reader :error_count, :integer, 'Number of times the measured block has raised an exception'
|
8
|
+
bean_attr_reader :total_time, :float, 'Total time in msec for all the runs of the timed instruction'
|
9
|
+
bean_attr_reader :max_time, :float, 'The maximum time for all the runs of the timed instruction'
|
10
|
+
bean_attr_reader :min_time, :float, 'The minimum time for all the runs of the timed instruction'
|
11
|
+
bean_attr_reader :last_time, :float, 'The time for the last run of the timed instruction'
|
12
|
+
bean_reader :avg_time, :float, 'The average time for all runs of the timed instruction'
|
13
|
+
bean_writer :reset, :boolean, 'Reset the times and counts to zero (Note that last_time and errors are not reset)'
|
14
|
+
bean_attr_embed_list :errors, 'List of the last occurring errors'
|
15
|
+
|
16
|
+
def initialize(opts={})
|
17
|
+
# Force initialization of Bean#bean_mutex to avoid race condition (See bean.rb)
|
18
|
+
bean_mutex
|
19
|
+
@last_time = 0.0
|
20
|
+
self.reset = true
|
21
|
+
@errors = []
|
22
|
+
@max_errors = (opts[:max_errors] || 1).to_i
|
23
|
+
end
|
24
|
+
|
25
|
+
def reset=(val)
|
26
|
+
if val
|
27
|
+
@total_count = 0
|
28
|
+
@error_count = 0
|
29
|
+
@min_time = nil
|
30
|
+
@max_time = 0.0
|
31
|
+
@total_time = 0.0
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def measure(prefix='')
|
36
|
+
start_time = Time.now
|
37
|
+
begin
|
38
|
+
yield
|
39
|
+
ensure
|
40
|
+
current_time = Time.now.to_f - start_time.to_f
|
41
|
+
bean_synchronize do
|
42
|
+
@last_time = current_time
|
43
|
+
@total_count += 1
|
44
|
+
@total_time += current_time
|
45
|
+
@min_time = current_time if !@min_time || current_time < @min_time
|
46
|
+
@max_time = current_time if current_time > @max_time
|
47
|
+
end
|
48
|
+
end
|
49
|
+
return current_time
|
50
|
+
rescue Exception => e
|
51
|
+
bean_synchronize do
|
52
|
+
@error_count += 1
|
53
|
+
@errors << Message.new(e.message)
|
54
|
+
@errors.shift while @errors.size > @max_errors
|
55
|
+
end
|
56
|
+
raise
|
57
|
+
end
|
58
|
+
|
59
|
+
def min_time
|
60
|
+
@min_time || 0.0
|
61
|
+
end
|
62
|
+
|
63
|
+
def avg_time
|
64
|
+
# Do the best we can w/o mutexing
|
65
|
+
count, time = @total_count, @total_time
|
66
|
+
return 0.0 if count == 0
|
67
|
+
time / count
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_s
|
71
|
+
"total_count=#{@total_count} min=#{('%.1f' % min_time)}ms max=#{('%.1f' % max_time)}ms avg=#{('%.1f' % avg_time)}ms"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/rumx/beans.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Rumx
|
2
|
+
class Operation
|
3
|
+
attr_reader :name, :type, :description, :arguments
|
4
|
+
|
5
|
+
def initialize(name, type_name, description, arguments)
|
6
|
+
@name = name.to_sym
|
7
|
+
@type = Type.find(type_name)
|
8
|
+
@description = description
|
9
|
+
@arguments = arguments
|
10
|
+
end
|
11
|
+
|
12
|
+
def run(bean, argument_hash)
|
13
|
+
args = @arguments.map do |argument|
|
14
|
+
if argument_hash.has_key?(argument.name)
|
15
|
+
value = argument_hash[argument.name]
|
16
|
+
elsif argument_hash.has_key?(argument.name.to_s)
|
17
|
+
value = argument_hash[argument.name.to_s]
|
18
|
+
else
|
19
|
+
raise "No value for argument #{argument.name}"
|
20
|
+
end
|
21
|
+
argument.type.string_to_value(value)
|
22
|
+
end
|
23
|
+
bean.send(self.name, *args)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|