big_spoon 0.0.1 → 0.1.0
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.
- data/CHANGES.md +5 -0
- data/README.md +89 -31
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/big_spoon.gemspec +2 -2
- data/lib/big_spoon/hook.rb +45 -25
- data/lib/big_spoon.rb +12 -0
- data/spec/lib/big_spoon_spec.rb +39 -11
- metadata +3 -3
data/CHANGES.md
CHANGED
@@ -1,4 +1,9 @@
|
|
1
1
|
# CHANGELOG
|
2
|
+
## 0.1.1
|
3
|
+
### :if, :unless, and tested in production!
|
4
|
+
- :if => :method and :unless => lambda { false } are now supported.
|
5
|
+
- That, or any variation of those two you can imagine.
|
6
|
+
|
2
7
|
## 0.0.1
|
3
8
|
### Basic functionality
|
4
9
|
- Hooks / callbacks are working BEFORE OR AFTER a method gets defined
|
data/README.md
CHANGED
@@ -1,58 +1,116 @@
|
|
1
1
|
# Big Spoon
|
2
2
|
Like the big spoon, **Big Spoon** wraps around your own methods.
|
3
3
|
It adds before and after callbacks to ANY method in any Ruby class.
|
4
|
+
Basically, now you can add hooks and/or callback to **any** Ruby method without fear of reprisals.
|
4
5
|
|
5
6
|
There were those who wanted to call it "sandwich," but they were killed.
|
6
7
|
|
7
|
-
|
8
|
-
or after the methods are defined, making it awesome for fun stuff like adding extra hooks around events at the top of
|
9
|
-
a class definition without having to worry about when the method gets defined.
|
8
|
+
## Basic Usage
|
10
9
|
|
11
|
-
|
10
|
+
Use **Big Spoon** like you would any other callbacks! Of course there's, like, at least three ways to do that. So **Big Spoon** supports all of em. All
|
11
|
+
three let you define before- and after-methods or blocks to any method your class could, like, ever call. The safest is block form:
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
```ruby
|
14
|
+
class User
|
15
|
+
hooks do
|
16
|
+
before :get_your_hands_off_of_my_woman, :listen_to_the_darkness
|
17
|
+
after :get_your_hands_off_of_my_woman { listen_to_moar_darkness! }
|
18
|
+
end
|
16
19
|
|
17
|
-
|
20
|
+
def get_your_hands_off_of_my_woman
|
21
|
+
puts "Get your hands off of my woman, motherf*cker!"
|
22
|
+
end
|
18
23
|
|
19
|
-
|
20
|
-
|
24
|
+
protected
|
25
|
+
def listen_to_the_darkness!
|
26
|
+
`osascript "tell iTunes to play some awesome"`
|
27
|
+
end
|
21
28
|
|
22
|
-
|
23
|
-
|
24
|
-
def name
|
25
|
-
@name ||= "#{first_name} #{last_name}"
|
29
|
+
def listen_to_moar_darkness
|
30
|
+
`osascript "tell iTuens to continue not to suck after that last rad song"`
|
26
31
|
end
|
27
32
|
end
|
28
33
|
```
|
29
34
|
|
30
|
-
|
35
|
+
This is designed not to conflict with Rails callbacks and their siblings. **But if'n
|
36
|
+
you're a real scofflaw (_and you f*cking should be!_), you can just do it normal-like:**
|
31
37
|
|
32
|
-
```
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
```ruby
|
39
|
+
class User
|
40
|
+
before_believe_in_a_thing_called_love :listen_to_the_rhythm_of_my_heart
|
41
|
+
|
42
|
+
def believe_in_a_thing_called_love
|
43
|
+
puts "We'll be rockin til the sun goes down!"
|
44
|
+
end
|
45
|
+
|
46
|
+
def listen_to_the_rhythm_of_my_heart
|
47
|
+
listen("127.0.0.1") do
|
48
|
+
match /(lub|dub)/ do
|
49
|
+
puts "Edgar Allan F*cking Poe?!"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
````
|
54
|
+
|
55
|
+
So. Add hooks. To any Ruby method. That's pretty damn awesome, where I come form. I SAID "FORM," son!
|
56
|
+
|
57
|
+
But, as they say, "love is only a feeling." So spoon like there's no tomorrow.
|
58
|
+
|
59
|
+
## But there's (conditionally) more!
|
60
|
+
|
61
|
+
Because ActiveModel callbacks are just so damn delightful, I've added some fun conditional sugar to match their wonderful. So g'head and add some `:if` conditions to your callbacks:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
class User
|
65
|
+
before :love_on_the_rocks, :add_ice, :if => :no_ice?
|
41
66
|
|
42
|
-
|
67
|
+
def love_on_the_rocks
|
68
|
+
puts "Loo-OOOVE ON THE ROCKS! YOU'D DO ANYTHING FOR A QUIET LIFE!"
|
69
|
+
end
|
70
|
+
|
71
|
+
def no_ice?
|
72
|
+
Ice.empty?
|
73
|
+
end
|
43
74
|
|
75
|
+
protected
|
76
|
+
def add_ice
|
77
|
+
Ice.create!
|
78
|
+
end
|
79
|
+
end
|
44
80
|
```
|
45
|
-
|
46
|
-
|
47
|
-
|
81
|
+
|
82
|
+
Conditional callbacks also support `:unless`, just like their ActiveModel ancestors. Or should I say "inspiritors?" Is that word? Shut up, of course it is. Anyway:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
class User
|
86
|
+
before :love_on_the_rocks, :add_ice, :unless => :not_in_tys_mazada?
|
87
|
+
|
88
|
+
def not_in_tys_mazada?
|
89
|
+
!((mazda = User.find_by_slug("ty").car) && mazda.has_rad_bass?)
|
48
90
|
end
|
49
91
|
|
50
|
-
|
51
|
-
|
92
|
+
protected
|
93
|
+
def add_ice
|
94
|
+
Ice.create!
|
52
95
|
end
|
53
96
|
end
|
54
97
|
```
|
55
98
|
|
56
|
-
|
99
|
+
And to recap! Just as with the believing-in-things-called-love example, both could be re-written as
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
before_love_on_the_rocks :add_ice, :if => :no_ice?
|
103
|
+
```
|
104
|
+
|
105
|
+
and
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
before_love_on_the_rocks :add_ice, :unless => :not_in_tys_mazda?
|
109
|
+
```
|
110
|
+
|
111
|
+
respectively.
|
112
|
+
|
113
|
+
HAPPY **CALLING-OF-THE-BACK**, FRIENDS!
|
114
|
+
|
57
115
|
|
58
116
|
Copyright © 2012 Delightful Widgets Inc. No warranty so don't sue me or my company THANKS!
|
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ begin
|
|
9
9
|
BigSpoon will add a hooks method to every class. Call that method with a block and add all kinds of fun hooks before and after your methods.
|
10
10
|
}
|
11
11
|
gemspec.email = "flip@x451.com"
|
12
|
-
gemspec.homepage = "
|
12
|
+
gemspec.homepage = "https://github.com/flipsasser/big_spoon"
|
13
13
|
gemspec.authors = ["Flip Sasser"]
|
14
14
|
end
|
15
15
|
rescue LoadError
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/big_spoon.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "big_spoon"
|
8
|
-
s.version = "0.0
|
8
|
+
s.version = "0.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Flip Sasser"]
|
@@ -32,7 +32,7 @@ Gem::Specification.new do |s|
|
|
32
32
|
"spec/lib/big_spoon_spec.rb",
|
33
33
|
"spec/spec_helper.rb"
|
34
34
|
]
|
35
|
-
s.homepage = "
|
35
|
+
s.homepage = "https://github.com/flipsasser/big_spoon"
|
36
36
|
s.require_paths = ["lib"]
|
37
37
|
s.rubygems_version = "1.8.24"
|
38
38
|
s.summary = "Adds before and after hooks to any method, because that's just how things should be"
|
data/lib/big_spoon/hook.rb
CHANGED
@@ -14,13 +14,13 @@ module BigSpoon
|
|
14
14
|
attr_accessor :klass
|
15
15
|
|
16
16
|
# Define a method to execute after another
|
17
|
-
def after(method_to_hook, method_to_call = nil, &block)
|
18
|
-
hook(:after, method_to_hook, method_to_call, &block)
|
17
|
+
def after(method_to_hook, method_to_call = nil, options = {}, &block)
|
18
|
+
hook(:after, method_to_hook, method_to_call, options, &block)
|
19
19
|
end
|
20
20
|
|
21
21
|
# Define a method to execute before another
|
22
|
-
def before(method_to_hook, method_to_call = nil, &block)
|
23
|
-
hook(:before, method_to_hook, method_to_call, &block)
|
22
|
+
def before(method_to_hook, method_to_call = nil, options = {}, &block)
|
23
|
+
hook(:before, method_to_hook, method_to_call, options, &block)
|
24
24
|
end
|
25
25
|
|
26
26
|
# def clear!
|
@@ -45,14 +45,14 @@ module BigSpoon
|
|
45
45
|
hooked_method = hooked_method(method_to_hook)
|
46
46
|
original_method = original_method(method_to_hook)
|
47
47
|
line = __LINE__; alias_these_hooks = <<-hooks
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
48
|
+
alias :#{original_method} :#{method_to_hook}
|
49
|
+
def #{hooked_method}(*args)
|
50
|
+
Hook.for(self.class).execute_before(:#{method_to_hook}, self)
|
51
|
+
result = #{original_method}
|
52
|
+
Hook.for(self.class).execute_after(:#{method_to_hook}, self)
|
53
|
+
result
|
54
|
+
end
|
55
|
+
alias :#{method_to_hook} :#{hooked_method}
|
56
56
|
hooks
|
57
57
|
klass.class_eval alias_these_hooks, __FILE__, line.succ
|
58
58
|
end
|
@@ -69,8 +69,8 @@ module BigSpoon
|
|
69
69
|
hooked_method = hooked_method(method_to_hook)
|
70
70
|
original_method = original_method(method_to_hook)
|
71
71
|
line = __LINE__; alias_these_hooks = <<-hooks
|
72
|
-
|
73
|
-
|
72
|
+
alias :#{method_to_hook} #{original_method}
|
73
|
+
remove_method #{hooked_method}
|
74
74
|
hooks
|
75
75
|
klass.class_eval alias_these_hooks, __FILE__, line.succ
|
76
76
|
end
|
@@ -79,18 +79,35 @@ module BigSpoon
|
|
79
79
|
def execute(before_or_after, method_to_hook, instance)
|
80
80
|
methods[method_to_hook] ||= {}
|
81
81
|
methods[method_to_hook][before_or_after] ||= []
|
82
|
-
methods[method_to_hook][before_or_after].each do |
|
83
|
-
|
84
|
-
|
85
|
-
|
82
|
+
methods[method_to_hook][before_or_after].each do |method_definition|
|
83
|
+
execute_for_reals = if method_definition[:if].is_a?(Proc)
|
84
|
+
instance.instance_eval(&method_definition[:if])
|
85
|
+
elsif method_definition[:if]
|
86
|
+
instance.send(method_definition[:if])
|
87
|
+
elsif method_definition[:unless].is_a?(Proc)
|
88
|
+
!instance.instance_eval(&method_definition[:unless])
|
89
|
+
elsif method_definition[:unless]
|
90
|
+
!instance.send(method_definition[:unless])
|
86
91
|
else
|
87
|
-
|
92
|
+
true
|
93
|
+
end
|
94
|
+
if execute_for_reals
|
95
|
+
case method_definition[:method]
|
96
|
+
when Proc
|
97
|
+
instance.instance_eval(&method_definition[:method])
|
98
|
+
else
|
99
|
+
instance.send(method_definition[:method])
|
100
|
+
end
|
88
101
|
end
|
89
102
|
end
|
90
103
|
end
|
91
104
|
|
92
|
-
def hook(before_or_after, method_to_hook, method_to_call = nil, &block)
|
105
|
+
def hook(before_or_after, method_to_hook, method_to_call = nil, options = {}, &block)
|
93
106
|
method_to_hook = method_to_hook.to_sym
|
107
|
+
if method_to_call.is_a? Hash
|
108
|
+
options = method_to_call
|
109
|
+
method_to_call = nil
|
110
|
+
end
|
94
111
|
if block_given?
|
95
112
|
method_to_call = block
|
96
113
|
else
|
@@ -99,7 +116,10 @@ module BigSpoon
|
|
99
116
|
|
100
117
|
methods[method_to_hook] ||= {}
|
101
118
|
methods[method_to_hook][before_or_after] ||= []
|
102
|
-
|
119
|
+
method_definition = options.merge({:method => method_to_call})
|
120
|
+
methods[method_to_hook][before_or_after].push(method_definition) unless methods[method_to_hook][before_or_after].any? do |other_method_definition|
|
121
|
+
other_method_definition[:method] == method_to_call
|
122
|
+
end
|
103
123
|
|
104
124
|
hook!(method_to_hook) if should_hook?(method_to_hook)
|
105
125
|
end
|
@@ -112,8 +132,8 @@ module BigSpoon
|
|
112
132
|
klass.method_defined?(hooked_method(method_to_hook))
|
113
133
|
end
|
114
134
|
|
115
|
-
|
116
|
-
|
135
|
+
def hooked_method(method_to_hook)
|
136
|
+
"_big_spoon_alias_#{method_to_hook}"
|
117
137
|
end
|
118
138
|
|
119
139
|
def method_missing(method_name, *args)
|
@@ -131,8 +151,8 @@ module BigSpoon
|
|
131
151
|
@methods ||= {}
|
132
152
|
end
|
133
153
|
|
134
|
-
|
135
|
-
|
154
|
+
def original_method(method_to_hook)
|
155
|
+
"_big_spoon_original_#{method_to_hook}"
|
136
156
|
end
|
137
157
|
end
|
138
158
|
end
|
data/lib/big_spoon.rb
CHANGED
@@ -19,6 +19,18 @@ module BigSpoon
|
|
19
19
|
end
|
20
20
|
@hooks
|
21
21
|
end # `hooks` method
|
22
|
+
|
23
|
+
private
|
24
|
+
def method_missing(method_name, *args)
|
25
|
+
case method_name.to_s
|
26
|
+
when /^after_(.+)$/
|
27
|
+
hooks.after $1, *args
|
28
|
+
when /^before_(.+)$/
|
29
|
+
hooks.before $1, *args
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
22
34
|
end # `ClassMethods` module
|
23
35
|
end # `BigSpoon` module
|
24
36
|
|
data/spec/lib/big_spoon_spec.rb
CHANGED
@@ -18,20 +18,12 @@ class BigSpoonTest
|
|
18
18
|
true
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
21
|
+
def please_dont_hook
|
22
22
|
false
|
23
23
|
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
def hook_2
|
30
|
-
:hook_2
|
31
|
-
end
|
32
|
-
|
33
|
-
def hook_3
|
34
|
-
:hook_3
|
25
|
+
(1..8).each do |index|
|
26
|
+
define_method("hook_#{index}") { "hook_#{index}"}
|
35
27
|
end
|
36
28
|
end
|
37
29
|
|
@@ -88,4 +80,40 @@ describe BigSpoon do
|
|
88
80
|
end
|
89
81
|
@big_spoon_test.foo!
|
90
82
|
end
|
83
|
+
|
84
|
+
it "should let me hook outside of the hooks block" do
|
85
|
+
@big_spoon_test.should_receive(:by_all_means_hook)
|
86
|
+
BigSpoonTest.before_foo! :by_all_means_hook
|
87
|
+
@big_spoon_test.foo!
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should not hook if an :if method returns false" do
|
91
|
+
@big_spoon_test.should_not_receive(:hook_4)
|
92
|
+
BigSpoonTest.before_foo! :hook_4, :if => :please_dont_hook
|
93
|
+
@big_spoon_test.foo!
|
94
|
+
end
|
95
|
+
|
96
|
+
it "SHOULD hook if an :if method returns true" do
|
97
|
+
@big_spoon_test.should_receive(:hook_5)
|
98
|
+
BigSpoonTest.before_foo! :hook_5, :if => :by_all_means_hook
|
99
|
+
@big_spoon_test.foo!
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should not hook if an :unless method returns true" do
|
103
|
+
@big_spoon_test.should_not_receive(:hook_6)
|
104
|
+
BigSpoonTest.before_foo! :hook_6, :unless => :by_all_means_hook
|
105
|
+
@big_spoon_test.foo!
|
106
|
+
end
|
107
|
+
|
108
|
+
it "SHOULD hook if an :unless method returns false" do
|
109
|
+
@big_spoon_test.should_receive(:hook_7)
|
110
|
+
BigSpoonTest.before_foo! :hook_7, :unless => :please_dont_hook
|
111
|
+
@big_spoon_test.foo!
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should meta-program before_* hooks" do
|
115
|
+
@big_spoon_test.should_receive(:hook_8)
|
116
|
+
BigSpoonTest.before_foo! :hook_8
|
117
|
+
@big_spoon_test.foo!
|
118
|
+
end
|
91
119
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: big_spoon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -35,7 +35,7 @@ files:
|
|
35
35
|
- lib/big_spoon/hook.rb
|
36
36
|
- spec/lib/big_spoon_spec.rb
|
37
37
|
- spec/spec_helper.rb
|
38
|
-
homepage:
|
38
|
+
homepage: https://github.com/flipsasser/big_spoon
|
39
39
|
licenses: []
|
40
40
|
post_install_message:
|
41
41
|
rdoc_options: []
|
@@ -49,7 +49,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
49
49
|
version: '0'
|
50
50
|
segments:
|
51
51
|
- 0
|
52
|
-
hash:
|
52
|
+
hash: -3518133336514115333
|
53
53
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
54
|
none: false
|
55
55
|
requirements:
|