methlab 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -0
- data/Rakefile +4 -0
- data/lib/methlab.rb +74 -10
- data/test/test_checks.rb +34 -0
- data/test/test_defaults.rb +60 -0
- metadata +4 -3
data/README
CHANGED
data/Rakefile
CHANGED
@@ -63,3 +63,7 @@ task :build => [:gem, :repackage]
|
|
63
63
|
task :distclean => [:clobber_package, :clobber_rdoc]
|
64
64
|
desc "Clean the source tree"
|
65
65
|
task :clean => [:distclean]
|
66
|
+
|
67
|
+
task :to_blog => [:clobber_rdoc, :rdoc] do
|
68
|
+
sh "rm -r $git/blog/content/docs/methlab && mv rdoc $git/blog/content/docs/methlab"
|
69
|
+
end
|
data/lib/methlab.rb
CHANGED
@@ -48,6 +48,10 @@
|
|
48
48
|
# * Returning false/nil will raise a generic error.
|
49
49
|
# * Returning a new exception object (e.g., ArgumentError.new) will raise your error as close to the call point as possible.
|
50
50
|
# * Raising yourself will raise in the validation routine, which will probably be confusing. Please use the above method.
|
51
|
+
# * A symbol is a pragma that implies a constraint -- see below.
|
52
|
+
# * A hash is a way of specifying a pragma (or check) with a parameter:
|
53
|
+
# * :respond_to calls Object#respond_to? on the method named as the value (a symbol)
|
54
|
+
# * :default specifies a default argument. This is still checked, so get it right!
|
51
55
|
# * If you need more than one constraint per parameter, enclose these constraints within an array.
|
52
56
|
# * Depending on the type of method you're constructing, there will be additional constraints both implied and explictly allowed:
|
53
57
|
# * named methods do not require any items by default, they must be specified as required.
|
@@ -55,7 +59,7 @@
|
|
55
59
|
#
|
56
60
|
module MethLab
|
57
61
|
|
58
|
-
VERSION = "0.0.
|
62
|
+
VERSION = "0.0.6"
|
59
63
|
|
60
64
|
# Integrates MethLab into all namespaces. It does this by patching itself
|
61
65
|
# into ::main and Module.
|
@@ -67,6 +71,51 @@ module MethLab
|
|
67
71
|
::Module.send(:include, self)
|
68
72
|
end
|
69
73
|
|
74
|
+
# internal, please do not use directly.
|
75
|
+
#
|
76
|
+
# used to set defaults on parameters that require one
|
77
|
+
def self.set_defaults(signature, params, kind=:array)
|
78
|
+
params = params[0] if kind == :hash
|
79
|
+
|
80
|
+
signature.each_with_index do |value, index|
|
81
|
+
case kind
|
82
|
+
when :array
|
83
|
+
if value.kind_of?(Array)
|
84
|
+
if hashes = value.find_all { |x| x.kind_of?(Hash) } and !hashes.empty?
|
85
|
+
hashes.each do |hash|
|
86
|
+
if hash.has_key?(:default) and (params.length - 1) < index
|
87
|
+
params[index] = hash[:default]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
when :hash
|
93
|
+
if value[1].kind_of?(Array)
|
94
|
+
if hashes = value[1].find_all { |x| x.kind_of?(Hash) } and !hashes.empty?
|
95
|
+
hashes.each do |hash|
|
96
|
+
if hash.has_key?(:default) and !params.has_key?(value[0])
|
97
|
+
params[value[0]] = hash[:default]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# internal, please do not use directly.
|
107
|
+
#
|
108
|
+
# used to perform our standard checks that are supplied via hash.
|
109
|
+
def self.check_hash_types(value_key, value_value, value, key)
|
110
|
+
case value_key
|
111
|
+
when :respond_to
|
112
|
+
unless value.respond_to?(value_value)
|
113
|
+
return ArgumentError.new("value of argument '#{key}' does not respond to '#{value_value}'")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
return nil
|
117
|
+
end
|
118
|
+
|
70
119
|
# internal, please do not use directly.
|
71
120
|
#
|
72
121
|
# used to perform our standard checks.
|
@@ -75,7 +124,12 @@ module MethLab
|
|
75
124
|
when Array
|
76
125
|
value_sig.flatten.each do |vs|
|
77
126
|
ret = check_type(vs, value, key)
|
78
|
-
return ret
|
127
|
+
return ret if ret
|
128
|
+
end
|
129
|
+
when Hash
|
130
|
+
value_sig.each do |value_key, value_value| # GUH
|
131
|
+
ret = check_hash_types(value_key, value_value, value, key)
|
132
|
+
return ret if ret
|
79
133
|
end
|
80
134
|
when Class
|
81
135
|
unless value.kind_of?(value_sig)
|
@@ -127,9 +181,9 @@ module MethLab
|
|
127
181
|
return ArgumentError.new("argument #{key} does not exist in prototype")
|
128
182
|
end
|
129
183
|
|
130
|
-
if
|
184
|
+
if signature[key]
|
131
185
|
ret = check_type(signature[key], value, key)
|
132
|
-
return ret
|
186
|
+
return ret if ret
|
133
187
|
end
|
134
188
|
end
|
135
189
|
|
@@ -151,9 +205,9 @@ module MethLab
|
|
151
205
|
return ArgumentError.new("argument '#{key}' does not exist in prototype")
|
152
206
|
end
|
153
207
|
|
154
|
-
if
|
208
|
+
if signature[key]
|
155
209
|
ret = check_type(signature[key], value, key)
|
156
|
-
return ret
|
210
|
+
return ret if ret
|
157
211
|
end
|
158
212
|
end
|
159
213
|
|
@@ -193,6 +247,7 @@ module MethLab
|
|
193
247
|
end
|
194
248
|
|
195
249
|
proc do |*args|
|
250
|
+
MethLab.set_defaults(signature, args, :array)
|
196
251
|
params = MethLab.validate_array_params(signature, args)
|
197
252
|
raise params if params.kind_of?(Exception)
|
198
253
|
block.call(params)
|
@@ -204,7 +259,7 @@ module MethLab
|
|
204
259
|
# or module. Currently cannot be a class method.
|
205
260
|
def def_ordered(method_name, *args, &block)
|
206
261
|
self.send(:define_method, method_name, &build_ordered(*args, &block))
|
207
|
-
method_name
|
262
|
+
return method_name
|
208
263
|
end
|
209
264
|
|
210
265
|
# Builds an unbound method as a proc with named (Hash) parameters.
|
@@ -227,6 +282,8 @@ module MethLab
|
|
227
282
|
signature = args[0]
|
228
283
|
|
229
284
|
proc do |*args|
|
285
|
+
args = [{}] if args.empty?
|
286
|
+
MethLab.set_defaults(signature, args, :hash)
|
230
287
|
params = MethLab.validate_params(signature, *args)
|
231
288
|
raise params if params.kind_of?(Exception)
|
232
289
|
block.call(params)
|
@@ -238,7 +295,7 @@ module MethLab
|
|
238
295
|
# or module. Currently cannot be a class method.
|
239
296
|
def def_named(method_name, *args, &block)
|
240
297
|
self.send(:define_method, method_name, &build_named(*args, &block))
|
241
|
-
method_name
|
298
|
+
return method_name
|
242
299
|
end
|
243
300
|
|
244
301
|
# Similar to MethLab#build_ordered, but builds attributes similar to
|
@@ -254,15 +311,22 @@ module MethLab
|
|
254
311
|
# myobj.set_me = "String" # valid
|
255
312
|
#
|
256
313
|
def def_attr(method_name, arg)
|
314
|
+
|
257
315
|
self.send(:define_method, (method_name.to_s + "=").to_sym) do |value|
|
258
316
|
signature = [arg]
|
259
317
|
params = MethLab.validate_array_params(signature, [value])
|
260
318
|
raise params if params.kind_of?(Exception)
|
261
|
-
send(:instance_variable_set, "@" + method_name.to_s,
|
319
|
+
send(:instance_variable_set, "@" + method_name.to_s, params[0])
|
262
320
|
end
|
263
321
|
|
264
322
|
self.send(:define_method, method_name) do
|
265
|
-
|
323
|
+
unless self.instance_variables.select { |x| x == "@#{method_name}" }[0]
|
324
|
+
args = []
|
325
|
+
MethLab.set_defaults([arg], args, :array)
|
326
|
+
send(:instance_variable_set, "@#{method_name}", args[0])
|
327
|
+
end
|
328
|
+
|
329
|
+
instance_variable_get("@#{method_name}")
|
266
330
|
end
|
267
331
|
end
|
268
332
|
|
data/test/test_checks.rb
CHANGED
@@ -33,6 +33,16 @@ class CheckedClass
|
|
33
33
|
def_ordered(:proc_raise, proc { |x| ArgumentError.new("foo") }) do |params|
|
34
34
|
params
|
35
35
|
end
|
36
|
+
|
37
|
+
def_named(:has_named_rt, :stuff => {:respond_to => :replace}) do |params|
|
38
|
+
params[:stuff]
|
39
|
+
end
|
40
|
+
|
41
|
+
def_ordered(:has_ordered_rt, {:respond_to => :replace}) do |params|
|
42
|
+
params[0]
|
43
|
+
end
|
44
|
+
|
45
|
+
def_attr :rt, {:respond_to => :replace}
|
36
46
|
end
|
37
47
|
|
38
48
|
$named_proc = build_named(:stuff => String) do |params|
|
@@ -156,4 +166,28 @@ class TestChecks < Test::Unit::TestCase
|
|
156
166
|
|
157
167
|
assert_equal(@checked.set_me, "Foo")
|
158
168
|
end
|
169
|
+
|
170
|
+
def test_06_respond_to
|
171
|
+
assert(@checked.respond_to?(:has_named_rt))
|
172
|
+
assert(@checked.respond_to?(:has_ordered_rt))
|
173
|
+
assert(@checked.respond_to?(:rt))
|
174
|
+
|
175
|
+
assert_raises(ArgumentError.new("value of argument '0' does not respond to 'replace'")) do
|
176
|
+
@checked.rt = nil
|
177
|
+
end
|
178
|
+
|
179
|
+
assert_raises(ArgumentError.new("value of argument '0' does not respond to 'replace'")) do
|
180
|
+
@checked.has_ordered_rt(nil)
|
181
|
+
end
|
182
|
+
|
183
|
+
assert_raises(ArgumentError.new("value of argument 'stuff' does not respond to 'replace'")) do
|
184
|
+
@checked.has_named_rt(:stuff => nil)
|
185
|
+
end
|
186
|
+
|
187
|
+
@checked.rt = "foo"
|
188
|
+
|
189
|
+
assert(@checked.rt, "foo")
|
190
|
+
assert(@checked.has_ordered_rt("foo"), "foo")
|
191
|
+
assert(@checked.has_named_rt(:stuff => "foo"), "foo")
|
192
|
+
end
|
159
193
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
begin
|
2
|
+
require 'rubygems'
|
3
|
+
gem 'test-unit'
|
4
|
+
rescue LoadError
|
5
|
+
end
|
6
|
+
|
7
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
8
|
+
|
9
|
+
require 'test/unit'
|
10
|
+
require 'methlab'
|
11
|
+
|
12
|
+
MethLab.integrate
|
13
|
+
|
14
|
+
class DefaultClass
|
15
|
+
def_named(:named,
|
16
|
+
:foo => [String, {:default => "foo"}, :required],
|
17
|
+
:bar => [String, {:default => "bar"}]
|
18
|
+
) do |params|
|
19
|
+
params
|
20
|
+
end
|
21
|
+
|
22
|
+
def_ordered(:ordered,
|
23
|
+
[String, {:default => "foo"}, :required],
|
24
|
+
[String, {:default => "bar"}]
|
25
|
+
) do |params|
|
26
|
+
params
|
27
|
+
end
|
28
|
+
|
29
|
+
def_attr :ml_attr, [String, {:default => "foo"}]
|
30
|
+
end
|
31
|
+
|
32
|
+
class TestDefaults < Test::Unit::TestCase
|
33
|
+
def setup
|
34
|
+
@default = DefaultClass.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_01_named
|
38
|
+
assert(@default.respond_to?(:named))
|
39
|
+
|
40
|
+
assert_equal(@default.named, {:foo => "foo", :bar => "bar"})
|
41
|
+
assert_equal(@default.named(:foo => "fixme"), {:foo => "fixme", :bar => "bar"})
|
42
|
+
assert_equal(@default.named(:foo => "fixme", :bar => "woot"), {:foo => "fixme", :bar => "woot"})
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_02_ordered
|
46
|
+
assert(@default.respond_to?(:ordered))
|
47
|
+
|
48
|
+
assert_equal(@default.ordered, ["foo", "bar"])
|
49
|
+
assert_equal(@default.ordered("fixme"), ["fixme", "bar"])
|
50
|
+
assert_equal(@default.ordered("fixme", "woot"), ["fixme", "woot"])
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_03_attr
|
54
|
+
assert(@default.respond_to?(:ml_attr))
|
55
|
+
|
56
|
+
assert_equal(@default.ml_attr, "foo")
|
57
|
+
@default.ml_attr = "bar"
|
58
|
+
assert_equal(@default.ml_attr, "bar")
|
59
|
+
end
|
60
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 6
|
9
|
+
version: 0.0.6
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Erik Hollensbe
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-05-
|
17
|
+
date: 2010-05-10 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -29,6 +29,7 @@ extra_rdoc_files: []
|
|
29
29
|
files:
|
30
30
|
- lib/methlab.rb
|
31
31
|
- test/test_checks.rb
|
32
|
+
- test/test_defaults.rb
|
32
33
|
- test/test_integrate.rb
|
33
34
|
- Rakefile
|
34
35
|
- README
|