meta_programming 0.0.8 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +36 -15
- data/lib/meta_programming/class.rb +2 -1
- data/lib/meta_programming/object.rb +35 -17
- data/spec/blank_slate_spec.rb +5 -3
- data/spec/ghost_methods_spec.rb +87 -36
- metadata +3 -3
data/README.rdoc
CHANGED
@@ -16,6 +16,11 @@ Concepts/Terminology
|
|
16
16
|
|
17
17
|
* Metaprogramming_Ruby[http://pragprog.com/titles/ppmetr/metaprogramming-ruby]
|
18
18
|
|
19
|
+
Example Code
|
20
|
+
|
21
|
+
* why_not[http://github.com/jeffp/why_not/blob/master/lib/why_not.rb]
|
22
|
+
* easy_nils[http://github.com/jeffp/easy_nils/blob/master/lib/easy_nils.rb]
|
23
|
+
|
19
24
|
== Beta Status
|
20
25
|
|
21
26
|
I consider this Gem in personal beta and suspect it will be in this state for
|
@@ -26,6 +31,21 @@ I welcome comments and collaborators who
|
|
26
31
|
would like to develop a library for simplifying common patterns and limit
|
27
32
|
the pitfalls of Ruby meta-programming.
|
28
33
|
|
34
|
+
== Changelog
|
35
|
+
|
36
|
+
* 0.2.0
|
37
|
+
|
38
|
+
Removes object parameter from method blocks and lambda matchers in define_ghost_method, and
|
39
|
+
adds more descriptive error handling. define_ghost_method block and matchers are now
|
40
|
+
evaluated in the context of the object instance.
|
41
|
+
|
42
|
+
I've bumped the version to 0.2.0 because this changes the interface.
|
43
|
+
|
44
|
+
* 0.0.8
|
45
|
+
|
46
|
+
initial implementation
|
47
|
+
|
48
|
+
|
29
49
|
== Issues
|
30
50
|
|
31
51
|
=== 1.9 vs 1.8
|
@@ -54,7 +74,6 @@ Current Methods
|
|
54
74
|
* blank_slate
|
55
75
|
|
56
76
|
|
57
|
-
|
58
77
|
== Usage
|
59
78
|
|
60
79
|
=== define_ghost_method
|
@@ -62,20 +81,21 @@ Current Methods
|
|
62
81
|
+define_ghost_method+ creates a 'ghost' method for an undefined method that corresponds
|
63
82
|
to the 'matcher' parameter.
|
64
83
|
|
65
|
-
define_ghost_method(matcher) do |
|
84
|
+
define_ghost_method(matcher) do |method_name_symbol, *args|
|
66
85
|
...method body...
|
67
86
|
end
|
68
87
|
|
69
88
|
A block must be present and it takes (optionally) the receiving object, the method name (as
|
70
|
-
a symbol with exception of a lambda matcher) and the method arguments.
|
89
|
+
a symbol with exception of a lambda matcher) and the method arguments. As of 0.2.0, the
|
90
|
+
block and lambda matcher is evaluated in the context of the object.
|
71
91
|
|
72
92
|
The matcher may be any of a symbol, string, regular expression or Proc/lambda.
|
73
93
|
|
74
94
|
==== String, symbols and regular expression matchers
|
75
95
|
|
76
|
-
define_ghost_method('my_method) {|
|
77
|
-
define_ghost_method(':my_method) {|
|
78
|
-
define_ghost_method(/^my_method$/) {|
|
96
|
+
define_ghost_method('my_method) {|sym, *args| ... }
|
97
|
+
define_ghost_method(':my_method) {|sym, *args| ... }
|
98
|
+
define_ghost_method(/^my_method$/) {|sym, *args| ... }
|
79
99
|
|
80
100
|
String and symbol matchers will only process the method if its name matches the string
|
81
101
|
or symbol exactly. Regular expressions provide greater flexibility and care must be
|
@@ -87,27 +107,28 @@ method block. This is not the case with lambda matchers.
|
|
87
107
|
|
88
108
|
==== Proc/lambda matchers
|
89
109
|
|
90
|
-
Lambda matchers provide an opportunity to greatly scrutinize the method call
|
91
|
-
parameters passed to the method block (object, method_name, *args). The method is
|
110
|
+
Lambda matchers provide an opportunity to greatly scrutinize the method call. The method is
|
92
111
|
invoked for any lambda not evaluating to nil or false.
|
93
112
|
|
94
|
-
proc = lambda{|
|
95
|
-
define_ghost_method(proc) {|
|
113
|
+
proc = lambda{|method_name, *args| ...matching code... }
|
114
|
+
define_ghost_method(proc) {|proc_result, *args| ... }
|
96
115
|
|
97
116
|
Proc and lambda matchers differ from the other matcher in that the second parameter passes
|
98
117
|
the result of the Proc/lambda matcher to the method block. This feature lets the matcher
|
99
118
|
pre-process the name of the method passed to the body.
|
100
119
|
|
101
|
-
proc = lambda{|
|
120
|
+
proc = lambda{|sym, *args| sym =~ /^not_(.+\?)$/ && self.class.method_defined?($1.to_sym) && $1.to_sym }
|
121
|
+
|
122
|
+
The lambda matcher is evaluated in the context of the object and can
|
123
|
+
call methods of the object as in the above example. The lambda matcher is also called
|
124
|
+
in the respond_to? method, so it is a good idea to avoid usind respond_to? in the lambda
|
125
|
+
matcher to avoid a stack overflow error. Instead call method_defined? on the class object.
|
102
126
|
|
103
127
|
The extra flexibility comes at greater responsibility. If you only want to pass the
|
104
128
|
method name symbol to the method block, don't forget to return it from the lambda.
|
105
129
|
|
106
|
-
proc = lambda{|
|
130
|
+
proc = lambda{|sym, *args| sym =~ /^not_.+\?$/ && sym }
|
107
131
|
|
108
|
-
Additionally, the 'return' keyword has different effects between Procs and lambdas.
|
109
|
-
I suggest not explicitly using the 'return' keyword in your method blocks. It's a Ruby thing.
|
110
|
-
define_ghost_method will remind you if a LocalJumpError is raised.
|
111
132
|
|
112
133
|
==== Critique
|
113
134
|
|
@@ -7,9 +7,10 @@ module MetaProgramming
|
|
7
7
|
def blank_slate(opts={})
|
8
8
|
opts[:except] = opts[:except] ? (opts[:except].is_a?(Array) ? opts[:except] : [opts[:except]]) : []
|
9
9
|
exceptions = opts[:except].map(&:to_s)
|
10
|
-
exceptions += ['method_missing', 'respond_to?'] unless opts[:all]
|
11
10
|
matchers = exceptions.map{|ex| "^#{ex.gsub(/\?/, '\?')}$" }
|
11
|
+
matchers += ['^method_missing', '^respond_to'] unless opts[:all]
|
12
12
|
matchers << '^__'
|
13
|
+
matchers << '^object_id$'
|
13
14
|
regexp = Regexp.new(matchers.join('|'))
|
14
15
|
instance_methods.each do |m|
|
15
16
|
undef_method m unless regexp.match(m.to_s)
|
@@ -74,32 +74,50 @@ module MetaProgramming
|
|
74
74
|
def define_ghost_method(matcher, &block)
|
75
75
|
raise "Must have a block" unless block_given?
|
76
76
|
raise ArgumentError, "Matcher argument must be either a 'string', :symbol, /regexp/ or proc" unless (matcher.nil? || [String, Symbol, Regexp, Proc].any?{|c| matcher.is_a?(c)})
|
77
|
-
ext = matcher.hash.abs.to_s
|
77
|
+
ext = "#{self.name.gsub(/^.+>::/,'')}_#{matcher.class.name.gsub(/^.+>::/,'')}#{matcher.hash.abs.to_s}"
|
78
|
+
_ghost_method_handler = "_ghost_method_handler_#{ext}".to_sym
|
79
|
+
_ghost_method_matcher = "_ghost_method_matcher_#{ext}".to_sym
|
80
|
+
define_method(_ghost_method_handler, block)
|
81
|
+
private _ghost_method_handler
|
82
|
+
if matcher.is_a?(Proc)
|
83
|
+
define_method(_ghost_method_matcher, matcher)
|
84
|
+
private _ghost_method_matcher
|
85
|
+
end
|
78
86
|
define_chained_method(:method_missing, ext.to_sym) do |symbol, *args|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
87
|
+
handled = case matcher
|
88
|
+
when Regexp then !(symbol.to_s =~ matcher).nil?
|
89
|
+
when String, Symbol then (symbol == matcher.to_sym)
|
90
|
+
when Proc
|
91
|
+
begin
|
92
|
+
__send__(_ghost_method_matcher, symbol)
|
93
|
+
rescue Exception => matcher_error
|
94
|
+
raise matcher_error, "#{matcher_error.message} in a ghost method matcher called for symbol :#{symbol}. Be sure to use self.class.method_defined? instead of respond_to? in a lambda matcher."
|
95
|
+
end
|
96
|
+
else nil
|
97
|
+
end
|
98
|
+
if handled
|
99
|
+
begin
|
100
|
+
__send__(_ghost_method_handler, (handled == true ? symbol : handled), *args)
|
101
|
+
rescue Exception => handler_error
|
102
|
+
raise handler_error, "#{handler_error.message} in a ghost method block called with symbol :#{symbol}."
|
89
103
|
end
|
90
|
-
|
91
|
-
|
92
|
-
raise LocalJumpError, "Remove the 'return' keyword in your method block."
|
104
|
+
else
|
105
|
+
__send__("method_missing_without_#{ext}".to_sym, symbol, *args)
|
93
106
|
end
|
94
107
|
end
|
95
108
|
#cripple respond_to? in deference of 1.8 -- the include_private no longer works
|
96
109
|
define_chained_method(:respond_to?, ext.to_sym) do |method_name| #1.9 only, include_private=nil|
|
97
110
|
responds = case matcher
|
98
|
-
when Regexp then method_name.to_s =~ matcher
|
111
|
+
when Regexp then !(method_name.to_s =~ matcher).nil?
|
99
112
|
when String, Symbol then method_name == matcher.to_sym
|
100
|
-
when Proc
|
113
|
+
when Proc
|
114
|
+
begin
|
115
|
+
__send__(_ghost_method_matcher, method_name)
|
116
|
+
rescue Exception => matcher_error
|
117
|
+
raise matcher_error, "#{matcher_error.message} in a ghost method matcher called in respond_to? for symbol :#{method_name}. Be sure to use self.class.method_defined? instead of respond_to? in a lambda matcher."
|
118
|
+
end
|
101
119
|
end
|
102
|
-
responds || __send__("respond_to_without_#{ext}?", method_name) #1.9 only, include_private)
|
120
|
+
responds || __send__("respond_to_without_#{ext}?".to_sym, method_name) #1.9 only, include_private)
|
103
121
|
end
|
104
122
|
end
|
105
123
|
end
|
data/spec/blank_slate_spec.rb
CHANGED
@@ -6,7 +6,8 @@ describe "blank_slate" do
|
|
6
6
|
all_methods = [:public_methods, :protected_methods, :private_methods].map do |method|
|
7
7
|
instance.send(method)
|
8
8
|
end.flatten.map(&:to_sym).uniq
|
9
|
-
|
9
|
+
matchers = (['^__', '^object_id$'] + (exceptions.is_a?(Array) ? exceptions : [exceptions])).join('|')
|
10
|
+
allowed_methods = all_methods.select{|method| method.to_s =~ Regexp.new(matchers)}.map(&:to_sym)
|
10
11
|
all_methods - allowed_methods
|
11
12
|
end
|
12
13
|
|
@@ -14,7 +15,7 @@ describe "blank_slate" do
|
|
14
15
|
class BlankSlate1
|
15
16
|
blank_slate
|
16
17
|
end
|
17
|
-
test_methods = collect_test_methods(Object.new, [
|
18
|
+
test_methods = collect_test_methods(Object.new, ['^method_missing', '^respond_to'])
|
18
19
|
|
19
20
|
bs = BlankSlate1.new
|
20
21
|
test_methods.each do |method|
|
@@ -39,7 +40,7 @@ describe "blank_slate" do
|
|
39
40
|
class BlankSlate3
|
40
41
|
blank_slate :except=>[:methods]
|
41
42
|
end
|
42
|
-
test_methods = collect_test_methods(Object.new, [
|
43
|
+
test_methods = collect_test_methods(Object.new, ['^methods$', '^method_missing', '^respond_to'])
|
43
44
|
|
44
45
|
bs=BlankSlate3.new
|
45
46
|
test_methods.each do |method|
|
@@ -51,3 +52,4 @@ describe "blank_slate" do
|
|
51
52
|
end
|
52
53
|
|
53
54
|
|
55
|
+
|
data/spec/ghost_methods_spec.rb
CHANGED
@@ -37,7 +37,7 @@ describe "MetaProgramming" do
|
|
37
37
|
it "should scream if matcher is not string, symbol or regular expression" do
|
38
38
|
lambda {
|
39
39
|
class GHA2
|
40
|
-
define_ghost_method(1) { puts 1}
|
40
|
+
define_ghost_method(1) {|sym| puts 1}
|
41
41
|
end
|
42
42
|
}.should raise_exception(ArgumentError)
|
43
43
|
end
|
@@ -50,28 +50,22 @@ describe "MetaProgramming" do
|
|
50
50
|
end
|
51
51
|
it "should define a ghost method using a symbol" do
|
52
52
|
class GHA1
|
53
|
-
define_ghost_method(:catch_this_one) { 'catch_this_one' }
|
53
|
+
define_ghost_method(:catch_this_one) {|sym| 'catch_this_one' }
|
54
54
|
end
|
55
55
|
lambda { GHA1.new.not_this_one }.should raise_exception(NoMethodError)
|
56
56
|
lambda { GHA1.new.catch_this_one.should == 'catch_this_one' }.should_not raise_exception
|
57
57
|
lambda { GHA1.new.catch_this_one_too }.should raise_exception(NoMethodError)
|
58
58
|
end
|
59
|
-
it "should warn about using 'return' keyword in method block" do
|
60
|
-
class GHA4
|
61
|
-
define_ghost_method(:catch_this_one) { return 'catch_this_one'}
|
62
|
-
end
|
63
|
-
lambda { GHA4.new.catch_this_one }.should raise_exception(LocalJumpError, /'return' keyword/)
|
64
|
-
end
|
65
59
|
it "should define a ghost method using a string" do
|
66
60
|
class GHA5
|
67
|
-
define_ghost_method('catch_another') { 'catch_another_one'}
|
61
|
+
define_ghost_method('catch_another') {|sym| 'catch_another_one'}
|
68
62
|
end
|
69
63
|
lambda { GHA5.new.catch_another.should == 'catch_another_one'}.should_not raise_exception
|
70
64
|
lambda { GHA5.new.catch_another_one }.should raise_exception(NoMethodError)
|
71
65
|
end
|
72
66
|
it "should define a ghost method using a regular expression" do
|
73
67
|
class GHA6
|
74
|
-
define_ghost_method(/catch/) do |
|
68
|
+
define_ghost_method(/catch/) do |symbol|
|
75
69
|
symbol
|
76
70
|
end
|
77
71
|
end
|
@@ -81,7 +75,7 @@ describe "MetaProgramming" do
|
|
81
75
|
end
|
82
76
|
it "should pass arguments to the block" do
|
83
77
|
class GHA7
|
84
|
-
define_ghost_method(/ghost/) do |
|
78
|
+
define_ghost_method(/ghost/) do |symbol, *args|
|
85
79
|
"#{symbol.to_s.gsub(/_/, ' ')} #{args.join(' ')}"
|
86
80
|
end
|
87
81
|
end
|
@@ -89,39 +83,39 @@ describe "MetaProgramming" do
|
|
89
83
|
end
|
90
84
|
it "should pass parameters" do
|
91
85
|
class GHA9
|
92
|
-
define_ghost_method('test_args') do |
|
86
|
+
define_ghost_method('test_args') do |sym, *args|
|
93
87
|
args.join(' ')
|
94
88
|
end
|
95
89
|
end
|
96
90
|
GHA9.new.test_args('hi', 'you').should == 'hi you'
|
97
91
|
end
|
98
92
|
#ghost methods that can call blocks are not supported
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
93
|
+
#it "should work for methods called with blocks in 1.9" do
|
94
|
+
# class GHA8
|
95
|
+
# define_ghost_method(:call_block) do |obj, sym, *args|
|
96
|
+
# yield(*args)
|
97
|
+
# end
|
98
|
+
# end
|
99
|
+
# GHA8.new.call_block(%w(hi you)) do |*args|
|
100
|
+
# args.join(' ')
|
101
|
+
# end.should == 'hi you'
|
102
|
+
#end
|
109
103
|
it "should define ghost methods for class Object" do
|
110
104
|
class Object
|
111
|
-
define_ghost_method(:alive!) do
|
105
|
+
define_ghost_method(:alive!) do |sym|
|
112
106
|
'ALIVE'
|
113
107
|
end
|
114
108
|
end
|
115
109
|
lambda { Object.new.alive!.should == 'ALIVE'}.should_not raise_exception
|
116
110
|
end
|
117
|
-
it "should accept lambda as an advanced matcher and lambda parameters should be
|
111
|
+
it "should accept lambda as an advanced matcher and lambda parameters should be matcher_result, *args" do
|
118
112
|
class TestObject1
|
119
113
|
def yes?; true; end
|
120
114
|
def no?; false; end
|
121
115
|
|
122
|
-
matcher = lambda {|
|
123
|
-
define_ghost_method(matcher) do |
|
124
|
-
|
116
|
+
matcher = lambda {|sym| sym.to_s =~ /^yn_(.*\?)$/ && self.class.method_defined?($1.to_sym) && $1.to_sym }
|
117
|
+
define_ghost_method(matcher) do |res, *args|
|
118
|
+
self.__send__(res, *args) ? 'yes' : 'no'
|
125
119
|
end
|
126
120
|
end
|
127
121
|
lambda { TestObject1.new.yes?.should == true}.should_not raise_exception
|
@@ -131,14 +125,23 @@ describe "MetaProgramming" do
|
|
131
125
|
lambda { TestObject1.new.yessir? }.should raise_exception(NoMethodError)
|
132
126
|
lambda { TestObject1.new.yn_yessir? }.should raise_exception(NoMethodError)
|
133
127
|
end
|
128
|
+
it "should create a private ghost_method_handler and ghost_method_matcher and not a public ones" do
|
129
|
+
class TestObject3
|
130
|
+
matcher = lambda {|sym| sym.to_s =~ /asdfjf/ && sym}
|
131
|
+
define_ghost_method(matcher) {|sym| 'hello' }
|
132
|
+
end
|
133
|
+
obj = TestObject3.new
|
134
|
+
obj.private_methods.map(&:to_s).detect{|method| method =~ /ghost_method_handler/}.should_not be_nil
|
135
|
+
obj.private_methods.map(&:to_s).detect{|method| method =~ /ghost_method_matcher/}.should_not be_nil
|
136
|
+
end
|
134
137
|
it "should accept Procs as an advanced matcher and the parameters should be obj, matcher_result, *args" do
|
135
138
|
class TestObject2
|
136
139
|
def yes?; true; end
|
137
140
|
def no?; false; end
|
138
141
|
|
139
|
-
matcher = Proc.new{|
|
140
|
-
define_ghost_method(matcher) do |
|
141
|
-
|
142
|
+
matcher = Proc.new{|sym| sym.to_s =~ /^yn_(.*\?)$/ && methods.map(&:to_sym).include?($1.to_sym) && $1.to_sym }
|
143
|
+
define_ghost_method(matcher) do |res, *args|
|
144
|
+
__send__(res, *args) ? 'yes' : 'no'
|
142
145
|
end
|
143
146
|
end
|
144
147
|
lambda { TestObject2.new.yes?.should == true}.should_not raise_exception
|
@@ -151,9 +154,9 @@ describe "MetaProgramming" do
|
|
151
154
|
it "should create an appropriate respond_to? for the string matchers" do
|
152
155
|
class StringMatcher
|
153
156
|
def hello; end
|
154
|
-
define_ghost_method('my_method') { 'yes_my_method'}
|
157
|
+
define_ghost_method('my_method') {|sym| 'yes_my_method'}
|
155
158
|
end
|
156
|
-
lambda { StringMatcher.new.my_method.should == 'yes_my_method'}.should_not raise_exception
|
159
|
+
lambda { StringMatcher.new.my_method.should == 'yes_my_method'}.should_not raise_exception
|
157
160
|
lambda { StringMatcher.new.respond_to?(:my_method2).should be_false}.should_not raise_exception
|
158
161
|
lambda { StringMatcher.new.respond_to?(:my_method).should be_true }.should_not raise_exception
|
159
162
|
StringMatcher.new.respond_to?(:hello).should be_true
|
@@ -161,7 +164,7 @@ describe "MetaProgramming" do
|
|
161
164
|
it "should create an appropriate respond_to? for the symbol matchers" do
|
162
165
|
class SymbolMatcher
|
163
166
|
def hello; end
|
164
|
-
define_ghost_method(:my_method2) { 'yep_my_method'}
|
167
|
+
define_ghost_method(:my_method2) {|sym| 'yep_my_method'}
|
165
168
|
end
|
166
169
|
lambda { SymbolMatcher.new.my_method2.should == 'yep_my_method'}.should_not raise_exception
|
167
170
|
lambda { SymbolMatcher.new.respond_to?(:my_method2).should be_true}.should_not raise_exception
|
@@ -171,14 +174,14 @@ describe "MetaProgramming" do
|
|
171
174
|
it "should create an appropriate respond_to? for the regexp matchers" do
|
172
175
|
class RegexpMatcher
|
173
176
|
def hello; end
|
174
|
-
define_ghost_method(/^my_method$/) { 'yo_my_method'}
|
177
|
+
define_ghost_method(/^my_method$/) {|sym| 'yo_my_method'}
|
175
178
|
end
|
176
179
|
lambda { RegexpMatcher.new.my_method.should == 'yo_my_method'}.should_not raise_exception
|
177
180
|
lambda { RegexpMatcher.new.respond_to?(:my_method).should be_true}.should_not raise_exception
|
178
181
|
RegexpMatcher.new.respond_to?(:hello).should be_true
|
179
182
|
class RegexpMatcher2
|
180
183
|
def hello; end
|
181
|
-
define_ghost_method(/^my_method\d$/) { 'yoo_my_method'}
|
184
|
+
define_ghost_method(/^my_method\d$/) {|sym| 'yoo_my_method'}
|
182
185
|
end
|
183
186
|
lambda { RegexpMatcher2.new.my_method1.should == 'yoo_my_method'}.should_not raise_exception
|
184
187
|
lambda { RegexpMatcher2.new.my_method }.should raise_exception(NoMethodError)
|
@@ -189,7 +192,7 @@ describe "MetaProgramming" do
|
|
189
192
|
it "should create an appropriate respond_to? for the lambda matchers" do
|
190
193
|
class LambdaMatcher
|
191
194
|
def hello; end
|
192
|
-
define_ghost_method(lambda{|
|
195
|
+
define_ghost_method(lambda{|sym| sym.to_s =~ /^my_method\d$/ }) {|sym| 'uhhuh_my_method'}
|
193
196
|
end
|
194
197
|
lambda { LambdaMatcher.new.my_method2.should == 'uhhuh_my_method'}.should_not raise_exception
|
195
198
|
lambda { LambdaMatcher.new.my_method}.should raise_exception(NoMethodError)
|
@@ -198,6 +201,54 @@ describe "MetaProgramming" do
|
|
198
201
|
lambda { LambdaMatcher.new.respond_to?(:my_methods).should be_false}.should_not raise_exception
|
199
202
|
LambdaMatcher.new.respond_to?(:hello).should be_true
|
200
203
|
end
|
204
|
+
|
205
|
+
if RUBY_VERSION >= '1.9'
|
206
|
+
it "should not raise a LocalJump error when 'return' keyword used in method block" do
|
207
|
+
class GHB1
|
208
|
+
define_ghost_method(:my_method) {|sym| return 'hello'}
|
209
|
+
end
|
210
|
+
lambda { GHB1.new.my_method.should == 'hello'}.should_not raise_exception
|
211
|
+
lambda { GHB1.new.my_method2}.should raise_exception(NoMethodError)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
it "should not raise a LocalJumpError when 'return' keyword used in lambda matcher" do
|
215
|
+
class GHB2
|
216
|
+
matcher = lambda{|sym| return true if sym == :my_method; return false }
|
217
|
+
define_ghost_method(matcher){|sym| 'hello'}
|
218
|
+
end
|
219
|
+
lambda { GHB2.new.my_method.should == 'hello'}.should_not raise_exception
|
220
|
+
lambda { GHB2.new.my_method2 }.should raise_exception(NoMethodError)
|
221
|
+
end
|
222
|
+
it "should indicate exceptions come from method block when originating in method block" do
|
223
|
+
class GHB3
|
224
|
+
define_ghost_method(:my_method){|sym| raise "my cool exception"}
|
225
|
+
end
|
226
|
+
lambda { GHB3.new.my_method}.should raise_exception(/ghost method block/)
|
227
|
+
lambda { GHB3.new.my_method}.should raise_exception(/my cool exception/)
|
228
|
+
end
|
229
|
+
it "should indicate exceptions come from lambda matcher when originating in lambda matcher" do
|
230
|
+
class GHB4
|
231
|
+
matcher = lambda{|sym| raise 'my cooler exception'}
|
232
|
+
define_ghost_method(matcher){|sym| 'hello'}
|
233
|
+
end
|
234
|
+
lambda { GHB4.new.my_method}.should raise_exception(/ghost method matcher/)
|
235
|
+
lambda { GHB4.new.my_method}.should raise_exception(/my cooler exception/)
|
236
|
+
end
|
237
|
+
it "should indicate exceptions come from respond_to? matcher when originating from there" do
|
238
|
+
class GHB6
|
239
|
+
matcher = lambda{|sym| raise 'my respond_to exception'}
|
240
|
+
define_ghost_method(matcher){|sym| 'hello'}
|
241
|
+
end
|
242
|
+
lambda { GHB6.new.respond_to?(:my_method)}.should raise_exception(/ghost method matcher/)
|
243
|
+
lambda { GHB6.new.respond_to?(:my_method)}.should raise_exception(/my respond_to exception/)
|
244
|
+
end
|
245
|
+
it "should inform about using method_defined? instead of respond_to? in matcher" do
|
246
|
+
class GHB5
|
247
|
+
matcher = lambda{|sym| sym.to_s =~ /^x_(.+)$/ && self.respond_to?($1.to_sym) && $1.to_sym }
|
248
|
+
define_ghost_method(matcher){|sym, *args| __send__(sym, *args) }
|
249
|
+
end
|
250
|
+
lambda { GHB5.new.x_methods }.should raise_exception(/method_defined\?/)
|
251
|
+
end
|
201
252
|
end
|
202
253
|
|
203
254
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
+
- 2
|
7
8
|
- 0
|
8
|
-
|
9
|
-
version: 0.0.8
|
9
|
+
version: 0.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Jeff Patmon
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-05-
|
17
|
+
date: 2010-05-02 00:00:00 -07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|