big_spoon 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|