methlab 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|