rumx 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|