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 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
- **Big Spoon** adds _hooks_ around ANY method. It can do this before
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
- I think I'm going to import it into all of my libraries to avoid alias\_method_chaining anything ever again.
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
- Anyway, here's how it works for now, DON'T use it cause I haven't tested it with shit:
14
-
15
- ## Usage
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
- Let's say, for example, you want to reset an instance variable in a model when it gets reloaded.
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
- For shits and giggles and real-world-clarity, I'll use an ActiveRecord model but this could be
20
- anything that knows about `reload`.
24
+ protected
25
+ def listen_to_the_darkness!
26
+ `osascript "tell iTunes to play some awesome"`
27
+ end
21
28
 
22
- ```
23
- class User < ActiveRecord::Base
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
- So now, when you do something like this:
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
- user = User.new(:first_name => "Flip", :last_name => "Sasser")
34
- user.name #=> "Flip Sasser"
35
- user.first_name = "Elizabeth"
36
- user.name #=> "Flip Sasser"
37
- # OH NOE MY INSTANCE VARIABLE GOT CACHED LIKE IT SHOULD
38
- user.reload.name #=> "Flip Sasser"
39
- # OH NOE RELOAD DOESN'T RESET INSTANCE VARIABLES
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
- But what if you could hook into `ActiveRecord::Base#reload`?
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
- class User < ActiveRecord::Base
46
- hooks do
47
- before_reload { @name = nil }
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
- def name
51
- @name ||= "#{first_name} #{last_name}"
92
+ protected
93
+ def add_ice
94
+ Ice.create!
52
95
  end
53
96
  end
54
97
  ```
55
98
 
56
- Now you can reset the instance variable. Neat, right? Obviously this is way more awesome way more places but that's the long and short of it.
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 = "http://github.com/Plinq/big_spoon"
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
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.1"
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 = "http://github.com/Plinq/big_spoon"
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"
@@ -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
- 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}
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
- alias :#{method_to_hook} #{original_method}
73
- remove_method #{hooked_method}
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 |hook_to_call|
83
- case hook_to_call
84
- when Proc
85
- instance.instance_eval(&hook_to_call)
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
- instance.send(hook_to_call)
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
- methods[method_to_hook][before_or_after].push(method_to_call) unless methods[method_to_hook][before_or_after].include?(method_to_call)
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
- def hooked_method(method_to_hook)
116
- "_big_spoon_alias_#{method_to_hook}"
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
- def original_method(method_to_hook)
135
- "_big_spoon_original_#{method_to_hook}"
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
 
@@ -18,20 +18,12 @@ class BigSpoonTest
18
18
  true
19
19
  end
20
20
 
21
- def dont_hook
21
+ def please_dont_hook
22
22
  false
23
23
  end
24
24
 
25
- def hook_1
26
- :hook_1
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.1
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: http://github.com/Plinq/big_spoon
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: 4152067215125062110
52
+ hash: -3518133336514115333
53
53
  required_rubygems_version: !ruby/object:Gem::Requirement
54
54
  none: false
55
55
  requirements: