rconditions 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +7 -0
- data/README +5 -0
- data/lib/rconditions.rb +234 -0
- data/test/rconditions_test.rb +261 -0
- metadata +50 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2007 Norman Timmler, Tammo Freese
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
= RConditions
|
2
|
+
|
3
|
+
RConditions generates a bang method (for example, <tt>Array#empty!</tt>) for each predicate method (for example, <tt>Array#empty?</tt>). The bang method will return true if the predicate method returns true, otherwise it will throw an exception. The exception will include auto-generated modules that give information which predicate methods passed or failed in the bang method's execution.
|
4
|
+
|
5
|
+
For more information, see the roc or ri documentation of the module RConditions.
|
data/lib/rconditions.rb
ADDED
@@ -0,0 +1,234 @@
|
|
1
|
+
# = RConditions
|
2
|
+
#
|
3
|
+
# RConditions generates a bang method (for example, <tt>Array#empty!</tt>)
|
4
|
+
# for each predicate method (for example, <tt>Array#empty?</tt>). The bang
|
5
|
+
# method will return true if the predicate method returns true, otherwise it
|
6
|
+
# will throw an exception. The exception will include auto-generated modules
|
7
|
+
# that give information which predicate methods passed or failed in the bang
|
8
|
+
# method's execution.
|
9
|
+
#
|
10
|
+
# == Example
|
11
|
+
#
|
12
|
+
# Here is a simple example. The raised exception includes a module defined
|
13
|
+
# on the class where the method is defined:
|
14
|
+
#
|
15
|
+
# require "rconditions"
|
16
|
+
#
|
17
|
+
# begin
|
18
|
+
# [1,2].empty!
|
19
|
+
# rescue Array::NotEmptyError => e
|
20
|
+
# p e
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # => #<Exception: Array::NotEmptyError>
|
24
|
+
#
|
25
|
+
# Here is a more complicated example:
|
26
|
+
#
|
27
|
+
# require "rconditions"
|
28
|
+
#
|
29
|
+
# class Posting
|
30
|
+
# attr_writer :spam, :active
|
31
|
+
#
|
32
|
+
# def spam?
|
33
|
+
# @spam
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# def active?
|
37
|
+
# @active
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# def visible?
|
41
|
+
# !spam? && active?
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# class User
|
46
|
+
# attr_writer :admin
|
47
|
+
#
|
48
|
+
# def admin?
|
49
|
+
# @admin
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# def can_view_posting?(posting)
|
53
|
+
# admin? || posting.visible?
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# user = User.new
|
58
|
+
# user.admin = false
|
59
|
+
#
|
60
|
+
# posting = Posting.new
|
61
|
+
# posting.active = false
|
62
|
+
# posting.spam = true
|
63
|
+
#
|
64
|
+
# begin
|
65
|
+
# user.can_view_posting!(posting)
|
66
|
+
# rescue Posting::SpamError => e
|
67
|
+
# p e
|
68
|
+
# rescue Posting::NotActiveError
|
69
|
+
# puts "should not get here"
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# # => #<Exception: User::NotAdminError, Posting::SpamError,
|
73
|
+
# # Posting::NotVisibleError, User::NotCanViewPostingError>
|
74
|
+
#
|
75
|
+
# As you can see, the exception includes modules for each of the evaluated
|
76
|
+
# predicate methods: <tt>User#can_view_posting!(posting)</tt> in the context
|
77
|
+
# above called <tt>User#can_view_posting?(posting)</tt>, which called
|
78
|
+
# <tt>User#admin?</tt> and <tt>Posting#can_view_posting?</tt>, which called
|
79
|
+
# <tt>Posting#spam?</tt>.
|
80
|
+
#
|
81
|
+
# The results were
|
82
|
+
#
|
83
|
+
# * <tt>User#admin? # => false</tt>
|
84
|
+
# * <tt>Posting#spam? # => true</tt>
|
85
|
+
# * <tt>Posting#can_view_posting? # => false</tt>
|
86
|
+
# * <tt>User#can_view_posting? # => false</tt>
|
87
|
+
#
|
88
|
+
# so the included exception modules are
|
89
|
+
#
|
90
|
+
# * <tt>User::NotAdminError</tt>
|
91
|
+
# * <tt>Posting::SpamError</tt>
|
92
|
+
# * <tt>Posting::NotCanViewPostingError</tt>
|
93
|
+
# * <tt>User::NotCanViewPostingError</tt>
|
94
|
+
#
|
95
|
+
# == Performance
|
96
|
+
#
|
97
|
+
# As almost all predicate methods are extended by default, RConditions carries
|
98
|
+
# a performance penalty which varies with the number of calls to predicate
|
99
|
+
# methods. A simple test setup using mongrel/rails was slowed down by 10-20%
|
100
|
+
# by adding <tt>require "rconditions"</tt> to the bottom of its
|
101
|
+
# <tt>enviroment.rb</tt>.
|
102
|
+
#
|
103
|
+
# The performance penalty can be avoided by applying RConditions only to new
|
104
|
+
# methods, that is, methods defined after <tt>require "rconditions"</tt>. To
|
105
|
+
# achieve this, set <tt>RCONDITIONS_ONLY_FOR_NEW_METHODS = true</tt> before
|
106
|
+
# the require call. Our test setup had no measurable slowdown afterwards.
|
107
|
+
#
|
108
|
+
# == Known Limitations
|
109
|
+
#
|
110
|
+
# * RConditions does only support predicate methods starting with a letter and
|
111
|
+
# containing only word characters except the question mark at the end.
|
112
|
+
# * RConditions does not support singleton methods. These includes all class
|
113
|
+
# methods.
|
114
|
+
module RConditions
|
115
|
+
class << self
|
116
|
+
|
117
|
+
# Extends the given predicate method and defines a bang method for it. You
|
118
|
+
# should never call this method directly, it is called from
|
119
|
+
# Module#method_added.
|
120
|
+
# * <tt>mod</tt> -- the module on which the method is defined.
|
121
|
+
# * <tt>id</tt> -- the name of the method.
|
122
|
+
def extend_predicate_method_and_define_bang_method(mod, id)
|
123
|
+
return if Thread.current[:rconditions_processing_predicate_method]
|
124
|
+
return if (predicate_method = id.to_s) !~ PREDICATE_METHOD
|
125
|
+
|
126
|
+
begin
|
127
|
+
Thread.current[:rconditions_processing_predicate_method] = true
|
128
|
+
extend_predicate_method(mod, predicate_method)
|
129
|
+
define_bang_method(mod, predicate_method)
|
130
|
+
ensure
|
131
|
+
Thread.current[:rconditions_processing_predicate_method] = false
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def exception_modules #:nodoc:
|
136
|
+
Thread.current[:rconditions_exception_modules]
|
137
|
+
end
|
138
|
+
|
139
|
+
def exception_modules=(value) #:nodoc:
|
140
|
+
Thread.current[:rconditions_exception_modules] = value
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
PREDICATE_METHOD = /\A[a-zA-Z]\w*\?\z/ #:nodoc:
|
146
|
+
|
147
|
+
def extend_predicate_method(mod, predicate_method)
|
148
|
+
predicate_method_without_questionmark = predicate_method[0...-1]
|
149
|
+
|
150
|
+
positive_module = camelize("#{predicate_method_without_questionmark}_error")
|
151
|
+
mod.const_set(positive_module, Module.new) unless mod.const_defined?(positive_module)
|
152
|
+
negative_module = camelize("not_#{predicate_method_without_questionmark}_error")
|
153
|
+
mod.const_set(negative_module, Module.new) unless mod.const_defined?(negative_module)
|
154
|
+
|
155
|
+
time = Time.now
|
156
|
+
predicate_method_without_rconditions = "#{predicate_method_without_questionmark}_rconditions_#{mod.object_id}_#{time.to_i}_#{time.usec}"
|
157
|
+
original_visibility = visibility(mod, predicate_method)
|
158
|
+
|
159
|
+
mod.class_eval <<-EOS, __FILE__, __LINE__ + 1
|
160
|
+
alias_method :#{predicate_method_without_rconditions}, :#{predicate_method}
|
161
|
+
private :#{predicate_method_without_rconditions}
|
162
|
+
|
163
|
+
def #{predicate_method}(*args, &block)
|
164
|
+
result = #{predicate_method_without_rconditions}(*args, &block)
|
165
|
+
RConditions.exception_modules << (result ? #{positive_module} : #{negative_module}) if RConditions.exception_modules
|
166
|
+
result
|
167
|
+
end
|
168
|
+
#{original_visibility} :#{predicate_method}
|
169
|
+
EOS
|
170
|
+
end
|
171
|
+
|
172
|
+
def define_bang_method(mod, predicate_method)
|
173
|
+
bang_method = predicate_method[0...-1] + '!'
|
174
|
+
return if mod.method_defined?(bang_method) || mod.private_method_defined?(bang_method)
|
175
|
+
|
176
|
+
visibility = visibility(mod, predicate_method)
|
177
|
+
|
178
|
+
mod.class_eval <<-EOS, __FILE__, __LINE__ + 1
|
179
|
+
def #{bang_method}(*args, &block)
|
180
|
+
RConditions.exception_modules = []
|
181
|
+
result = #{predicate_method}(*args, &block)
|
182
|
+
return result if result
|
183
|
+
|
184
|
+
e = Exception.new(RConditions.exception_modules.map { |m| m.name }.join(', '))
|
185
|
+
RConditions.exception_modules.each { |m| e.extend(m) }
|
186
|
+
raise e
|
187
|
+
ensure
|
188
|
+
RConditions.exception_modules = nil
|
189
|
+
end
|
190
|
+
#{visibility} :#{bang_method}
|
191
|
+
EOS
|
192
|
+
end
|
193
|
+
|
194
|
+
def camelize(lower_case_and_underscored_word)
|
195
|
+
lower_case_and_underscored_word.gsub(/(^|_)(.)/) { $2.upcase }
|
196
|
+
end
|
197
|
+
|
198
|
+
def visibility(mod, id)
|
199
|
+
case id
|
200
|
+
when *mod.public_instance_methods(false): 'public'
|
201
|
+
when *mod.protected_instance_methods(false): 'protected'
|
202
|
+
when *mod.private_instance_methods(false): 'private'
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
unless defined? RCONDITIONS_ONLY_FOR_NEW_METHODS
|
209
|
+
# To apply RConditions to new methods only, set this constant to <tt>true</tt>
|
210
|
+
# before <tt>require "rconditions"</tt>.
|
211
|
+
RCONDITIONS_ONLY_FOR_NEW_METHODS = false
|
212
|
+
end
|
213
|
+
|
214
|
+
unless RCONDITIONS_ONLY_FOR_NEW_METHODS
|
215
|
+
ObjectSpace.each_object(Module) do |mod|
|
216
|
+
mod.instance_methods(false).each do |id|
|
217
|
+
RConditions.extend_predicate_method_and_define_bang_method(mod, id)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
class Module
|
223
|
+
alias_method :method_added_without_rconditions, :method_added
|
224
|
+
private :method_added_without_rconditions
|
225
|
+
|
226
|
+
# To provide a bang method and exception modules for each predicate method,
|
227
|
+
# RConditions hooks into <tt>method_added</tt>. An existing
|
228
|
+
# <tt>method_added</tt> implementation will not be replaced, but executed
|
229
|
+
# afterwards.
|
230
|
+
def method_added(id)
|
231
|
+
RConditions.extend_predicate_method_and_define_bang_method(self, id)
|
232
|
+
method_added_without_rconditions(id)
|
233
|
+
end
|
234
|
+
end
|
@@ -0,0 +1,261 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rconditions'
|
3
|
+
|
4
|
+
class RConditionsTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
class Foo
|
7
|
+
def a?; false; end
|
8
|
+
def b?; false; end
|
9
|
+
def c?; a? || b?; end
|
10
|
+
def d?; true; end
|
11
|
+
def e?; !d?; end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Bar < Foo
|
15
|
+
def a?; super; end
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_defines_bang_method_on_predicate_methods_defined_before_r_conditions_was_required
|
19
|
+
assert [].class.method_defined?(:empty!)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_defines_bang_method_on_predicate_methods_defined_after_r_conditions_was_required
|
23
|
+
assert Foo.method_defined?(:a!)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_does_not_define_methods_for_non_predicate_methods
|
27
|
+
foo_methods_with_new_method = Foo.new.methods + ['new_method']
|
28
|
+
eval "class Foo;def new_method; end; end"
|
29
|
+
assert_equal foo_methods_with_new_method.sort, Foo.new.methods.sort
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_bang_method_returns_true_if_predicate_method_returns_true
|
33
|
+
assert Foo.new.d!
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_bang_method_passes_predicate_method_result
|
37
|
+
eval <<-EOS
|
38
|
+
class Foo
|
39
|
+
def find_file?; 'a string'; end
|
40
|
+
end
|
41
|
+
EOS
|
42
|
+
assert_equal 'a string', Foo.new.find_file!
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_bang_method_raises_exception_if_predicate_method_returns_false
|
46
|
+
assert_raises(Exception) { Foo.new.a! }
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_bang_method_passes_arguments_to_the_predicate_method
|
50
|
+
eval <<-EOS
|
51
|
+
class Foo
|
52
|
+
attr_reader :args, :block
|
53
|
+
def store_args?(*args, &block); @args, @block = args, block; end
|
54
|
+
end
|
55
|
+
EOS
|
56
|
+
foo = Foo.new
|
57
|
+
block = lambda { }
|
58
|
+
foo.store_args!(1, 2, &block)
|
59
|
+
assert_equal [1, 2], foo.args
|
60
|
+
assert_equal block, foo.block
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_exception_raised_by_bang_method_includes_exception_module_named_after_the_predicate_method
|
64
|
+
assert exception_raised_by { Foo.new.a! }.kind_of?(Foo::NotAError)
|
65
|
+
assert exception_raised_by { Foo.new.b! }.kind_of?(Foo::NotBError)
|
66
|
+
assert exception_raised_by { Foo.new.c! }.kind_of?(Foo::NotCError)
|
67
|
+
assert exception_raised_by { Bar.new.a! }.kind_of?(Bar::NotAError)
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_exception_raised_by_bang_method_includes_exception_modules_from_predicate_method_called_inside
|
71
|
+
e = exception_raised_by { Foo.new.c! }
|
72
|
+
assert e.kind_of?(Foo::NotAError)
|
73
|
+
assert e.kind_of?(Foo::NotBError)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_exception_raised_by_bang_method_includes_exception_module_from_superclass_predicate_method
|
77
|
+
exception_raised_by { Bar.new.a! }.kind_of?(Foo::AError)
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_exception_raised_by_bang_method_includes_negated_exception_module_from_called_predicate_method
|
81
|
+
exception_raised_by { Foo.new.e! }.kind_of?(Foo::NotDError)
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_no_visible_methods_added_except_bang_method
|
85
|
+
foo_methods_with_predicate_method = Foo.new.methods + ['new_predicate_method?']
|
86
|
+
eval "class Foo;def new_predicate_method?; false; end; end"
|
87
|
+
assert_equal ['new_predicate_method!'], Foo.new.methods - foo_methods_with_predicate_method
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_no_bang_method_will_be_overridden
|
91
|
+
eval "class Foo;def do_not_override_me!; 'public'; end; end"
|
92
|
+
eval "class Foo;def do_not_override_me?; true; end; end"
|
93
|
+
|
94
|
+
assert_equal 'public', Foo.new.do_not_override_me!
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_no_bang_method_will_be_overridden_even_if_it_is_private
|
98
|
+
eval "class Foo;private;def private_do_not_override_me!; 'private'; end; end"
|
99
|
+
eval "class Foo;def private_do_not_override_me?; true; end; end"
|
100
|
+
assert_equal 'private', Foo.new.__send__(:private_do_not_override_me!)
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_no_bang_method_will_be_overridden_even_if_it_is_in_a_superclas
|
104
|
+
eval "class Foo;def super_do_not_override_me!; 'super'; end; end"
|
105
|
+
eval "class Bar;def super_do_not_override_me?; true; end; end"
|
106
|
+
assert_equal 'super', Foo.new.super_do_not_override_me!
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_some_super_complex_thing
|
110
|
+
eval <<-EOS
|
111
|
+
class Foo
|
112
|
+
def k?; false; end
|
113
|
+
def m?; true; end
|
114
|
+
def n?; !(k? || m?); end
|
115
|
+
def o?; true; end
|
116
|
+
def p?; o? && !n?; end
|
117
|
+
def q?; !p?; end
|
118
|
+
end
|
119
|
+
EOS
|
120
|
+
e = exception_raised_by { Foo.new.q! }
|
121
|
+
assert e.kind_of?(Foo::NotKError)
|
122
|
+
assert e.kind_of?(Foo::MError)
|
123
|
+
assert e.kind_of?(Foo::NotNError)
|
124
|
+
assert e.kind_of?(Foo::OError)
|
125
|
+
assert e.kind_of?(Foo::PError)
|
126
|
+
assert e.kind_of?(Foo::NotQError)
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_does_work_for_modules
|
130
|
+
# any? is defined in the module Enumerable and included in Array
|
131
|
+
assert Enumerable.instance_methods(false).include?('any?')
|
132
|
+
assert !Array.instance_methods(false).include?('any?')
|
133
|
+
assert Array.ancestors.include?(Enumerable)
|
134
|
+
|
135
|
+
e = exception_raised_by { [].any! }
|
136
|
+
assert e.kind_of?(Enumerable::NotAnyError)
|
137
|
+
assert_same Array::NotAnyError, Enumerable::NotAnyError
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_does_work_for_alias_method
|
141
|
+
eval <<-EOS
|
142
|
+
class Foo
|
143
|
+
alias_method :a_alias?, :a?
|
144
|
+
end
|
145
|
+
EOS
|
146
|
+
e = exception_raised_by { Foo.new.a_alias! }
|
147
|
+
assert e.kind_of?(Foo::NotAAliasError)
|
148
|
+
assert e.kind_of?(Foo::NotAError)
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_does_work_for_redefined_methods
|
152
|
+
eval <<-EOS
|
153
|
+
class Foo
|
154
|
+
alias_method :b_old?, :b?
|
155
|
+
def b?
|
156
|
+
b_old?
|
157
|
+
end
|
158
|
+
end
|
159
|
+
EOS
|
160
|
+
e = exception_raised_by { Foo.new.b! }
|
161
|
+
assert e.kind_of?(Foo::NotBError)
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_ignores_methods_starting_with_non_letter
|
165
|
+
eval <<-EOS
|
166
|
+
class Foo
|
167
|
+
def _e?
|
168
|
+
end
|
169
|
+
end
|
170
|
+
EOS
|
171
|
+
assert !Foo.respond_to?(:_e!)
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_ignores_methods_with_whitespace
|
175
|
+
eval <<-EOS
|
176
|
+
class Foo
|
177
|
+
define_method "I?\n am a method?" do
|
178
|
+
true
|
179
|
+
end
|
180
|
+
end
|
181
|
+
EOS
|
182
|
+
assert !Foo.new.respond_to?(:"I?\n am a method!")
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_does_work_for_unnamed_class
|
186
|
+
c = Class.new
|
187
|
+
c.class_eval <<-EOS
|
188
|
+
def activated?
|
189
|
+
false
|
190
|
+
end
|
191
|
+
EOS
|
192
|
+
e = exception_raised_by { c.new.activated! }
|
193
|
+
assert e.kind_of?(c.const_get(:NotActivatedError))
|
194
|
+
self.class.const_set(:NowANamedClass, c)
|
195
|
+
assert e.kind_of?(NowANamedClass::NotActivatedError)
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_does_work_for_unnamed_module
|
199
|
+
m = Module.new
|
200
|
+
m.module_eval <<-EOS
|
201
|
+
def activated?
|
202
|
+
false
|
203
|
+
end
|
204
|
+
EOS
|
205
|
+
Foo.send(:include, m)
|
206
|
+
e = exception_raised_by { Foo.new.activated! }
|
207
|
+
assert e.kind_of?(m.const_get(:NotActivatedError))
|
208
|
+
self.class.const_set(:NowANamedModule, m)
|
209
|
+
assert e.kind_of?(NowANamedModule::NotActivatedError)
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_does_not_work_for_virtual_classes
|
213
|
+
f = Foo.new
|
214
|
+
class << f
|
215
|
+
def x?; b?; end
|
216
|
+
end
|
217
|
+
assert !f.respond_to?(:x!)
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_exception_in_a_predicate_method_does_not_screw_up_the_next_result
|
221
|
+
eval <<-EOS
|
222
|
+
class Foo
|
223
|
+
def raises?; a?; raise "FAILURE"; end
|
224
|
+
end
|
225
|
+
EOS
|
226
|
+
e = exception_raised_by { Foo.new.raises! }
|
227
|
+
assert e.message == "FAILURE"
|
228
|
+
e = exception_raised_by { Foo.new.b! }
|
229
|
+
assert !e.kind_of?(Foo::NotAError)
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_generated_methods_have_the_visibility_of_the_original_methods
|
233
|
+
eval <<-EOS
|
234
|
+
class Foo
|
235
|
+
public
|
236
|
+
def public_p?; true; end
|
237
|
+
protected
|
238
|
+
def protected_p?; true; end
|
239
|
+
private
|
240
|
+
def private_p?; true; end
|
241
|
+
end
|
242
|
+
EOS
|
243
|
+
|
244
|
+
assert Foo.public_instance_methods(false).include?('public_p?')
|
245
|
+
assert Foo.protected_instance_methods(false).include?('protected_p?')
|
246
|
+
assert Foo.private_instance_methods(false).include?('private_p?')
|
247
|
+
|
248
|
+
assert Foo.public_instance_methods(false).include?('public_p!')
|
249
|
+
assert Foo.protected_instance_methods(false).include?('protected_p!')
|
250
|
+
assert Foo.private_instance_methods(false).include?('private_p!')
|
251
|
+
end
|
252
|
+
|
253
|
+
private
|
254
|
+
|
255
|
+
def exception_raised_by(&block)
|
256
|
+
block.call
|
257
|
+
fail("No exception raised")
|
258
|
+
rescue Exception => e
|
259
|
+
e
|
260
|
+
end
|
261
|
+
end
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.2
|
3
|
+
specification_version: 1
|
4
|
+
name: rconditions
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2007-09-27 00:00:00 +02:00
|
8
|
+
summary: RConditions generates a bang method (for example, Array#empty!) for each predicate method (for example, Array#empty?). The bang method will return true if the predicate method returns true, otherwise it will throw an exception. The exception will include auto-generated modules that give information on predicate methods passed or failed in the bang method's execution.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: tammo@tammofreese.de
|
12
|
+
homepage: http://rconditions.rubyforge.org
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: rconditions
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Norman Timmler
|
31
|
+
- Tammo Freese
|
32
|
+
files:
|
33
|
+
- test/rconditions_test.rb
|
34
|
+
- lib/rconditions.rb
|
35
|
+
- README
|
36
|
+
- MIT-LICENSE
|
37
|
+
test_files:
|
38
|
+
- test/rconditions_test.rb
|
39
|
+
rdoc_options: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
executables: []
|
44
|
+
|
45
|
+
extensions: []
|
46
|
+
|
47
|
+
requirements: []
|
48
|
+
|
49
|
+
dependencies: []
|
50
|
+
|