method_callbacks 1.0.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bbf0e679bd6e803446afce6df859949314259077
4
+ data.tar.gz: f1c885539200a66a3b71eb2a875f46d07bac3fce
5
+ SHA512:
6
+ metadata.gz: 7e2609566689254861eb16ceef74c4a71e6025253b420f99e68866edd36555ede6dfd93557fcdb9e696be01926064d5245bc542d1ed0dc53bc184fd8fdaf3b18
7
+ data.tar.gz: cffb1bb69568ab5d172d8861351688cafcc66eb9fd30da97ea9e0f02dca0c7df2bbe386abb4745649f755983ac169d42cb2fdbb9f2c94bc750eae5f1872ea22c
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ cache: bundler
3
+
4
+ rvm:
5
+ - 1.9.3
6
+ - 2.0.0
7
+
8
+ script: 'bundle exec rake'
9
+
10
+ notifications:
11
+ email:
12
+ recipients:
13
+ - showactive@gmail.com
14
+ on_failure: change
15
+ on_success: never
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in method_callbacks.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,9 @@
1
+ guard 'rspec' do
2
+ watch(%r{^lib/(.+).rb$}) do |m|
3
+ "spec/#{m[1]}_spec.rb"
4
+ end
5
+
6
+ watch(%r{^spec/(.+).rb$}) do |m|
7
+ "spec/#{m[1]}.rb"
8
+ end
9
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Morgan Showman
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # MethodCallbacks
2
+
3
+ Add after, around, and before callbacks to your methods.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'method_callbacks'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install method_callbacks
18
+
19
+ ## Usage
20
+
21
+ ```rb
22
+ require "method_callbacks"
23
+
24
+ class ExampleCallbacks
25
+ include MethodCallbacks
26
+
27
+ after_method :action, :farewell, :unload
28
+ after_method :action do
29
+ puts "Executing block callback after action and everything else!"
30
+ end
31
+
32
+ before_method :action do
33
+ puts "Executing block callback before action and everything else!"
34
+ end
35
+ before_method :action, :intro
36
+ before_method :action, :greet
37
+
38
+ around_method :action, :outer_around, :inner_around
39
+
40
+ def outer_around
41
+ puts "Executing pre outer_around!"
42
+ return_value = yield
43
+ puts "Executin post outer_around!"
44
+ return_value
45
+ end
46
+
47
+ def inner_around
48
+ puts "Executing pre inner_around!"
49
+ return_value = yield
50
+ puts "Executing post inner_around!"
51
+ return_value
52
+ end
53
+
54
+ def action
55
+ puts "Executing action, the method with all teh callbacks!"
56
+
57
+ "My return value!"
58
+ end
59
+
60
+ def greet
61
+ puts "Executing greet before action but after intro!"
62
+ end
63
+
64
+ def intro
65
+ puts "Executing intro before action and greet!"
66
+ end
67
+
68
+ def farewell
69
+ puts "Executing farewell after action but before unload!"
70
+ end
71
+
72
+ def unload
73
+ puts "Executing unload after action and farewell!"
74
+ end
75
+ end
76
+
77
+ > ExampleCallbacks.new.action
78
+ Executing block callback before action and everything else!
79
+ Executing intro before action and greet!
80
+ Executing greet before action but after intro!
81
+ Executing pre outer_around!
82
+ Executing pre inner_around!
83
+ Executing action, the method with all teh callbacks!
84
+ Executing post inner_around!
85
+ Executin post outer_around!
86
+ Executing farewell after action but before unload!
87
+ Executing unload after action and farewell!
88
+ Executing block callback after action and everything else!
89
+ => "My return value!"
90
+ ```
91
+
92
+ ## Contributing
93
+
94
+ 1. Fork it ( http://github.com/MorganShowman/method_callbacks/fork )
95
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
96
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
97
+ 4. Push to the branch (`git push origin my-new-feature`)
98
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rspec/core/rake_task'
2
+ require "bundler/gem_tasks"
3
+
4
+ RSpec::Core::RakeTask.new(:spec) do |task|
5
+ task.rspec_opts = ['--color', '--format', 'nested']
6
+ end
7
+
8
+ task default: :spec
@@ -0,0 +1,25 @@
1
+ require "forwardable"
2
+
3
+ module MethodCallbacks
4
+ class Definer
5
+ extend Forwardable
6
+
7
+ attr_reader :method
8
+
9
+ def_delegators :method, :callbacks, :name
10
+
11
+ def initialize(method)
12
+ @method = method
13
+ end
14
+
15
+ def define(type, callbacks)
16
+ callbacks.each do |callback|
17
+ callbacks(type) << callback if !callbacks(type).include?(callback)
18
+ end
19
+ end
20
+
21
+ def define_with_block(type, &block)
22
+ callbacks(type) << block if !callbacks(type).include?(block)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ module MethodCallbacks
2
+ class Executor
3
+ attr_reader :method, :type, :object
4
+
5
+ def initialize(method, type, object)
6
+ @method = method
7
+ @type = type
8
+ @object = object
9
+ end
10
+
11
+ def execute
12
+ return execute_callbacks if !block_given?
13
+
14
+ callbacks.empty? ? yield : execute_around_callbacks(&Proc.new)
15
+ end
16
+
17
+ private
18
+
19
+ def callbacks
20
+ method.callbacks(type)
21
+ end
22
+
23
+ def execute_around_callbacks
24
+ callbacks.reverse.reduce(Proc.new) { |block, callback_name| Proc.new { object.send(callback_name, &block) } }.call
25
+ end
26
+
27
+ def execute_callbacks
28
+ callbacks.each { |callback_name| callback_name.is_a?(Proc) ? object.instance_eval(&callback_name) : object.send(callback_name) }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,32 @@
1
+ require "method_callbacks/method"
2
+
3
+ module MethodCallbacks
4
+ class Finder
5
+ attr_reader :name
6
+
7
+ def initialize(name)
8
+ @name = name
9
+ end
10
+
11
+ def find
12
+ @_find ||= {}
13
+ @_find[name] ||= methods.select { |callback| callback == self }.first
14
+ end
15
+
16
+ def find_or_new
17
+ find || new
18
+ end
19
+
20
+ private
21
+
22
+ def new
23
+ method = Method.new(name)
24
+ methods << method
25
+ method
26
+ end
27
+
28
+ def methods
29
+ @_methods ||= []
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,21 @@
1
+ module MethodCallbacks
2
+ class Locker
3
+ attr_accessor :state
4
+
5
+ def initialize
6
+ self.state = :unlocked
7
+ end
8
+
9
+ def lock!
10
+ self.state = :locked
11
+ end
12
+
13
+ def locked?
14
+ state == :locked
15
+ end
16
+
17
+ def unlock!
18
+ self.state = :unlocked
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,46 @@
1
+ require "forwardable"
2
+ require "method_callbacks/definer"
3
+ require "method_callbacks/executor"
4
+ require "method_callbacks/locker"
5
+
6
+ module MethodCallbacks
7
+ class Method
8
+ extend Forwardable
9
+
10
+ attr_reader :name
11
+
12
+ def_delegators :definer, :define, :define_with_block
13
+ def_delegators :locker, :lock!, :locked?, :unlock!
14
+
15
+ def initialize(name)
16
+ @name = name
17
+ end
18
+
19
+ def ==(other)
20
+ self.name == other.name
21
+ end
22
+
23
+ def callbacks(type)
24
+ @_callbacks ||= {}
25
+ @_callbacks[type] ||= []
26
+ end
27
+
28
+ def execute(type, object)
29
+ block_given? ? executor(type, object).execute(&Proc.new) : executor(type, object).execute
30
+ end
31
+
32
+ private
33
+
34
+ def executor(type, object)
35
+ Executor.new(self, type, object)
36
+ end
37
+
38
+ def definer
39
+ @_definer ||= Definer.new(self)
40
+ end
41
+
42
+ def locker
43
+ @_method_lock ||= Locker.new
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,3 @@
1
+ module MethodCallbacks
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,72 @@
1
+ require "method_callbacks/finder"
2
+ require "method_callbacks/version"
3
+
4
+ module MethodCallbacks
5
+ ALIAS_PREFIX = "__method_callback_alias_to_original"
6
+
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ end
10
+
11
+ module ClassMethods
12
+ def after_method(method_name, *callback_names)
13
+ define(method_name, :after, callback_names)
14
+ define_with_block(method_name, :after, &Proc.new) if block_given?
15
+ end
16
+
17
+ def around_method(method_name, *callback_names)
18
+ define(method_name, :around, callback_names)
19
+ end
20
+
21
+ def before_method(method_name, *callback_names)
22
+ define(method_name, :before, callback_names)
23
+ define_with_block(method_name, :before, &Proc.new) if block_given?
24
+ end
25
+
26
+ private
27
+
28
+ def define(method_name, type, callback_names)
29
+ find_or_new(method_name).define(type, callback_names)
30
+ end
31
+
32
+ def define_with_block(method_name, type)
33
+ find_or_new(method_name).define_with_block(type, &Proc.new)
34
+ end
35
+
36
+ def find(method_name)
37
+ finder(method_name).find
38
+ end
39
+
40
+ def finder(method_name)
41
+ @_finder ||= {}
42
+ @_finder[method_name] ||= MethodCallbacks::Finder.new(method_name)
43
+ end
44
+
45
+ def find_or_new(method_name)
46
+ finder(method_name).find_or_new
47
+ end
48
+
49
+ def method_added(method_name)
50
+ redefine_method(find(method_name))
51
+
52
+ super
53
+ end
54
+
55
+ def redefine_method(method)
56
+ return if !method || method.locked?
57
+
58
+ method.lock! && alias_method("#{ALIAS_PREFIX}_#{method.name}", method.name)
59
+
60
+ define_method(method.name) do
61
+ method.execute(:before, self)
62
+ return_value = method.execute(:around, self) do
63
+ send("#{ALIAS_PREFIX}_#{method.name}")
64
+ end
65
+ method.execute(:after, self)
66
+ return_value
67
+ end
68
+
69
+ method.unlock!
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'method_callbacks/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "method_callbacks"
8
+ spec.version = MethodCallbacks::VERSION
9
+ spec.authors = ["Morgan Showman"]
10
+ spec.email = ["morganshowman@gmail.com"]
11
+ spec.summary = %q{Add method callbacks to your classes}
12
+ spec.description = %q{Add after, around, and before callbacks to methods in your classes}
13
+ spec.homepage = "https://github.com/MorganShowman/method_callbacks"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "guard"
25
+ spec.add_development_dependency "guard-rspec"
26
+ end
@@ -0,0 +1,74 @@
1
+ require "spec_helper"
2
+
3
+ describe MethodCallbacks do
4
+ let(:test_callbacks) { TestCallbacks.new }
5
+
6
+ it "should execute all the callbacks on action" do
7
+ expect(test_callbacks).to receive(:puts).with("Executing block").ordered
8
+ expect(test_callbacks).to receive(:puts).with("Executing intro").ordered
9
+ expect(test_callbacks).to receive(:puts).with("Executing greet").ordered
10
+ expect(test_callbacks).to receive(:puts).with("Executing pre outer_around").ordered
11
+ expect(test_callbacks).to receive(:puts).with("Executing pre inner_around").ordered
12
+ expect(test_callbacks).to receive(:puts).with("Executing action").ordered
13
+ expect(test_callbacks).to receive(:puts).with("Executing post inner_around").ordered
14
+ expect(test_callbacks).to receive(:puts).with("Executing post outer_around").ordered
15
+ expect(test_callbacks).to receive(:puts).with("Executing farewell").ordered
16
+ expect(test_callbacks).to receive(:puts).with("Executing unload").ordered
17
+ expect(test_callbacks).to receive(:puts).with("Executing block").ordered
18
+
19
+ test_callbacks.action
20
+ end
21
+ end
22
+
23
+ class TestCallbacks
24
+ include MethodCallbacks
25
+
26
+ after_method :action, :farewell, :unload
27
+ after_method :action do
28
+ puts "Executing block"
29
+ end
30
+
31
+ before_method :action do
32
+ puts "Executing block"
33
+ end
34
+ before_method :action, :intro
35
+ before_method :action, :greet
36
+
37
+ around_method :action, :outer_around, :inner_around
38
+
39
+ def outer_around
40
+ puts "Executing pre outer_around"
41
+ return_value = yield
42
+ puts "Executing post outer_around"
43
+ return_value
44
+ end
45
+
46
+ def inner_around
47
+ puts "Executing pre inner_around"
48
+ return_value = yield
49
+ puts "Executing post inner_around"
50
+ return_value
51
+ end
52
+
53
+ def action
54
+ puts "Executing action"
55
+
56
+ "Return value"
57
+ end
58
+
59
+ def greet
60
+ puts "Executing greet"
61
+ end
62
+
63
+ def intro
64
+ puts "Executing intro"
65
+ end
66
+
67
+ def farewell
68
+ puts "Executing farewell"
69
+ end
70
+
71
+ def unload
72
+ puts "Executing unload"
73
+ end
74
+ end
@@ -0,0 +1 @@
1
+ require "method_callbacks"
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: method_callbacks
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Morgan Showman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ version_requirements: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ~>
17
+ - !ruby/object:Gem::Version
18
+ version: '1.5'
19
+ prerelease: false
20
+ name: bundler
21
+ requirement: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ~>
24
+ - !ruby/object:Gem::Version
25
+ version: '1.5'
26
+ type: :development
27
+ - !ruby/object:Gem::Dependency
28
+ version_requirements: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ prerelease: false
34
+ name: rake
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :development
41
+ - !ruby/object:Gem::Dependency
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ prerelease: false
48
+ name: rspec
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ - !ruby/object:Gem::Dependency
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ prerelease: false
62
+ name: guard
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :development
69
+ - !ruby/object:Gem::Dependency
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ prerelease: false
76
+ name: guard-rspec
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ description: Add after, around, and before callbacks to methods in your classes
84
+ email:
85
+ - morganshowman@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - .gitignore
91
+ - .travis.yml
92
+ - Gemfile
93
+ - Guardfile
94
+ - LICENSE.txt
95
+ - README.md
96
+ - Rakefile
97
+ - lib/method_callbacks.rb
98
+ - lib/method_callbacks/definer.rb
99
+ - lib/method_callbacks/executor.rb
100
+ - lib/method_callbacks/finder.rb
101
+ - lib/method_callbacks/locker.rb
102
+ - lib/method_callbacks/method.rb
103
+ - lib/method_callbacks/version.rb
104
+ - method_callbacks.gemspec
105
+ - spec/method_callbacks_spec.rb
106
+ - spec/spec_helper.rb
107
+ homepage: https://github.com/MorganShowman/method_callbacks
108
+ licenses:
109
+ - MIT
110
+ metadata: {}
111
+ post_install_message:
112
+ rdoc_options: []
113
+ require_paths:
114
+ - lib
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ required_rubygems_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ requirements: []
126
+ rubyforge_project:
127
+ rubygems_version: 2.2.2
128
+ signing_key:
129
+ specification_version: 4
130
+ summary: Add method callbacks to your classes
131
+ test_files:
132
+ - spec/method_callbacks_spec.rb
133
+ - spec/spec_helper.rb