method_wrapper 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|