wonkavision 0.5.4 → 0.5.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/CHANGELOG.rdoc +28 -16
  2. data/Gemfile +5 -0
  3. data/LICENSE.txt +21 -21
  4. data/Rakefile +47 -47
  5. data/lib/wonkavision.rb +75 -74
  6. data/lib/wonkavision/acts_as_oompa_loompa.rb +22 -22
  7. data/lib/wonkavision/event_binding.rb +21 -21
  8. data/lib/wonkavision/event_context.rb +9 -9
  9. data/lib/wonkavision/event_coordinator.rb +75 -75
  10. data/lib/wonkavision/event_handler.rb +15 -15
  11. data/lib/wonkavision/event_namespace.rb +79 -79
  12. data/lib/wonkavision/event_path_segment.rb +35 -35
  13. data/lib/wonkavision/message_mapper.rb +30 -30
  14. data/lib/wonkavision/message_mapper/indifferent_access.rb +30 -26
  15. data/lib/wonkavision/message_mapper/map.rb +241 -153
  16. data/lib/wonkavision/persistence/mongo_mapper_adapter.rb +32 -32
  17. data/lib/wonkavision/persistence/mongoid_adapter.rb +32 -0
  18. data/lib/wonkavision/plugins.rb +30 -30
  19. data/lib/wonkavision/plugins/business_activity.rb +92 -92
  20. data/lib/wonkavision/plugins/business_activity/event_binding.rb +15 -15
  21. data/lib/wonkavision/plugins/callbacks.rb +182 -182
  22. data/lib/wonkavision/plugins/event_handling.rb +111 -111
  23. data/lib/wonkavision/plugins/timeline.rb +79 -79
  24. data/lib/wonkavision/version.rb +3 -3
  25. data/test/business_activity_test.rb +31 -31
  26. data/test/event_handler_test.rb +68 -69
  27. data/test/event_namespace_test.rb +108 -108
  28. data/test/event_path_segment_test.rb +41 -41
  29. data/test/log/test.log +817 -18354
  30. data/test/map_test.rb +315 -201
  31. data/test/message_mapper_test.rb +20 -20
  32. data/test/test_activity_models.rb +72 -72
  33. data/test/test_helper.rb +70 -63
  34. data/test/timeline_test.rb +55 -61
  35. data/test/wonkavision_test.rb +9 -9
  36. metadata +72 -12
  37. data/wonkavision.gemspec +0 -97
@@ -0,0 +1,32 @@
1
+ module Wonkavision
2
+ module Mongoid
3
+ module Activity
4
+
5
+ def self.included(model)
6
+ model.send(:include,::Mongoid::Document)
7
+ model.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ include Wonkavision::ActsAsOompaLoompa
12
+
13
+ def define_document_key(key_name,key_type,options={})
14
+ options[:type] = key_type
15
+ field(key_name, options) unless fields[key_name]
16
+ end
17
+
18
+ def update_activity(activity,event_data)
19
+ activity.write_attributes(event_data)
20
+ :updated
21
+ end
22
+
23
+ def find_activity_instance(correlation_field_name,correlation_id)
24
+ self.find_or_create_by({correlation_field_name=>correlation_id})
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+ end
32
+
@@ -1,30 +1,30 @@
1
- #This concept (and code) shamelessly stolen from MongoMapper
2
- #(http://railstips.org/blog/archives/2010/02/21/mongomapper-07-plugins/)
3
- #as so much of my Ruby code tends to be. I added a few little things and changed some
4
- #names to avoid conflicts.
5
- module Wonkavision
6
- module Plugins
7
- def wonkavision_plugins
8
- @wonkavision_plugins ||= []
9
- end
10
-
11
- def has_wonkavision_plugin?(plugin)
12
- wonkavision_plugins.detect{|p|p==plugin}
13
- end
14
-
15
- def ensure_wonkavision_plugin(plugin,option={})
16
- use(plugin,options) unless has_wonkavision_plugin?(plugin)
17
- end
18
-
19
- def plug(mod,options={})
20
- extend mod::ClassMethods if mod.const_defined?(:ClassMethods)
21
- include mod::InstanceMethods if mod.const_defined?(:InstanceMethods)
22
- extend mod::Fields if mod.const_defined?(:Fields)
23
- include mod::Fields if mod.const_defined?(:Fields)
24
- mod.configure(self,options) if mod.respond_to?(:configure)
25
- wonkavision_plugins << mod
26
- end
27
- alias use plug
28
-
29
- end
30
- end
1
+ #This concept (and code) shamelessly stolen from MongoMapper
2
+ #(http://railstips.org/blog/archives/2010/02/21/mongomapper-07-plugins/)
3
+ #as so much of my Ruby code tends to be. I added a few little things and changed some
4
+ #names to avoid conflicts.
5
+ module Wonkavision
6
+ module Plugins
7
+ def wonkavision_plugins
8
+ @wonkavision_plugins ||= []
9
+ end
10
+
11
+ def has_wonkavision_plugin?(plugin)
12
+ wonkavision_plugins.detect{|p|p==plugin}
13
+ end
14
+
15
+ def ensure_wonkavision_plugin(plugin,option={})
16
+ use(plugin,options) unless has_wonkavision_plugin?(plugin)
17
+ end
18
+
19
+ def plug(mod,options={})
20
+ extend mod::ClassMethods if mod.const_defined?(:ClassMethods)
21
+ include mod::InstanceMethods if mod.const_defined?(:InstanceMethods)
22
+ extend mod::Fields if mod.const_defined?(:Fields)
23
+ include mod::Fields if mod.const_defined?(:Fields)
24
+ mod.configure(self,options) if mod.respond_to?(:configure)
25
+ wonkavision_plugins << mod
26
+ end
27
+ alias use plug
28
+
29
+ end
30
+ end
@@ -1,93 +1,93 @@
1
- module Wonkavision
2
- module Plugins
3
- module BusinessActivity
4
-
5
- def self.all
6
- @@all ||= []
7
- end
8
-
9
-
10
- def self.configure(activity,options={})
11
- activity.write_inheritable_attribute :business_activity_options, {}
12
- activity.class_inheritable_reader :business_activity_options
13
-
14
- activity.write_inheritable_attribute :correlation_ids, []
15
- activity.class_inheritable_reader :correlation_ids
16
-
17
- BusinessActivity.all << activity
18
- end
19
-
20
- def self.normalize_correlation_ids(*args)
21
- model_field,event_field = if args.length == 1 then
22
- case args[0]
23
- when Hash then [args[0][:model], args[0][:event] || args[0][:model]]
24
- else [args[0],args[0]]
25
- end
26
- else
27
- [args[0],args[1] || args[0]]
28
- end
29
- {:model=>model_field,:event=>event_field}
30
- end
31
-
32
- module ClassMethods
33
- def instantiate_handler(event_context)
34
- correlation = event_context.binding.correlation
35
- event_id = correlation ? (correlation[:event] || event_correlation_id_key) : event_correlation_id_key
36
- model_id = correlation ? (correlation[:model] || correlation_id_field) : correlation_id_field
37
-
38
- correlation_id = event_context.data[event_id.to_s]
39
- find_activity_instance(model_id,correlation_id)
40
- end
41
-
42
- def event(name,*args,&block)
43
- handle(name,args) do
44
- ctx = @wonkavision_event_context
45
- result = :ok
46
- if (block_given?)
47
- result = case block.arity
48
- when 3 then yield ctx.data,ctx.path,self
49
- when 2 then yield ctx.data, ctx.path
50
- when 1 then yield ctx.data
51
- else instance_eval &block
52
- end
53
- end
54
- unless result == :handled
55
- result = self.class.update_activity(self,ctx.data) unless result == :updated
56
- save!
57
- end
58
- result
59
- end
60
- end
61
-
62
- def correlate_by(*args)
63
- return {:model=>correlation_id_field, :event=>event_correlation_id_key} if args.blank?
64
-
65
- correlation = BusinessActivity.normalize_correlation_ids(*args)
66
-
67
- business_activity_options[:correlation_id_field] = correlation[:model]
68
- business_activity_options[:event_correlation_id_key] = correlation[:event]
69
-
70
- define_document_key correlation_id_field, String, :index=>true
71
- correlation_ids << correlation
72
- end
73
-
74
- def create_binding(name,handler,*args)
75
- Wonkavision::Plugins::BusinessActivity::EventBinding.new(name,handler,*args)
76
- end
77
-
78
- end
79
-
80
- module Fields
81
-
82
- def correlation_id_field
83
- business_activity_options[:correlation_id_field] ||= "id"
84
- end
85
-
86
- def event_correlation_id_key
87
- business_activity_options[:event_correlation_id_key] || correlation_id_field
88
- end
89
-
90
- end
91
- end
92
- end
1
+ module Wonkavision
2
+ module Plugins
3
+ module BusinessActivity
4
+
5
+ def self.all
6
+ @@all ||= []
7
+ end
8
+
9
+
10
+ def self.configure(activity,options={})
11
+ activity.write_inheritable_attribute :business_activity_options, {}
12
+ activity.class_inheritable_reader :business_activity_options
13
+
14
+ activity.write_inheritable_attribute :correlation_ids, []
15
+ activity.class_inheritable_reader :correlation_ids
16
+
17
+ BusinessActivity.all << activity
18
+ end
19
+
20
+ def self.normalize_correlation_ids(*args)
21
+ model_field,event_field = if args.length == 1 then
22
+ case args[0]
23
+ when Hash then [args[0][:model], args[0][:event] || args[0][:model]]
24
+ else [args[0],args[0]]
25
+ end
26
+ else
27
+ [args[0],args[1] || args[0]]
28
+ end
29
+ {:model=>model_field,:event=>event_field}
30
+ end
31
+
32
+ module ClassMethods
33
+ def instantiate_handler(event_context)
34
+ correlation = event_context.binding.correlation
35
+ event_id = correlation ? (correlation[:event] || event_correlation_id_key) : event_correlation_id_key
36
+ model_id = correlation ? (correlation[:model] || correlation_id_field) : correlation_id_field
37
+
38
+ correlation_id = event_context.data[event_id.to_s]
39
+ find_activity_instance(model_id,correlation_id)
40
+ end
41
+
42
+ def event(name,*args,&block)
43
+ handle(name,args) do
44
+ ctx = @wonkavision_event_context
45
+ result = :ok
46
+ if (block_given?)
47
+ result = case block.arity
48
+ when 3 then yield ctx.data,ctx.path,self
49
+ when 2 then yield ctx.data, ctx.path
50
+ when 1 then yield ctx.data
51
+ else instance_eval &block
52
+ end
53
+ end
54
+ unless result == :handled
55
+ result = self.class.update_activity(self,ctx.data) unless result == :updated
56
+ save!
57
+ end
58
+ result
59
+ end
60
+ end
61
+
62
+ def correlate_by(*args)
63
+ return {:model=>correlation_id_field, :event=>event_correlation_id_key} if args.blank?
64
+
65
+ correlation = BusinessActivity.normalize_correlation_ids(*args)
66
+
67
+ business_activity_options[:correlation_id_field] = correlation[:model]
68
+ business_activity_options[:event_correlation_id_key] = correlation[:event]
69
+
70
+ define_document_key correlation_id_field, String, :index=>true
71
+ correlation_ids << correlation
72
+ end
73
+
74
+ def create_binding(name,handler,*args)
75
+ Wonkavision::Plugins::BusinessActivity::EventBinding.new(name,handler,*args)
76
+ end
77
+
78
+ end
79
+
80
+ module Fields
81
+
82
+ def correlation_id_field
83
+ business_activity_options[:correlation_id_field] ||= "id"
84
+ end
85
+
86
+ def event_correlation_id_key
87
+ business_activity_options[:event_correlation_id_key] || correlation_id_field
88
+ end
89
+
90
+ end
91
+ end
92
+ end
93
93
  end
@@ -1,16 +1,16 @@
1
- module Wonkavision
2
- module Plugins
3
- module BusinessActivity
4
- class EventBinding < Wonkavision::EventBinding
5
- attr_reader :correlation
6
- def initialize(*args)
7
- super(*args)
8
- if (correlation_args = @options.delete(:correlate_by))
9
- correlation_args = [correlation_args] unless correlation_args.is_a?(Array)
10
- @correlation = BusinessActivity.normalize_correlation_ids(*correlation_args)
11
- end
12
- end
13
- end
14
- end
15
- end
1
+ module Wonkavision
2
+ module Plugins
3
+ module BusinessActivity
4
+ class EventBinding < Wonkavision::EventBinding
5
+ attr_reader :correlation
6
+ def initialize(*args)
7
+ super(*args)
8
+ if (correlation_args = @options.delete(:correlate_by))
9
+ correlation_args = [correlation_args] unless correlation_args.is_a?(Array)
10
+ @correlation = BusinessActivity.normalize_correlation_ids(*correlation_args)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
16
  end
@@ -1,182 +1,182 @@
1
- # The note you see below, 'Almost all of this callback stuff...', along with all the code adapted from ActiveSupport,
2
- # is in turn adapted from MongoMapper, and for the same reasons.
3
- # encoding: UTF-8
4
- # Almost all of this callback stuff is pulled directly from ActiveSupport
5
- # in the interest of support rails 2 and 3 at the same time and is the
6
- # same copyright as rails.
7
- module Wonkavision
8
- module Plugins
9
- module Callbacks
10
- def self.configure(handler,options)
11
- handler.define_wonkavision_callbacks :before_event,
12
- :after_event
13
-
14
- handler.alias_method_chain :handle_event, :callbacks
15
- end
16
-
17
- module ClassMethods
18
- #The ODM library may already have taken care of mixing in callback functioanlity,
19
- #in which case we'll just use that
20
- def define_wonkavision_callbacks(*callbacks)
21
- callbacks.each do |callback|
22
- class_eval <<-"end_eval"
23
- def self.#{callback}(*methods, &block)
24
- callbacks = CallbackChain.build(:#{callback}, *methods, &block)
25
- @#{callback}_callbacks ||= CallbackChain.new
26
- @#{callback}_callbacks.concat callbacks
27
- end
28
-
29
- def self.#{callback}_callback_chain
30
- @#{callback}_callbacks ||= CallbackChain.new
31
-
32
- if superclass.respond_to?(:#{callback}_callback_chain)
33
- CallbackChain.new(
34
- superclass.#{callback}_callback_chain +
35
- @#{callback}_callbacks
36
- )
37
- else
38
- @#{callback}_callbacks
39
- end
40
- end
41
- end_eval
42
- end
43
- end
44
- end
45
-
46
- module InstanceMethods
47
- def handle_event_with_callbacks
48
- ctx = @wonkavision_event_context
49
- run_wonkavision_callbacks(:before_event)
50
- handle_event_without_callbacks
51
- run_wonkavision_callbacks(:after_event)
52
- end
53
-
54
- def run_wonkavision_callbacks(kind, options={}, &block)
55
- callback_chain_method = "#{kind}_callback_chain"
56
- return unless self.class.respond_to?(callback_chain_method)
57
- self.class.send(callback_chain_method).run(self, options, &block)
58
- end
59
- end
60
-
61
- class CallbackChain < Array
62
- def self.build(kind, *methods, &block)
63
- methods, options = extract_options(*methods, &block)
64
- methods.map! { |method| Callback.new(kind, method, options) }
65
- new(methods)
66
- end
67
-
68
- def run(object, options={}, &terminator)
69
- enumerator = options[:enumerator] || :each
70
-
71
- unless block_given?
72
- send(enumerator) { |callback| callback.call(object) }
73
- else
74
- send(enumerator) do |callback|
75
- result = callback.call(object)
76
- break result if terminator.call(result, object)
77
- end
78
- end
79
- end
80
-
81
- def replace_or_append!(chain)
82
- if index = index(chain)
83
- self[index] = chain
84
- else
85
- self << chain
86
- end
87
- self
88
- end
89
-
90
- def find(callback, &block)
91
- select { |c| c == callback && (!block_given? || yield(c)) }.first
92
- end
93
-
94
- def delete(callback)
95
- super(callback.is_a?(Callback) ? callback : find(callback))
96
- end
97
-
98
- private
99
- def self.extract_options(*methods, &block)
100
- methods.flatten!
101
- options = methods.extract_options!
102
- methods << block if block_given?
103
- return methods, options
104
- end
105
-
106
- def extract_options(*methods, &block)
107
- self.class.extract_options(*methods, &block)
108
- end
109
- end
110
-
111
- class Callback
112
- attr_reader :kind, :method, :identifier, :options
113
-
114
- def initialize(kind, method, options={})
115
- @kind = kind
116
- @method = method
117
- @identifier = options[:identifier]
118
- @options = options
119
- end
120
-
121
- def ==(other)
122
- case other
123
- when Callback
124
- (self.identifier && self.identifier == other.identifier) || self.method == other.method
125
- else
126
- (self.identifier && self.identifier == other) || self.method == other
127
- end
128
- end
129
-
130
- def eql?(other)
131
- self == other
132
- end
133
-
134
- def dup
135
- self.class.new(@kind, @method, @options.dup)
136
- end
137
-
138
- def hash
139
- if @identifier
140
- @identifier.hash
141
- else
142
- @method.hash
143
- end
144
- end
145
-
146
- def call(*args, &block)
147
- evaluate_method(method, *args, &block) if should_run_callback?(*args)
148
- rescue LocalJumpError
149
- raise ArgumentError,
150
- "Cannot yield from a Proc type filter. The Proc must take two " +
151
- "arguments and execute #call on the second argument."
152
- end
153
-
154
- private
155
- def evaluate_method(method, *args, &block)
156
- case method
157
- when Symbol
158
- object = args.shift
159
- object.send(method, *args, &block)
160
- when String
161
- eval(method, args.first.instance_eval { binding })
162
- when Proc, Method
163
- method.call(*args, &block)
164
- else
165
- if method.respond_to?(kind)
166
- method.send(kind, *args, &block)
167
- else
168
- raise ArgumentError,
169
- "Callbacks must be a symbol denoting the method to call, a string to be evaluated, " +
170
- "a block to be invoked, or an object responding to the callback method."
171
- end
172
- end
173
- end
174
-
175
- def should_run_callback?(*args)
176
- [options[:if]].flatten.compact.all? { |a| evaluate_method(a, *args) } &&
177
- ![options[:unless]].flatten.compact.any? { |a| evaluate_method(a, *args) }
178
- end
179
- end
180
- end
181
- end
182
- end
1
+ # The note you see below, 'Almost all of this callback stuff...', along with all the code adapted from ActiveSupport,
2
+ # is in turn adapted from MongoMapper, and for the same reasons.
3
+ # encoding: UTF-8
4
+ # Almost all of this callback stuff is pulled directly from ActiveSupport
5
+ # in the interest of support rails 2 and 3 at the same time and is the
6
+ # same copyright as rails.
7
+ module Wonkavision
8
+ module Plugins
9
+ module Callbacks
10
+ def self.configure(handler,options)
11
+ handler.define_wonkavision_callbacks :before_event,
12
+ :after_event
13
+
14
+ handler.alias_method_chain :handle_event, :callbacks
15
+ end
16
+
17
+ module ClassMethods
18
+ #The ODM library may already have taken care of mixing in callback functioanlity,
19
+ #in which case we'll just use that
20
+ def define_wonkavision_callbacks(*callbacks)
21
+ callbacks.each do |callback|
22
+ class_eval <<-"end_eval"
23
+ def self.#{callback}(*methods, &block)
24
+ callbacks = CallbackChain.build(:#{callback}, *methods, &block)
25
+ @#{callback}_callbacks ||= CallbackChain.new
26
+ @#{callback}_callbacks.concat callbacks
27
+ end
28
+
29
+ def self.#{callback}_callback_chain
30
+ @#{callback}_callbacks ||= CallbackChain.new
31
+
32
+ if superclass.respond_to?(:#{callback}_callback_chain)
33
+ CallbackChain.new(
34
+ superclass.#{callback}_callback_chain +
35
+ @#{callback}_callbacks
36
+ )
37
+ else
38
+ @#{callback}_callbacks
39
+ end
40
+ end
41
+ end_eval
42
+ end
43
+ end
44
+ end
45
+
46
+ module InstanceMethods
47
+ def handle_event_with_callbacks
48
+ ctx = @wonkavision_event_context
49
+ run_wonkavision_callbacks(:before_event)
50
+ handle_event_without_callbacks
51
+ run_wonkavision_callbacks(:after_event)
52
+ end
53
+
54
+ def run_wonkavision_callbacks(kind, options={}, &block)
55
+ callback_chain_method = "#{kind}_callback_chain"
56
+ return unless self.class.respond_to?(callback_chain_method)
57
+ self.class.send(callback_chain_method).run(self, options, &block)
58
+ end
59
+ end
60
+
61
+ class CallbackChain < Array
62
+ def self.build(kind, *methods, &block)
63
+ methods, options = extract_options(*methods, &block)
64
+ methods.map! { |method| Callback.new(kind, method, options) }
65
+ new(methods)
66
+ end
67
+
68
+ def run(object, options={}, &terminator)
69
+ enumerator = options[:enumerator] || :each
70
+
71
+ unless block_given?
72
+ send(enumerator) { |callback| callback.call(object) }
73
+ else
74
+ send(enumerator) do |callback|
75
+ result = callback.call(object)
76
+ break result if terminator.call(result, object)
77
+ end
78
+ end
79
+ end
80
+
81
+ def replace_or_append!(chain)
82
+ if index = index(chain)
83
+ self[index] = chain
84
+ else
85
+ self << chain
86
+ end
87
+ self
88
+ end
89
+
90
+ def find(callback, &block)
91
+ select { |c| c == callback && (!block_given? || yield(c)) }.first
92
+ end
93
+
94
+ def delete(callback)
95
+ super(callback.is_a?(Callback) ? callback : find(callback))
96
+ end
97
+
98
+ private
99
+ def self.extract_options(*methods, &block)
100
+ methods.flatten!
101
+ options = methods.extract_options!
102
+ methods << block if block_given?
103
+ return methods, options
104
+ end
105
+
106
+ def extract_options(*methods, &block)
107
+ self.class.extract_options(*methods, &block)
108
+ end
109
+ end
110
+
111
+ class Callback
112
+ attr_reader :kind, :method, :identifier, :options
113
+
114
+ def initialize(kind, method, options={})
115
+ @kind = kind
116
+ @method = method
117
+ @identifier = options[:identifier]
118
+ @options = options
119
+ end
120
+
121
+ def ==(other)
122
+ case other
123
+ when Callback
124
+ (self.identifier && self.identifier == other.identifier) || self.method == other.method
125
+ else
126
+ (self.identifier && self.identifier == other) || self.method == other
127
+ end
128
+ end
129
+
130
+ def eql?(other)
131
+ self == other
132
+ end
133
+
134
+ def dup
135
+ self.class.new(@kind, @method, @options.dup)
136
+ end
137
+
138
+ def hash
139
+ if @identifier
140
+ @identifier.hash
141
+ else
142
+ @method.hash
143
+ end
144
+ end
145
+
146
+ def call(*args, &block)
147
+ evaluate_method(method, *args, &block) if should_run_callback?(*args)
148
+ rescue LocalJumpError
149
+ raise ArgumentError,
150
+ "Cannot yield from a Proc type filter. The Proc must take two " +
151
+ "arguments and execute #call on the second argument."
152
+ end
153
+
154
+ private
155
+ def evaluate_method(method, *args, &block)
156
+ case method
157
+ when Symbol
158
+ object = args.shift
159
+ object.send(method, *args, &block)
160
+ when String
161
+ eval(method, args.first.instance_eval { binding })
162
+ when Proc, Method
163
+ method.call(*args, &block)
164
+ else
165
+ if method.respond_to?(kind)
166
+ method.send(kind, *args, &block)
167
+ else
168
+ raise ArgumentError,
169
+ "Callbacks must be a symbol denoting the method to call, a string to be evaluated, " +
170
+ "a block to be invoked, or an object responding to the callback method."
171
+ end
172
+ end
173
+ end
174
+
175
+ def should_run_callback?(*args)
176
+ [options[:if]].flatten.compact.all? { |a| evaluate_method(a, *args) } &&
177
+ ![options[:unless]].flatten.compact.any? { |a| evaluate_method(a, *args) }
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end