big_spoon 0.0.1

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/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.3@working_girl --create
data/.simplecov ADDED
@@ -0,0 +1 @@
1
+ SimpleCov.start
data/CHANGES.md ADDED
@@ -0,0 +1,5 @@
1
+ # CHANGELOG
2
+ ## 0.0.1
3
+ ### Basic functionality
4
+ - Hooks / callbacks are working BEFORE OR AFTER a method gets defined
5
+ - No :if or :unless options
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'http://rubygems.org'
2
+
3
+ group :test do
4
+ gem 'guard-rspec'
5
+ gem 'simplecov', :require => false
6
+ gem 'rspec'
7
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,41 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.3)
5
+ ffi (1.1.5)
6
+ guard (1.3.0)
7
+ listen (>= 0.4.2)
8
+ thor (>= 0.14.6)
9
+ guard-rspec (1.2.1)
10
+ guard (>= 1.1)
11
+ listen (0.4.7)
12
+ rb-fchange (~> 0.0.5)
13
+ rb-fsevent (~> 0.9.1)
14
+ rb-inotify (~> 0.8.8)
15
+ multi_json (1.3.6)
16
+ rb-fchange (0.0.5)
17
+ ffi
18
+ rb-fsevent (0.9.1)
19
+ rb-inotify (0.8.8)
20
+ ffi (>= 0.5.0)
21
+ rspec (2.11.0)
22
+ rspec-core (~> 2.11.0)
23
+ rspec-expectations (~> 2.11.0)
24
+ rspec-mocks (~> 2.11.0)
25
+ rspec-core (2.11.1)
26
+ rspec-expectations (2.11.2)
27
+ diff-lcs (~> 1.1.3)
28
+ rspec-mocks (2.11.1)
29
+ simplecov (0.6.4)
30
+ multi_json (~> 1.0)
31
+ simplecov-html (~> 0.5.3)
32
+ simplecov-html (0.5.3)
33
+ thor (0.15.4)
34
+
35
+ PLATFORMS
36
+ ruby
37
+
38
+ DEPENDENCIES
39
+ guard-rspec
40
+ rspec
41
+ simplecov
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', :version => 2 do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # Big Spoon
2
+ Like the big spoon, **Big Spoon** wraps around your own methods.
3
+ It adds before and after callbacks to ANY method in any Ruby class.
4
+
5
+ There were those who wanted to call it "sandwich," but they were killed.
6
+
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.
10
+
11
+ I think I'm going to import it into all of my libraries to avoid alias\_method_chaining anything ever again.
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
16
+
17
+ Let's say, for example, you want to reset an instance variable in a model when it gets reloaded.
18
+
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`.
21
+
22
+ ```
23
+ class User < ActiveRecord::Base
24
+ def name
25
+ @name ||= "#{first_name} #{last_name}"
26
+ end
27
+ end
28
+ ```
29
+
30
+ So now, when you do something like this:
31
+
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
+ ```
41
+
42
+ But what if you could hook into `ActiveRecord::Base#reload`?
43
+
44
+ ```
45
+ class User < ActiveRecord::Base
46
+ hooks do
47
+ before_reload { @name = nil }
48
+ end
49
+
50
+ def name
51
+ @name ||= "#{first_name} #{last_name}"
52
+ end
53
+ end
54
+ ```
55
+
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.
57
+
58
+ Copyright © 2012 Delightful Widgets Inc. No warranty so don't sue me or my company THANKS!
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require 'rake'
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |gemspec|
6
+ gemspec.name = "big_spoon"
7
+ gemspec.summary = "Adds before and after hooks to any method, because that's just how things should be"
8
+ gemspec.description = %{
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
+ }
11
+ gemspec.email = "flip@x451.com"
12
+ gemspec.homepage = "http://github.com/Plinq/big_spoon"
13
+ gemspec.authors = ["Flip Sasser"]
14
+ end
15
+ rescue LoadError
16
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/big_spoon.gemspec ADDED
@@ -0,0 +1,49 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "big_spoon"
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Flip Sasser"]
12
+ s.date = "2012-08-12"
13
+ s.description = "\n 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.\n "
14
+ s.email = "flip@x451.com"
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".rspec",
20
+ ".rvmrc",
21
+ ".simplecov",
22
+ "CHANGES.md",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "Guardfile",
26
+ "README.md",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "big_spoon.gemspec",
30
+ "lib/big_spoon.rb",
31
+ "lib/big_spoon/hook.rb",
32
+ "spec/lib/big_spoon_spec.rb",
33
+ "spec/spec_helper.rb"
34
+ ]
35
+ s.homepage = "http://github.com/Plinq/big_spoon"
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = "1.8.24"
38
+ s.summary = "Adds before and after hooks to any method, because that's just how things should be"
39
+
40
+ if s.respond_to? :specification_version then
41
+ s.specification_version = 3
42
+
43
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
44
+ else
45
+ end
46
+ else
47
+ end
48
+ end
49
+
@@ -0,0 +1,138 @@
1
+ module BigSpoon
2
+ class Hook
3
+ class << self
4
+ def for(klass)
5
+ all[klass.to_s] ||= new(klass)
6
+ end
7
+
8
+ private
9
+ def all
10
+ @all ||= {}
11
+ end
12
+ end
13
+
14
+ attr_accessor :klass
15
+
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)
19
+ end
20
+
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)
24
+ end
25
+
26
+ # def clear!
27
+ # methods.each do |method_to_hook, hooks|
28
+ # unhook! method_to_hook
29
+ # end
30
+ # methods.clear
31
+ # end
32
+
33
+ # Execute after a method
34
+ def execute_after(method_to_hook, instance)
35
+ execute(:after, method_to_hook, instance)
36
+ end
37
+
38
+ # Execute before a method
39
+ def execute_before(method_to_hook, instance)
40
+ execute(:before, method_to_hook, instance)
41
+ end
42
+
43
+ # Alias a method for hookable-ness
44
+ def hook!(method_to_hook)
45
+ hooked_method = hooked_method(method_to_hook)
46
+ original_method = original_method(method_to_hook)
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}
56
+ hooks
57
+ klass.class_eval alias_these_hooks, __FILE__, line.succ
58
+ end
59
+
60
+ def initialize(klass)
61
+ self.klass = klass
62
+ end
63
+
64
+ def should_hook?(method_to_hook)
65
+ methods[method_to_hook.to_sym] && hookable?(method_to_hook) && !hooked?(method_to_hook)
66
+ end
67
+
68
+ def unhook!(method_to_hook)
69
+ hooked_method = hooked_method(method_to_hook)
70
+ original_method = original_method(method_to_hook)
71
+ line = __LINE__; alias_these_hooks = <<-hooks
72
+ alias :#{method_to_hook} #{original_method}
73
+ remove_method #{hooked_method}
74
+ hooks
75
+ klass.class_eval alias_these_hooks, __FILE__, line.succ
76
+ end
77
+
78
+ private
79
+ def execute(before_or_after, method_to_hook, instance)
80
+ methods[method_to_hook] ||= {}
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)
86
+ else
87
+ instance.send(hook_to_call)
88
+ end
89
+ end
90
+ end
91
+
92
+ def hook(before_or_after, method_to_hook, method_to_call = nil, &block)
93
+ method_to_hook = method_to_hook.to_sym
94
+ if block_given?
95
+ method_to_call = block
96
+ else
97
+ method_to_call = method_to_call.to_sym
98
+ end
99
+
100
+ methods[method_to_hook] ||= {}
101
+ 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)
103
+
104
+ hook!(method_to_hook) if should_hook?(method_to_hook)
105
+ end
106
+
107
+ def hookable?(method_to_hook)
108
+ klass.method_defined?(method_to_hook)
109
+ end
110
+
111
+ def hooked?(method_to_hook)
112
+ klass.method_defined?(hooked_method(method_to_hook))
113
+ end
114
+
115
+ def hooked_method(method_to_hook)
116
+ "_big_spoon_alias_#{method_to_hook}"
117
+ end
118
+
119
+ def method_missing(method_name, *args)
120
+ case method_name.to_s
121
+ when /^after_(.+)$/
122
+ after $1, *args
123
+ when /^before_(.+)$/
124
+ before $1, *args
125
+ else
126
+ super
127
+ end
128
+ end
129
+
130
+ def methods
131
+ @methods ||= {}
132
+ end
133
+
134
+ def original_method(method_to_hook)
135
+ "_big_spoon_original_#{method_to_hook}"
136
+ end
137
+ end
138
+ end
data/lib/big_spoon.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'big_spoon/hook'
2
+
3
+ module BigSpoon
4
+ module ClassMethods
5
+ def hooks(options = {}, &block)
6
+ @hooks ||= Hook.for(self)
7
+ @hooks.instance_eval(&block) if block_given?
8
+
9
+ unless respond_to?(:_big_spoon_original_method_added)
10
+ class << self
11
+ alias :_big_spoon_original_method_added :method_added
12
+ def _big_spoon_alias_method_added(method_to_hook, *args)
13
+ if @hooks.should_hook?(method_to_hook)
14
+ @hooks.hook! method_to_hook
15
+ end
16
+ end
17
+ alias :method_added :_big_spoon_alias_method_added
18
+ end
19
+ end
20
+ @hooks
21
+ end # `hooks` method
22
+ end # `ClassMethods` module
23
+ end # `BigSpoon` module
24
+
25
+ Object.extend BigSpoon::ClassMethods
@@ -0,0 +1,91 @@
1
+ require 'big_spoon'
2
+
3
+ class BigSpoonTest
4
+ hooks do
5
+ before :foo!, :hook_1
6
+ end
7
+
8
+ def foo!
9
+ :foo
10
+ end
11
+
12
+ def bar!
13
+ :bar
14
+ end
15
+
16
+ private
17
+ def by_all_means_hook
18
+ true
19
+ end
20
+
21
+ def dont_hook
22
+ false
23
+ end
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
35
+ end
36
+ end
37
+
38
+ describe BigSpoon do
39
+ before :each do
40
+ @big_spoon_test = BigSpoonTest.new
41
+ end
42
+
43
+ it "should monkeypatch Object" do
44
+ Object.should respond_to(:hooks)
45
+ end
46
+
47
+ it "should allow me to add a hook before an object's methods BEFORE THEY EXIST" do
48
+ @big_spoon_test.should_receive(:hook_1)
49
+ @big_spoon_test.foo!
50
+ end
51
+
52
+ it "should allow me to add a hook after an object's methods AFTER THEY EXIST" do
53
+ BigSpoonTest.hooks do
54
+ after :bar!, :hook_2
55
+ end
56
+ @big_spoon_test.should_receive(:hook_2)
57
+ @big_spoon_test.bar!
58
+ end
59
+
60
+ it "should allow me to add a hook lambda" do
61
+ BigSpoonTest.hooks do
62
+ after :bar! do
63
+ puts self.inspect
64
+ end
65
+ end
66
+ @big_spoon_test.should_receive(:puts)
67
+ @big_spoon_test.should_receive(:inspect)
68
+ @big_spoon_test.bar!
69
+ end
70
+
71
+ it "should still return the appropriate method's value" do
72
+ @big_spoon_test.should_receive(:hook_1)
73
+ @big_spoon_test.foo!.should == :foo
74
+ end
75
+
76
+ it "should allow me to metaprogram before_* hooks" do
77
+ @big_spoon_test.should_receive(:hook_2)
78
+ BigSpoonTest.hooks do
79
+ before_foo! :hook_2
80
+ end
81
+ @big_spoon_test.foo!
82
+ end
83
+
84
+ it "should allow me to metaprogram after_* hooks" do
85
+ @big_spoon_test.should_receive(:hook_3)
86
+ BigSpoonTest.hooks do
87
+ after_foo! :hook_3
88
+ end
89
+ @big_spoon_test.foo!
90
+ end
91
+ end
@@ -0,0 +1,10 @@
1
+ # Add lib/ to the load path
2
+ $LOAD_PATH.unshift(File.expand_path(File.join('..', 'lib'), File.dirname(__FILE__)))
3
+
4
+ # Load up our Gemfile
5
+ require 'rubygems'
6
+ require 'bundler/setup'
7
+ Bundler.require(:default, :test)
8
+
9
+ # Enable coverage reporting
10
+ require 'simplecov'
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: big_spoon
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Flip Sasser
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-12 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ! "\n BigSpoon will add a hooks method to every class. Call that
15
+ method with a block and add all kinds of fun hooks before and after your methods.\n
16
+ \ "
17
+ email: flip@x451.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files:
21
+ - README.md
22
+ files:
23
+ - .rspec
24
+ - .rvmrc
25
+ - .simplecov
26
+ - CHANGES.md
27
+ - Gemfile
28
+ - Gemfile.lock
29
+ - Guardfile
30
+ - README.md
31
+ - Rakefile
32
+ - VERSION
33
+ - big_spoon.gemspec
34
+ - lib/big_spoon.rb
35
+ - lib/big_spoon/hook.rb
36
+ - spec/lib/big_spoon_spec.rb
37
+ - spec/spec_helper.rb
38
+ homepage: http://github.com/Plinq/big_spoon
39
+ licenses: []
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ! '>='
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ segments:
51
+ - 0
52
+ hash: 4152067215125062110
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubyforge_project:
61
+ rubygems_version: 1.8.24
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Adds before and after hooks to any method, because that's just how things
65
+ should be
66
+ test_files: []