method_wrapper 0.1.1 → 0.2.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.
- data/Gemfile.lock +1 -2
- data/README.rdoc +28 -39
- data/lib/method_wrapper.rb +62 -25
- data/lib/method_wrapper/version.rb +1 -1
- data/method_wrapper.gemspec +2 -2
- data/spec/class_builder.rb +16 -57
- data/spec/method_wrapper_spec.rb +23 -34
- data/spec/spec_helper.rb +6 -0
- metadata +6 -6
data/Gemfile.lock
CHANGED
data/README.rdoc
CHANGED
@@ -4,71 +4,60 @@
|
|
4
4
|
|
5
5
|
== Introduction
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
The before_ and after_ callbacks will run as soon as you call wrapped method.
|
7
|
+
alias_method_chain alternative. How easy to wrap new features around existing methods with method_wrapper.
|
10
8
|
|
11
9
|
== Installation
|
12
10
|
|
13
11
|
gem install method_wrapper
|
14
12
|
|
15
13
|
== Examples
|
16
|
-
require 'method_wrapper'
|
17
|
-
|
18
|
-
class Klass
|
19
|
-
include MethodWrapper
|
20
|
-
wrap_methods :method_name
|
21
|
-
|
22
|
-
def method_name
|
23
|
-
puts 'hi'
|
24
|
-
end
|
25
|
-
|
26
|
-
def before_method_name
|
27
|
-
puts "calls before method name"
|
28
|
-
end
|
29
14
|
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
You can also has partial callback
|
15
|
+
* Wrap multi methods to a feature in a line.
|
16
|
+
* Be able to call wrap_methods before methods defined.
|
36
17
|
require 'method_wrapper'
|
18
|
+
* Call original method(origin_method_name). Note: I take different style from alias_method_chain because we don't want users to know what feature has been wrapped.
|
19
|
+
|
20
|
+
== Examples
|
37
21
|
|
38
22
|
class Klass
|
39
23
|
include MethodWrapper
|
40
|
-
wrap_methods :
|
24
|
+
wrap_methods [:save!, :query] => :log
|
41
25
|
|
42
|
-
def
|
43
|
-
|
26
|
+
def save!
|
27
|
+
"save"
|
44
28
|
end
|
45
29
|
|
46
|
-
def
|
47
|
-
|
30
|
+
def query
|
31
|
+
"update"
|
48
32
|
end
|
49
33
|
|
50
|
-
def
|
51
|
-
|
34
|
+
def save_with_log!
|
35
|
+
origin_save! + " with log"
|
52
36
|
end
|
53
37
|
|
54
|
-
def
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
def after_second_method_name
|
59
|
-
puts "calls after second method name"
|
38
|
+
def query_with_log
|
39
|
+
origin_query! + " with log"
|
60
40
|
end
|
61
41
|
end
|
62
42
|
|
63
|
-
|
43
|
+
obj = Klass.new
|
44
|
+
obj.save!
|
45
|
+
=> "save with log"
|
46
|
+
obj.origin_save!
|
47
|
+
=> "save"
|
48
|
+
|
49
|
+
You can also open the existing classes to wrap methods. Note: Be careful, you know what you are doing.
|
64
50
|
require 'method_wrapper'
|
65
51
|
|
66
52
|
class String
|
67
53
|
include MethodWrapper
|
68
|
-
wrap_methods :reverse
|
54
|
+
wrap_methods :reverse => :upcase
|
69
55
|
|
70
|
-
def
|
71
|
-
|
56
|
+
def reverse_with_upcase
|
57
|
+
origin_reverse.upcase
|
72
58
|
end
|
73
59
|
end
|
74
60
|
|
61
|
+
"nuhhc gnanmas".reverse
|
62
|
+
=> SAMNANG CHHUN
|
63
|
+
|
data/lib/method_wrapper.rb
CHANGED
@@ -1,51 +1,88 @@
|
|
1
1
|
module MethodWrapper
|
2
2
|
def self.included(base)
|
3
|
-
base.instance_variable_set(:@
|
3
|
+
base.instance_variable_set(:@__wrapped_methods, {})
|
4
4
|
base.extend ClassMethods
|
5
5
|
end
|
6
6
|
|
7
|
-
private
|
8
|
-
def invoke_method(name)
|
9
|
-
send(name) if respond_to? name, true
|
10
|
-
end
|
11
|
-
|
12
7
|
module ClassMethods
|
8
|
+
def wrap_methods(params)
|
9
|
+
method_names, feature = params.first
|
10
|
+
method_names = [method_names] unless method_names.instance_of? Array
|
11
|
+
|
12
|
+
method_names.each do |name|
|
13
|
+
feature_name = feature_method_name(name, feature)
|
14
|
+
@__wrapped_methods[name] = feature_name
|
15
|
+
|
16
|
+
__wrap_method!(name, feature_name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
13
20
|
def method_added(name)
|
14
|
-
return if @
|
21
|
+
return if @disable_method_added_hook
|
15
22
|
|
16
|
-
|
23
|
+
new_added_method_has_in_wrpped_methods(name)
|
17
24
|
end
|
18
25
|
|
19
|
-
def
|
20
|
-
|
26
|
+
def include(*modules)
|
27
|
+
super
|
21
28
|
|
22
|
-
@
|
23
|
-
|
29
|
+
@__wrapped_methods.each do |k, v|
|
30
|
+
__wrap_method!(k, v)
|
24
31
|
end
|
25
32
|
end
|
26
33
|
|
27
34
|
private
|
28
|
-
def
|
29
|
-
|
35
|
+
def __wrap_method!(name, feature_name)
|
36
|
+
return unless methods_have_already_defined?(name, feature_name)
|
37
|
+
|
38
|
+
origin_name = origin_method_name(name)
|
30
39
|
|
31
|
-
|
32
|
-
origin_method = instance_method(name)
|
40
|
+
@disable_method_added_hook = true
|
33
41
|
|
34
|
-
alias_method
|
42
|
+
alias_method origin_name, name
|
43
|
+
alias_method name, feature_name
|
35
44
|
|
36
|
-
|
37
|
-
invoke_method("before_#{name}")
|
38
|
-
return_result = origin_method.bind(self).call(*args, &block)
|
39
|
-
invoke_method("after_#{name}")
|
45
|
+
@disable_method_added_hook = false
|
40
46
|
|
41
|
-
|
47
|
+
[:public, :protected, :private].each do |v|
|
48
|
+
send(v, name) if send("#{v}_method_defined?", origin_name)
|
42
49
|
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def feature_method_name(name, feature)
|
53
|
+
name = name.to_s
|
54
|
+
feature_name = name.end_with?("!", "?", "=") ?
|
55
|
+
"#{name[0..-2]}_with_#{feature}#{name[-1]}" :
|
56
|
+
"#{name}_with_#{feature}"
|
43
57
|
|
44
|
-
|
58
|
+
feature_name.to_sym
|
45
59
|
end
|
46
60
|
|
47
|
-
def
|
48
|
-
|
61
|
+
def origin_method_name(name)
|
62
|
+
"origin_#{name}"
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def methods_have_already_defined?(*args)
|
67
|
+
args.each {|name| return false unless all_instance_methods.include? name }
|
68
|
+
|
69
|
+
true
|
70
|
+
end
|
71
|
+
|
72
|
+
def all_instance_methods
|
73
|
+
public_instance_methods +
|
74
|
+
protected_instance_methods +
|
75
|
+
private_instance_methods
|
76
|
+
end
|
77
|
+
|
78
|
+
def new_added_method_has_in_wrpped_methods(name)
|
79
|
+
if @__wrapped_methods.has_key? name
|
80
|
+
feature_name = @__wrapped_methods[name]
|
81
|
+
__wrap_method!(name, feature_name)
|
82
|
+
elsif @__wrapped_methods.has_value? name
|
83
|
+
name, feature_name = @__wrapped_methods.select{|k, v| v == name }.first
|
84
|
+
__wrap_method!(name, feature_name)
|
85
|
+
end
|
49
86
|
end
|
50
87
|
end
|
51
88
|
end
|
data/method_wrapper.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.authors = ["Samnang Chhun"]
|
10
10
|
s.email = ["samnang.chhun@gmail.com"]
|
11
11
|
s.homepage = "http://github.com/samnang/method_wrapper"
|
12
|
-
s.summary = "How easy to wrap new features around
|
13
|
-
s.description = "
|
12
|
+
s.summary = "Alternative alias_method_chain. How easy to wrap new features around existing methods with method_wrapper."
|
13
|
+
s.description = "alias_method_chain alternative. How easy to wrap new features around existing methods with method_wrapper."
|
14
14
|
|
15
15
|
s.required_rubygems_version = ">= 1.3.6"
|
16
16
|
s.rubyforge_project = "[none]"
|
data/spec/class_builder.rb
CHANGED
@@ -1,81 +1,40 @@
|
|
1
1
|
class ClassBuilder
|
2
2
|
class << self
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
def method_name
|
8
|
-
end
|
9
|
-
|
10
|
-
def second_method_name
|
11
|
-
end
|
12
|
-
|
13
|
-
wrap_methods :method_name, :second_method_name
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def a_class_has_methods_and_calls_before_methods_defined
|
18
|
-
Class.new do
|
19
|
-
include MethodWrapper
|
20
|
-
wrap_methods :method_name, :second_method_name
|
3
|
+
module Methods
|
4
|
+
def name!; end
|
5
|
+
def name1; end
|
21
6
|
|
22
|
-
|
23
|
-
|
7
|
+
def name_with_feature!; end
|
8
|
+
def name1_with_feature; end
|
24
9
|
|
25
|
-
|
26
|
-
end
|
27
|
-
end
|
10
|
+
private :name1
|
28
11
|
end
|
29
12
|
|
30
|
-
def
|
13
|
+
def a_class_with_2_methods_add_feature
|
31
14
|
Class.new do
|
32
15
|
include MethodWrapper
|
33
|
-
|
34
|
-
|
35
|
-
def method_name
|
36
|
-
end
|
16
|
+
include Methods
|
37
17
|
|
38
|
-
|
39
|
-
|
40
|
-
@has_called_before_callback = true
|
41
|
-
end
|
42
|
-
|
43
|
-
def after_method_name
|
44
|
-
@has_called_after_callback = true
|
45
|
-
end
|
18
|
+
wrap_methods :name! => :feature
|
19
|
+
wrap_methods :name1 => :feature
|
46
20
|
end
|
47
21
|
end
|
48
22
|
|
49
|
-
def
|
23
|
+
def a_class_calls_wrap_methods_with_array_of_methods
|
50
24
|
Class.new do
|
51
25
|
include MethodWrapper
|
26
|
+
include Methods
|
52
27
|
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
private
|
57
|
-
def before_method_name
|
58
|
-
@has_called_before_callback = true
|
59
|
-
end
|
60
|
-
|
61
|
-
wrap_methods :method_name
|
28
|
+
wrap_methods [:name!, :name1] => :feature
|
62
29
|
end
|
63
30
|
end
|
64
31
|
|
65
|
-
def
|
32
|
+
def a_class_calls_wrap_methods_before_methods_defined
|
66
33
|
Class.new do
|
67
34
|
include MethodWrapper
|
68
|
-
wrap_methods :
|
69
|
-
|
70
|
-
def method_name(param)
|
71
|
-
@param = param
|
72
|
-
yield
|
73
|
-
end
|
35
|
+
wrap_methods [:name!, :name1] => :feature
|
74
36
|
|
75
|
-
|
76
|
-
def after_method_name
|
77
|
-
@has_called_after_callback = true
|
78
|
-
end
|
37
|
+
include Methods
|
79
38
|
end
|
80
39
|
end
|
81
40
|
end
|
data/spec/method_wrapper_spec.rb
CHANGED
@@ -1,57 +1,46 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe MethodWrapper do
|
4
|
-
describe ".wrap_methods
|
5
|
-
|
6
|
-
klass = ClassBuilder.a_class_has_methods_and_calls_after_methods_defined
|
4
|
+
describe ".wrap_methods" do
|
5
|
+
let(:klass) { klass = ClassBuilder.a_class_with_2_methods_add_feature }
|
7
6
|
|
7
|
+
it "should stores the wrapped methods with feature" do
|
8
8
|
verify_wrapped_methods(klass)
|
9
9
|
end
|
10
10
|
|
11
|
-
it "
|
12
|
-
klass = ClassBuilder.
|
11
|
+
it "should be able call wrap_methods with array of method" do
|
12
|
+
klass = ClassBuilder.a_class_calls_wrap_methods_with_array_of_methods
|
13
13
|
|
14
14
|
verify_wrapped_methods(klass)
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
klass
|
19
|
-
[:method_name, :second_method_name]
|
17
|
+
it "should wrap new feature to methods" do
|
18
|
+
verify_alias_methods(klass)
|
20
19
|
end
|
21
|
-
end
|
22
|
-
|
23
|
-
context "invoke the wrapped methods" do
|
24
|
-
it "should invoke _before_method_name and after_method_name" do
|
25
|
-
klass = ClassBuilder.a_class_has_before_and_after_wrap_methods
|
26
|
-
obj = klass.new
|
27
|
-
|
28
|
-
obj.method_name
|
29
20
|
|
30
|
-
|
31
|
-
|
21
|
+
it "should create new method for origin method" do
|
22
|
+
klass.new.should be_respond_to :origin_name!
|
23
|
+
klass.new.should be_respond_to :origin_name1, true #include private
|
32
24
|
end
|
33
25
|
|
34
|
-
it "should
|
35
|
-
klass
|
36
|
-
|
26
|
+
it "should restore visibility to origin method" do
|
27
|
+
klass.private_instance_methods.should include(:name1)
|
28
|
+
end
|
37
29
|
|
38
|
-
|
30
|
+
it "should be able to calls before methods defined" do
|
31
|
+
klass = ClassBuilder.a_class_calls_wrap_methods_before_methods_defined
|
39
32
|
|
40
|
-
|
33
|
+
verify_alias_methods(klass)
|
41
34
|
end
|
42
35
|
|
43
|
-
|
44
|
-
klass
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
obj.method_name("value") do
|
49
|
-
has_called = true
|
50
|
-
end
|
36
|
+
def verify_wrapped_methods(klass)
|
37
|
+
klass.instance_variable_get(:@__wrapped_methods).should ==
|
38
|
+
{:name! => :name_with_feature!, :name1 => :name1_with_feature}
|
39
|
+
end
|
51
40
|
|
52
|
-
|
53
|
-
|
54
|
-
|
41
|
+
def verify_alias_methods(klass)
|
42
|
+
klass.should has_alias_method(:name!, :name_with_feature!)
|
43
|
+
klass.should has_alias_method(:name1, :name1_with_feature)
|
55
44
|
end
|
56
45
|
end
|
57
46
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,3 +3,9 @@ require 'rspec'
|
|
3
3
|
require_relative 'class_builder'
|
4
4
|
require_relative '../lib/method_wrapper.rb'
|
5
5
|
|
6
|
+
RSpec::Matchers.define :has_alias_method do |first, second|
|
7
|
+
match do |klass|
|
8
|
+
klass.instance_method(first).should == klass.instance_method(second)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Samnang Chhun
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-11-01 00:00:00 +07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -49,7 +49,7 @@ dependencies:
|
|
49
49
|
version: 2.0.0
|
50
50
|
type: :development
|
51
51
|
version_requirements: *id002
|
52
|
-
description:
|
52
|
+
description: alias_method_chain alternative. How easy to wrap new features around existing methods with method_wrapper.
|
53
53
|
email:
|
54
54
|
- samnang.chhun@gmail.com
|
55
55
|
executables: []
|
@@ -103,6 +103,6 @@ rubyforge_project: "[none]"
|
|
103
103
|
rubygems_version: 1.3.7
|
104
104
|
signing_key:
|
105
105
|
specification_version: 3
|
106
|
-
summary: How easy to wrap new features around
|
106
|
+
summary: Alternative alias_method_chain. How easy to wrap new features around existing methods with method_wrapper.
|
107
107
|
test_files: []
|
108
108
|
|