rconditions 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +117 -2
- data/lib/rconditions.rb +23 -128
- metadata +11 -5
data/README
CHANGED
@@ -1,5 +1,120 @@
|
|
1
1
|
= RConditions
|
2
2
|
|
3
|
-
RConditions generates a bang method (for example, <tt>Array#empty!</tt>)
|
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 pass if the predicate method passes, 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.
|
4
9
|
|
5
|
-
|
10
|
+
== A Simple Example
|
11
|
+
|
12
|
+
require "rconditions"
|
13
|
+
|
14
|
+
begin
|
15
|
+
[1,2].empty!
|
16
|
+
rescue Array::NotEmptyError => e
|
17
|
+
p e
|
18
|
+
end
|
19
|
+
|
20
|
+
# => #<Exception: Array::NotEmptyError>
|
21
|
+
|
22
|
+
The raised exception includes a module defined on the class where the method is defined. The module's name is derived from the predicate method's name.
|
23
|
+
|
24
|
+
== A More Complicated Example
|
25
|
+
|
26
|
+
require "rconditions"
|
27
|
+
|
28
|
+
class Posting
|
29
|
+
attr_writer :spam, :active
|
30
|
+
|
31
|
+
def spam?
|
32
|
+
@spam
|
33
|
+
end
|
34
|
+
|
35
|
+
def active?
|
36
|
+
@active
|
37
|
+
end
|
38
|
+
|
39
|
+
def visible?
|
40
|
+
!spam? && active?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class User
|
45
|
+
attr_writer :admin
|
46
|
+
|
47
|
+
def admin?
|
48
|
+
@admin
|
49
|
+
end
|
50
|
+
|
51
|
+
def can_view_posting?(posting)
|
52
|
+
admin? || posting.visible?
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
user = User.new
|
57
|
+
user.admin = false
|
58
|
+
|
59
|
+
posting = Posting.new
|
60
|
+
posting.active = false
|
61
|
+
posting.spam = true
|
62
|
+
|
63
|
+
begin
|
64
|
+
user.can_view_posting!(posting)
|
65
|
+
rescue Posting::SpamError => e
|
66
|
+
p e
|
67
|
+
rescue Posting::NotActiveError
|
68
|
+
puts "should not get here"
|
69
|
+
end
|
70
|
+
|
71
|
+
# => #<Exception: User::NotAdminError, Posting::SpamError,
|
72
|
+
# Posting::NotVisibleError, User::NotCanViewPostingError>
|
73
|
+
|
74
|
+
As you can see, the exception includes modules for each of the evaluated
|
75
|
+
predicate methods: <tt>User#can_view_posting!(posting)</tt> in the context
|
76
|
+
above called <tt>User#can_view_posting?(posting)</tt>, which called
|
77
|
+
<tt>User#admin?</tt> and <tt>Posting#can_view_posting?</tt>, which called
|
78
|
+
<tt>Posting#spam?</tt>.
|
79
|
+
|
80
|
+
The results were
|
81
|
+
|
82
|
+
* <tt>User#admin? # => false</tt>
|
83
|
+
* <tt>Posting#spam? # => true</tt>
|
84
|
+
* <tt>Posting#can_view_posting? # => false</tt>
|
85
|
+
* <tt>User#can_view_posting? # => false</tt>
|
86
|
+
|
87
|
+
so the included exception modules are
|
88
|
+
|
89
|
+
* <tt>User::NotAdminError</tt>
|
90
|
+
* <tt>Posting::SpamError</tt>
|
91
|
+
* <tt>Posting::NotCanViewPostingError</tt>
|
92
|
+
* <tt>User::NotCanViewPostingError</tt>
|
93
|
+
|
94
|
+
== Performance
|
95
|
+
|
96
|
+
As almost all predicate methods are extended by default, RConditions carries
|
97
|
+
a performance penalty which varies with the number of calls to predicate
|
98
|
+
methods. A simple test setup using mongrel/rails was slowed down by 10-20%
|
99
|
+
by adding <tt>require "rconditions"</tt> to the bottom of its
|
100
|
+
<tt>enviroment.rb</tt>.
|
101
|
+
|
102
|
+
The performance penalty can be avoided by applying RConditions only to new
|
103
|
+
methods, that is, methods defined after <tt>require "rconditions"</tt>. To
|
104
|
+
achieve this, set <tt>RCONDITIONS_ONLY_FOR_NEW_METHODS = true</tt> before
|
105
|
+
the require call. Our test setup had no measurable slowdown afterwards.
|
106
|
+
|
107
|
+
== Limitations
|
108
|
+
|
109
|
+
* RConditions currently only support predicate methods starting with a letter
|
110
|
+
and containing only word characters except the question mark at the end.
|
111
|
+
* RConditions does not support singleton methods. These includes all class
|
112
|
+
methods.
|
113
|
+
|
114
|
+
== License
|
115
|
+
|
116
|
+
RConditions is released under the MIT license.
|
117
|
+
|
118
|
+
== Authors
|
119
|
+
|
120
|
+
RConditions is written by Norman Timmler and Tammo Freese.
|
data/lib/rconditions.rb
CHANGED
@@ -1,122 +1,12 @@
|
|
1
|
-
#
|
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.
|
1
|
+
# Holds RCondition's methods. You should never call these methods
|
2
|
+
# directly, as they are automatically called.
|
114
3
|
module RConditions
|
115
4
|
class << self
|
116
5
|
|
117
|
-
# Extends
|
118
|
-
# should never call this method
|
119
|
-
#
|
6
|
+
# Extends a given predicate method and defines a bang method for it. You
|
7
|
+
# should never call this method yourself, it is called either from
|
8
|
+
# RConditions#extend_predicate_methods_and_define_bang_methods, or from
|
9
|
+
# <tt>Module#method_added</tt> which is extended by RConditions.
|
120
10
|
# * <tt>mod</tt> -- the module on which the method is defined.
|
121
11
|
# * <tt>id</tt> -- the name of the method.
|
122
12
|
def extend_predicate_method_and_define_bang_method(mod, id)
|
@@ -132,6 +22,19 @@ module RConditions
|
|
132
22
|
end
|
133
23
|
end
|
134
24
|
|
25
|
+
# Extends almost all predicate methods and defines bang methods for them.
|
26
|
+
# You should never call this method yourself, it is called automatically
|
27
|
+
# when RConditions is required. To prevent it from being called, set
|
28
|
+
# <tt>RCONDITIONS_ONLY_FOR_NEW_METHODS</tt> to <tt>true</tt> before
|
29
|
+
# requiring RConditions.
|
30
|
+
def extend_predicate_methods_and_define_bang_methods
|
31
|
+
ObjectSpace.each_object(Module) do |mod|
|
32
|
+
mod.instance_methods(false).each do |id|
|
33
|
+
RConditions.extend_predicate_method_and_define_bang_method(mod, id)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
135
38
|
def exception_modules #:nodoc:
|
136
39
|
Thread.current[:rconditions_exception_modules]
|
137
40
|
end
|
@@ -212,22 +115,14 @@ unless defined? RCONDITIONS_ONLY_FOR_NEW_METHODS
|
|
212
115
|
end
|
213
116
|
|
214
117
|
unless RCONDITIONS_ONLY_FOR_NEW_METHODS
|
215
|
-
|
216
|
-
mod.instance_methods(false).each do |id|
|
217
|
-
RConditions.extend_predicate_method_and_define_bang_method(mod, id)
|
218
|
-
end
|
219
|
-
end
|
118
|
+
RConditions.extend_predicate_methods_and_define_bang_methods
|
220
119
|
end
|
221
|
-
|
222
|
-
class Module
|
120
|
+
|
121
|
+
class Module #:nodoc:
|
223
122
|
alias_method :method_added_without_rconditions, :method_added
|
224
123
|
private :method_added_without_rconditions
|
225
124
|
|
226
|
-
|
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)
|
125
|
+
def method_added(id) #:nodoc:
|
231
126
|
RConditions.extend_predicate_method_and_define_bang_method(self, id)
|
232
127
|
method_added_without_rconditions(id)
|
233
128
|
end
|
metadata
CHANGED
@@ -3,7 +3,7 @@ rubygems_version: 0.9.2
|
|
3
3
|
specification_version: 1
|
4
4
|
name: rconditions
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.1.
|
6
|
+
version: 0.1.1
|
7
7
|
date: 2007-09-27 00:00:00 +02:00
|
8
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
9
|
require_paths:
|
@@ -36,10 +36,16 @@ files:
|
|
36
36
|
- MIT-LICENSE
|
37
37
|
test_files:
|
38
38
|
- test/rconditions_test.rb
|
39
|
-
rdoc_options:
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
rdoc_options:
|
40
|
+
- --title
|
41
|
+
- RConditions RDoc Documentation
|
42
|
+
- --main
|
43
|
+
- README
|
44
|
+
- --charset
|
45
|
+
- utf-8
|
46
|
+
extra_rdoc_files:
|
47
|
+
- README
|
48
|
+
- MIT-LICENSE
|
43
49
|
executables: []
|
44
50
|
|
45
51
|
extensions: []
|