uberhook 0.0.3 → 0.0.4

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/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