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.
Files changed (70) hide show
  1. data/History.md +6 -0
  2. data/LICENSE.txt +201 -0
  3. data/README.md +107 -0
  4. data/Rakefile +23 -0
  5. data/examples/bean_list/README +2 -0
  6. data/examples/bean_list/config.ru +9 -0
  7. data/examples/bean_list/my_bean.rb +35 -0
  8. data/examples/embedded/README +2 -0
  9. data/examples/embedded/config.ru +9 -0
  10. data/examples/embedded/my_bean.rb +23 -0
  11. data/examples/embedded/my_embedded_bean.rb +22 -0
  12. data/examples/list/README +2 -0
  13. data/examples/list/config.ru +9 -0
  14. data/examples/list/my_bean.rb +28 -0
  15. data/examples/simple/README +2 -0
  16. data/examples/simple/config.ru +11 -0
  17. data/examples/simple/my_bean.rb +36 -0
  18. data/examples/timer/README +7 -0
  19. data/examples/timer/config.ru +9 -0
  20. data/examples/timer/my_bean.rb +28 -0
  21. data/lib/rumx/argument.rb +11 -0
  22. data/lib/rumx/attribute.rb +38 -0
  23. data/lib/rumx/bean.rb +484 -0
  24. data/lib/rumx/beans/folder.rb +9 -0
  25. data/lib/rumx/beans/message.rb +16 -0
  26. data/lib/rumx/beans/timer.rb +75 -0
  27. data/lib/rumx/beans.rb +3 -0
  28. data/lib/rumx/operation.rb +26 -0
  29. data/lib/rumx/server/public/_lib/jquery.cookie.js +96 -0
  30. data/lib/rumx/server/public/_lib/jquery.hotkeys.js +99 -0
  31. data/lib/rumx/server/public/_lib/jquery.js +18 -0
  32. data/lib/rumx/server/public/attribute_test.html +148 -0
  33. data/lib/rumx/server/public/jquery-ui-1.8.16.custom.min.js +132 -0
  34. data/lib/rumx/server/public/jquery.jstree.js +4551 -0
  35. data/lib/rumx/server/public/jquery.layout.min-1.2.0.js +80 -0
  36. data/lib/rumx/server/public/themes/apple/bg.jpg +0 -0
  37. data/lib/rumx/server/public/themes/apple/d.png +0 -0
  38. data/lib/rumx/server/public/themes/apple/dot_for_ie.gif +0 -0
  39. data/lib/rumx/server/public/themes/apple/style.css +61 -0
  40. data/lib/rumx/server/public/themes/apple/throbber.gif +0 -0
  41. data/lib/rumx/server/public/themes/classic/d.gif +0 -0
  42. data/lib/rumx/server/public/themes/classic/d.png +0 -0
  43. data/lib/rumx/server/public/themes/classic/dot_for_ie.gif +0 -0
  44. data/lib/rumx/server/public/themes/classic/style.css +77 -0
  45. data/lib/rumx/server/public/themes/classic/throbber.gif +0 -0
  46. data/lib/rumx/server/public/themes/default/d.gif +0 -0
  47. data/lib/rumx/server/public/themes/default/d.png +0 -0
  48. data/lib/rumx/server/public/themes/default/style.css +74 -0
  49. data/lib/rumx/server/public/themes/default/throbber.gif +0 -0
  50. data/lib/rumx/server/public/themes/default-rtl/d.gif +0 -0
  51. data/lib/rumx/server/public/themes/default-rtl/d.png +0 -0
  52. data/lib/rumx/server/public/themes/default-rtl/dots.gif +0 -0
  53. data/lib/rumx/server/public/themes/default-rtl/style.css +84 -0
  54. data/lib/rumx/server/public/themes/default-rtl/throbber.gif +0 -0
  55. data/lib/rumx/server/views/attribute_value_tag.haml +4 -0
  56. data/lib/rumx/server/views/content_attribute.haml +35 -0
  57. data/lib/rumx/server/views/content_attributes.haml +31 -0
  58. data/lib/rumx/server/views/content_operation.haml +39 -0
  59. data/lib/rumx/server/views/content_operations.haml +36 -0
  60. data/lib/rumx/server/views/index.haml +1 -0
  61. data/lib/rumx/server/views/layout.haml +18 -0
  62. data/lib/rumx/server/views/link_to_content.haml +1 -0
  63. data/lib/rumx/server/views/tree.haml +11 -0
  64. data/lib/rumx/server/views/tree_bean.haml +6 -0
  65. data/lib/rumx/server/views/tree_bean_attributes.haml +6 -0
  66. data/lib/rumx/server/views/tree_bean_operations.haml +6 -0
  67. data/lib/rumx/server.rb +185 -0
  68. data/lib/rumx/type.rb +36 -0
  69. data/lib/rumx.rb +7 -0
  70. 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,9 @@
1
+ module Rumx
2
+ module Beans
3
+ # Bean that contains child beans. Since all beans have this functionality, this is
4
+ # essentially just a Bean that has no attributes or operations.
5
+ class Folder
6
+ include Bean
7
+ end
8
+ end
9
+ 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,3 @@
1
+ require 'rumx/beans/folder'
2
+ require 'rumx/beans/message'
3
+ require 'rumx/beans/timer'
@@ -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