PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/activesupport/test/callbacks_test.rb

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