rumx 0.0.8 → 0.1.0

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 (43) hide show
  1. data/History.md +28 -0
  2. data/README.md +8 -6
  3. data/examples/bean_hash/README +2 -0
  4. data/examples/bean_hash/config.ru +9 -0
  5. data/examples/bean_hash/my_bean.rb +44 -0
  6. data/examples/bean_list/my_bean.rb +3 -3
  7. data/examples/embedded/my_bean.rb +3 -2
  8. data/examples/hash/README +2 -0
  9. data/examples/hash/config.ru +9 -0
  10. data/examples/hash/my_bean.rb +30 -0
  11. data/examples/list/my_bean.rb +5 -2
  12. data/examples/monitor_script/README +8 -0
  13. data/examples/monitor_script/rumx_attributes +67 -0
  14. data/examples/simple/config.ru +3 -1
  15. data/examples/simple/my_other_bean.rb +11 -0
  16. data/examples/timer/README +1 -1
  17. data/examples/timer/my_bean.rb +2 -1
  18. data/examples/timer_hash/README +2 -0
  19. data/examples/timer_hash/config.ru +9 -0
  20. data/examples/timer_hash/my_bean.rb +29 -0
  21. data/lib/rumx.rb +5 -0
  22. data/lib/rumx/attribute.rb +26 -17
  23. data/lib/rumx/attribute_info.rb +12 -0
  24. data/lib/rumx/bean.rb +146 -248
  25. data/lib/rumx/beans.rb +2 -0
  26. data/lib/rumx/beans/error.rb +1 -1
  27. data/lib/rumx/beans/hash.rb +34 -0
  28. data/lib/rumx/beans/timer.rb +2 -2
  29. data/lib/rumx/beans/timer_and_error.rb +1 -1
  30. data/lib/rumx/beans/timer_hash.rb +9 -0
  31. data/lib/rumx/hash_attribute.rb +39 -0
  32. data/lib/rumx/hash_bean.rb +55 -0
  33. data/lib/rumx/list_attribute.rb +65 -0
  34. data/lib/rumx/list_bean.rb +52 -0
  35. data/lib/rumx/server.rb +65 -69
  36. data/lib/rumx/server/views/attribute_value_tag.haml +3 -3
  37. data/lib/rumx/server/views/content_attributes.haml +4 -4
  38. data/lib/rumx/server/views/content_operations.haml +2 -2
  39. data/lib/rumx/server/views/tree_bean_attributes.haml +0 -4
  40. data/lib/rumx/server/views/tree_bean_operations.haml +2 -2
  41. data/lib/rumx/type.rb +15 -7
  42. metadata +21 -3
  43. data/lib/rumx/server/views/content_attribute.haml +0 -35
data/lib/rumx/beans.rb CHANGED
@@ -3,3 +3,5 @@ require 'rumx/beans/message'
3
3
  require 'rumx/beans/timer'
4
4
  require 'rumx/beans/error'
5
5
  require 'rumx/beans/timer_and_error'
6
+ require 'rumx/beans/hash'
7
+ require 'rumx/beans/timer_hash'
@@ -4,7 +4,7 @@ module Rumx
4
4
  include Bean
5
5
 
6
6
  bean_attr_reader :error_count, :integer, 'Number of times the measured block has raised an exception'
7
- bean_attr_embed_list :errors, 'List of the last occurring errors'
7
+ bean_attr_reader :errors, :list, 'List of the last occurring errors', :list_type => :bean
8
8
 
9
9
  def initialize(opts={})
10
10
  @errors = []
@@ -0,0 +1,34 @@
1
+ module Rumx
2
+ module Beans
3
+ class Hash
4
+ include Bean
5
+
6
+ def initialize(&block)
7
+ raise 'Must be given initialize instance to create the bean' unless block_given?
8
+ @block = block
9
+ # Hacks for potential race conditions
10
+ bean_children
11
+ bean_synchronize {}
12
+ end
13
+
14
+ def [](key)
15
+ child = bean_children[key]
16
+ return child if child
17
+ bean_synchronize do
18
+ # Try it again to prevent race
19
+ child = bean_children[key]
20
+ return child if child
21
+ child = @block.call(key)
22
+ bean_add_child(key, child)
23
+ end
24
+ return child
25
+ end
26
+
27
+ def delete(key)
28
+ bean_synchronize do
29
+ bean_remove_child(key)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -12,8 +12,8 @@ module Rumx
12
12
  bean_writer :reset, :boolean, 'Reset the times and counts to zero (Note that last_time is not reset)'
13
13
 
14
14
  def initialize(opts={})
15
- # Force initialization of Bean#bean_mutex to avoid race condition (See bean.rb)
16
- bean_mutex
15
+ # Force initialization of Bean#bean_monitor to avoid race condition (See bean.rb)
16
+ bean_monitor
17
17
  @last_time = 0.0
18
18
  self.reset = true
19
19
  end
@@ -3,7 +3,7 @@ module Rumx
3
3
  class TimerAndError < Timer
4
4
 
5
5
  bean_attr_reader :error_count, :integer, 'Number of times the measured block has raised an exception'
6
- bean_attr_embed_list :errors, 'List of the last occurring errors'
6
+ bean_attr_reader :errors, :list, 'List of the last occurring errors', :list_type => :bean
7
7
 
8
8
  def initialize(opts={})
9
9
  super
@@ -0,0 +1,9 @@
1
+ module Rumx
2
+ module Beans
3
+ class TimerHash < Hash
4
+ def initialize
5
+ super { Timer.new }
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,39 @@
1
+ module Rumx
2
+ class HashAttribute < Attribute
3
+
4
+ def initialize(name, type, description, allow_read, allow_write, options)
5
+ super
6
+ raise 'Hash attribute called without hash_type option' unless options[:hash_type]
7
+ @hash_type = Type.find(options[:hash_type])
8
+ end
9
+
10
+ def each_attribute_info(bean, ancestry, &block)
11
+ hash = bean.send(name)
12
+ child_ancestry = ancestry+[name]
13
+ index_index = child_ancestry.size
14
+ hash.each do |name, value|
15
+ value = nil unless allow_read
16
+ child_ancestry[index_index] = name
17
+ yield AttributeInfo.new(self, bean, child_ancestry, value)
18
+ end
19
+ end
20
+
21
+ def write?(bean, params)
22
+ #puts "hash write params=#{params.inspect}"
23
+ return false unless params.kind_of?(Hash)
24
+ is_written = false
25
+ if allow_write
26
+ hash = bean.send(name)
27
+ param_value(params) do |hash_params|
28
+ if hash && hash_params && hash_params.kind_of?(Hash)
29
+ hash_params.each do |name, value|
30
+ hash[name.to_sym] = @hash_type.string_to_value(value)
31
+ is_written = true
32
+ end
33
+ end
34
+ end
35
+ end
36
+ return is_written
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,55 @@
1
+ module Rumx
2
+ class HashBean
3
+ include Bean
4
+
5
+ def initialize(hash)
6
+ @hash = hash
7
+ end
8
+
9
+ # Find the bean
10
+ def bean_find(name_array, index = 0)
11
+ return self if index == name_array.size
12
+ name = name_array[index].to_s
13
+ child = @hash[name] || @hash[name.to_sym]
14
+ return nil unless child
15
+ return child.bean_find(name_array, index+1)
16
+ end
17
+
18
+ def bean_each_embedded_child(&block)
19
+ @hash.each do |name, child|
20
+ yield name, child
21
+ end
22
+ end
23
+
24
+ protected
25
+
26
+ def do_bean_get_attributes(ancestry, &block)
27
+ return do_bean_get_attributes_json unless block_given?
28
+ child_ancestry = ancestry.dup
29
+ # Save some object creation
30
+ child_index = child_ancestry.size
31
+ @hash.each do |name, bean|
32
+ child_ancestry[child_index] = name
33
+ bean.bean_get_attributes(child_ancestry, &block)
34
+ end
35
+ end
36
+
37
+ def do_bean_get_attributes_json
38
+ json_hash = {}
39
+ @hash.each do |name, bean|
40
+ json_hash[name] = bean.bean_get_attributes
41
+ end
42
+ return json_hash
43
+ end
44
+
45
+ def do_bean_set_attributes(params)
46
+ return if !params || params.empty?
47
+ changed = false
48
+ @hash.each do |name, bean|
49
+ changed = true
50
+ bean.bean_set_attributes(params[name] || params[name.to_sym])
51
+ end
52
+ bean_attributes_changed if changed
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,65 @@
1
+ module Rumx
2
+ class ListAttribute < Attribute
3
+
4
+ # options
5
+ # list_type - any of the available types (required)
6
+ # max_size - max size of the list, can be a symbol representing a method or an integer (defaults to the current size of the list)
7
+ def initialize(name, type, description, allow_read, allow_write, options)
8
+ super
9
+ raise 'List attribute called without list_type option' unless options[:list_type]
10
+ @list_type = Type.find(options[:list_type])
11
+ end
12
+
13
+ def each_attribute_info(bean, ancestry, &block)
14
+ list = bean.send(name)
15
+ child_ancestry = ancestry+[name]
16
+ index_index = child_ancestry.size
17
+ list.each_with_index do |value, i|
18
+ value = nil unless allow_read
19
+ child_ancestry[index_index] = i
20
+ yield AttributeInfo.new(self, bean, child_ancestry, value)
21
+ end
22
+ end
23
+
24
+ def write?(bean, params)
25
+ #puts "list write params=#{params.inspect}"
26
+ is_written = false
27
+ if allow_write
28
+ list = bean.send(name)
29
+ return false unless list
30
+ max_size = self[:max_size]
31
+ if max_size
32
+ if max_size.kind_of?(Symbol)
33
+ max_size = bean.send(max_size)
34
+ end
35
+ else
36
+ # Default to current size of the list if unset
37
+ max_size = obj.size
38
+ end
39
+ param_value(params) do |sub_params|
40
+ each_param(sub_params) do |index, value|
41
+ if index < max_size
42
+ list[index] = @list_type.string_to_value(value)
43
+ is_written = true
44
+ end
45
+ end
46
+ end
47
+ end
48
+ return is_written
49
+ end
50
+
51
+ private
52
+
53
+ def each_param(params, &block)
54
+ if params.kind_of?(Hash)
55
+ params.each do |index, value|
56
+ yield index.to_i, value
57
+ end
58
+ elsif params.kind_of?(Array)
59
+ params.each_with_index do |value, index|
60
+ yield index, value
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,52 @@
1
+ module Rumx
2
+ class ListBean
3
+ include Bean
4
+
5
+ def initialize(list)
6
+ @list = list
7
+ end
8
+
9
+ # Find the bean
10
+ def bean_find(name_array, index = 0)
11
+ return self if index == name_array.size
12
+ name = name_array[index]
13
+ return nil unless name.match(/^\d+$/)
14
+ child = @list[name.to_i]
15
+ return nil unless child
16
+ return child.bean_find(name_array, index+1)
17
+ end
18
+
19
+ def bean_each_embedded_child(&block)
20
+ @list.each_with_index do |child, i|
21
+ yield i, child
22
+ end
23
+ end
24
+
25
+ protected
26
+
27
+ def do_bean_get_attributes(ancestry, &block)
28
+ return do_bean_get_attributes_json unless block_given?
29
+ child_ancestry = ancestry.dup
30
+ # Save some object creation
31
+ child_index = child_ancestry.size
32
+ @list.each_with_index do |bean, i|
33
+ child_ancestry[child_index] = i
34
+ bean.bean_get_attributes(child_ancestry, &block)
35
+ end
36
+ end
37
+
38
+ def do_bean_get_attributes_json
39
+ @list.map { |bean| bean.bean_get_attributes }
40
+ end
41
+
42
+ def do_bean_set_attributes(params)
43
+ return if !params || params.empty?
44
+ changed = false
45
+ @list.each_with_index do |bean, i|
46
+ changed = true
47
+ bean.bean_set_attributes(params[i] || params[i.to_s])
48
+ end
49
+ bean_attributes_changed if changed
50
+ end
51
+ end
52
+ end
data/lib/rumx/server.rb CHANGED
@@ -2,6 +2,9 @@ require 'sinatra/base'
2
2
  require 'json'
3
3
  require 'haml'
4
4
  require 'uri'
5
+ require 'cgi'
6
+ # See http://groups.google.com/group/sinatrarb/browse_thread/thread/87bf7613631e48aa
7
+ require 'rack/file'
5
8
 
6
9
  module Rumx
7
10
  class Server < Sinatra::Base
@@ -26,7 +29,7 @@ module Rumx
26
29
 
27
30
  def render_tree_bean_children(parent_path, parent_bean)
28
31
  val = ''
29
- parent_bean.bean_children.each do |name, bean|
32
+ parent_bean.bean_each_child do |name, bean|
30
33
  #puts "in child name=#{name} bean=#{bean}"
31
34
  path = "#{parent_path}/#{name}"
32
35
  val << partial(:tree_bean, :locals => {:path => path, :name =>name, :bean => bean})
@@ -77,20 +80,33 @@ module Rumx
77
80
  partial :link_to_content, :locals => {:href => attributes_path(path), :name => 'Attributes'}
78
81
  end
79
82
 
80
- def link_to_attribute(parent_path, rel_path)
81
- partial :link_to_content, :locals => {:href => attribute_path(parent_path+'/'+rel_path), :name => rel_path}
83
+ def link_to_attribute(parent_path, attribute_info)
84
+ path = rel_path(attribute_info.ancestry)
85
+ partial :link_to_content, :locals => {:href => attribute_path(parent_path+'/'+path), :name => path}
82
86
  end
83
87
 
84
88
  def link_to_operations(path)
85
89
  partial :link_to_content, :locals => {:href => operations_path(path), :name => 'Operations'}
86
90
  end
87
91
 
88
- def link_to_operation(parent_path, rel_path)
89
- partial :link_to_content, :locals => {:href => operation_path(parent_path+'/'+rel_path), :name => rel_path}
92
+ def link_to_operation(parent_path, operation)
93
+ partial :link_to_content, :locals => {:href => operation_path(parent_path+'/'+operation.name.to_s), :name => operation.name}
90
94
  end
91
95
 
92
- def attribute_value_tag(attribute, param_name, value)
93
- partial :attribute_value_tag, :locals => {:attribute => attribute, :param_name => param_name, :value => value}
96
+ def attribute_value_tag(attribute_info)
97
+ partial :attribute_value_tag, :locals => {:attribute_info => attribute_info}
98
+ end
99
+
100
+ def rel_path(ancestry)
101
+ ancestry.join('/')
102
+ end
103
+
104
+ def param_name(ancestry)
105
+ pname = ancestry[0].to_s
106
+ ancestry[1..-1].each do |name|
107
+ pname += "[#{name}]"
108
+ end
109
+ return pname
94
110
  end
95
111
  end
96
112
 
@@ -99,70 +115,23 @@ module Rumx
99
115
  end
100
116
 
101
117
  get '/*/attributes.?:format?' do
102
- path = params[:splat][0]
103
- bean = Bean.find(path.split('/'))
104
- return 404 unless bean
105
118
  # For get we read, then write. post is the other way around.
106
- if params[:format]
107
- handle_attributes(bean.bean_get_and_set_attributes(params), params[:format])
108
- else
109
- haml_for_ajax :content_attributes, :locals => {:get_set_method => :bean_get_and_set_attributes, :params => params, :path => path, :bean => bean}
110
- end
119
+ do_get_or_post_splat_attributes(params, :bean_get_and_set_attributes)
111
120
  end
112
121
 
113
122
  post '/*/attributes.?:format?' do
114
- path = params[:splat][0]
115
- bean = Bean.find(path.split('/'))
116
- return 404 unless bean
117
123
  # For post we write, then read. get is the other way around.
118
- if params[:format]
119
- handle_attributes(bean.bean_set_and_get_attributes(params), params[:format])
120
- else
121
- haml_for_ajax :content_attributes, :locals => {:get_set_method => :bean_set_and_get_attributes, :params => params, :path => path, :bean => bean}
122
- end
124
+ do_get_or_post_splat_attributes(params, :bean_set_and_get_attributes)
123
125
  end
124
126
 
125
127
  # Allow a monitor to get the attributes from multiple beans.
126
128
  # Use with params such as prefix_0=bean0&bean_0=MyFolder/MyBean&prefix_1=bean1&bean_1=MyOtherFolder/SomeOtherBean
127
129
  get '/attributes.?:format?' do
128
- hash = {}
129
- with_indexed_params(params) do |prefix, bean, new_params|
130
- return 404 unless bean
131
- hash[prefix.to_sym] = bean.bean_get_and_set_attributes(new_params)
132
- end
133
- handle_attributes(hash, params[:format])
130
+ do_get_or_post_attributes(params, :bean_get_and_set_attributes)
134
131
  end
135
132
 
136
133
  post '/attributes.?:format?' do
137
- hash = {}
138
- with_indexed_params(params) do |prefix, bean, new_params|
139
- return 404 unless bean
140
- hash[prefix.to_sym] = bean.bean_set_and_get_attributes(new_params)
141
- end
142
- handle_attributes(hash, params[:format])
143
- end
144
-
145
- get '/*/attribute.?:format?' do
146
- path = params[:splat][0]
147
- bean, attribute, param_name, value = Bean.find_attribute(path.split('/'))
148
- return 404 unless bean
149
- if params[:format] == 'json'
150
- else
151
- haml_for_ajax :content_attribute, :locals => {:path => '/' + path, :bean => bean, :attribute => attribute, :param_name => param_name, :value => value}
152
- end
153
- end
154
-
155
- post '/*/attribute.?:format?' do
156
- path = params[:splat][0]
157
- bean, attribute, param_name, value = Bean.find_attribute(path.split('/'))
158
- return 404 unless bean
159
- bean.bean_set_attributes(params)
160
- # Do it again to get the updated value
161
- bean, attribute, param_name, value = Bean.find_attribute(path.split('/'))
162
- if params[:format] == 'json'
163
- else
164
- haml_for_ajax :content_attribute, :locals => {:path => '/' + path, :bean => bean, :attribute => attribute, :param_name => param_name, :value => value}
165
- end
134
+ do_get_or_post_attributes(params, :bean_set_and_get_attributes)
166
135
  end
167
136
 
168
137
  get '/*/operations' do
@@ -228,21 +197,48 @@ module Rumx
228
197
  return str
229
198
  end
230
199
 
231
- def with_indexed_params(params)
232
- i = 0
233
- while (prefix = params[prefix_key = "prefix_#{i}"]) && (bean_name = params[bean_key = "bean_#{i}"])
200
+ def do_get_or_post_splat_attributes(params, get_set_method)
201
+ #puts "params=#{params.inspect}"
202
+ path = params[:splat][0]
203
+ bean = Bean.find(path.split('/'))
204
+ return 404 unless bean
205
+ if params[:format]
206
+ handle_attributes(bean.send(get_set_method, params), params[:format])
207
+ else
208
+ haml_for_ajax :content_attributes, :locals => {:get_set_method => get_set_method, :params => params, :path => path, :bean => bean}
209
+ end
210
+ end
211
+
212
+ def do_get_or_post_attributes(params, get_set_method)
213
+ hash = {}
214
+ index = 0
215
+ while query = params["query_#{index}"]
216
+ index += 1
217
+ uri = URI.parse(query)
218
+ prefix = nil
219
+ bean_path = uri.path
220
+ if i = bean_path.index('=')
221
+ prefix = bean_path[0,i]
222
+ bean_path = bean_path[(i+1)..-1]
223
+ end
224
+ bean = Bean.find(bean_path.split('/'))
225
+ return 404 unless bean
234
226
  new_params = {}
235
- postfix = "_#{i}"
236
- bean = Bean.find(bean_name.split('/'))
237
- params.each do |key, value|
238
- if key.end_with?(postfix) && key != prefix_key && key != bean_key
239
- new_params[key[0...-(postfix.size)]] = value
227
+ if uri.query
228
+ cgi = CGI.parse(uri.query)
229
+ # We shouldn't have any dual params so let's turn this into a params object we can understand
230
+ cgi.each do |key, value|
231
+ new_params[key] = value[0]
240
232
  end
241
233
  end
242
- yield prefix, bean, new_params
243
- i += 1
234
+ bean_hash = bean.send(get_set_method, new_params)
235
+ if prefix
236
+ hash[prefix.to_sym] = bean_hash
237
+ else
238
+ hash = hash.merge(bean_hash)
239
+ end
244
240
  end
241
+ handle_attributes(hash, params[:format])
245
242
  end
246
-
247
243
  end
248
244
  end