motion_blender-support 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (182) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.yardopts +1 -0
  4. data/Gemfile +4 -0
  5. data/HACKS.md +7 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +359 -0
  8. data/Rakefile +14 -0
  9. data/app/app_delegate.rb +5 -0
  10. data/examples/Inflector/.gitignore +16 -0
  11. data/examples/Inflector/Gemfile +5 -0
  12. data/examples/Inflector/Rakefile +13 -0
  13. data/examples/Inflector/app/app_delegate.rb +8 -0
  14. data/examples/Inflector/app/inflections.rb +5 -0
  15. data/examples/Inflector/app/inflector_view_controller.rb +109 -0
  16. data/examples/Inflector/app/words_view_controller.rb +101 -0
  17. data/examples/Inflector/resources/Default-568h@2x.png +0 -0
  18. data/examples/Inflector/spec/main_spec.rb +9 -0
  19. data/lib/motion-support/callbacks.rb +8 -0
  20. data/lib/motion-support/concern.rb +4 -0
  21. data/lib/motion-support/core_ext/array.rb +10 -0
  22. data/lib/motion-support/core_ext/class.rb +5 -0
  23. data/lib/motion-support/core_ext/hash.rb +13 -0
  24. data/lib/motion-support/core_ext/integer.rb +6 -0
  25. data/lib/motion-support/core_ext/module.rb +11 -0
  26. data/lib/motion-support/core_ext/numeric.rb +6 -0
  27. data/lib/motion-support/core_ext/object.rb +12 -0
  28. data/lib/motion-support/core_ext/range.rb +5 -0
  29. data/lib/motion-support/core_ext/string.rb +13 -0
  30. data/lib/motion-support/core_ext/time.rb +16 -0
  31. data/lib/motion-support/core_ext.rb +13 -0
  32. data/lib/motion-support/inflector.rb +8 -0
  33. data/lib/motion-support.rb +81 -0
  34. data/motion/_stdlib/array.rb +13 -0
  35. data/motion/_stdlib/cgi.rb +22 -0
  36. data/motion/_stdlib/date.rb +81 -0
  37. data/motion/_stdlib/enumerable.rb +9 -0
  38. data/motion/_stdlib/time.rb +19 -0
  39. data/motion/callbacks.rb +511 -0
  40. data/motion/concern.rb +122 -0
  41. data/motion/core_ext/array/access.rb +28 -0
  42. data/motion/core_ext/array/conversions.rb +86 -0
  43. data/motion/core_ext/array/extract_options.rb +11 -0
  44. data/motion/core_ext/array/grouping.rb +99 -0
  45. data/motion/core_ext/array/prepend_and_append.rb +7 -0
  46. data/motion/core_ext/array/wrap.rb +45 -0
  47. data/motion/core_ext/array.rb +19 -0
  48. data/motion/core_ext/class/attribute.rb +119 -0
  49. data/motion/core_ext/class/attribute_accessors.rb +168 -0
  50. data/motion/core_ext/date/acts_like.rb +8 -0
  51. data/motion/core_ext/date/calculations.rb +117 -0
  52. data/motion/core_ext/date/conversions.rb +56 -0
  53. data/motion/core_ext/date_and_time/calculations.rb +232 -0
  54. data/motion/core_ext/enumerable.rb +90 -0
  55. data/motion/core_ext/hash/deep_delete_if.rb +23 -0
  56. data/motion/core_ext/hash/deep_merge.rb +27 -0
  57. data/motion/core_ext/hash/except.rb +15 -0
  58. data/motion/core_ext/hash/indifferent_access.rb +19 -0
  59. data/motion/core_ext/hash/keys.rb +150 -0
  60. data/motion/core_ext/hash/reverse_merge.rb +22 -0
  61. data/motion/core_ext/hash/slice.rb +40 -0
  62. data/motion/core_ext/integer/inflections.rb +27 -0
  63. data/motion/core_ext/integer/multiple.rb +10 -0
  64. data/motion/core_ext/integer/time.rb +41 -0
  65. data/motion/core_ext/kernel/singleton_class.rb +6 -0
  66. data/motion/core_ext/metaclass.rb +8 -0
  67. data/motion/core_ext/module/aliasing.rb +69 -0
  68. data/motion/core_ext/module/anonymous.rb +19 -0
  69. data/motion/core_ext/module/attr_internal.rb +38 -0
  70. data/motion/core_ext/module/attribute_accessors.rb +64 -0
  71. data/motion/core_ext/module/delegation.rb +175 -0
  72. data/motion/core_ext/module/introspection.rb +60 -0
  73. data/motion/core_ext/module/reachable.rb +5 -0
  74. data/motion/core_ext/module/remove_method.rb +12 -0
  75. data/motion/core_ext/ns_dictionary.rb +14 -0
  76. data/motion/core_ext/ns_string.rb +14 -0
  77. data/motion/core_ext/numeric/bytes.rb +44 -0
  78. data/motion/core_ext/numeric/conversions.rb +49 -0
  79. data/motion/core_ext/numeric/time.rb +75 -0
  80. data/motion/core_ext/object/acts_like.rb +10 -0
  81. data/motion/core_ext/object/blank.rb +105 -0
  82. data/motion/core_ext/object/deep_dup.rb +44 -0
  83. data/motion/core_ext/object/duplicable.rb +87 -0
  84. data/motion/core_ext/object/inclusion.rb +15 -0
  85. data/motion/core_ext/object/instance_variables.rb +28 -0
  86. data/motion/core_ext/object/to_param.rb +58 -0
  87. data/motion/core_ext/object/to_query.rb +26 -0
  88. data/motion/core_ext/object/try.rb +78 -0
  89. data/motion/core_ext/range/include_range.rb +23 -0
  90. data/motion/core_ext/range/overlaps.rb +8 -0
  91. data/motion/core_ext/regexp.rb +5 -0
  92. data/motion/core_ext/string/access.rb +104 -0
  93. data/motion/core_ext/string/behavior.rb +6 -0
  94. data/motion/core_ext/string/exclude.rb +11 -0
  95. data/motion/core_ext/string/filters.rb +55 -0
  96. data/motion/core_ext/string/indent.rb +43 -0
  97. data/motion/core_ext/string/inflections.rb +178 -0
  98. data/motion/core_ext/string/starts_ends_with.rb +4 -0
  99. data/motion/core_ext/string/strip.rb +24 -0
  100. data/motion/core_ext/time/acts_like.rb +8 -0
  101. data/motion/core_ext/time/calculations.rb +215 -0
  102. data/motion/core_ext/time/conversions.rb +52 -0
  103. data/motion/descendants_tracker.rb +50 -0
  104. data/motion/duration.rb +104 -0
  105. data/motion/hash_with_indifferent_access.rb +253 -0
  106. data/motion/inflections.rb +67 -0
  107. data/motion/inflector/inflections.rb +203 -0
  108. data/motion/inflector/methods.rb +321 -0
  109. data/motion/logger.rb +47 -0
  110. data/motion/number_helper.rb +54 -0
  111. data/motion/version.rb +3 -0
  112. data/motion_blender-support.gemspec +21 -0
  113. data/spec/motion-support/_helpers/constantize_test_cases.rb +75 -0
  114. data/spec/motion-support/_helpers/inflector_test_cases.rb +270 -0
  115. data/spec/motion-support/callback_spec.rb +702 -0
  116. data/spec/motion-support/concern_spec.rb +93 -0
  117. data/spec/motion-support/core_ext/array/access_spec.rb +29 -0
  118. data/spec/motion-support/core_ext/array/conversion_spec.rb +60 -0
  119. data/spec/motion-support/core_ext/array/extract_options_spec.rb +15 -0
  120. data/spec/motion-support/core_ext/array/grouping_spec.rb +85 -0
  121. data/spec/motion-support/core_ext/array/prepend_and_append_spec.rb +25 -0
  122. data/spec/motion-support/core_ext/array/wrap_spec.rb +19 -0
  123. data/spec/motion-support/core_ext/array_spec.rb +16 -0
  124. data/spec/motion-support/core_ext/class/attribute_accessor_spec.rb +127 -0
  125. data/spec/motion-support/core_ext/class/attribute_spec.rb +92 -0
  126. data/spec/motion-support/core_ext/date/acts_like_spec.rb +11 -0
  127. data/spec/motion-support/core_ext/date/calculation_spec.rb +186 -0
  128. data/spec/motion-support/core_ext/date/conversion_spec.rb +18 -0
  129. data/spec/motion-support/core_ext/date_and_time/calculation_spec.rb +336 -0
  130. data/spec/motion-support/core_ext/enumerable_spec.rb +130 -0
  131. data/spec/motion-support/core_ext/hash/deep_delete_if_spec.rb +19 -0
  132. data/spec/motion-support/core_ext/hash/deep_merge_spec.rb +32 -0
  133. data/spec/motion-support/core_ext/hash/except_spec.rb +43 -0
  134. data/spec/motion-support/core_ext/hash/key_spec.rb +236 -0
  135. data/spec/motion-support/core_ext/hash/reverse_merge_spec.rb +26 -0
  136. data/spec/motion-support/core_ext/hash/slice_spec.rb +61 -0
  137. data/spec/motion-support/core_ext/integer/inflection_spec.rb +23 -0
  138. data/spec/motion-support/core_ext/integer/multiple_spec.rb +19 -0
  139. data/spec/motion-support/core_ext/kernel/singleton_class_spec.rb +9 -0
  140. data/spec/motion-support/core_ext/metaclass_spec.rb +9 -0
  141. data/spec/motion-support/core_ext/module/aliasing_spec.rb +143 -0
  142. data/spec/motion-support/core_ext/module/anonymous_spec.rb +29 -0
  143. data/spec/motion-support/core_ext/module/attr_internal_spec.rb +104 -0
  144. data/spec/motion-support/core_ext/module/attribute_accessor_spec.rb +86 -0
  145. data/spec/motion-support/core_ext/module/delegation_spec.rb +136 -0
  146. data/spec/motion-support/core_ext/module/introspection_spec.rb +70 -0
  147. data/spec/motion-support/core_ext/module/reachable_spec.rb +61 -0
  148. data/spec/motion-support/core_ext/module/remove_method_spec.rb +25 -0
  149. data/spec/motion-support/core_ext/numeric/bytes_spec.rb +43 -0
  150. data/spec/motion-support/core_ext/numeric/conversions_spec.rb +40 -0
  151. data/spec/motion-support/core_ext/object/acts_like_spec.rb +21 -0
  152. data/spec/motion-support/core_ext/object/blank_spec.rb +54 -0
  153. data/spec/motion-support/core_ext/object/deep_dup_spec.rb +54 -0
  154. data/spec/motion-support/core_ext/object/duplicable_spec.rb +31 -0
  155. data/spec/motion-support/core_ext/object/inclusion_spec.rb +34 -0
  156. data/spec/motion-support/core_ext/object/instance_variable_spec.rb +19 -0
  157. data/spec/motion-support/core_ext/object/to_param_spec.rb +75 -0
  158. data/spec/motion-support/core_ext/object/to_query_spec.rb +37 -0
  159. data/spec/motion-support/core_ext/object/try_spec.rb +92 -0
  160. data/spec/motion-support/core_ext/range/include_range_spec.rb +31 -0
  161. data/spec/motion-support/core_ext/range/overlap_spec.rb +43 -0
  162. data/spec/motion-support/core_ext/regexp_spec.rb +7 -0
  163. data/spec/motion-support/core_ext/string/access_spec.rb +53 -0
  164. data/spec/motion-support/core_ext/string/behavior_spec.rb +7 -0
  165. data/spec/motion-support/core_ext/string/exclude_spec.rb +8 -0
  166. data/spec/motion-support/core_ext/string/filter_spec.rb +49 -0
  167. data/spec/motion-support/core_ext/string/indent_spec.rb +56 -0
  168. data/spec/motion-support/core_ext/string/inflection_spec.rb +142 -0
  169. data/spec/motion-support/core_ext/string/starts_end_with_spec.rb +14 -0
  170. data/spec/motion-support/core_ext/string/strip_spec.rb +34 -0
  171. data/spec/motion-support/core_ext/string_spec.rb +88 -0
  172. data/spec/motion-support/core_ext/time/acts_like_spec.rb +11 -0
  173. data/spec/motion-support/core_ext/time/calculation_spec.rb +201 -0
  174. data/spec/motion-support/core_ext/time/conversion_spec.rb +53 -0
  175. data/spec/motion-support/descendants_tracker_spec.rb +58 -0
  176. data/spec/motion-support/duration_spec.rb +107 -0
  177. data/spec/motion-support/hash_with_indifferent_access_spec.rb +605 -0
  178. data/spec/motion-support/inflector_spec.rb +504 -0
  179. data/spec/motion-support/ns_dictionary_spec.rb +89 -0
  180. data/spec/motion-support/ns_string_spec.rb +182 -0
  181. data/spec/motion-support/number_helper_spec.rb +55 -0
  182. metadata +352 -0
@@ -0,0 +1,702 @@
1
+ module CallbacksTest
2
+ class Record
3
+ include MotionSupport::Callbacks
4
+
5
+ define_callbacks :save
6
+
7
+ def self.before_save(*filters, &blk)
8
+ set_callback(:save, :before, *filters, &blk)
9
+ end
10
+
11
+ def self.after_save(*filters, &blk)
12
+ set_callback(:save, :after, *filters, &blk)
13
+ end
14
+
15
+ class << self
16
+ def callback_symbol(callback_method)
17
+ method_name = :"#{callback_method}_method"
18
+ define_method(method_name) do
19
+ history << [callback_method, :symbol]
20
+ end
21
+ method_name
22
+ end
23
+
24
+ def callback_proc(callback_method)
25
+ Proc.new { |model| model.history << [callback_method, :proc] }
26
+ end
27
+
28
+ def callback_object(callback_method)
29
+ klass = Class.new
30
+ klass.send(:define_method, callback_method) do |model|
31
+ model.history << [:"#{callback_method}_save", :object]
32
+ end
33
+ klass.new
34
+ end
35
+ end
36
+
37
+ def history
38
+ @history ||= []
39
+ end
40
+ end
41
+
42
+ class Person < Record
43
+ [:before_save, :after_save].each do |callback_method|
44
+ callback_method_sym = callback_method.to_sym
45
+ send(callback_method, callback_symbol(callback_method_sym))
46
+ send(callback_method, callback_proc(callback_method_sym))
47
+ send(callback_method, callback_object(callback_method_sym.to_s.gsub(/_save/, '')))
48
+ send(callback_method) { |model| model.history << [callback_method_sym, :block] }
49
+ end
50
+
51
+ def save
52
+ run_callbacks :save
53
+ end
54
+ end
55
+
56
+ class PersonSkipper < Person
57
+ skip_callback :save, :before, :before_save_method, :if => :yes
58
+ skip_callback :save, :after, :before_save_method, :unless => :yes
59
+ skip_callback :save, :after, :before_save_method, :if => :no
60
+ skip_callback :save, :before, :before_save_method, :unless => :no
61
+ def yes; true; end
62
+ def no; false; end
63
+ end
64
+
65
+ class ParentController
66
+ include MotionSupport::Callbacks
67
+
68
+ define_callbacks :dispatch
69
+
70
+ set_callback :dispatch, :before, :log, :unless => proc {|c| c.action_name == :index || c.action_name == :show }
71
+ set_callback :dispatch, :after, :log2
72
+
73
+ attr_reader :action_name, :logger
74
+ def initialize(action_name)
75
+ @action_name, @logger = action_name, []
76
+ end
77
+
78
+ def log
79
+ @logger << action_name
80
+ end
81
+
82
+ def log2
83
+ @logger << action_name
84
+ end
85
+
86
+ def dispatch
87
+ run_callbacks :dispatch do
88
+ @logger << "Done"
89
+ end
90
+ self
91
+ end
92
+ end
93
+
94
+ class Child < ParentController
95
+ skip_callback :dispatch, :before, :log, :if => proc {|c| c.action_name == :update}
96
+ skip_callback :dispatch, :after, :log2
97
+ end
98
+
99
+ class OneTimeCompile < Record
100
+ @@starts_true, @@starts_false = true, false
101
+
102
+ def initialize
103
+ super
104
+ end
105
+
106
+ before_save Proc.new {|r| r.history << [:before_save, :starts_true, :if] }, :if => :starts_true
107
+ before_save Proc.new {|r| r.history << [:before_save, :starts_false, :if] }, :if => :starts_false
108
+ before_save Proc.new {|r| r.history << [:before_save, :starts_true, :unless] }, :unless => :starts_true
109
+ before_save Proc.new {|r| r.history << [:before_save, :starts_false, :unless] }, :unless => :starts_false
110
+
111
+ def starts_true
112
+ if @@starts_true
113
+ @@starts_true = false
114
+ return true
115
+ end
116
+ @@starts_true
117
+ end
118
+
119
+ def starts_false
120
+ unless @@starts_false
121
+ @@starts_false = true
122
+ return false
123
+ end
124
+ @@starts_false
125
+ end
126
+
127
+ def save
128
+ run_callbacks :save
129
+ end
130
+ end
131
+
132
+ class AfterSaveConditionalPerson < Record
133
+ after_save Proc.new { |r| r.history << [:after_save, :string1] }
134
+ after_save Proc.new { |r| r.history << [:after_save, :string2] }
135
+ def save
136
+ run_callbacks :save
137
+ end
138
+ end
139
+
140
+ class ConditionalPerson < Record
141
+ # proc
142
+ before_save Proc.new { |r| r.history << [:before_save, :proc] }, :if => Proc.new { |r| true }
143
+ before_save Proc.new { |r| r.history << "b00m" }, :if => Proc.new { |r| false }
144
+ before_save Proc.new { |r| r.history << [:before_save, :proc] }, :unless => Proc.new { |r| false }
145
+ before_save Proc.new { |r| r.history << "b00m" }, :unless => Proc.new { |r| true }
146
+ # symbol
147
+ before_save Proc.new { |r| r.history << [:before_save, :symbol] }, :if => :yes
148
+ before_save Proc.new { |r| r.history << "b00m" }, :if => :no
149
+ before_save Proc.new { |r| r.history << [:before_save, :symbol] }, :unless => :no
150
+ before_save Proc.new { |r| r.history << "b00m" }, :unless => :yes
151
+ # string
152
+ before_save Proc.new { |r| r.history << [:before_save, :string] }, :if => 'yes'
153
+ before_save Proc.new { |r| r.history << "b00m" }, :if => 'no'
154
+ before_save Proc.new { |r| r.history << [:before_save, :string] }, :unless => 'no'
155
+ before_save Proc.new { |r| r.history << "b00m" }, :unless => 'yes'
156
+ # Combined if and unless
157
+ before_save Proc.new { |r| r.history << [:before_save, :combined_symbol] }, :if => :yes, :unless => :no
158
+ before_save Proc.new { |r| r.history << "b00m" }, :if => :yes, :unless => :yes
159
+
160
+ def yes; true; end
161
+ def other_yes; true; end
162
+ def no; false; end
163
+ def other_no; false; end
164
+
165
+ def save
166
+ run_callbacks :save
167
+ end
168
+ end
169
+
170
+ class CleanPerson < ConditionalPerson
171
+ reset_callbacks :save
172
+ end
173
+
174
+ class MySuper
175
+ include MotionSupport::Callbacks
176
+ define_callbacks :save
177
+ end
178
+
179
+ class AroundPerson < MySuper
180
+ attr_reader :history
181
+
182
+ set_callback :save, :before, :nope, :if => :no
183
+ set_callback :save, :before, :nope, :unless => :yes
184
+ set_callback :save, :after, :tweedle
185
+ set_callback :save, :before, "tweedle_dee"
186
+ set_callback :save, :before, proc {|m| m.history << "yup" }
187
+ set_callback :save, :before, :nope, :if => proc { false }
188
+ set_callback :save, :before, :nope, :unless => proc { true }
189
+ set_callback :save, :before, :yup, :if => proc { true }
190
+ set_callback :save, :before, :yup, :unless => proc { false }
191
+ set_callback :save, :around, :tweedle_dum
192
+ set_callback :save, :around, :w0tyes, :if => :yes
193
+ set_callback :save, :around, :w0tno, :if => :no
194
+ set_callback :save, :around, :tweedle_deedle
195
+
196
+ def no; false; end
197
+ def yes; true; end
198
+
199
+ def nope
200
+ @history << "boom"
201
+ end
202
+
203
+ def yup
204
+ @history << "yup"
205
+ end
206
+
207
+ def w0tyes
208
+ @history << "w0tyes before"
209
+ yield
210
+ @history << "w0tyes after"
211
+ end
212
+
213
+ def w0tno
214
+ @history << "boom"
215
+ yield
216
+ end
217
+
218
+ def tweedle_dee
219
+ @history << "tweedle dee"
220
+ end
221
+
222
+ def tweedle_dum
223
+ @history << "tweedle dum pre"
224
+ yield
225
+ @history << "tweedle dum post"
226
+ end
227
+
228
+ def tweedle
229
+ @history << "tweedle"
230
+ end
231
+
232
+ def tweedle_deedle
233
+ @history << "tweedle deedle pre"
234
+ yield
235
+ @history << "tweedle deedle post"
236
+ end
237
+
238
+ def initialize
239
+ @history = []
240
+ end
241
+
242
+ def save
243
+ run_callbacks :save do
244
+ @history << "running"
245
+ end
246
+ end
247
+ end
248
+
249
+ class AroundPersonResult < MySuper
250
+ attr_reader :result
251
+
252
+ set_callback :save, :after, :tweedle_1
253
+ set_callback :save, :around, :tweedle_dum
254
+ set_callback :save, :after, :tweedle_2
255
+
256
+ def tweedle_dum
257
+ @result = yield
258
+ end
259
+
260
+ def tweedle_1
261
+ :tweedle_1
262
+ end
263
+
264
+ def tweedle_2
265
+ :tweedle_2
266
+ end
267
+
268
+ def save
269
+ run_callbacks :save do
270
+ :running
271
+ end
272
+ end
273
+ end
274
+
275
+ class HyphenatedCallbacks
276
+ include MotionSupport::Callbacks
277
+ define_callbacks :save
278
+ attr_reader :stuff
279
+
280
+ set_callback :save, :before, :action, :if => :yes
281
+
282
+ def yes() true end
283
+
284
+ def action
285
+ @stuff = "ACTION"
286
+ end
287
+
288
+ def save
289
+ run_callbacks :save do
290
+ @stuff
291
+ end
292
+ end
293
+ end
294
+
295
+ module ExtendModule
296
+ def self.extended(base)
297
+ base.class_eval do
298
+ set_callback :save, :before, :record3
299
+ end
300
+ end
301
+ def record3
302
+ @recorder << 3
303
+ end
304
+ end
305
+
306
+ module IncludeModule
307
+ def self.included(base)
308
+ base.class_eval do
309
+ set_callback :save, :before, :record2
310
+ end
311
+ end
312
+ def record2
313
+ @recorder << 2
314
+ end
315
+ end
316
+
317
+ class ExtendCallbacks
318
+
319
+ include MotionSupport::Callbacks
320
+
321
+ define_callbacks :save
322
+ set_callback :save, :before, :record1
323
+
324
+ include IncludeModule
325
+
326
+ def save
327
+ run_callbacks :save
328
+ end
329
+
330
+ attr_reader :recorder
331
+
332
+ def initialize
333
+ @recorder = []
334
+ end
335
+
336
+ private
337
+
338
+ def record1
339
+ @recorder << 1
340
+ end
341
+ end
342
+
343
+ class CallbackTerminator
344
+ include MotionSupport::Callbacks
345
+
346
+ define_callbacks :save, :terminator => lambda { |result| result == :halt }
347
+
348
+ set_callback :save, :before, :first
349
+ set_callback :save, :before, :second
350
+ set_callback :save, :around, :around_it
351
+ set_callback :save, :before, :third
352
+ set_callback :save, :after, :first
353
+ set_callback :save, :around, :around_it
354
+ set_callback :save, :after, :second
355
+ set_callback :save, :around, :around_it
356
+ set_callback :save, :after, :third
357
+
358
+
359
+ attr_reader :history, :saved, :halted
360
+ def initialize
361
+ @history = []
362
+ end
363
+
364
+ def around_it
365
+ @history << "around1"
366
+ yield
367
+ @history << "around2"
368
+ end
369
+
370
+ def first
371
+ @history << "first"
372
+ end
373
+
374
+ def second
375
+ @history << "second"
376
+ :halt
377
+ end
378
+
379
+ def third
380
+ @history << "third"
381
+ end
382
+
383
+ def save
384
+ run_callbacks :save do
385
+ @saved = true
386
+ end
387
+ end
388
+
389
+ def halted_callback_hook(filter)
390
+ @halted = filter
391
+ end
392
+ end
393
+
394
+ class CallbackObject
395
+ def before(caller)
396
+ caller.record << "before"
397
+ end
398
+
399
+ def before_save(caller)
400
+ caller.record << "before save"
401
+ end
402
+
403
+ def around(caller)
404
+ caller.record << "around before"
405
+ yield
406
+ caller.record << "around after"
407
+ end
408
+ end
409
+
410
+ class UsingObjectBefore
411
+ include MotionSupport::Callbacks
412
+
413
+ define_callbacks :save
414
+ set_callback :save, :before, CallbackObject.new
415
+
416
+ attr_accessor :record
417
+ def initialize
418
+ @record = []
419
+ end
420
+
421
+ def save
422
+ run_callbacks :save do
423
+ @record << "yielded"
424
+ end
425
+ end
426
+ end
427
+
428
+ class UsingObjectAround
429
+ include MotionSupport::Callbacks
430
+
431
+ define_callbacks :save
432
+ set_callback :save, :around, CallbackObject.new
433
+
434
+ attr_accessor :record
435
+ def initialize
436
+ @record = []
437
+ end
438
+
439
+ def save
440
+ run_callbacks :save do
441
+ @record << "yielded"
442
+ end
443
+ end
444
+ end
445
+
446
+ class CustomScopeObject
447
+ include MotionSupport::Callbacks
448
+
449
+ define_callbacks :save, :scope => [:kind, :name]
450
+ set_callback :save, :before, CallbackObject.new
451
+
452
+ attr_accessor :record
453
+ def initialize
454
+ @record = []
455
+ end
456
+
457
+ def save
458
+ run_callbacks :save do
459
+ @record << "yielded"
460
+ "CallbackResult"
461
+ end
462
+ end
463
+ end
464
+
465
+ class OneTwoThreeSave
466
+ include MotionSupport::Callbacks
467
+
468
+ define_callbacks :save
469
+
470
+ attr_accessor :record
471
+
472
+ def initialize
473
+ @record = []
474
+ end
475
+
476
+ def save
477
+ run_callbacks :save do
478
+ @record << "yielded"
479
+ end
480
+ end
481
+
482
+ def first
483
+ @record << "one"
484
+ end
485
+
486
+ def second
487
+ @record << "two"
488
+ end
489
+
490
+ def third
491
+ @record << "three"
492
+ end
493
+ end
494
+
495
+ class DuplicatingCallbacks < OneTwoThreeSave
496
+ set_callback :save, :before, :first, :second
497
+ set_callback :save, :before, :first, :third
498
+ end
499
+
500
+ class DuplicatingCallbacksInSameCall < OneTwoThreeSave
501
+ set_callback :save, :before, :first, :second, :first, :third
502
+ end
503
+
504
+ class WriterSkipper < Person
505
+ attr_accessor :age
506
+ skip_callback :save, :before, :before_save_method, :if => lambda { |obj| obj.age > 21 }
507
+ end
508
+ end
509
+
510
+ describe "Callbacks" do
511
+ describe "around filter" do
512
+ it "should optimize on first compile" do
513
+ around = CallbacksTest::OneTimeCompile.new
514
+ around.save
515
+ around.history.should == [
516
+ [:before_save, :starts_true, :if],
517
+ [:before_save, :starts_true, :unless]
518
+ ]
519
+ end
520
+
521
+ it "should call nested around filter" do
522
+ around = CallbacksTest::AroundPerson.new
523
+ around.save
524
+ around.history.should == [
525
+ "tweedle dee",
526
+ "yup", "yup",
527
+ "tweedle dum pre",
528
+ "w0tyes before",
529
+ "tweedle deedle pre",
530
+ "running",
531
+ "tweedle deedle post",
532
+ "w0tyes after",
533
+ "tweedle dum post",
534
+ "tweedle"
535
+ ]
536
+ end
537
+
538
+ it "should return result" do
539
+ around = CallbacksTest::AroundPersonResult.new
540
+ around.save
541
+ around.result.should == :running
542
+ end
543
+ end
544
+
545
+ describe "after save" do
546
+ it "should run in reverse order" do
547
+ person = CallbacksTest::AfterSaveConditionalPerson.new
548
+ person.save
549
+ person.history.should == [
550
+ [:after_save, :string2],
551
+ [:after_save, :string1]
552
+ ]
553
+ end
554
+ end
555
+
556
+ describe "skip callbacks" do
557
+ it "should skip callback" do
558
+ person = CallbacksTest::PersonSkipper.new
559
+ person.history.should == []
560
+ person.save
561
+ person.history.should == [
562
+ [:before_save, :proc],
563
+ [:before_save, :object],
564
+ [:before_save, :block],
565
+ [:after_save, :block],
566
+ [:after_save, :object],
567
+ [:after_save, :proc],
568
+ [:after_save, :symbol]
569
+ ]
570
+ end
571
+
572
+ it "should not skip if condition is not met" do
573
+ writer = CallbacksTest::WriterSkipper.new
574
+ writer.age = 18
575
+ writer.history.should == []
576
+ writer.save
577
+ writer.history.should == [
578
+ [:before_save, :symbol],
579
+ [:before_save, :proc],
580
+ [:before_save, :object],
581
+ [:before_save, :block],
582
+ [:after_save, :block],
583
+ [:after_save, :object],
584
+ [:after_save, :proc],
585
+ [:after_save, :symbol]
586
+ ]
587
+ end
588
+ end
589
+
590
+ it "should run callbacks" do
591
+ person = CallbacksTest::Person.new
592
+ person.history.should == []
593
+ person.save
594
+ person.history.should == [
595
+ [:before_save, :symbol],
596
+ [:before_save, :proc],
597
+ [:before_save, :object],
598
+ [:before_save, :block],
599
+ [:after_save, :block],
600
+ [:after_save, :object],
601
+ [:after_save, :proc],
602
+ [:after_save, :symbol]
603
+ ]
604
+ end
605
+
606
+ it "should run conditional callbacks" do
607
+ person = CallbacksTest::ConditionalPerson.new
608
+ person.save
609
+ person.history.should == [
610
+ [:before_save, :proc],
611
+ [:before_save, :proc],
612
+ [:before_save, :symbol],
613
+ [:before_save, :symbol],
614
+ [:before_save, :string],
615
+ [:before_save, :string],
616
+ [:before_save, :combined_symbol],
617
+ ]
618
+ end
619
+
620
+ it "should return result" do
621
+ obj = CallbacksTest::HyphenatedCallbacks.new
622
+ obj.save
623
+ obj.stuff.should == "ACTION"
624
+ end
625
+
626
+ describe "reset_callbacks" do
627
+ it "should reset callbacks" do
628
+ person = CallbacksTest::CleanPerson.new
629
+ person.save
630
+ person.history.should == []
631
+ end
632
+ end
633
+
634
+ describe "callback object" do
635
+ it "should use callback object for before callback" do
636
+ u = CallbacksTest::UsingObjectBefore.new
637
+ u.save
638
+ u.record.should == ["before", "yielded"]
639
+ end
640
+
641
+ it "should use callback object for around callback" do
642
+ u = CallbacksTest::UsingObjectAround.new
643
+ u.save
644
+ u.record.should == ["around before", "yielded", "around after"]
645
+ end
646
+
647
+ describe "custom scope" do
648
+ it "should use custom scope" do
649
+ u = CallbacksTest::CustomScopeObject.new
650
+ u.save
651
+ u.record.should == ["before save", "yielded"]
652
+ end
653
+
654
+ it "should return block result" do
655
+ u = CallbacksTest::CustomScopeObject.new
656
+ u.save.should == "CallbackResult"
657
+ end
658
+ end
659
+ end
660
+
661
+ describe "callback terminator" do
662
+ it "should terminate" do
663
+ terminator = CallbacksTest::CallbackTerminator.new
664
+ terminator.save
665
+ terminator.history.should == ["first", "second", "third", "second", "first"]
666
+ end
667
+
668
+ it "should invoke hook" do
669
+ terminator = CallbacksTest::CallbackTerminator.new
670
+ terminator.save
671
+ terminator.halted.should == ":second"
672
+ end
673
+
674
+ it "should never call block if terminated" do
675
+ obj = CallbacksTest::CallbackTerminator.new
676
+ obj.save
677
+ obj.saved.should.be.nil
678
+ end
679
+ end
680
+
681
+ describe "extending object" do
682
+ it "should work with extending object" do
683
+ model = CallbacksTest::ExtendCallbacks.new.extend CallbacksTest::ExtendModule
684
+ model.save
685
+ model.recorder.should == [1, 2, 3]
686
+ end
687
+ end
688
+
689
+ describe "exclude duplicates" do
690
+ it "should exclude duplicates in separate calls" do
691
+ model = CallbacksTest::DuplicatingCallbacks.new
692
+ model.save
693
+ model.record.should == ["two", "one", "three", "yielded"]
694
+ end
695
+
696
+ it "should exclude duplicates in one call" do
697
+ model = CallbacksTest::DuplicatingCallbacksInSameCall.new
698
+ model.save
699
+ model.record.should == ["two", "one", "three", "yielded"]
700
+ end
701
+ end
702
+ end