PageRenderTime 61ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/activesupport/test/callbacks_test.rb

https://github.com/boyjunqiang/rails
Ruby | 528 lines | 436 code | 87 blank | 5 comment | 6 complexity | 0c06a58960043bdcf447555e126fbc29 MD5 | raw file
  1. # require 'abstract_unit'
  2. require 'test/unit'
  3. $:.unshift "#{File.dirname(__FILE__)}/../lib"
  4. require 'active_support'
  5. module CallbacksTest
  6. class Record
  7. include ActiveSupport::Callbacks
  8. define_callbacks :save
  9. def self.before_save(*filters, &blk)
  10. set_callback(:save, :before, *filters, &blk)
  11. end
  12. def self.after_save(*filters, &blk)
  13. set_callback(:save, :after, *filters, &blk)
  14. end
  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. def callback_string(callback_method)
  24. "history << [#{callback_method.to_sym.inspect}, :string]"
  25. end
  26. def callback_proc(callback_method)
  27. Proc.new { |model| model.history << [callback_method, :proc] }
  28. end
  29. def callback_object(callback_method)
  30. klass = Class.new
  31. klass.send(:define_method, callback_method) do |model|
  32. model.history << [:"#{callback_method}_save", :object]
  33. end
  34. klass.new
  35. end
  36. end
  37. def history
  38. @history ||= []
  39. end
  40. end
  41. class Person < Record
  42. [:before_save, :after_save].each do |callback_method|
  43. callback_method_sym = callback_method.to_sym
  44. send(callback_method, callback_symbol(callback_method_sym))
  45. send(callback_method, callback_string(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. def save
  51. run_callbacks :save
  52. end
  53. end
  54. class PersonSkipper < Person
  55. skip_callback :save, :before, :before_save_method, :if => :yes
  56. skip_callback :save, :after, :before_save_method, :unless => :yes
  57. skip_callback :save, :after, :before_save_method, :if => :no
  58. skip_callback :save, :before, :before_save_method, :unless => :no
  59. def yes; true; end
  60. def no; false; end
  61. end
  62. class ParentController
  63. include ActiveSupport::Callbacks
  64. define_callbacks :dispatch
  65. set_callback :dispatch, :before, :log, :per_key => {:unless => proc {|c| c.action_name == :index || c.action_name == :show }}
  66. set_callback :dispatch, :after, :log2
  67. attr_reader :action_name, :logger
  68. def initialize(action_name)
  69. @action_name, @logger = action_name, []
  70. end
  71. def log
  72. @logger << action_name
  73. end
  74. def log2
  75. @logger << action_name
  76. end
  77. def dispatch
  78. run_callbacks :dispatch, action_name do
  79. @logger << "Done"
  80. end
  81. self
  82. end
  83. end
  84. class Child < ParentController
  85. skip_callback :dispatch, :before, :log, :per_key => {:if => proc {|c| c.action_name == :update} }
  86. skip_callback :dispatch, :after, :log2
  87. end
  88. class OneTimeCompile < Record
  89. @@starts_true, @@starts_false = true, false
  90. def initialize
  91. super
  92. end
  93. before_save Proc.new {|r| r.history << [:before_save, :starts_true, :if] }, :per_key => {:if => :starts_true}
  94. before_save Proc.new {|r| r.history << [:before_save, :starts_false, :if] }, :per_key => {:if => :starts_false}
  95. before_save Proc.new {|r| r.history << [:before_save, :starts_true, :unless] }, :per_key => {:unless => :starts_true}
  96. before_save Proc.new {|r| r.history << [:before_save, :starts_false, :unless] }, :per_key => {:unless => :starts_false}
  97. def starts_true
  98. if @@starts_true
  99. @@starts_true = false
  100. return true
  101. end
  102. @@starts_true
  103. end
  104. def starts_false
  105. unless @@starts_false
  106. @@starts_false = true
  107. return false
  108. end
  109. @@starts_false
  110. end
  111. def save
  112. run_callbacks :save, :action
  113. end
  114. end
  115. class OneTimeCompileTest < Test::Unit::TestCase
  116. def test_optimized_first_compile
  117. around = OneTimeCompile.new
  118. around.save
  119. assert_equal [
  120. [:before_save, :starts_true, :if],
  121. [:before_save, :starts_true, :unless]
  122. ], around.history
  123. end
  124. end
  125. class ConditionalPerson < Record
  126. # proc
  127. before_save Proc.new { |r| r.history << [:before_save, :proc] }, :if => Proc.new { |r| true }
  128. before_save Proc.new { |r| r.history << "b00m" }, :if => Proc.new { |r| false }
  129. before_save Proc.new { |r| r.history << [:before_save, :proc] }, :unless => Proc.new { |r| false }
  130. before_save Proc.new { |r| r.history << "b00m" }, :unless => Proc.new { |r| true }
  131. # symbol
  132. before_save Proc.new { |r| r.history << [:before_save, :symbol] }, :if => :yes
  133. before_save Proc.new { |r| r.history << "b00m" }, :if => :no
  134. before_save Proc.new { |r| r.history << [:before_save, :symbol] }, :unless => :no
  135. before_save Proc.new { |r| r.history << "b00m" }, :unless => :yes
  136. # string
  137. before_save Proc.new { |r| r.history << [:before_save, :string] }, :if => 'yes'
  138. before_save Proc.new { |r| r.history << "b00m" }, :if => 'no'
  139. before_save Proc.new { |r| r.history << [:before_save, :string] }, :unless => 'no'
  140. before_save Proc.new { |r| r.history << "b00m" }, :unless => 'yes'
  141. # Combined if and unless
  142. before_save Proc.new { |r| r.history << [:before_save, :combined_symbol] }, :if => :yes, :unless => :no
  143. before_save Proc.new { |r| r.history << "b00m" }, :if => :yes, :unless => :yes
  144. def yes; true; end
  145. def other_yes; true; end
  146. def no; false; end
  147. def other_no; false; end
  148. def save
  149. run_callbacks :save
  150. end
  151. end
  152. class CleanPerson < ConditionalPerson
  153. reset_callbacks :save
  154. end
  155. class MySuper
  156. include ActiveSupport::Callbacks
  157. define_callbacks :save
  158. end
  159. class AroundPerson < MySuper
  160. attr_reader :history
  161. set_callback :save, :before, :nope, :if => :no
  162. set_callback :save, :before, :nope, :unless => :yes
  163. set_callback :save, :after, :tweedle
  164. set_callback :save, :before, "tweedle_dee"
  165. set_callback :save, :before, proc {|m| m.history << "yup" }
  166. set_callback :save, :before, :nope, :if => proc { false }
  167. set_callback :save, :before, :nope, :unless => proc { true }
  168. set_callback :save, :before, :yup, :if => proc { true }
  169. set_callback :save, :before, :yup, :unless => proc { false }
  170. set_callback :save, :around, :tweedle_dum
  171. set_callback :save, :around, :w0tyes, :if => :yes
  172. set_callback :save, :around, :w0tno, :if => :no
  173. set_callback :save, :around, :tweedle_deedle
  174. def no; false; end
  175. def yes; true; end
  176. def nope
  177. @history << "boom"
  178. end
  179. def yup
  180. @history << "yup"
  181. end
  182. def w0tyes
  183. @history << "w0tyes before"
  184. yield
  185. @history << "w0tyes after"
  186. end
  187. def w0tno
  188. @history << "boom"
  189. yield
  190. end
  191. def tweedle_dee
  192. @history << "tweedle dee"
  193. end
  194. def tweedle_dum
  195. @history << "tweedle dum pre"
  196. yield
  197. @history << "tweedle dum post"
  198. end
  199. def tweedle
  200. @history << "tweedle"
  201. end
  202. def tweedle_deedle
  203. @history << "tweedle deedle pre"
  204. yield
  205. @history << "tweedle deedle post"
  206. end
  207. def initialize
  208. @history = []
  209. end
  210. def save
  211. run_callbacks :save do
  212. @history << "running"
  213. end
  214. end
  215. end
  216. class HyphenatedCallbacks
  217. include ActiveSupport::Callbacks
  218. define_callbacks :save
  219. attr_reader :stuff
  220. set_callback :save, :before, :action, :per_key => {:if => :yes}
  221. def yes() true end
  222. def action
  223. @stuff = "ACTION"
  224. end
  225. def save
  226. run_callbacks :save, "hyphen-ated" do
  227. @stuff
  228. end
  229. end
  230. end
  231. class AroundCallbacksTest < Test::Unit::TestCase
  232. def test_save_around
  233. around = AroundPerson.new
  234. around.save
  235. assert_equal [
  236. "tweedle dee",
  237. "yup", "yup",
  238. "tweedle dum pre",
  239. "w0tyes before",
  240. "tweedle deedle pre",
  241. "running",
  242. "tweedle deedle post",
  243. "w0tyes after",
  244. "tweedle dum post",
  245. "tweedle"
  246. ], around.history
  247. end
  248. end
  249. class SkipCallbacksTest < Test::Unit::TestCase
  250. def test_skip_person
  251. person = PersonSkipper.new
  252. assert_equal [], person.history
  253. person.save
  254. assert_equal [
  255. [:before_save, :string],
  256. [:before_save, :proc],
  257. [:before_save, :object],
  258. [:before_save, :block],
  259. [:after_save, :block],
  260. [:after_save, :object],
  261. [:after_save, :proc],
  262. [:after_save, :string],
  263. [:after_save, :symbol]
  264. ], person.history
  265. end
  266. end
  267. class CallbacksTest < Test::Unit::TestCase
  268. def test_save_person
  269. person = Person.new
  270. assert_equal [], person.history
  271. person.save
  272. assert_equal [
  273. [:before_save, :symbol],
  274. [:before_save, :string],
  275. [:before_save, :proc],
  276. [:before_save, :object],
  277. [:before_save, :block],
  278. [:after_save, :block],
  279. [:after_save, :object],
  280. [:after_save, :proc],
  281. [:after_save, :string],
  282. [:after_save, :symbol]
  283. ], person.history
  284. end
  285. end
  286. class ConditionalCallbackTest < Test::Unit::TestCase
  287. def test_save_conditional_person
  288. person = ConditionalPerson.new
  289. person.save
  290. assert_equal [
  291. [:before_save, :proc],
  292. [:before_save, :proc],
  293. [:before_save, :symbol],
  294. [:before_save, :symbol],
  295. [:before_save, :string],
  296. [:before_save, :string],
  297. [:before_save, :combined_symbol],
  298. ], person.history
  299. end
  300. end
  301. class ResetCallbackTest < Test::Unit::TestCase
  302. def test_save_conditional_person
  303. person = CleanPerson.new
  304. person.save
  305. assert_equal [], person.history
  306. end
  307. end
  308. class CallbackTerminator
  309. include ActiveSupport::Callbacks
  310. define_callbacks :save, :terminator => "result == :halt"
  311. set_callback :save, :before, :first
  312. set_callback :save, :before, :second
  313. set_callback :save, :around, :around_it
  314. set_callback :save, :before, :third
  315. set_callback :save, :after, :first
  316. set_callback :save, :around, :around_it
  317. set_callback :save, :after, :second
  318. set_callback :save, :around, :around_it
  319. set_callback :save, :after, :third
  320. attr_reader :history, :saved
  321. def initialize
  322. @history = []
  323. end
  324. def around_it
  325. @history << "around1"
  326. yield
  327. @history << "around2"
  328. end
  329. def first
  330. @history << "first"
  331. end
  332. def second
  333. @history << "second"
  334. :halt
  335. end
  336. def third
  337. @history << "third"
  338. end
  339. def save
  340. run_callbacks :save do
  341. @saved = true
  342. end
  343. end
  344. end
  345. class CallbackObject
  346. def before(caller)
  347. caller.record << "before"
  348. end
  349. def before_save(caller)
  350. caller.record << "before save"
  351. end
  352. def around(caller)
  353. caller.record << "around before"
  354. yield
  355. caller.record << "around after"
  356. end
  357. end
  358. class UsingObjectBefore
  359. include ActiveSupport::Callbacks
  360. define_callbacks :save
  361. set_callback :save, :before, CallbackObject.new
  362. attr_accessor :record
  363. def initialize
  364. @record = []
  365. end
  366. def save
  367. run_callbacks :save do
  368. @record << "yielded"
  369. end
  370. end
  371. end
  372. class UsingObjectAround
  373. include ActiveSupport::Callbacks
  374. define_callbacks :save
  375. set_callback :save, :around, CallbackObject.new
  376. attr_accessor :record
  377. def initialize
  378. @record = []
  379. end
  380. def save
  381. run_callbacks :save do
  382. @record << "yielded"
  383. end
  384. end
  385. end
  386. class CustomScopeObject
  387. include ActiveSupport::Callbacks
  388. define_callbacks :save, :scope => [:kind, :name]
  389. set_callback :save, :before, CallbackObject.new
  390. attr_accessor :record
  391. def initialize
  392. @record = []
  393. end
  394. def save
  395. run_callbacks :save do
  396. @record << "yielded"
  397. "CallbackResult"
  398. end
  399. end
  400. end
  401. class UsingObjectTest < Test::Unit::TestCase
  402. def test_before_object
  403. u = UsingObjectBefore.new
  404. u.save
  405. assert_equal ["before", "yielded"], u.record
  406. end
  407. def test_around_object
  408. u = UsingObjectAround.new
  409. u.save
  410. assert_equal ["around before", "yielded", "around after"], u.record
  411. end
  412. def test_customized_object
  413. u = CustomScopeObject.new
  414. u.save
  415. assert_equal ["before save", "yielded"], u.record
  416. end
  417. def test_block_result_is_returned
  418. u = CustomScopeObject.new
  419. assert_equal "CallbackResult", u.save
  420. end
  421. end
  422. class CallbackTerminatorTest < Test::Unit::TestCase
  423. def test_termination
  424. terminator = CallbackTerminator.new
  425. terminator.save
  426. assert_equal ["first", "second", "third", "second", "first"], terminator.history
  427. end
  428. def test_block_never_called_if_terminated
  429. obj = CallbackTerminator.new
  430. obj.save
  431. assert !obj.saved
  432. end
  433. end
  434. class HyphenatedKeyTest < Test::Unit::TestCase
  435. def test_save
  436. obj = HyphenatedCallbacks.new
  437. obj.save
  438. assert_equal obj.stuff, "ACTION"
  439. end
  440. end
  441. end