mongomatic 0.6.5 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +29 -0
- data/lib/mongomatic/base.rb +14 -1
- data/lib/mongomatic/errors.rb +8 -0
- data/lib/mongomatic/observable.rb +46 -0
- data/lib/mongomatic/observer.rb +4 -0
- data/lib/mongomatic.rb +8 -3
- data/test/helper.rb +8 -0
- data/test/test_observable.rb +200 -0
- metadata +10 -6
data/README.rdoc
CHANGED
@@ -201,6 +201,35 @@ Mongomatic doesn't have any kind of special support for relationship management
|
|
201
201
|
end
|
202
202
|
end
|
203
203
|
|
204
|
+
== Observers
|
205
|
+
|
206
|
+
Mongomatic does have one thing in common with ActiveRecord and that is observers. You can add observers to your class to decouple distinct functionality in callbacks. To add observation to your model you must include the Mongomatic::Observable module. All observers inherit from Mongomatic::Observer.
|
207
|
+
|
208
|
+
Unlike ActiveRecord the existence of a CollectionNameObserver will automatically add the observer the CollectionName class. Instead you must use the observer macro or CollectionName.add_observer
|
209
|
+
|
210
|
+
You can add your own observers to CollectionName using CollectionName.add_observer(klass).
|
211
|
+
|
212
|
+
class MyCustomCallbacks < Mongomatic::Observer
|
213
|
+
def after_insert_or_update
|
214
|
+
puts "after insert or update"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
class Person < Mongomatic::Base
|
219
|
+
include Mongomatic::Observable
|
220
|
+
observer :PersonObserver
|
221
|
+
observer MyCustomCallbacks
|
222
|
+
end
|
223
|
+
|
224
|
+
# this observer is automatically added to the Person class
|
225
|
+
class PersonObserver < Mongomatic::Observer
|
226
|
+
def after_insert(instance)
|
227
|
+
puts "new person inserted"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
It is worth noting that you should be careful the operations you perform on the instance of your class passed to the observer callbacks. Calling operations that invoke callbacks can result in an infinite loop if improperly structured. To avoid this future implementations may only pass the document (instance of Mongomatic::MHash) to observers.
|
232
|
+
|
204
233
|
== Note on Patches/Pull Requests
|
205
234
|
|
206
235
|
* Fork the project.
|
data/lib/mongomatic/base.rb
CHANGED
@@ -147,7 +147,18 @@ module Mongomatic
|
|
147
147
|
field, hash = hash_for_field(key.to_s, true)
|
148
148
|
hash[field]
|
149
149
|
end
|
150
|
-
|
150
|
+
|
151
|
+
##
|
152
|
+
# Same as Hash#delete
|
153
|
+
#
|
154
|
+
# mydoc.delete("name")
|
155
|
+
# => "Ben"
|
156
|
+
# mydoc.has_hey?("name")
|
157
|
+
# => false
|
158
|
+
def delete(key)
|
159
|
+
@doc.delete(key)
|
160
|
+
end
|
161
|
+
|
151
162
|
# Fetch a field (just like a hash):
|
152
163
|
# mydoc["name"]
|
153
164
|
# => "Ben"
|
@@ -297,6 +308,8 @@ module Mongomatic
|
|
297
308
|
end
|
298
309
|
|
299
310
|
def do_callback(meth)
|
311
|
+
notify(meth) if self.class.included_modules.include?(Mongomatic::Observable) # TODO entire block is smelly, doesnt belong here
|
312
|
+
|
300
313
|
return false unless respond_to?(meth, true)
|
301
314
|
send(meth)
|
302
315
|
end
|
data/lib/mongomatic/errors.rb
CHANGED
@@ -32,6 +32,14 @@ module Mongomatic
|
|
32
32
|
!(@errors.any? { |k,v| v && !v.empty? })
|
33
33
|
end
|
34
34
|
|
35
|
+
def any?
|
36
|
+
!empty?
|
37
|
+
end
|
38
|
+
|
39
|
+
def count
|
40
|
+
@errors.values.inject(0) { |sum, errors| sum += errors.size }
|
41
|
+
end
|
42
|
+
|
35
43
|
def full_messages
|
36
44
|
full_messages = []
|
37
45
|
@errors.each do |field, messages|
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Mongomatic
|
2
|
+
module Observable
|
3
|
+
def self.included(base)
|
4
|
+
base.send(:extend, ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
def notify(meth, opts = {})
|
8
|
+
self.class.observers.each do |observer|
|
9
|
+
@observer_cache ||= {}
|
10
|
+
unless observer_klass = @observer_cache[observer]
|
11
|
+
@observer_cache[observer] = observer_klass = Object.const_get(observer) if Module.const_defined?(observer)
|
12
|
+
end
|
13
|
+
|
14
|
+
if observer_klass
|
15
|
+
instance = observer_klass.new
|
16
|
+
instance.send(meth, self, opts) if instance.respond_to?(meth)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
def observers
|
23
|
+
@observers ||= []
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_observer(klass)
|
27
|
+
@observers ||= []
|
28
|
+
@observers << klass.to_s.to_sym unless @observers.include?(klass.to_s.to_sym)
|
29
|
+
end
|
30
|
+
alias :observer :add_observer
|
31
|
+
|
32
|
+
def has_observer?(klass_or_sym)
|
33
|
+
case klass_or_sym
|
34
|
+
when Symbol
|
35
|
+
@observers.include?(klass)
|
36
|
+
else
|
37
|
+
@observers.include?(klass.to_s.to_sym)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def remove_observers
|
42
|
+
@observers = []
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/mongomatic.rb
CHANGED
@@ -5,11 +5,14 @@ gem "activesupport", ">= 2.3.5"
|
|
5
5
|
require "bson"
|
6
6
|
require "mongo"
|
7
7
|
|
8
|
-
|
8
|
+
require 'active_support/version'
|
9
|
+
|
10
|
+
if ActiveSupport::VERSION::MAJOR == 3
|
11
|
+
gem 'i18n', '>= 0.4.2'
|
9
12
|
require 'active_support/core_ext/object/blank' # newer versions of active_support (>= 3.0)
|
10
13
|
require 'active_support/core_ext/hash' # newer versions of active_support (>= 3.0)
|
11
|
-
|
12
|
-
require 'active_support
|
14
|
+
else
|
15
|
+
require 'active_support'
|
13
16
|
end
|
14
17
|
|
15
18
|
module Mongomatic
|
@@ -29,6 +32,8 @@ module Mongomatic
|
|
29
32
|
end
|
30
33
|
end
|
31
34
|
|
35
|
+
require "#{File.dirname(__FILE__)}/mongomatic/observer"
|
36
|
+
require "#{File.dirname(__FILE__)}/mongomatic/observable"
|
32
37
|
require "#{File.dirname(__FILE__)}/mongomatic/exceptions"
|
33
38
|
require "#{File.dirname(__FILE__)}/mongomatic/util"
|
34
39
|
require "#{File.dirname(__FILE__)}/mongomatic/m_hash"
|
data/test/helper.rb
CHANGED
@@ -99,13 +99,21 @@ class Thing < Mongomatic::Base
|
|
99
99
|
end
|
100
100
|
|
101
101
|
class Foobar < Mongomatic::Base
|
102
|
+
include Mongomatic::Observable
|
103
|
+
observer :FoobarObserver
|
104
|
+
|
102
105
|
def validate
|
103
106
|
errors << ["color", "must not be blank"] if self["color"].blank?
|
104
107
|
errors << "missing style" if self["style"].blank?
|
105
108
|
end
|
106
109
|
end
|
107
110
|
|
111
|
+
class RigObserver < Mongomatic::Observer
|
112
|
+
end
|
113
|
+
|
108
114
|
class Rig < Mongomatic::Base
|
115
|
+
include Mongomatic::Observable
|
116
|
+
|
109
117
|
# :cast => true, :raise => false is the default
|
110
118
|
typed_field "age", :type => :fixnum, :cast => true
|
111
119
|
typed_field "manufacturer.name", :type => :string, :cast => true
|
@@ -0,0 +1,200 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
|
4
|
+
class MyCoolCallbacks < Mongomatic::Observer
|
5
|
+
end
|
6
|
+
|
7
|
+
class ThingObserver < Mongomatic::Observer
|
8
|
+
end
|
9
|
+
|
10
|
+
class FoobarObserver < Mongomatic::Observer
|
11
|
+
class << self
|
12
|
+
attr_accessor :observable_instance, :observer_opts
|
13
|
+
|
14
|
+
def observer_tests
|
15
|
+
@observer_tests || []
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_observer_test_val(val)
|
19
|
+
@observer_tests ||= []
|
20
|
+
@observer_tests << val
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def do_something(instance, opts)
|
25
|
+
self.class.observer_opts = opts
|
26
|
+
self.class.add_observer_test_val(:do_something)
|
27
|
+
end
|
28
|
+
|
29
|
+
def before_validate(instance, opts)
|
30
|
+
self.class.observable_instance = instance
|
31
|
+
self.class.add_observer_test_val(:before_validate)
|
32
|
+
end
|
33
|
+
|
34
|
+
def after_validate(instance, opts)
|
35
|
+
self.class.add_observer_test_val(:after_validate)
|
36
|
+
end
|
37
|
+
|
38
|
+
def before_insert(instance, opts)
|
39
|
+
self.class.add_observer_test_val(:before_insert)
|
40
|
+
end
|
41
|
+
|
42
|
+
def before_insert_or_update(instance, opts)
|
43
|
+
self.class.add_observer_test_val(:before_insert_or_update)
|
44
|
+
end
|
45
|
+
|
46
|
+
def after_insert_or_update(instance, opts)
|
47
|
+
self.class.add_observer_test_val(:after_insert_or_update)
|
48
|
+
end
|
49
|
+
|
50
|
+
def after_insert(instance, opts)
|
51
|
+
self.class.add_observer_test_val(:after_insert)
|
52
|
+
end
|
53
|
+
|
54
|
+
def before_update(instance, opts)
|
55
|
+
self.class.add_observer_test_val(:before_update)
|
56
|
+
end
|
57
|
+
|
58
|
+
def after_update(instance, opts)
|
59
|
+
self.class.add_observer_test_val(:after_update)
|
60
|
+
end
|
61
|
+
|
62
|
+
def before_remove(instance, opts)
|
63
|
+
self.class.add_observer_test_val(:before_remove)
|
64
|
+
end
|
65
|
+
|
66
|
+
def after_remove(instance, opts)
|
67
|
+
self.class.add_observer_test_val(:after_remove)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class TestObservable < MiniTest::Unit::TestCase
|
72
|
+
def test_add_observer_to_class
|
73
|
+
Person.send(:include, Mongomatic::Observable)
|
74
|
+
Person.remove_observers
|
75
|
+
|
76
|
+
assert_equal [], Person.observers
|
77
|
+
|
78
|
+
Person.add_observer(MyCoolCallbacks)
|
79
|
+
assert_equal Person.observers, [:MyCoolCallbacks]
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_add_observer_to_class_as_symbol
|
83
|
+
Person.send(:include, Mongomatic::Observable)
|
84
|
+
Person.remove_observers
|
85
|
+
|
86
|
+
assert_equal [], Person.observers
|
87
|
+
Person.add_observer(:MyCoolCallbacks)
|
88
|
+
|
89
|
+
assert_equal Person.observers, [:MyCoolCallbacks]
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_add_observer_using_directive
|
93
|
+
assert_equal Foobar.observers, [:FoobarObserver]
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_does_not_bomb_with_nonexistent_observer
|
97
|
+
Person.send(:include, Mongomatic::Observable)
|
98
|
+
Person.remove_observers
|
99
|
+
|
100
|
+
Person.add_observer(:DoesNotExist)
|
101
|
+
p = Person.new
|
102
|
+
|
103
|
+
p.valid?
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_passes_instance_to_observer
|
107
|
+
f = Foobar.new
|
108
|
+
f.valid?
|
109
|
+
|
110
|
+
assert_equal f, FoobarObserver.observable_instance
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_before_validate
|
114
|
+
f = Foobar.new
|
115
|
+
f.valid?
|
116
|
+
|
117
|
+
assert FoobarObserver.observer_tests.include?(:before_validate)
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_after_validate
|
121
|
+
f = Foobar.new
|
122
|
+
f.valid?
|
123
|
+
|
124
|
+
assert FoobarObserver.observer_tests.include?(:after_validate)
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_before_insert
|
128
|
+
f = Foobar.new('style' => 'cool', 'color' => 'green')
|
129
|
+
f.insert
|
130
|
+
|
131
|
+
assert FoobarObserver.observer_tests.include?(:before_insert)
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_after_insert
|
135
|
+
f = Foobar.new('style' => 'cool', 'color' => 'green')
|
136
|
+
f.insert
|
137
|
+
|
138
|
+
assert FoobarObserver.observer_tests.include?(:after_insert)
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_before_insert_or_update
|
142
|
+
f = Foobar.new('style' => 'cool', 'color' => 'green')
|
143
|
+
f.insert
|
144
|
+
|
145
|
+
assert FoobarObserver.observer_tests.include?(:before_insert_or_update)
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_after_insert_or_update
|
149
|
+
f = Foobar.new('style' => 'cool', 'color' => 'green')
|
150
|
+
f.insert
|
151
|
+
|
152
|
+
assert FoobarObserver.observer_tests.include?(:after_insert_or_update)
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_before_update
|
156
|
+
f = Foobar.new('style' => 'cool', 'color' => 'green')
|
157
|
+
f.insert
|
158
|
+
f.update
|
159
|
+
|
160
|
+
assert FoobarObserver.observer_tests.include?(:before_update)
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_after_update
|
164
|
+
f = Foobar.new('style' => 'cool', 'color' => 'green')
|
165
|
+
f.insert
|
166
|
+
f.update
|
167
|
+
|
168
|
+
assert FoobarObserver.observer_tests.include?(:after_update)
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_before_remove
|
172
|
+
f = Foobar.new('style' => 'cool', 'color' => 'green')
|
173
|
+
f.insert
|
174
|
+
f.remove
|
175
|
+
|
176
|
+
assert FoobarObserver.observer_tests.include?(:before_remove)
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_after_remove
|
180
|
+
f = Foobar.new('style' => 'cool', 'color' => 'green')
|
181
|
+
f.insert
|
182
|
+
f.remove
|
183
|
+
|
184
|
+
assert FoobarObserver.observer_tests.include?(:after_remove)
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_custom_callback
|
188
|
+
opts = {:a => 1234}
|
189
|
+
f = Foobar.new('style' => 'cool', 'color' => 'green')
|
190
|
+
class << f
|
191
|
+
def do_something
|
192
|
+
notify(:do_something, {:a => 1234})
|
193
|
+
end
|
194
|
+
end
|
195
|
+
f.do_something
|
196
|
+
|
197
|
+
assert FoobarObserver.observer_tests.include?(:do_something)
|
198
|
+
assert_equal opts, FoobarObserver.observer_opts
|
199
|
+
end
|
200
|
+
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 7
|
8
|
+
- 0
|
9
|
+
version: 0.7.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Ben Myles
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-11-
|
17
|
+
date: 2010-11-18 00:00:00 -08:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -99,6 +99,8 @@ files:
|
|
99
99
|
- lib/mongomatic/expectations/present.rb
|
100
100
|
- lib/mongomatic/m_hash.rb
|
101
101
|
- lib/mongomatic/modifiers.rb
|
102
|
+
- lib/mongomatic/observable.rb
|
103
|
+
- lib/mongomatic/observer.rb
|
102
104
|
- lib/mongomatic/type_converters.rb
|
103
105
|
- lib/mongomatic/typed_fields.rb
|
104
106
|
- lib/mongomatic/util.rb
|
@@ -109,6 +111,7 @@ files:
|
|
109
111
|
- test/test_find.rb
|
110
112
|
- test/test_misc.rb
|
111
113
|
- test/test_modifiers.rb
|
114
|
+
- test/test_observable.rb
|
112
115
|
- test/test_persistence.rb
|
113
116
|
- test/test_typed_fields.rb
|
114
117
|
- test/test_validations.rb
|
@@ -117,8 +120,8 @@ homepage: http://mongomatic.com/
|
|
117
120
|
licenses: []
|
118
121
|
|
119
122
|
post_install_message:
|
120
|
-
rdoc_options:
|
121
|
-
|
123
|
+
rdoc_options: []
|
124
|
+
|
122
125
|
require_paths:
|
123
126
|
- lib
|
124
127
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -150,6 +153,7 @@ test_files:
|
|
150
153
|
- test/test_find.rb
|
151
154
|
- test/test_misc.rb
|
152
155
|
- test/test_modifiers.rb
|
156
|
+
- test/test_observable.rb
|
153
157
|
- test/test_persistence.rb
|
154
158
|
- test/test_typed_fields.rb
|
155
159
|
- test/test_validations.rb
|