rails-observers 0.1.2 → 0.1.5
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.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +29 -13
- data/lib/rails/observers/action_controller/caching/sweeper.rb +61 -0
- data/lib/rails/observers/action_controller/caching/sweeping.rb +3 -59
- data/lib/rails/observers/action_controller/caching.rb +1 -1
- data/lib/rails/observers/active_resource/observing.rb +41 -0
- data/lib/rails/observers/activerecord/observer.rb +4 -0
- data/lib/rails/observers/railtie.rb +35 -5
- data/lib/rails/observers/version.rb +1 -1
- metadata +39 -62
- data/.gitignore +0 -18
- data/.travis.yml +0 -12
- data/Gemfile +0 -8
- data/Rakefile +0 -34
- data/rails-observers.gemspec +0 -26
- data/rails-observers.gemspec.erb +0 -26
- data/test/configuration_test.rb +0 -37
- data/test/console_test.rb +0 -38
- data/test/fixtures/developers.yml +0 -4
- data/test/fixtures/minimalistics.yml +0 -2
- data/test/fixtures/topics.yml +0 -41
- data/test/generators/generators_test_helper.rb +0 -16
- data/test/generators/namespaced_generators_test.rb +0 -34
- data/test/generators/observer_generator_test.rb +0 -33
- data/test/helper.rb +0 -74
- data/test/isolation/abstract_unit.rb +0 -119
- data/test/lifecycle_test.rb +0 -249
- data/test/models/observers.rb +0 -27
- data/test/observer_array_test.rb +0 -222
- data/test/observing_test.rb +0 -183
- data/test/rake_test.rb +0 -40
- data/test/sweeper_test.rb +0 -83
- data/test/transaction_callbacks_test.rb +0 -246
data/test/lifecycle_test.rb
DELETED
@@ -1,249 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class SpecialDeveloper < Developer; end
|
4
|
-
|
5
|
-
class DeveloperObserver < ActiveRecord::Observer
|
6
|
-
def calls
|
7
|
-
@calls ||= []
|
8
|
-
end
|
9
|
-
|
10
|
-
def before_save(developer)
|
11
|
-
calls << developer
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
class SalaryChecker < ActiveRecord::Observer
|
16
|
-
observe :special_developer
|
17
|
-
attr_accessor :last_saved
|
18
|
-
|
19
|
-
def before_save(developer)
|
20
|
-
return developer.salary > 80000
|
21
|
-
end
|
22
|
-
|
23
|
-
module Implementation
|
24
|
-
def after_save(developer)
|
25
|
-
self.last_saved = developer
|
26
|
-
end
|
27
|
-
end
|
28
|
-
include Implementation
|
29
|
-
end
|
30
|
-
|
31
|
-
class TopicaAuditor < ActiveRecord::Observer
|
32
|
-
observe :topic
|
33
|
-
|
34
|
-
attr_reader :topic
|
35
|
-
|
36
|
-
def after_find(topic)
|
37
|
-
@topic = topic
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
class TopicObserver < ActiveRecord::Observer
|
42
|
-
attr_reader :topic
|
43
|
-
|
44
|
-
def after_find(topic)
|
45
|
-
@topic = topic
|
46
|
-
end
|
47
|
-
|
48
|
-
# Create an after_save callback, so a notify_observer hook is created
|
49
|
-
# on :topic.
|
50
|
-
def after_save(nothing)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
class MinimalisticObserver < ActiveRecord::Observer
|
55
|
-
attr_reader :minimalistic
|
56
|
-
|
57
|
-
def after_find(minimalistic)
|
58
|
-
@minimalistic = minimalistic
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
class MultiObserver < ActiveRecord::Observer
|
63
|
-
attr_reader :record
|
64
|
-
|
65
|
-
def self.observed_class() [ Topic, Developer ] end
|
66
|
-
|
67
|
-
cattr_reader :last_inherited
|
68
|
-
@@last_inherited = nil
|
69
|
-
|
70
|
-
def observed_class_inherited_with_testing(subclass)
|
71
|
-
observed_class_inherited_without_testing(subclass)
|
72
|
-
@@last_inherited = subclass
|
73
|
-
end
|
74
|
-
|
75
|
-
alias_method_chain :observed_class_inherited, :testing
|
76
|
-
|
77
|
-
def after_find(record)
|
78
|
-
@record = record
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
class ValidatedComment < Comment
|
83
|
-
attr_accessor :callers
|
84
|
-
|
85
|
-
before_validation :record_callers
|
86
|
-
|
87
|
-
after_validation do
|
88
|
-
record_callers
|
89
|
-
end
|
90
|
-
|
91
|
-
def record_callers
|
92
|
-
callers << self.class if callers
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
class ValidatedCommentObserver < ActiveRecord::Observer
|
97
|
-
attr_accessor :callers
|
98
|
-
|
99
|
-
def after_validation(model)
|
100
|
-
callers << self.class if callers
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
|
105
|
-
class AroundTopic < Topic
|
106
|
-
end
|
107
|
-
|
108
|
-
class AroundTopicObserver < ActiveRecord::Observer
|
109
|
-
observe :around_topic
|
110
|
-
def topic_ids
|
111
|
-
@topic_ids ||= []
|
112
|
-
end
|
113
|
-
|
114
|
-
def around_save(topic)
|
115
|
-
topic_ids << topic.id
|
116
|
-
yield(topic)
|
117
|
-
topic_ids << topic.id
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
class LifecycleTest < ActiveRecord::TestCase
|
122
|
-
fixtures :topics, :developers, :minimalistics
|
123
|
-
|
124
|
-
def test_before_destroy
|
125
|
-
topic = Topic.find(1)
|
126
|
-
assert_difference 'Topic.count', -(1 + topic.replies.size) do
|
127
|
-
topic.destroy
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
def test_auto_observer
|
132
|
-
topic_observer = TopicaAuditor.instance
|
133
|
-
assert_nil TopicaAuditor.observed_class
|
134
|
-
assert_equal [Topic], TopicaAuditor.observed_classes.to_a
|
135
|
-
|
136
|
-
topic = Topic.find(1)
|
137
|
-
assert_equal topic.title, topic_observer.topic.title
|
138
|
-
end
|
139
|
-
|
140
|
-
def test_inferred_auto_observer
|
141
|
-
topic_observer = TopicObserver.instance
|
142
|
-
assert_equal Topic, TopicObserver.observed_class
|
143
|
-
|
144
|
-
topic = Topic.find(1)
|
145
|
-
assert_equal topic.title, topic_observer.topic.title
|
146
|
-
end
|
147
|
-
|
148
|
-
def test_observing_two_classes
|
149
|
-
multi_observer = MultiObserver.instance
|
150
|
-
|
151
|
-
topic = Topic.find(1)
|
152
|
-
assert_equal topic.title, multi_observer.record.title
|
153
|
-
|
154
|
-
developer = Developer.find(1)
|
155
|
-
assert_equal developer.name, multi_observer.record.name
|
156
|
-
end
|
157
|
-
|
158
|
-
def test_observing_subclasses
|
159
|
-
multi_observer = MultiObserver.instance
|
160
|
-
|
161
|
-
developer = SpecialDeveloper.find(1)
|
162
|
-
assert_equal developer.name, multi_observer.record.name
|
163
|
-
|
164
|
-
klass = Class.new(Developer)
|
165
|
-
assert_equal klass, multi_observer.last_inherited
|
166
|
-
|
167
|
-
developer = klass.find(1)
|
168
|
-
assert_equal developer.name, multi_observer.record.name
|
169
|
-
end
|
170
|
-
|
171
|
-
def test_after_find_can_be_observed_when_its_not_defined_on_the_model
|
172
|
-
observer = MinimalisticObserver.instance
|
173
|
-
assert_equal Minimalistic, MinimalisticObserver.observed_class
|
174
|
-
|
175
|
-
minimalistic = Minimalistic.find(1)
|
176
|
-
assert_equal minimalistic, observer.minimalistic
|
177
|
-
end
|
178
|
-
|
179
|
-
def test_after_find_can_be_observed_when_its_defined_on_the_model
|
180
|
-
observer = TopicObserver.instance
|
181
|
-
assert_equal Topic, TopicObserver.observed_class
|
182
|
-
|
183
|
-
topic = Topic.find(1)
|
184
|
-
assert_equal topic, observer.topic
|
185
|
-
end
|
186
|
-
|
187
|
-
def test_invalid_observer
|
188
|
-
assert_raise(ArgumentError) { Topic.observers = Object.new; Topic.instantiate_observers }
|
189
|
-
end
|
190
|
-
|
191
|
-
test "model callbacks fire before observers are notified" do
|
192
|
-
callers = []
|
193
|
-
|
194
|
-
comment = ValidatedComment.new
|
195
|
-
comment.callers = ValidatedCommentObserver.instance.callers = callers
|
196
|
-
|
197
|
-
comment.valid?
|
198
|
-
assert_equal [ValidatedComment, ValidatedComment, ValidatedCommentObserver], callers,
|
199
|
-
"model callbacks did not fire before observers were notified"
|
200
|
-
end
|
201
|
-
|
202
|
-
test "able to save developer" do
|
203
|
-
SalaryChecker.instance # activate
|
204
|
-
developer = SpecialDeveloper.new :name => 'Roger', :salary => 100000
|
205
|
-
assert developer.save, "developer with normal salary failed to save"
|
206
|
-
end
|
207
|
-
|
208
|
-
test "unable to save developer with low salary" do
|
209
|
-
SalaryChecker.instance # activate
|
210
|
-
developer = SpecialDeveloper.new :name => 'Rookie', :salary => 50000
|
211
|
-
assert !developer.save, "allowed to save a developer with too low salary"
|
212
|
-
end
|
213
|
-
|
214
|
-
test "able to call methods defined with included module" do # https://rails.lighthouseapp.com/projects/8994/tickets/6065-activerecordobserver-is-not-aware-of-method-added-by-including-modules
|
215
|
-
SalaryChecker.instance # activate
|
216
|
-
developer = SpecialDeveloper.create! :name => 'Roger', :salary => 100000
|
217
|
-
assert_equal developer, SalaryChecker.instance.last_saved
|
218
|
-
end
|
219
|
-
|
220
|
-
test "around filter from observer should accept block" do
|
221
|
-
observer = AroundTopicObserver.instance
|
222
|
-
topic = AroundTopic.new
|
223
|
-
topic.save
|
224
|
-
assert_nil observer.topic_ids.first
|
225
|
-
assert_not_nil observer.topic_ids.last
|
226
|
-
end
|
227
|
-
|
228
|
-
test "able to disable observers" do
|
229
|
-
observer = DeveloperObserver.instance # activate
|
230
|
-
observer.calls.clear
|
231
|
-
|
232
|
-
ActiveRecord::Base.observers.disable DeveloperObserver do
|
233
|
-
Developer.create! :name => 'Ancestor', :salary => 100000
|
234
|
-
SpecialDeveloper.create! :name => 'Descendent', :salary => 100000
|
235
|
-
end
|
236
|
-
|
237
|
-
assert_equal [], observer.calls
|
238
|
-
end
|
239
|
-
|
240
|
-
def test_observer_is_called_once
|
241
|
-
observer = DeveloperObserver.instance # activate
|
242
|
-
observer.calls.clear
|
243
|
-
|
244
|
-
developer = Developer.create! :name => 'Ancestor', :salary => 100000
|
245
|
-
special_developer = SpecialDeveloper.create! :name => 'Descendent', :salary => 100000
|
246
|
-
|
247
|
-
assert_equal [developer, special_developer], observer.calls
|
248
|
-
end
|
249
|
-
end
|
data/test/models/observers.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
class ORM
|
2
|
-
include ActiveModel::Observing
|
3
|
-
|
4
|
-
def save
|
5
|
-
notify_observers :before_save
|
6
|
-
end
|
7
|
-
|
8
|
-
class Observer < ActiveModel::Observer
|
9
|
-
def before_save_invocations
|
10
|
-
@before_save_invocations ||= []
|
11
|
-
end
|
12
|
-
|
13
|
-
def before_save(record)
|
14
|
-
before_save_invocations << record
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
class Widget < ORM; end
|
20
|
-
class Budget < ORM; end
|
21
|
-
class WidgetObserver < ORM::Observer; end
|
22
|
-
class BudgetObserver < ORM::Observer; end
|
23
|
-
class AuditTrail < ORM::Observer
|
24
|
-
observe :widget, :budget
|
25
|
-
end
|
26
|
-
|
27
|
-
ORM.instantiate_observers
|
data/test/observer_array_test.rb
DELETED
@@ -1,222 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'active_model'
|
3
|
-
require 'rails/observers/active_model/active_model'
|
4
|
-
require 'models/observers'
|
5
|
-
|
6
|
-
class ObserverArrayTest < ActiveModel::TestCase
|
7
|
-
def teardown
|
8
|
-
ORM.observers.enable :all
|
9
|
-
Budget.observers.enable :all
|
10
|
-
Widget.observers.enable :all
|
11
|
-
end
|
12
|
-
|
13
|
-
def assert_observer_notified(model_class, observer_class)
|
14
|
-
observer_class.instance.before_save_invocations.clear
|
15
|
-
model_instance = model_class.new
|
16
|
-
model_instance.save
|
17
|
-
assert_equal [model_instance], observer_class.instance.before_save_invocations
|
18
|
-
end
|
19
|
-
|
20
|
-
def assert_observer_not_notified(model_class, observer_class)
|
21
|
-
observer_class.instance.before_save_invocations.clear
|
22
|
-
model_instance = model_class.new
|
23
|
-
model_instance.save
|
24
|
-
assert_equal [], observer_class.instance.before_save_invocations
|
25
|
-
end
|
26
|
-
|
27
|
-
test "all observers are enabled by default" do
|
28
|
-
assert_observer_notified Widget, WidgetObserver
|
29
|
-
assert_observer_notified Budget, BudgetObserver
|
30
|
-
assert_observer_notified Widget, AuditTrail
|
31
|
-
assert_observer_notified Budget, AuditTrail
|
32
|
-
end
|
33
|
-
|
34
|
-
test "can disable individual observers using a class constant" do
|
35
|
-
ORM.observers.disable WidgetObserver
|
36
|
-
|
37
|
-
assert_observer_not_notified Widget, WidgetObserver
|
38
|
-
assert_observer_notified Budget, BudgetObserver
|
39
|
-
assert_observer_notified Widget, AuditTrail
|
40
|
-
assert_observer_notified Budget, AuditTrail
|
41
|
-
end
|
42
|
-
|
43
|
-
test "can enable individual observers using a class constant" do
|
44
|
-
ORM.observers.disable :all
|
45
|
-
ORM.observers.enable AuditTrail
|
46
|
-
|
47
|
-
assert_observer_not_notified Widget, WidgetObserver
|
48
|
-
assert_observer_not_notified Budget, BudgetObserver
|
49
|
-
assert_observer_notified Widget, AuditTrail
|
50
|
-
assert_observer_notified Budget, AuditTrail
|
51
|
-
end
|
52
|
-
|
53
|
-
test "can disable individual observers using a symbol" do
|
54
|
-
ORM.observers.disable :budget_observer
|
55
|
-
|
56
|
-
assert_observer_notified Widget, WidgetObserver
|
57
|
-
assert_observer_not_notified Budget, BudgetObserver
|
58
|
-
assert_observer_notified Widget, AuditTrail
|
59
|
-
assert_observer_notified Budget, AuditTrail
|
60
|
-
end
|
61
|
-
|
62
|
-
test "can enable individual observers using a symbol" do
|
63
|
-
ORM.observers.disable :all
|
64
|
-
ORM.observers.enable :audit_trail
|
65
|
-
|
66
|
-
assert_observer_not_notified Widget, WidgetObserver
|
67
|
-
assert_observer_not_notified Budget, BudgetObserver
|
68
|
-
assert_observer_notified Widget, AuditTrail
|
69
|
-
assert_observer_notified Budget, AuditTrail
|
70
|
-
end
|
71
|
-
|
72
|
-
test "can disable multiple observers at a time" do
|
73
|
-
ORM.observers.disable :widget_observer, :budget_observer
|
74
|
-
|
75
|
-
assert_observer_not_notified Widget, WidgetObserver
|
76
|
-
assert_observer_not_notified Budget, BudgetObserver
|
77
|
-
assert_observer_notified Widget, AuditTrail
|
78
|
-
assert_observer_notified Budget, AuditTrail
|
79
|
-
end
|
80
|
-
|
81
|
-
test "can enable multiple observers at a time" do
|
82
|
-
ORM.observers.disable :all
|
83
|
-
ORM.observers.enable :widget_observer, :budget_observer
|
84
|
-
|
85
|
-
assert_observer_notified Widget, WidgetObserver
|
86
|
-
assert_observer_notified Budget, BudgetObserver
|
87
|
-
assert_observer_not_notified Widget, AuditTrail
|
88
|
-
assert_observer_not_notified Budget, AuditTrail
|
89
|
-
end
|
90
|
-
|
91
|
-
test "can disable all observers using :all" do
|
92
|
-
ORM.observers.disable :all
|
93
|
-
|
94
|
-
assert_observer_not_notified Widget, WidgetObserver
|
95
|
-
assert_observer_not_notified Budget, BudgetObserver
|
96
|
-
assert_observer_not_notified Widget, AuditTrail
|
97
|
-
assert_observer_not_notified Budget, AuditTrail
|
98
|
-
end
|
99
|
-
|
100
|
-
test "can enable all observers using :all" do
|
101
|
-
ORM.observers.disable :all
|
102
|
-
ORM.observers.enable :all
|
103
|
-
|
104
|
-
assert_observer_notified Widget, WidgetObserver
|
105
|
-
assert_observer_notified Budget, BudgetObserver
|
106
|
-
assert_observer_notified Widget, AuditTrail
|
107
|
-
assert_observer_notified Budget, AuditTrail
|
108
|
-
end
|
109
|
-
|
110
|
-
test "can disable observers on individual models without affecting those observers on other models" do
|
111
|
-
Widget.observers.disable :all
|
112
|
-
|
113
|
-
assert_observer_not_notified Widget, WidgetObserver
|
114
|
-
assert_observer_notified Budget, BudgetObserver
|
115
|
-
assert_observer_not_notified Widget, AuditTrail
|
116
|
-
assert_observer_notified Budget, AuditTrail
|
117
|
-
end
|
118
|
-
|
119
|
-
test "can enable observers on individual models without affecting those observers on other models" do
|
120
|
-
ORM.observers.disable :all
|
121
|
-
Budget.observers.enable AuditTrail
|
122
|
-
|
123
|
-
assert_observer_not_notified Widget, WidgetObserver
|
124
|
-
assert_observer_not_notified Budget, BudgetObserver
|
125
|
-
assert_observer_not_notified Widget, AuditTrail
|
126
|
-
assert_observer_notified Budget, AuditTrail
|
127
|
-
end
|
128
|
-
|
129
|
-
test "can disable observers for the duration of a block" do
|
130
|
-
yielded = false
|
131
|
-
ORM.observers.disable :budget_observer do
|
132
|
-
yielded = true
|
133
|
-
assert_observer_notified Widget, WidgetObserver
|
134
|
-
assert_observer_not_notified Budget, BudgetObserver
|
135
|
-
assert_observer_notified Widget, AuditTrail
|
136
|
-
assert_observer_notified Budget, AuditTrail
|
137
|
-
end
|
138
|
-
|
139
|
-
assert yielded
|
140
|
-
assert_observer_notified Widget, WidgetObserver
|
141
|
-
assert_observer_notified Budget, BudgetObserver
|
142
|
-
assert_observer_notified Widget, AuditTrail
|
143
|
-
assert_observer_notified Budget, AuditTrail
|
144
|
-
end
|
145
|
-
|
146
|
-
test "can enable observers for the duration of a block" do
|
147
|
-
yielded = false
|
148
|
-
Widget.observers.disable :all
|
149
|
-
|
150
|
-
Widget.observers.enable :all do
|
151
|
-
yielded = true
|
152
|
-
assert_observer_notified Widget, WidgetObserver
|
153
|
-
assert_observer_notified Budget, BudgetObserver
|
154
|
-
assert_observer_notified Widget, AuditTrail
|
155
|
-
assert_observer_notified Budget, AuditTrail
|
156
|
-
end
|
157
|
-
|
158
|
-
assert yielded
|
159
|
-
assert_observer_not_notified Widget, WidgetObserver
|
160
|
-
assert_observer_notified Budget, BudgetObserver
|
161
|
-
assert_observer_not_notified Widget, AuditTrail
|
162
|
-
assert_observer_notified Budget, AuditTrail
|
163
|
-
end
|
164
|
-
|
165
|
-
test "raises an appropriate error when a developer accidentally enables or disables the wrong class (i.e. Widget instead of WidgetObserver)" do
|
166
|
-
assert_raise ArgumentError do
|
167
|
-
ORM.observers.enable :widget
|
168
|
-
end
|
169
|
-
|
170
|
-
assert_raise ArgumentError do
|
171
|
-
ORM.observers.enable Widget
|
172
|
-
end
|
173
|
-
|
174
|
-
assert_raise ArgumentError do
|
175
|
-
ORM.observers.disable :widget
|
176
|
-
end
|
177
|
-
|
178
|
-
assert_raise ArgumentError do
|
179
|
-
ORM.observers.disable Widget
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
test "allows #enable at the superclass level to override #disable at the subclass level when called last" do
|
184
|
-
Widget.observers.disable :all
|
185
|
-
ORM.observers.enable :all
|
186
|
-
|
187
|
-
assert_observer_notified Widget, WidgetObserver
|
188
|
-
assert_observer_notified Budget, BudgetObserver
|
189
|
-
assert_observer_notified Widget, AuditTrail
|
190
|
-
assert_observer_notified Budget, AuditTrail
|
191
|
-
end
|
192
|
-
|
193
|
-
test "allows #disable at the superclass level to override #enable at the subclass level when called last" do
|
194
|
-
Budget.observers.enable :audit_trail
|
195
|
-
ORM.observers.disable :audit_trail
|
196
|
-
|
197
|
-
assert_observer_notified Widget, WidgetObserver
|
198
|
-
assert_observer_notified Budget, BudgetObserver
|
199
|
-
assert_observer_not_notified Widget, AuditTrail
|
200
|
-
assert_observer_not_notified Budget, AuditTrail
|
201
|
-
end
|
202
|
-
|
203
|
-
test "can use the block form at different levels of the hierarchy" do
|
204
|
-
yielded = false
|
205
|
-
Widget.observers.disable :all
|
206
|
-
|
207
|
-
ORM.observers.enable :all do
|
208
|
-
yielded = true
|
209
|
-
assert_observer_notified Widget, WidgetObserver
|
210
|
-
assert_observer_notified Budget, BudgetObserver
|
211
|
-
assert_observer_notified Widget, AuditTrail
|
212
|
-
assert_observer_notified Budget, AuditTrail
|
213
|
-
end
|
214
|
-
|
215
|
-
assert yielded
|
216
|
-
assert_observer_not_notified Widget, WidgetObserver
|
217
|
-
assert_observer_notified Budget, BudgetObserver
|
218
|
-
assert_observer_not_notified Widget, AuditTrail
|
219
|
-
assert_observer_notified Budget, AuditTrail
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
data/test/observing_test.rb
DELETED
@@ -1,183 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'active_model'
|
3
|
-
require 'rails/observers/active_model/active_model'
|
4
|
-
|
5
|
-
class ObservedModel
|
6
|
-
include ActiveModel::Observing
|
7
|
-
|
8
|
-
class Observer
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
class FooObserver < ActiveModel::Observer
|
13
|
-
class << self
|
14
|
-
public :new
|
15
|
-
end
|
16
|
-
|
17
|
-
attr_accessor :stub
|
18
|
-
|
19
|
-
def on_spec(record, *args)
|
20
|
-
stub.event_with(record, *args) if stub
|
21
|
-
end
|
22
|
-
|
23
|
-
def around_save(record)
|
24
|
-
yield :in_around_save
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
class Foo
|
29
|
-
include ActiveModel::Observing
|
30
|
-
end
|
31
|
-
|
32
|
-
class ObservingTest < ActiveModel::TestCase
|
33
|
-
def setup
|
34
|
-
ObservedModel.observers.clear
|
35
|
-
end
|
36
|
-
|
37
|
-
test "initializes model with no cached observers" do
|
38
|
-
assert ObservedModel.observers.empty?, "Not empty: #{ObservedModel.observers.inspect}"
|
39
|
-
end
|
40
|
-
|
41
|
-
test "stores cached observers in an array" do
|
42
|
-
ObservedModel.observers << :foo
|
43
|
-
assert ObservedModel.observers.include?(:foo), ":foo not in #{ObservedModel.observers.inspect}"
|
44
|
-
end
|
45
|
-
|
46
|
-
test "flattens array of assigned cached observers" do
|
47
|
-
ObservedModel.observers = [[:foo], :bar]
|
48
|
-
assert ObservedModel.observers.include?(:foo), ":foo not in #{ObservedModel.observers.inspect}"
|
49
|
-
assert ObservedModel.observers.include?(:bar), ":bar not in #{ObservedModel.observers.inspect}"
|
50
|
-
end
|
51
|
-
|
52
|
-
test "uses an ObserverArray so observers can be disabled" do
|
53
|
-
ObservedModel.observers = [:foo, :bar]
|
54
|
-
assert ObservedModel.observers.is_a?(ActiveModel::ObserverArray)
|
55
|
-
end
|
56
|
-
|
57
|
-
test "instantiates observer names passed as strings" do
|
58
|
-
ObservedModel.observers << 'foo_observer'
|
59
|
-
FooObserver.expects(:instance)
|
60
|
-
ObservedModel.instantiate_observers
|
61
|
-
end
|
62
|
-
|
63
|
-
test "instantiates observer names passed as symbols" do
|
64
|
-
ObservedModel.observers << :foo_observer
|
65
|
-
FooObserver.expects(:instance)
|
66
|
-
ObservedModel.instantiate_observers
|
67
|
-
end
|
68
|
-
|
69
|
-
test "instantiates observer classes" do
|
70
|
-
ObservedModel.observers << ObservedModel::Observer
|
71
|
-
ObservedModel::Observer.expects(:instance)
|
72
|
-
ObservedModel.instantiate_observers
|
73
|
-
end
|
74
|
-
|
75
|
-
test "raises an appropriate error when a developer accidentally adds the wrong class (i.e. Widget instead of WidgetObserver)" do
|
76
|
-
assert_raise ArgumentError do
|
77
|
-
ObservedModel.observers = ['string']
|
78
|
-
ObservedModel.instantiate_observers
|
79
|
-
end
|
80
|
-
assert_raise ArgumentError do
|
81
|
-
ObservedModel.observers = [:string]
|
82
|
-
ObservedModel.instantiate_observers
|
83
|
-
end
|
84
|
-
assert_raise ArgumentError do
|
85
|
-
ObservedModel.observers = [String]
|
86
|
-
ObservedModel.instantiate_observers
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
test "passes observers to subclasses" do
|
91
|
-
FooObserver.instance
|
92
|
-
bar = Class.new(Foo)
|
93
|
-
assert_equal Foo.observers_count, bar.observers_count
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
class ObserverTest < ActiveModel::TestCase
|
98
|
-
def setup
|
99
|
-
ObservedModel.observers = :foo_observer
|
100
|
-
FooObserver.singleton_class.instance_eval do
|
101
|
-
alias_method :original_observed_classes, :observed_classes
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def teardown
|
106
|
-
FooObserver.singleton_class.instance_eval do
|
107
|
-
undef_method :observed_classes
|
108
|
-
alias_method :observed_classes, :original_observed_classes
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
test "guesses implicit observable model name" do
|
113
|
-
assert_equal Foo, FooObserver.observed_class
|
114
|
-
end
|
115
|
-
|
116
|
-
test "tracks implicit observable models" do
|
117
|
-
instance = FooObserver.new
|
118
|
-
assert_equal [Foo], instance.observed_classes
|
119
|
-
end
|
120
|
-
|
121
|
-
test "tracks explicit observed model class" do
|
122
|
-
FooObserver.observe ObservedModel
|
123
|
-
instance = FooObserver.new
|
124
|
-
assert_equal [ObservedModel], instance.observed_classes
|
125
|
-
end
|
126
|
-
|
127
|
-
test "tracks explicit observed model as string" do
|
128
|
-
FooObserver.observe 'observed_model'
|
129
|
-
instance = FooObserver.new
|
130
|
-
assert_equal [ObservedModel], instance.observed_classes
|
131
|
-
end
|
132
|
-
|
133
|
-
test "tracks explicit observed model as symbol" do
|
134
|
-
FooObserver.observe :observed_model
|
135
|
-
instance = FooObserver.new
|
136
|
-
assert_equal [ObservedModel], instance.observed_classes
|
137
|
-
end
|
138
|
-
|
139
|
-
test "calls existing observer event" do
|
140
|
-
foo = Foo.new
|
141
|
-
FooObserver.instance.stub = stub
|
142
|
-
FooObserver.instance.stub.expects(:event_with).with(foo)
|
143
|
-
Foo.notify_observers(:on_spec, foo)
|
144
|
-
end
|
145
|
-
|
146
|
-
test "calls existing observer event from the instance" do
|
147
|
-
foo = Foo.new
|
148
|
-
FooObserver.instance.stub = stub
|
149
|
-
FooObserver.instance.stub.expects(:event_with).with(foo)
|
150
|
-
foo.notify_observers(:on_spec)
|
151
|
-
end
|
152
|
-
|
153
|
-
test "passes extra arguments" do
|
154
|
-
foo = Foo.new
|
155
|
-
FooObserver.instance.stub = stub
|
156
|
-
FooObserver.instance.stub.expects(:event_with).with(foo, :bar)
|
157
|
-
Foo.send(:notify_observers, :on_spec, foo, :bar)
|
158
|
-
end
|
159
|
-
|
160
|
-
test "skips nonexistent observer event" do
|
161
|
-
foo = Foo.new
|
162
|
-
Foo.notify_observers(:whatever, foo)
|
163
|
-
end
|
164
|
-
|
165
|
-
test "update passes a block on to the observer" do
|
166
|
-
yielded_value = nil
|
167
|
-
FooObserver.instance.update(:around_save, Foo.new) do |val|
|
168
|
-
yielded_value = val
|
169
|
-
end
|
170
|
-
assert_equal :in_around_save, yielded_value
|
171
|
-
end
|
172
|
-
|
173
|
-
test "observe redefines observed_classes class method" do
|
174
|
-
class BarObserver < ActiveModel::Observer
|
175
|
-
observe :foo
|
176
|
-
end
|
177
|
-
|
178
|
-
assert_equal [Foo], BarObserver.observed_classes
|
179
|
-
|
180
|
-
BarObserver.observe(ObservedModel)
|
181
|
-
assert_equal [ObservedModel], BarObserver.observed_classes
|
182
|
-
end
|
183
|
-
end
|