uberhook 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Build Status](https://secure.travis-ci.org/mjio/uberhook.png)](http://travis-ci.org/mjio/uberhook)
4
4
 
5
- The Uberhook gem allows you to define `before` and `after` hooks for your classes and models.
5
+ The Uberhook gem allows you to define `before` and `after` hooks for your Ruby classes.
6
6
 
7
7
  ## Installation
8
8
 
@@ -22,7 +22,7 @@ gem 'uberhook'
22
22
  require 'uberhook'
23
23
 
24
24
  class Car
25
- include Uberhook::Abstract
25
+ extend Uberhook
26
26
 
27
27
  before :drive do
28
28
  p 'start engine'
@@ -45,42 +45,3 @@ beatle.drive
45
45
  # drive
46
46
  # turn radio on
47
47
  ```
48
-
49
- Use the `Uberhook::Base` module to define class hooks.
50
-
51
- ``` ruby
52
- require 'uberhook'
53
-
54
- class Dance
55
- include Uberhook::Base
56
-
57
- instance_hook :after, :step_one do
58
- p 'two!'
59
- end
60
-
61
- def step_one
62
- p 'one!'
63
- end
64
-
65
- class_hook :before, :rock do
66
- p 'prepare'
67
- end
68
-
69
- def self.rock
70
- p 'and rock'
71
- end
72
- end
73
-
74
- waltz = Dance.new
75
- waltz.step_one
76
-
77
- # Output:
78
- # one!
79
- # two!
80
-
81
- Dance.rock
82
-
83
- # Output:
84
- # prepare
85
- # and rock
86
- ```
@@ -1,3 +1,41 @@
1
- require 'uberhook/abstract'
2
- require 'uberhook/base'
3
1
  require 'uberhook/version'
2
+
3
+ module Uberhook
4
+ [:before, :after].each do |type|
5
+ define_method(type) do |target, &callback|
6
+ install_hook(target, type, &callback)
7
+ end
8
+ end
9
+
10
+ def method_added(target)
11
+ define_hook(target) if hooks.has_key? target
12
+ end
13
+
14
+ private
15
+
16
+ def hooks
17
+ @hooks ||= Hash.new do |hash, target|
18
+ hash[target] = {before: [], after: [], defined: false}
19
+ end
20
+ end
21
+
22
+ def install_hook(target, type, &callback)
23
+ hooks[target][type] << callback
24
+ define_hook(target)
25
+ end
26
+
27
+ def define_hook(target)
28
+ return if hooks[target][:defined] || !instance_methods.include?(target)
29
+
30
+ hooks[target][:defined] = true
31
+ unbound_target_method = instance_method(target)
32
+ instance_hooks = hooks
33
+
34
+ define_method(target) do |*args, &block|
35
+ instance_hooks[target][:before].each { |callback| instance_eval(&callback) }
36
+ retval = unbound_target_method.bind(self).call(*args, &block)
37
+ instance_hooks[target][:after].each { |callback| instance_eval(&callback) }
38
+ retval
39
+ end
40
+ end
41
+ end
@@ -1,3 +1,3 @@
1
1
  module Uberhook
2
- VERSION = '0.0.3'
2
+ VERSION = '0.0.4'
3
3
  end
@@ -1,4 +1,4 @@
1
1
  require 'minitest/autorun'
2
- require 'mocha'
2
+ require 'mocha/setup'
3
3
 
4
4
  require 'uberhook'
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe Uberhook do
4
+ let :klass do
5
+ Class.new do
6
+ extend Uberhook
7
+
8
+ attr_accessor :array
9
+ def initialize; @array = []; end
10
+
11
+ def one
12
+ array << :one
13
+ end
14
+ end
15
+ end
16
+
17
+ let(:instance) { klass.new }
18
+
19
+ specify 'hooks can be applied to run before and after the target' do
20
+ klass.before(:one) { array << :before }
21
+ klass.after(:one) { array << :after }
22
+ instance.one
23
+ instance.array.must_equal [:before, :one, :after]
24
+ end
25
+
26
+ specify 'hooks can be defined before or after the target method' do
27
+ klass.class_eval do
28
+ before(:two) { array << :before_1 }
29
+ after(:two) { array << :after_1 }
30
+ define_method(:two) { array << :two }
31
+ before(:two) { array << :before_2 }
32
+ after(:two) { array << :after_2 }
33
+ end
34
+ instance.two
35
+ instance.array == [:before_1, :before_2, :two, :after_1, :after_2]
36
+ end
37
+
38
+ specify 'hooks can call ather methods' do
39
+ klass.class_eval do
40
+ before(:one) { zero }
41
+ after(:one) { two }
42
+ define_method(:zero) { array << :zero }
43
+ define_method(:two) { array << :two }
44
+ end
45
+ instance.one
46
+ instance.array == [:zero, :one, :two]
47
+ end
48
+
49
+ it 'keeps the return values' do
50
+ klass.class_eval do
51
+ def two(*args, &block); [args, block]; end
52
+ before(:two) { }
53
+ after(:two) { }
54
+ end
55
+ retval = klass.new.two(1, 2) { 5 }
56
+ retval[0].must_equal [1, 2]
57
+ retval[1].call.must_equal 5
58
+ end
59
+ end
@@ -2,16 +2,16 @@ require File.expand_path('../lib/uberhook/version', __FILE__)
2
2
 
3
3
  Gem::Specification.new do |gem|
4
4
  gem.name = 'uberhook'
5
+ gem.version = Uberhook::VERSION
5
6
  gem.authors = ['Martin Jagusch']
6
7
  gem.email = ['_@mj.io']
7
- gem.version = Uberhook::VERSION
8
- gem.description = 'Allows you to define :before and :after hooks for your classes and models.'
9
- gem.summary = ':before and :after hooks'
8
+ gem.description = 'Define :before and :after hooks for your Ruby classes.'
9
+ gem.summary = "uberhook-#{Uberhook::VERSION}"
10
10
  gem.homepage = 'https://github.com/mjio/uberhook'
11
11
 
12
- gem.add_development_dependency 'rake', '~> 0.9.2.2'
13
- gem.add_development_dependency 'mocha', '~> 0.12.3'
14
- gem.add_development_dependency 'minitest', '~> 3.3.0'
12
+ gem.add_development_dependency 'rake', '~> 10.0.0'
13
+ gem.add_development_dependency 'mocha', '~> 0.13.0'
14
+ gem.add_development_dependency 'minitest', '~> 4.2.0'
15
15
 
16
16
  gem.files = `git ls-files`.split($/)
17
17
  gem.test_files = gem.files.grep(%r{^spec/})
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uberhook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-23 00:00:00.000000000 Z
12
+ date: 2012-11-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: 0.9.2.2
21
+ version: 10.0.0
22
22
  type: :development
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- version: 0.9.2.2
29
+ version: 10.0.0
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: mocha
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -34,7 +34,7 @@ dependencies:
34
34
  requirements:
35
35
  - - ~>
36
36
  - !ruby/object:Gem::Version
37
- version: 0.12.3
37
+ version: 0.13.0
38
38
  type: :development
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,7 +42,7 @@ dependencies:
42
42
  requirements:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
- version: 0.12.3
45
+ version: 0.13.0
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: minitest
48
48
  requirement: !ruby/object:Gem::Requirement
@@ -50,7 +50,7 @@ dependencies:
50
50
  requirements:
51
51
  - - ~>
52
52
  - !ruby/object:Gem::Version
53
- version: 3.3.0
53
+ version: 4.2.0
54
54
  type: :development
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
@@ -58,8 +58,8 @@ dependencies:
58
58
  requirements:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
- version: 3.3.0
62
- description: Allows you to define :before and :after hooks for your classes and models.
61
+ version: 4.2.0
62
+ description: Define :before and :after hooks for your Ruby classes.
63
63
  email:
64
64
  - _@mj.io
65
65
  executables: []
@@ -73,12 +73,9 @@ files:
73
73
  - README.md
74
74
  - Rakefile
75
75
  - lib/uberhook.rb
76
- - lib/uberhook/abstract.rb
77
- - lib/uberhook/base.rb
78
76
  - lib/uberhook/version.rb
79
- - spec/abstract_spec.rb
80
- - spec/base_spec.rb
81
77
  - spec/spec_helper.rb
78
+ - spec/uberhook_spec.rb
82
79
  - uberhook.gemspec
83
80
  homepage: https://github.com/mjio/uberhook
84
81
  licenses: []
@@ -103,8 +100,7 @@ rubyforge_project:
103
100
  rubygems_version: 1.8.24
104
101
  signing_key:
105
102
  specification_version: 3
106
- summary: ':before and :after hooks'
103
+ summary: uberhook-0.0.4
107
104
  test_files:
108
- - spec/abstract_spec.rb
109
- - spec/base_spec.rb
110
105
  - spec/spec_helper.rb
106
+ - spec/uberhook_spec.rb
@@ -1,30 +0,0 @@
1
- module Uberhook
2
- module Abstract
3
- def self.included(base)
4
- base.send :include, Uberhook::Base
5
- base.extend ClassMethods
6
- end
7
-
8
- module ClassMethods
9
- # Define a before or after hook for a specific method.
10
- #
11
- # @example Define before hook.
12
- # before :foo do
13
- # p 'before callback'
14
- # end
15
- #
16
- # @example Define after hook.
17
- # after :foo do
18
- # p 'after callback'
19
- # end
20
- #
21
- # @param [ Symbol ] target The target method.
22
- # @param [ Proc ] callback The callback block.
23
- [:before, :after].each do |type|
24
- define_method(type) do |target, &callback|
25
- instance_hook(type, target, &callback)
26
- end
27
- end
28
- end
29
- end
30
- end
@@ -1,112 +0,0 @@
1
- module Uberhook
2
- module Base
3
- def self.included(base)
4
- base.extend ClassMethods
5
- base.class_eval do
6
- class << self
7
- def method_added(name)
8
- process_instance_method_added(name)
9
- end
10
-
11
- def singleton_method_added(name)
12
- process_class_method_added(name)
13
- end
14
- end
15
- end
16
- end
17
-
18
- module ClassMethods
19
- def instance_hook(type, target, &callback)
20
- instance_hooks[target][type] = callback
21
-
22
- # Define instance hook if target is defined and
23
- # hook is not defined yet
24
- define_instance_hook(target) if
25
- method_defined?(target) and
26
- instance_hooks.has_key?(target) and
27
- not instance_hooks[target].has_key?(:defined)
28
- end
29
-
30
- def class_hook(type, target, &callback)
31
- class_hooks[target][type] = callback
32
-
33
- # Define class hook if target is defined and
34
- # hook is not defined yet
35
- define_class_hook(target) if
36
- respond_to?(target) and
37
- class_hooks.has_key?(target) and
38
- not class_hooks[target].has_key?(:defined)
39
- end
40
-
41
- private
42
-
43
- def instance_hooks
44
- @instance_hooks ||= Hash.new { |hash, key| hash[key] = {} }
45
- end
46
-
47
- def class_hooks
48
- @class_hooks ||= Hash.new { |hash, key| hash[key] = {} }
49
- end
50
-
51
- def process_instance_method_added(name)
52
- return unless instance_hooks.has_key?(name) and
53
- not instance_hooks[name].has_key?(:defined)
54
-
55
- define_instance_hook(name)
56
- end
57
-
58
- def process_class_method_added(name)
59
- return unless class_hooks.has_key?(name) and
60
- not class_hooks[name].has_key?(:defined)
61
-
62
- define_class_hook(name)
63
- end
64
-
65
- def define_instance_hook(target)
66
- instance_hooks[target][:defined] = true
67
- original_target = "#{target}_without_callbacks"
68
-
69
- alias_method original_target, target
70
- private original_target
71
-
72
- class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
73
- def #{target}(*args, &block)
74
- self.class.send(:run_instance_callback, :before, :#{target}, self)
75
- retval = send(:#{original_target}, *args, &block)
76
- self.class.send(:run_instance_callback, :after, :#{target}, self)
77
- retval
78
- end
79
- RUBY_EVAL
80
- end
81
-
82
- def define_class_hook(target)
83
- class_hooks[target][:defined] = true
84
- original_target = "#{target}_without_callbacks"
85
-
86
- class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
87
- class << self
88
- alias_method :#{original_target}, :#{target}
89
- private :#{original_target}
90
-
91
- def #{target}(*args, &block)
92
- self.send(:run_class_callback, :before, :#{target}, self)
93
- retval = send(:#{original_target}, *args, &block)
94
- self.send(:run_class_callback, :after, :#{target}, self)
95
- retval
96
- end
97
- end
98
- RUBY_EVAL
99
- end
100
-
101
- def run_instance_callback(type, target, scope)
102
- return unless instance_hooks[target].has_key?(type)
103
- scope.instance_eval(&instance_hooks[target][type])
104
- end
105
-
106
- def run_class_callback(type, target, scope)
107
- return unless class_hooks[target].has_key?(type)
108
- scope.instance_eval(&class_hooks[target][type])
109
- end
110
- end
111
- end
112
- end
@@ -1,25 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Uberhook::Abstract do
4
- let(:klass) do
5
- Class.new { include Uberhook::Abstract }
6
- end
7
-
8
- describe :before do
9
- it 'should forward hook definition' do
10
- klass.expects(:instance_hook).with(:before, :one).once
11
- klass.class_eval { before :one }
12
- end
13
- end
14
-
15
- describe :around do
16
- it 'should forward hook definition'
17
- end
18
-
19
- describe :after do
20
- it 'should forward hook definition' do
21
- klass.expects(:instance_hook).with(:after, :one).once
22
- klass.class_eval { after :one }
23
- end
24
- end
25
- end
@@ -1,165 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Uberhook::Base do
4
- let(:klass) do
5
- Class.new do
6
- include Uberhook::Base
7
-
8
- def one
9
- @hook_calls << :one
10
- end
11
-
12
- def self.two
13
- @hook_calls << :two
14
- end
15
- end
16
- end
17
-
18
- describe :instance_hook do
19
- it 'should save a callback' do
20
- klass.class_eval { instance_hook :before, :one }
21
- hash = {:one => {:before => nil, :defined => true}}
22
- klass.send(:instance_hooks).must_equal hash
23
- end
24
- end
25
-
26
- it 'should forward a hook definition' do
27
- klass.expects(:define_instance_hook).with(:one).once
28
- klass.class_eval { instance_hook :before, :one }
29
- end
30
-
31
- it 'should not forward a unkown hook definition' do
32
- klass.expects(:define_instance_hook).times(0)
33
- klass.class_eval { instance_hook :before, :unkown }
34
- end
35
-
36
- it 'should excecute hooks' do
37
- klass.class_eval do
38
- attr_reader :hook_calls
39
- def initialize
40
- @hook_calls = []
41
- end
42
- instance_hook :before, :one do
43
- @hook_calls << :before_one
44
- end
45
- instance_hook :after, :one do
46
- @hook_calls << :after_one
47
- end
48
- end
49
- inst = klass.new
50
- inst.one
51
- inst.hook_calls.must_equal [:before_one, :one, :after_one]
52
- end
53
-
54
- describe :class_hook do
55
- it 'should save a callback' do
56
- klass.class_eval { class_hook :before, :two }
57
- hash = {:two => {:before => nil, :defined => true}}
58
- klass.send(:class_hooks).must_equal hash
59
- end
60
-
61
- it 'should forward a hook definition' do
62
- klass.expects(:define_class_hook).with(:two).once
63
- klass.class_eval { class_hook :before, :two }
64
- end
65
-
66
- it 'should not forward a unkown hook definition' do
67
- klass.expects(:define_class_hook).times(0)
68
- klass.class_eval { class_hook :before, :unkown }
69
- end
70
-
71
- it 'should excecute hooks' do
72
- klass.class_eval do
73
- @hook_calls = []
74
- class_hook :before, :two do
75
- @hook_calls << :before_two
76
- end
77
- class_hook :after, :two do
78
- @hook_calls << :after_two
79
- end
80
- end
81
- hooks = [:before_two, :two, :after_two]
82
- klass.two
83
- klass.instance_variable_get(:@hook_calls).must_equal hooks
84
- end
85
- end
86
-
87
- describe :process_instance_method_added do
88
- it 'should excecute when methods get added' do
89
- klass.expects(:process_instance_method_added).with(:three).once
90
- klass.class_eval { def three; end }
91
- end
92
-
93
- it 'should continue when hooks get defined' do
94
- klass.expects(:define_instance_hook).with(:three).once
95
- klass.class_eval do
96
- instance_hook :before, :three
97
- def three; end
98
- end
99
- end
100
-
101
- it 'should not continue without a hook' do
102
- klass.expects(:define_instance_hook).times(0)
103
- klass.class_eval { def three; end }
104
- end
105
- end
106
-
107
- describe :process_class_method_added do
108
- it 'should excecute when methods get added' do
109
- skip 'Ignore methods like :singleton_method_added'
110
- klass.expects(:process_class_method_added).with(:four).once
111
- klass.class_eval { def self.four; end }
112
- end
113
-
114
- it 'should continue when hooks get defined' do
115
- klass.expects(:define_class_hook).with(:four).once
116
- klass.class_eval do
117
- class_hook :before, :four
118
- def self.four; end
119
- end
120
- end
121
-
122
- it 'should not continue without a hook' do
123
- klass.expects(:define_class_hook).times(0)
124
- klass.class_eval { def self.four; end }
125
- end
126
- end
127
-
128
- describe :define_instance_hook do
129
- it 'should return the targets return value' do
130
- klass.class_eval do
131
- instance_hook :after, :three do
132
- 'after'
133
- end
134
- def three
135
- 'three'
136
- end
137
- end
138
- klass.new.three.must_equal 'three'
139
- end
140
-
141
- it 'should make the original target method private' do
142
- klass.class_eval { instance_hook :before, :one }
143
- klass.new.private_methods.must_include :one_without_callbacks
144
- end
145
- end
146
-
147
- describe :define_class_hook do
148
- it 'should return the targets return value' do
149
- klass.class_eval do
150
- class_hook :after, :four do
151
- 'after'
152
- end
153
- def self.four
154
- 'four'
155
- end
156
- end
157
- klass.four.must_equal 'four'
158
- end
159
-
160
- it 'should make the original target method private' do
161
- klass.class_eval { class_hook :before, :two }
162
- klass.private_methods.must_include :two_without_callbacks
163
- end
164
- end
165
- end