super_callbacks 1.0.3 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,394 +1,439 @@
1
- # SuperCallbacks
2
-
3
- [![Build Status](https://travis-ci.org/jrpolidario/super_callbacks.svg?branch=master)](https://travis-ci.org/jrpolidario/super_callbacks)
4
- [![Gem Version](https://badge.fury.io/rb/super_callbacks.svg)](https://badge.fury.io/rb/super_callbacks)
5
-
6
- * Allows `before` and `after` callbacks to any Class.
7
- * Supports both class and instance level callbacks
8
- * Supports conditional callbacks
9
- * Supports inherited callbacks; hence named "Super", get it? :D haha!
10
- ---
11
- * Focuses on performance and flexibility as intended primarily for game development, and event-driven apps
12
- * Standalone; no other gem dependencies
13
- * `super_callbacks` is the upgraded version of my other repo [`dragon_ruby_callbacks`](https://github.com/jrpolidario/dragonruby_callbacks)
14
- * Heavily influenced by [Rails' ActiveSupport::Callbacks](https://api.rubyonrails.org/classes/ActiveSupport/Callbacks.html)
15
-
16
- ## Dependencies
17
-
18
- * **Ruby ~> 2.0**
19
-
20
- ## Installation
21
-
22
- Add this line to your application's Gemfile:
23
-
24
- ```ruby
25
- gem 'super_callbacks', '~> 1.0'
26
- ```
27
-
28
- And then execute:
29
-
30
- $ bundle
31
-
32
- Or install it yourself as:
33
-
34
- $ gem install super_callbacks
35
-
36
- ## Usage
37
-
38
- ### Example 1 (Block Mode)
39
-
40
- ```ruby
41
- require 'super_callbacks'
42
-
43
- class Foo
44
- # add this line inside your Class file/s
45
- include SuperCallbacks
46
-
47
- # add this block of lines
48
- before :bar do
49
- puts 'before bar!'
50
- end
51
-
52
- def bar
53
- puts 'bar!'
54
- end
55
- end
56
-
57
- foo = Foo.new
58
- foo.bar
59
- # => 'before bar!'
60
- # => 'bar!'
61
- ```
62
-
63
- *Notice above that the before block gets called first before the method `bar`*
64
-
65
- ```ruby
66
- class Foo
67
- include SuperCallbacks
68
-
69
- after :bar do
70
- puts 'after bar!'
71
- end
72
-
73
- def bar
74
- puts 'bar!'
75
- end
76
- end
77
-
78
- foo = Foo.new
79
- foo.bar
80
- # => 'bar!'
81
- # => 'after bar!'
82
- ```
83
-
84
- *Notice above that the after block gets called after the method `bar`*
85
-
86
- ### Example 2 (Method Calling)
87
-
88
- ```ruby
89
- class Foo
90
- include SuperCallbacks
91
-
92
- before :bar, :baz
93
-
94
- def bar
95
- puts 'bar!'
96
- end
97
-
98
- def baz
99
- puts 'baz!'
100
- end
101
- end
102
-
103
- foo = Foo.new
104
- foo.bar
105
- # => 'baz!'
106
- # => 'bar!'
107
- ```
108
-
109
- *Notice above that you can also call another method instead of supplying a block.*
110
-
111
- *Above uses `before`, but works similarly with `after`*
112
-
113
- ### Example 3 (Multiple Callbacks)
114
-
115
- ```ruby
116
- class Foo
117
- include SuperCallbacks
118
-
119
- before :bar, :baz_1
120
- before :bar do
121
- puts 'baz 2!'
122
- end
123
- before :bar, :baz_3
124
-
125
- def bar
126
- puts 'bar!'
127
- end
128
-
129
- def baz_1
130
- puts 'baz 1!'
131
- end
132
-
133
- def baz_3
134
- puts 'baz 3!'
135
- end
136
- end
137
-
138
- foo = Foo.new
139
- foo.bar
140
- # => 'baz 1!'
141
- # => 'bar 2!'
142
- # => 'bar 3!'
143
- # => 'bar!'
144
- ```
145
-
146
- *Notice above multiple callbacks are supported, and that they are called in firt-come-first-served order.*
147
-
148
- *Above uses `before`, but works similarly with `after`*
149
-
150
- ### Example 4 (Setter Method Callbacks)
151
-
152
- > This is the primary reason why I made this game: to handle "change-dependent" logic in my game engine
153
-
154
- ```ruby
155
- class Foo
156
- include SuperCallbacks
157
-
158
- attr_accessor :bar
159
-
160
- before :bar= do |arg|
161
- puts "@bar currently has a value of #{@bar}"
162
- puts "@bar will have a new value of #{arg}"
163
- end
164
-
165
- before :baz do |arg1, arg2|
166
- puts "baz will be called with arguments #{arg1}, #{arg2}"
167
- end
168
-
169
- def baz(x, y)
170
- puts 'baz has been called!'
171
- end
172
- end
173
-
174
- foo = Foo.new
175
- foo.bar = 5
176
- # => '@bar currently has a value of '
177
- # => '@bar will have a new value of 5'
178
- puts foo.bar
179
- # => 5
180
-
181
- foo.baz(1, 2)
182
- # => 'baz will be called with arguments 1, 2'
183
- # => 'baz has been called!'
184
- ```
185
-
186
- *Above uses `before`, but works similarly with `after`*
187
-
188
- ### Example 5 (Conditional Callbacks)
189
-
190
- ```ruby
191
- class Monster
192
- include SuperCallbacks
193
-
194
- attr_accessor :hp
195
-
196
- after :hp=, :despawn, if: -> (arg) { @hp == 0 }
197
-
198
- # above is just equivalently:
199
- # after :hp= do |arg|
200
- # despawn if @hp == 0
201
- # end
202
-
203
- def despawn
204
- puts 'despawning!'
205
- # do something here, like say removing the Monster from the world
206
- end
207
- end
208
-
209
- monster = Monster.new
210
- monster.hp = 5
211
- monster.hp -= 1 # 4
212
- monster.hp -= 1 # 3
213
- monster.hp -= 1 # 2
214
- monster.hp -= 1 # 1
215
- monster.hp -= 1 # hp is now 0, so despawn!
216
- # => despawning!
217
- ```
218
-
219
- *Above uses `after`, but works similarly with `before`*
220
-
221
- ### Example 6 (Pseudo-Skipping Callbacks)
222
-
223
- * via Ruby's [`instance_variable_get`](https://ruby-doc.org/core-1.9.1/Object.html#method-i-instance_variable_get) and [`instance_variable_set`](https://ruby-doc.org/core-1.9.1/Object.html#method-i-instance_variable_set)
224
-
225
- ```ruby
226
- class Foo
227
- include SuperCallbacks
228
-
229
- attr_accessor :bar
230
-
231
- before :bar= do |arg|
232
- puts 'before bar= is called!'
233
- end
234
- end
235
-
236
- foo = Foo.new
237
-
238
- # normal way (callbacks are called):
239
- foo.bar = 'somevalue'
240
- # => 'before_bar= is called!'
241
-
242
- # but to "pseudo" skip all callbacks, and directly manipulate the instance variable value:
243
- foo.instance_variable_set(:@bar, 'somevalue')
244
- ```
245
-
246
- *At the moment, I am not compelled (yet?) to fully support skipping callbacks because I do not want to pollute the DSL and I do not find myself yet needing such behaviour, because the callbacks are there for "integrity". If I really want the callbacks conditional, I'll just use the conditional argument.*
247
-
248
- ### Example 7 (Class and Instance Level Callbacks)
249
-
250
- ```ruby
251
- class Foo
252
- include SuperCallbacks
253
-
254
- before :bar do
255
- puts 'before bar 1!'
256
- end
257
-
258
- before :bar do
259
- puts 'before bar 2!'
260
- end
261
-
262
- def bar
263
- puts 'bar!'
264
- end
265
- end
266
-
267
- foo_1 = Foo.new
268
- foo_2 = Foo.new
269
-
270
- foo_1.before :bar do
271
- puts 'before bar 3'
272
- end
273
-
274
- foo_1.before :bar do
275
- puts 'before bar 4'
276
- end
277
-
278
- foo_1.bar
279
- # => 'before bar 1!'
280
- # => 'before bar 2!'
281
- # => 'before bar 3'
282
- # => 'before bar 4'
283
- # => 'bar!'
284
-
285
- foo_2.bar
286
- # => 'before bar 1!'
287
- # => 'before bar 2!'
288
- # => 'bar!'
289
- ```
290
-
291
- *Notice above that foo_1 and foo_2 both call the class-level callbacks, while they have independent (not-shared) instance-level callbacks defined. Order of execution is class-level first then instance-level, of which defined callbacks are then in order of first-come-first-serve.*
292
-
293
- *Above uses `before`, but works similarly with `after`*
294
-
295
- ### Example 8 (Inherited Callbacks)
296
-
297
- ```ruby
298
- class Foo
299
- include SuperCallbacks
300
-
301
- before :bar do
302
- puts 'Foo: before bar 1!'
303
- end
304
-
305
- def bar
306
- puts 'bar!'
307
- end
308
- end
309
-
310
- class SubFoo < Foo
311
- before :bar do
312
- puts 'SubFoo: bar'
313
- end
314
- end
315
-
316
- foo = Foo.new
317
- foo.bar
318
- # => 'Foo: before bar 1!'
319
- # => 'bar!'
320
-
321
- sub_foo = SubFoo.new
322
- sub_foo.bar
323
- # => 'Foo: before bar 1!'
324
- # => 'SubFoo: bar'
325
- # => 'bar!'
326
- ```
327
-
328
- *Notice above `sub_foo` calls both `before` callbacks defined in `Foo` and `SubFoo`, because SubFoo inherits from Foo. Callbacks are called in order of ancestors descending; meaning it starts calling the top-level ancestor superclass callbacks, and then calling its subclass callbacks, until it reaches the instance's class callbacks*
329
-
330
- *Above uses `before`, but works similarly with `after`*
331
-
332
- ### Example 9 (Requiring Method To Be Defined)
333
-
334
- ```ruby
335
- class Foo
336
- include SuperCallbacks
337
-
338
- after! :bar do
339
- puts 'after bar!'
340
- end
341
-
342
- def bar
343
- puts 'bar!'
344
- end
345
- end
346
- # => ArgumentError: `bar` is not or not yet defined for Foo
347
-
348
- class Foo
349
- include SuperCallbacks
350
-
351
- def bar
352
- puts 'bar!'
353
- end
354
-
355
- after! :bar do
356
- puts 'after bar!'
357
- end
358
- end
359
- # => [NO ERRORS]
360
- ```
361
-
362
- *From above, sometimes I noticed that I forgot to define a method! So the bang `!` version is just basically like `after` except that this raises an error if `method_name` is not defined or not yet defined (at the time `after!` is called). This works perfect with `attr_accesors` I normally put them at the top of the lines of a Class, and so I can now safely call `before!` or `after!` because I am sure that I already defined everything I needed to define. If I forgot something then, this `before!` would raise an error and alert me, and not silently failing. Helps debugging :)*
363
-
364
- *Above uses `after!`, but works similarly with `before!`*
365
-
366
- ## TODOs
367
- * when the need already arises, implement `around` (If you have ideas or want to help this part, please feel free to fork or send me a message! :)
368
-
369
- ## Development
370
-
371
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
372
-
373
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
374
-
375
- ## Contributing
376
-
377
- Bug reports and pull requests are welcome on GitHub at https://github.com/jrpolidario/super_callbacks. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
378
-
379
- ## License
380
-
381
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
382
-
383
- ## Changelog
384
-
385
- * 1.0.3 (2019-08-12)
386
- * Cleaner code without explicitly calling `run_callbacks` anymore; done now because of ruby upgrade from 1.9 to 2.0+ which already supports `prepend`
387
- * Supported both class and instance level callbacks
388
- * Supported inherited callbacks
389
- * v0.2.1 (2019-08-09) *From `dragonruby_callbacks`*
390
- * Fixed syntax errors for ruby 1.9.3; Fixed not supporting subclasses of Proc, String, or Symbol
391
- * v0.2 (2019-08-08) *From `dragonruby_callbacks`*
392
- * Supported [conditional callbacks](#conditional-callbacks) with `:if`
393
- * v0.1 (2019-08-07) *From `dragonruby_callbacks`*
394
- * Done all
1
+ # SuperCallbacks
2
+
3
+ [![Build Status](https://travis-ci.org/jrpolidario/super_callbacks.svg?branch=master)](https://travis-ci.org/jrpolidario/super_callbacks)
4
+ [![Gem Version](https://badge.fury.io/rb/super_callbacks.svg)](https://badge.fury.io/rb/super_callbacks)
5
+
6
+ * Allows `before` and `after` callbacks to any Class.
7
+ * Supports "dirty" checking of instance variables changes
8
+ * Supports both class and instance level callbacks
9
+ * Supports conditional callbacks
10
+ * Supports inherited callbacks; hence named "Super", get it? :D haha!
11
+ ---
12
+ * Focuses on performance and flexibility as intended primarily for game development, and event-driven apps
13
+ * Standalone; no other gem dependencies
14
+ * `super_callbacks` is the upgraded version of my other repo [`dragonruby_callbacks`](https://github.com/jrpolidario/dragonruby_callbacks)
15
+ * Heavily influenced by [Rails' ActiveSupport::Callbacks](https://api.rubyonrails.org/classes/ActiveSupport/Callbacks.html)
16
+
17
+ ## Dependencies
18
+
19
+ * **Ruby ~> 2.0**
20
+
21
+ ## Installation
22
+
23
+ Add this line to your application's Gemfile:
24
+
25
+ ```ruby
26
+ gem 'super_callbacks', '~> 1.1'
27
+ ```
28
+
29
+ And then execute:
30
+
31
+ $ bundle
32
+
33
+ Or install it yourself as:
34
+
35
+ $ gem install super_callbacks
36
+
37
+ ## Usage
38
+
39
+ ### Example 1 (Block Mode)
40
+
41
+ ```ruby
42
+ require 'super_callbacks'
43
+
44
+ class Foo
45
+ # add this line inside your Class file/s
46
+ include SuperCallbacks
47
+
48
+ # add this block of lines
49
+ before :bar do
50
+ puts 'before bar!'
51
+ end
52
+
53
+ def bar
54
+ puts 'bar!'
55
+ end
56
+ end
57
+
58
+ foo = Foo.new
59
+ foo.bar
60
+ # => 'before bar!'
61
+ # => 'bar!'
62
+ ```
63
+
64
+ *Notice above that the before block gets called first before the method `bar`*
65
+
66
+ ```ruby
67
+ class Foo
68
+ include SuperCallbacks
69
+
70
+ after :bar do
71
+ puts 'after bar!'
72
+ end
73
+
74
+ def bar
75
+ puts 'bar!'
76
+ end
77
+ end
78
+
79
+ foo = Foo.new
80
+ foo.bar
81
+ # => 'bar!'
82
+ # => 'after bar!'
83
+ ```
84
+
85
+ *Notice above that the after block gets called after the method `bar`*
86
+
87
+ ### Example 2 (Method Calling)
88
+
89
+ ```ruby
90
+ class Foo
91
+ include SuperCallbacks
92
+
93
+ before :bar, :baz
94
+
95
+ def bar
96
+ puts 'bar!'
97
+ end
98
+
99
+ def baz
100
+ puts 'baz!'
101
+ end
102
+ end
103
+
104
+ foo = Foo.new
105
+ foo.bar
106
+ # => 'baz!'
107
+ # => 'bar!'
108
+ ```
109
+
110
+ *Notice above that you can also call another method instead of supplying a block.*
111
+
112
+ *Above uses `before`, but works similarly with `after`*
113
+
114
+ ### Example 3 (Multiple Callbacks)
115
+
116
+ ```ruby
117
+ class Foo
118
+ include SuperCallbacks
119
+
120
+ before :bar, :baz_1
121
+ before :bar do
122
+ puts 'baz 2!'
123
+ end
124
+ before :bar, :baz_3
125
+
126
+ def bar
127
+ puts 'bar!'
128
+ end
129
+
130
+ def baz_1
131
+ puts 'baz 1!'
132
+ end
133
+
134
+ def baz_3
135
+ puts 'baz 3!'
136
+ end
137
+ end
138
+
139
+ foo = Foo.new
140
+ foo.bar
141
+ # => 'baz 1!'
142
+ # => 'bar 2!'
143
+ # => 'bar 3!'
144
+ # => 'bar!'
145
+ ```
146
+
147
+ *Notice above multiple callbacks are supported, and that they are called in firt-come-first-served order.*
148
+
149
+ *Above uses `before`, but works similarly with `after`*
150
+
151
+ ### Example 4 (Setter Method Callbacks)
152
+
153
+ > This is the primary reason why I made this: to handle "change-dependent" logic in my game engine
154
+
155
+ ```ruby
156
+ class Foo
157
+ include SuperCallbacks
158
+
159
+ attr_accessor :bar
160
+
161
+ before :bar= do |arg|
162
+ puts "@bar currently has a value of #{@bar}"
163
+ puts "@bar will have a new value of #{arg}"
164
+ end
165
+
166
+ before :baz do |arg1, arg2|
167
+ puts "baz will be called with arguments #{arg1}, #{arg2}"
168
+ end
169
+
170
+ def baz(x, y)
171
+ puts 'baz has been called!'
172
+ end
173
+ end
174
+
175
+ foo = Foo.new
176
+ foo.bar = 5
177
+ # => '@bar currently has a value of '
178
+ # => '@bar will have a new value of 5'
179
+ puts foo.bar
180
+ # => 5
181
+
182
+ foo.baz(1, 2)
183
+ # => 'baz will be called with arguments 1, 2'
184
+ # => 'baz has been called!'
185
+ ```
186
+
187
+ *Above uses `before`, but works similarly with `after`*
188
+
189
+ ### Example 5 (Conditional Callbacks)
190
+
191
+ ```ruby
192
+ class Monster
193
+ include SuperCallbacks
194
+
195
+ attr_accessor :hp
196
+
197
+ after :hp=, :despawn, if: -> (arg) { @hp == 0 }
198
+
199
+ # above is just equivalently:
200
+ # after :hp= do |arg|
201
+ # despawn if @hp == 0
202
+ # end
203
+
204
+ def despawn
205
+ puts 'despawning!'
206
+ # do something here, like say removing the Monster from the world
207
+ end
208
+ end
209
+
210
+ monster = Monster.new
211
+ monster.hp = 5
212
+ monster.hp -= 1 # 4
213
+ monster.hp -= 1 # 3
214
+ monster.hp -= 1 # 2
215
+ monster.hp -= 1 # 1
216
+ monster.hp -= 1 # hp is now 0, so despawn!
217
+ # => despawning!
218
+ ```
219
+
220
+ *Above uses `after`, but works similarly with `before`*
221
+
222
+ ### Example 6 (Pseudo-Skipping Callbacks)
223
+
224
+ * via Ruby's [`instance_variable_get`](https://ruby-doc.org/core-1.9.1/Object.html#method-i-instance_variable_get) and [`instance_variable_set`](https://ruby-doc.org/core-1.9.1/Object.html#method-i-instance_variable_set)
225
+
226
+ ```ruby
227
+ class Foo
228
+ include SuperCallbacks
229
+
230
+ attr_accessor :bar
231
+
232
+ before :bar= do |arg|
233
+ puts 'before bar= is called!'
234
+ end
235
+ end
236
+
237
+ foo = Foo.new
238
+
239
+ # normal way (callbacks are called):
240
+ foo.bar = 'somevalue'
241
+ # => 'before_bar= is called!'
242
+
243
+ # but to "pseudo" skip all callbacks, and directly manipulate the instance variable value:
244
+ foo.instance_variable_set(:@bar, 'somevalue')
245
+ ```
246
+
247
+ *At the moment, I am not compelled (yet?) to fully support skipping callbacks because I do not want to pollute the DSL and I do not find myself yet needing such behaviour, because the callbacks are there for "integrity". If I really want the callbacks conditional, I'll just use the conditional argument.*
248
+
249
+ ### Example 7 (Class and Instance Level Callbacks)
250
+
251
+ ```ruby
252
+ class Foo
253
+ include SuperCallbacks
254
+
255
+ before :bar do
256
+ puts 'before bar 1!'
257
+ end
258
+
259
+ before :bar do
260
+ puts 'before bar 2!'
261
+ end
262
+
263
+ def bar
264
+ puts 'bar!'
265
+ end
266
+ end
267
+
268
+ foo_1 = Foo.new
269
+ foo_2 = Foo.new
270
+
271
+ foo_1.before :bar do
272
+ puts 'before bar 3'
273
+ end
274
+
275
+ foo_1.before :bar do
276
+ puts 'before bar 4'
277
+ end
278
+
279
+ foo_1.bar
280
+ # => 'before bar 1!'
281
+ # => 'before bar 2!'
282
+ # => 'before bar 3'
283
+ # => 'before bar 4'
284
+ # => 'bar!'
285
+
286
+ foo_2.bar
287
+ # => 'before bar 1!'
288
+ # => 'before bar 2!'
289
+ # => 'bar!'
290
+ ```
291
+
292
+ *Notice above that foo_1 and foo_2 both call the class-level callbacks, while they have independent (not-shared) instance-level callbacks defined. Order of execution is class-level first then instance-level, of which defined callbacks are then in order of first-come-first-serve.*
293
+
294
+ *Above uses `before`, but works similarly with `after`*
295
+
296
+ ### Example 8 (Inherited Callbacks)
297
+
298
+ ```ruby
299
+ class Foo
300
+ include SuperCallbacks
301
+
302
+ before :bar do
303
+ puts 'Foo: before bar 1!'
304
+ end
305
+
306
+ def bar
307
+ puts 'bar!'
308
+ end
309
+ end
310
+
311
+ class SubFoo < Foo
312
+ before :bar do
313
+ puts 'SubFoo: bar'
314
+ end
315
+ end
316
+
317
+ foo = Foo.new
318
+ foo.bar
319
+ # => 'Foo: before bar 1!'
320
+ # => 'bar!'
321
+
322
+ sub_foo = SubFoo.new
323
+ sub_foo.bar
324
+ # => 'Foo: before bar 1!'
325
+ # => 'SubFoo: bar'
326
+ # => 'bar!'
327
+ ```
328
+
329
+ *Notice above `sub_foo` calls both `before` callbacks defined in `Foo` and `SubFoo`, because SubFoo inherits from Foo. Callbacks are called in order of ancestors descending; meaning it starts calling the top-level ancestor superclass callbacks, and then calling its subclass callbacks, until it reaches the instance's class callbacks*
330
+
331
+ *Above uses `before`, but works similarly with `after`*
332
+
333
+ ### Example 9 (Requiring Method To Be Defined)
334
+
335
+ ```ruby
336
+ class Foo
337
+ include SuperCallbacks
338
+
339
+ after! :bar do
340
+ puts 'after bar!'
341
+ end
342
+
343
+ def bar
344
+ puts 'bar!'
345
+ end
346
+ end
347
+ # => ArgumentError: `bar` is not or not yet defined for Foo
348
+
349
+ class Foo
350
+ include SuperCallbacks
351
+
352
+ def bar
353
+ puts 'bar!'
354
+ end
355
+
356
+ after! :bar do
357
+ puts 'after bar!'
358
+ end
359
+ end
360
+ # => [NO ERRORS]
361
+ ```
362
+
363
+ *From above, sometimes I noticed that I forgot to define a method! So the bang `!` version is just basically like `after` except that this raises an error if `method_name` is not defined or not yet defined (at the time `after!` is called). This works perfect with `attr_accesors` I normally put them at the top of the lines of a Class, and so I can now safely call `before!` or `after!` because I am sure that I already defined everything I needed to define. If I forgot something then, this `before!` would raise an error and alert me, and not silently failing. Helps debugging :)*
364
+
365
+ *Above uses `after!`, but works similarly with `before!`*
366
+
367
+ ### Example 10 (Dirty Checking of Instance Variables Changes)
368
+
369
+ ```ruby
370
+ class Foo
371
+ include SuperCallbacks
372
+
373
+ attr_accessor :bar, :baz
374
+
375
+ after :bar= do |arg|
376
+ puts 'original values of all instance attributes:'
377
+ puts instance_variables_before_change
378
+
379
+ puts 'original value:'
380
+ puts instance_variable_before_change :@bar
381
+
382
+ if instance_variable_changed? :@bar
383
+ puts 'new value'
384
+ @arg
385
+ end
386
+ end
387
+ end
388
+
389
+ foo = Foo.new
390
+ foo.bar = 1 # bar is changed from nil to 1
391
+ # => original values of all instance attributes:
392
+ # => {}
393
+ # => original value:
394
+ # => nil
395
+ # => new value:
396
+ # => 1
397
+ foo.bar = 1 # bar is not changed from 1 to 1
398
+ # => original values of all instance attributes:
399
+ # => { :@bar => 1 }
400
+ # => original value:
401
+ # => 1
402
+ ```
403
+
404
+ *Notice above on the second time `foo.bar = 1` is called, "new value" was no longer "puts", because `@bar` didn't change from 1 to 1. You can only use `instance_variables_before_change`, instance_variable_before_change` and `instance_variable_changed?` inside the SuperCallback cycle; otherwise you will get a `"You cannot call this method outside the SuperCallback cycle"` error.
405
+
406
+ *Above uses `after!`, but works similarly with `before!`*
407
+
408
+ ## TODOs
409
+ * when the need already arises, implement `around` (If you have ideas or want to help this part, please feel free to fork or send me a message! :)
410
+ * [Found a new bug I could not solve](https://github.com/jrpolidario/super_callbacks/issues/1). If you have any ideas how to solve this, please feel to submit a merge request! :) At the moment, this is not important to me (yet?) as I develop my game engine, so I'm leaving this here for now, and I'll come back again into this later.
411
+
412
+ ## Development
413
+
414
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
415
+
416
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
417
+
418
+ ## Contributing
419
+
420
+ Bug reports and pull requests are welcome on GitHub at https://github.com/jrpolidario/super_callbacks. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
421
+
422
+ ## License
423
+
424
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
425
+
426
+ ## Changelog
427
+
428
+ * 1.1.0 (2019-08-14)
429
+ * [Supported "dirty" checking of instance variable changes](#example-10-dirty-checking-of-instance-variables-changes)
430
+ * 1.0.3 (2019-08-12)
431
+ * Cleaner code without explicitly calling `run_callbacks` anymore; done now because of ruby upgrade from 1.9 to 2.0+ which already supports `prepend`
432
+ * Supported both class and instance level callbacks
433
+ * Supported inherited callbacks
434
+ * v0.2.1 (2019-08-09) *From `dragonruby_callbacks`*
435
+ * Fixed syntax errors for ruby 1.9.3; Fixed not supporting subclasses of Proc, String, or Symbol
436
+ * v0.2 (2019-08-08) *From `dragonruby_callbacks`*
437
+ * Supported [conditional callbacks](#conditional-callbacks) with `:if`
438
+ * v0.1 (2019-08-07) *From `dragonruby_callbacks`*
439
+ * Done all