wonkavision 0.5.4 → 0.5.9

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 (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