minilab 1.0.0-mswin32
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/.document +2 -0
- data/CHANGES +2 -0
- data/LICENSE +19 -0
- data/README +107 -0
- data/Rakefile +145 -0
- data/config/environment.rb +15 -0
- data/config/objects.yml +22 -0
- data/lib/analog_io.rb +30 -0
- data/lib/digital_auxport_io.rb +49 -0
- data/lib/digital_configuration.rb +66 -0
- data/lib/digital_port_io.rb +68 -0
- data/lib/extension/extconf.rb +4 -0
- data/lib/extension/minilab_hardware.c +235 -0
- data/lib/extension/minilab_hardware.so +0 -0
- data/lib/library_translator.rb +48 -0
- data/lib/minilab.rb +149 -0
- data/lib/minilab_context.rb +39 -0
- data/lib/result_verifier.rb +14 -0
- data/test/integration/analog_input_output_test.rb +43 -0
- data/test/integration/connect_to_hardware_test.rb +13 -0
- data/test/integration/digital_input_output_test.rb +114 -0
- data/test/integration/integration_test.rb +53 -0
- data/test/integration/require_minilab_test.rb +9 -0
- data/test/system/analog_input.test +3 -0
- data/test/system/analog_output.test +37 -0
- data/test/system/digital_port_input.test +5 -0
- data/test/system/digital_port_output.test +39 -0
- data/test/system/digital_port_read_byte.test +26 -0
- data/test/system/digital_screw_terminals_input.test +2 -0
- data/test/system/digital_screw_terminals_output.test +11 -0
- data/test/system/minilab_driver.rb +85 -0
- data/test/test_helper.rb +11 -0
- data/test/unit/analog_io_test.rb +87 -0
- data/test/unit/digital_auxport_io_test.rb +114 -0
- data/test/unit/digital_configuration_test.rb +136 -0
- data/test/unit/digital_port_io_test.rb +117 -0
- data/test/unit/library_translator_test.rb +100 -0
- data/test/unit/minilab_context_test.rb +82 -0
- data/test/unit/minilab_hardware_test.rb +83 -0
- data/test/unit/minilab_test.rb +131 -0
- data/test/unit/result_verifier_test.rb +33 -0
- data/vendor/behaviors/lib/behaviors.rb +50 -0
- data/vendor/behaviors/tasks/behaviors_tasks.rake +140 -0
- data/vendor/behaviors/test/behaviors_tasks_test.rb +71 -0
- data/vendor/behaviors/test/behaviors_test.rb +50 -0
- data/vendor/behaviors/test/tasks_test/Rakefile +16 -0
- data/vendor/behaviors/test/tasks_test/doc/behaviors.html +55 -0
- data/vendor/behaviors/test/tasks_test/lib/user.rb +2 -0
- data/vendor/behaviors/test/tasks_test/test/user_test.rb +17 -0
- data/vendor/constructor/Rakefile +44 -0
- data/vendor/constructor/config/environment.rb +12 -0
- data/vendor/constructor/lib/constructor.rb +132 -0
- data/vendor/constructor/test/constructor_test.rb +366 -0
- data/vendor/constructor/test/helper.rb +3 -0
- data/vendor/diy/README +26 -0
- data/vendor/diy/Rakefile +18 -0
- data/vendor/diy/lib/constructor.rb +114 -0
- data/vendor/diy/lib/diy.rb +329 -0
- data/vendor/diy/proto/context.rb +117 -0
- data/vendor/diy/proto/context.yml +20 -0
- data/vendor/diy/test/diy_test.rb +370 -0
- data/vendor/diy/test/files/broken_construction.yml +7 -0
- data/vendor/diy/test/files/cat/cat.rb +4 -0
- data/vendor/diy/test/files/cat/extra_conflict.yml +5 -0
- data/vendor/diy/test/files/cat/heritage.rb +2 -0
- data/vendor/diy/test/files/cat/needs_input.yml +3 -0
- data/vendor/diy/test/files/cat/the_cat_lineage.rb +1 -0
- data/vendor/diy/test/files/dog/dog_model.rb +4 -0
- data/vendor/diy/test/files/dog/dog_presenter.rb +4 -0
- data/vendor/diy/test/files/dog/dog_view.rb +2 -0
- data/vendor/diy/test/files/dog/file_resolver.rb +2 -0
- data/vendor/diy/test/files/dog/other_thing.rb +2 -0
- data/vendor/diy/test/files/dog/simple.yml +11 -0
- data/vendor/diy/test/files/donkey/foo.rb +8 -0
- data/vendor/diy/test/files/donkey/foo/bar/qux.rb +7 -0
- data/vendor/diy/test/files/fud/objects.yml +13 -0
- data/vendor/diy/test/files/fud/toy.rb +15 -0
- data/vendor/diy/test/files/gnu/objects.yml +14 -0
- data/vendor/diy/test/files/gnu/thinger.rb +8 -0
- data/vendor/diy/test/files/goat/base.rb +8 -0
- data/vendor/diy/test/files/goat/can.rb +6 -0
- data/vendor/diy/test/files/goat/goat.rb +6 -0
- data/vendor/diy/test/files/goat/objects.yml +12 -0
- data/vendor/diy/test/files/goat/paper.rb +6 -0
- data/vendor/diy/test/files/goat/plane.rb +8 -0
- data/vendor/diy/test/files/goat/shirt.rb +6 -0
- data/vendor/diy/test/files/goat/wings.rb +8 -0
- data/vendor/diy/test/files/horse/holder_thing.rb +4 -0
- data/vendor/diy/test/files/horse/objects.yml +7 -0
- data/vendor/diy/test/files/yak/core_model.rb +4 -0
- data/vendor/diy/test/files/yak/core_presenter.rb +4 -0
- data/vendor/diy/test/files/yak/core_view.rb +1 -0
- data/vendor/diy/test/files/yak/data_source.rb +1 -0
- data/vendor/diy/test/files/yak/fringe_model.rb +4 -0
- data/vendor/diy/test/files/yak/fringe_presenter.rb +4 -0
- data/vendor/diy/test/files/yak/fringe_view.rb +1 -0
- data/vendor/diy/test/files/yak/my_objects.yml +21 -0
- data/vendor/diy/test/test_helper.rb +40 -0
- data/vendor/hardmock/CHANGES +8 -0
- data/vendor/hardmock/LICENSE +7 -0
- data/vendor/hardmock/README +48 -0
- data/vendor/hardmock/Rakefile +100 -0
- data/vendor/hardmock/TODO +7 -0
- data/vendor/hardmock/config/environment.rb +12 -0
- data/vendor/hardmock/homepage/demo.rb +21 -0
- data/vendor/hardmock/homepage/hardmock_sample.png +0 -0
- data/vendor/hardmock/homepage/index.html +65 -0
- data/vendor/hardmock/init.rb +3 -0
- data/vendor/hardmock/lib/hardmock.rb +634 -0
- data/vendor/hardmock/lib/method_cleanout.rb +14 -0
- data/vendor/hardmock/rcov.rake +18 -0
- data/vendor/hardmock/test/functional/assert_error_test.rb +52 -0
- data/vendor/hardmock/test/functional/auto_verify_test.rb +192 -0
- data/vendor/hardmock/test/functional/direct_mock_usage_test.rb +396 -0
- data/vendor/hardmock/test/functional/hardmock_test.rb +380 -0
- data/vendor/hardmock/test/test_helper.rb +23 -0
- data/vendor/hardmock/test/unit/expectation_builder_test.rb +18 -0
- data/vendor/hardmock/test/unit/expector_test.rb +56 -0
- data/vendor/hardmock/test/unit/method_cleanout_test.rb +35 -0
- data/vendor/hardmock/test/unit/mock_control_test.rb +172 -0
- data/vendor/hardmock/test/unit/mock_test.rb +273 -0
- data/vendor/hardmock/test/unit/simple_expectation_test.rb +345 -0
- data/vendor/hardmock/test/unit/trapper_test.rb +60 -0
- data/vendor/hardmock/test/unit/verify_error_test.rb +34 -0
- data/vendor/systir/systir.rb +403 -0
- data/vendor/systir/test/unit/ui/xml/testrunner.rb +192 -0
- data/vendor/systir/test/unit/ui/xml/xmltestrunner.xslt +109 -0
- metadata +235 -0
@@ -0,0 +1,366 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
require 'behaviors'
|
3
|
+
require 'constructor'
|
4
|
+
|
5
|
+
class ConstructorTest < Test::Unit::TestCase
|
6
|
+
extend Behaviors
|
7
|
+
|
8
|
+
class TestingClass
|
9
|
+
attr_accessor :foo, :bar, :why, :qux
|
10
|
+
constructor :foo, :bar, :why, :qux, :strict => false
|
11
|
+
|
12
|
+
def to_pretty_pretty
|
13
|
+
"#{@foo} #{@bar}"
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
class Mama
|
19
|
+
attr_accessor :fat, :age
|
20
|
+
constructor :age, :strict => false
|
21
|
+
def setup
|
22
|
+
@fat = "much"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Sissy < Mama
|
27
|
+
attr_accessor :friends, :beauty
|
28
|
+
constructor :beauty, :strict => false
|
29
|
+
def setup
|
30
|
+
super #IMPORTANT!
|
31
|
+
@friends = "many"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class TestingStrictArgsDefault
|
36
|
+
constructor :foo, :bar
|
37
|
+
def to_pretty_pretty
|
38
|
+
"#{@foo} #{@bar}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class TestingStrictArgs
|
43
|
+
constructor :foo, :bar, :strict => true
|
44
|
+
def to_pretty_pretty
|
45
|
+
"#{@foo} #{@bar}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class TestingStrictArgs2
|
50
|
+
constructor :foo, :bar, :accessors => true
|
51
|
+
end
|
52
|
+
|
53
|
+
class SubclassOfTestingClass < TestingClass
|
54
|
+
end
|
55
|
+
|
56
|
+
class SubclassOfTestingClass2 < TestingClass
|
57
|
+
def initialize; end
|
58
|
+
end
|
59
|
+
|
60
|
+
class SubclassOfTestingClass3 < TestingClass
|
61
|
+
attr_reader :my_new_var
|
62
|
+
def initialize(hash = nil)
|
63
|
+
super
|
64
|
+
@my_new_var = "something"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class TestingAutoAccessors
|
69
|
+
constructor :foo, :bar, :why, :qux, :accessors => true, :strict => false
|
70
|
+
def to_pretty_pretty
|
71
|
+
"#{@foo} #{@bar}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class TestingSuperConstructorBase
|
76
|
+
attr_reader :a, :b
|
77
|
+
def initialize(a,b)
|
78
|
+
@a = a
|
79
|
+
@b = b
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class TestingSuperConstructor < TestingSuperConstructorBase
|
84
|
+
constructor :far, :away, :accessors => true, :super => ["once", :twice], :strict => false
|
85
|
+
end
|
86
|
+
|
87
|
+
class TestingSuperConstructorBase2
|
88
|
+
attr_reader :c, :d
|
89
|
+
def initialize
|
90
|
+
@c = 'what a'
|
91
|
+
@d = 'day for'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class TestingSuperConstructor2 < TestingSuperConstructorBase2
|
96
|
+
constructor :some, :accessors => true, :super => [], :strict => false
|
97
|
+
end
|
98
|
+
|
99
|
+
class TestingBlockedAccessors
|
100
|
+
constructor :foo, :bar, :accessors => false
|
101
|
+
def to_pretty_pretty
|
102
|
+
"#{@foo} #{@bar}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class Papa
|
107
|
+
constructor :car, :saw
|
108
|
+
end
|
109
|
+
|
110
|
+
class Sonny < Papa
|
111
|
+
constructor :computer, :accessors => true
|
112
|
+
end
|
113
|
+
|
114
|
+
class Llamma
|
115
|
+
attr_accessor :hungry, :hair
|
116
|
+
constructor :hair
|
117
|
+
def setup
|
118
|
+
@hungry = true
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
#
|
123
|
+
# TESTS
|
124
|
+
#
|
125
|
+
|
126
|
+
should "construct an object using a hash of named constructor arguments" do
|
127
|
+
fuh = TestingClass.new(
|
128
|
+
:foo => 'my foo',
|
129
|
+
:bar => 'my bar',
|
130
|
+
:qux => 'my qux',
|
131
|
+
:why => 'lucky'
|
132
|
+
)
|
133
|
+
|
134
|
+
assert_equal 'my foo', fuh.foo
|
135
|
+
assert_equal 'my bar', fuh.bar
|
136
|
+
assert_equal 'my qux', fuh.qux
|
137
|
+
assert_equal 'lucky', fuh.why
|
138
|
+
assert_equal 'my foo my bar', fuh.to_pretty_pretty
|
139
|
+
end
|
140
|
+
|
141
|
+
should "allow omission of arguments when strict is off" do
|
142
|
+
fuh = TestingClass.new( :foo => 'my foo' )
|
143
|
+
assert_equal 'my foo', fuh.foo
|
144
|
+
assert_nil fuh.bar
|
145
|
+
assert_nil fuh.qux
|
146
|
+
assert_nil fuh.why
|
147
|
+
end
|
148
|
+
|
149
|
+
should "allow no arguments to a constructor when strict is off" do
|
150
|
+
fuh = TestingClass.new
|
151
|
+
assert_nil fuh.foo
|
152
|
+
assert_nil fuh.bar
|
153
|
+
assert_nil fuh.qux
|
154
|
+
assert_nil fuh.why
|
155
|
+
end
|
156
|
+
|
157
|
+
should "that objects that do not use constructor work normally" do
|
158
|
+
require 'rexml/document'
|
159
|
+
d = REXML::Document.new("<base/>")
|
160
|
+
assert_not_nil d, 'nil document'
|
161
|
+
assert_equal "base", d.root.name
|
162
|
+
end
|
163
|
+
|
164
|
+
should "inherit constructor arguments" do
|
165
|
+
fuh = SubclassOfTestingClass.new(:foo => 'whu?')
|
166
|
+
assert_equal "whu?", fuh.foo
|
167
|
+
assert_nil fuh.bar
|
168
|
+
assert_nil fuh.qux
|
169
|
+
assert_nil fuh.why
|
170
|
+
end
|
171
|
+
|
172
|
+
should "still be able to use a standard constructor in a subclass" do
|
173
|
+
fuh = SubclassOfTestingClass2.new
|
174
|
+
assert_nil fuh.foo
|
175
|
+
end
|
176
|
+
|
177
|
+
should "call subclass constructor" do
|
178
|
+
fuh = SubclassOfTestingClass3.new
|
179
|
+
assert_equal "something", fuh.my_new_var
|
180
|
+
end
|
181
|
+
|
182
|
+
should "be able to use named constructor args when a subclass defines a constructor and calls super" do
|
183
|
+
fuh = SubclassOfTestingClass3.new(:foo => 12)
|
184
|
+
assert_equal "something", fuh.my_new_var
|
185
|
+
assert_equal 12, fuh.foo
|
186
|
+
end
|
187
|
+
|
188
|
+
should "provide accessors for constructor arguments when the accessor option is used" do
|
189
|
+
fuh = TestingAutoAccessors.new(
|
190
|
+
:foo => 'my foo',
|
191
|
+
:bar => 'my bar',
|
192
|
+
:qux => 'my qux',
|
193
|
+
:why => 'lucky'
|
194
|
+
)
|
195
|
+
assert_equal 'my foo', fuh.foo
|
196
|
+
assert_equal 'my bar', fuh.bar
|
197
|
+
assert_equal 'my qux', fuh.qux
|
198
|
+
assert_equal 'lucky', fuh.why
|
199
|
+
assert_equal 'my foo my bar', fuh.to_pretty_pretty
|
200
|
+
end
|
201
|
+
|
202
|
+
should "not provide accessors for constructor arguments when the accessor option is false" do
|
203
|
+
fuh = TestingBlockedAccessors.new(
|
204
|
+
:foo => 'my foo',
|
205
|
+
:bar => 'my bar'
|
206
|
+
)
|
207
|
+
[:foo, :bar].each do |accessor_name|
|
208
|
+
assert_raise NoMethodError do
|
209
|
+
fuh.send accessor_name
|
210
|
+
end
|
211
|
+
end
|
212
|
+
assert_equal 'my foo my bar', fuh.to_pretty_pretty
|
213
|
+
end
|
214
|
+
|
215
|
+
should "inherit constructor arguments" do
|
216
|
+
s = Sonny.new(:car => "Nissan", :saw => "Dewalt", :computer => "Dell")
|
217
|
+
assert_equal "Dell", s.computer
|
218
|
+
assert_equal "Dewalt", s.saw
|
219
|
+
assert_equal "Nissan", s.car
|
220
|
+
end
|
221
|
+
|
222
|
+
should "call setup method if defined" do
|
223
|
+
ralph = Llamma.new(:hair => "red")
|
224
|
+
assert ralph.hungry
|
225
|
+
assert_equal "red", ralph.hair
|
226
|
+
end
|
227
|
+
|
228
|
+
class Baby < Mama
|
229
|
+
constructor :cuteness
|
230
|
+
end
|
231
|
+
|
232
|
+
should "call setup on superclass if subclass does not define a setup method" do
|
233
|
+
baby = Baby.new(:cuteness => 'little', :age => 1)
|
234
|
+
assert_equal "much", baby.fat
|
235
|
+
end
|
236
|
+
|
237
|
+
should "let parent class setup affect subclass setup" do
|
238
|
+
m = Mama.new(:age => 55)
|
239
|
+
assert_equal 55, m.age
|
240
|
+
assert_equal "much", m.fat
|
241
|
+
|
242
|
+
s = Sissy.new(:age => 19, :beauty => "medium")
|
243
|
+
assert_equal 19, s.age
|
244
|
+
assert_equal "medium", s.beauty
|
245
|
+
assert_equal "much", s.fat
|
246
|
+
assert_equal "many", s.friends
|
247
|
+
end
|
248
|
+
|
249
|
+
should "default to strict argument enforcement" do
|
250
|
+
fuh = TestingStrictArgsDefault.new(
|
251
|
+
:foo => 'my foo',
|
252
|
+
:bar => 'my bar')
|
253
|
+
assert_equal 'my foo my bar', fuh.to_pretty_pretty
|
254
|
+
|
255
|
+
# Omit foo
|
256
|
+
err = assert_raise ConstructorArgumentError do
|
257
|
+
TestingStrictArgsDefault.new :bar => 'ok,yeah'
|
258
|
+
end
|
259
|
+
assert_match(/foo/, err.message)
|
260
|
+
|
261
|
+
# Omit bar
|
262
|
+
err = assert_raise ConstructorArgumentError do
|
263
|
+
TestingStrictArgsDefault.new :foo => 'ok,yeah'
|
264
|
+
end
|
265
|
+
assert_match(/bar/, err.message)
|
266
|
+
end
|
267
|
+
|
268
|
+
should "enforce strict arguments when the strict option is true" do
|
269
|
+
fuh = TestingStrictArgs.new(
|
270
|
+
:foo => 'my foo',
|
271
|
+
:bar => 'my bar')
|
272
|
+
assert_equal 'my foo my bar', fuh.to_pretty_pretty
|
273
|
+
|
274
|
+
# Omit foo
|
275
|
+
err = assert_raise ConstructorArgumentError do
|
276
|
+
TestingStrictArgs.new :bar => 'ok,yeah'
|
277
|
+
end
|
278
|
+
assert_match(/foo/, err.message)
|
279
|
+
|
280
|
+
# Omit bar
|
281
|
+
err = assert_raise ConstructorArgumentError do
|
282
|
+
TestingStrictArgs.new :foo => 'ok,yeah'
|
283
|
+
end
|
284
|
+
assert_match(/bar/, err.message)
|
285
|
+
end
|
286
|
+
|
287
|
+
|
288
|
+
should "not allow an empty construction when using strict arguments" do
|
289
|
+
# Omit foo and bar
|
290
|
+
err = assert_raise ConstructorArgumentError do
|
291
|
+
TestingStrictArgs.new {}
|
292
|
+
end
|
293
|
+
assert_match(/bar/, err.message)
|
294
|
+
assert_match(/foo/, err.message)
|
295
|
+
|
296
|
+
# Nil
|
297
|
+
err = assert_raise ConstructorArgumentError do
|
298
|
+
TestingStrictArgs.new
|
299
|
+
end
|
300
|
+
assert_match(/bar/, err.message)
|
301
|
+
assert_match(/foo/, err.message)
|
302
|
+
|
303
|
+
# Nil explicitly
|
304
|
+
err = assert_raise ConstructorArgumentError do
|
305
|
+
TestingStrictArgs.new nil
|
306
|
+
end
|
307
|
+
assert_match(/bar/, err.message)
|
308
|
+
assert_match(/foo/, err.message)
|
309
|
+
end
|
310
|
+
|
311
|
+
should "not allow extraneous arguments in strict mode" do
|
312
|
+
err = assert_raise ConstructorArgumentError do
|
313
|
+
TestingStrictArgs.new(:foo => 1, :bar => 2, :other => 3, :thing => 4)
|
314
|
+
end
|
315
|
+
assert_match(/other/, err.message)
|
316
|
+
assert_match(/thing/, err.message)
|
317
|
+
|
318
|
+
end
|
319
|
+
|
320
|
+
should "raise an exception mentioning missing or extra arguments in strict mode" do
|
321
|
+
err = assert_raise ConstructorArgumentError do
|
322
|
+
TestingStrictArgs.new(:other => 3, :thing => 4)
|
323
|
+
end
|
324
|
+
assert_match(/foo/, err.message)
|
325
|
+
assert_match(/bar/, err.message)
|
326
|
+
assert_match(/thing/, err.message)
|
327
|
+
assert_match(/thing/, err.message)
|
328
|
+
end
|
329
|
+
|
330
|
+
|
331
|
+
should "provide accessors for constructor arguments in strict mode" do
|
332
|
+
t2 = TestingStrictArgs2.new(:foo => 1, :bar => 2)
|
333
|
+
# See that accessors work
|
334
|
+
assert_equal 1, t2.foo
|
335
|
+
assert_equal 2, t2.bar
|
336
|
+
|
337
|
+
# See that strictness still applies
|
338
|
+
err = assert_raise ConstructorArgumentError do
|
339
|
+
TestingStrictArgs2.new(:no => 'good')
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
should "allow generic rescue of constructor argument catching" do
|
344
|
+
begin
|
345
|
+
TestingStrictArgs.new(:broken => 'yoobetcha')
|
346
|
+
rescue => oops
|
347
|
+
assert oops.kind_of?(ConstructorArgumentError)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
should "pass arguments given in the super option to the initializer of a parent class" do
|
352
|
+
tsc = TestingSuperConstructor.new(:far => 'oo', :away => 'kk')
|
353
|
+
assert_equal 'oo', tsc.far
|
354
|
+
assert_equal 'kk', tsc.away
|
355
|
+
assert_equal "once", tsc.a
|
356
|
+
assert_equal :twice, tsc.b
|
357
|
+
end
|
358
|
+
|
359
|
+
should "call a super constructor when the super option is an empty array" do
|
360
|
+
tsc = TestingSuperConstructor2.new(:some => 'thing')
|
361
|
+
assert_equal 'thing', tsc.some
|
362
|
+
assert_equal 'what a', tsc.c
|
363
|
+
assert_equal 'day for', tsc.d
|
364
|
+
end
|
365
|
+
|
366
|
+
end
|
data/vendor/diy/README
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Tue Oct 25 01:48:45 EDT 2005
|
2
|
+
crosby
|
3
|
+
|
4
|
+
DIY - Dependency Injection with YAML
|
5
|
+
|
6
|
+
Constructor-based dependency injection container using YAML input.
|
7
|
+
|
8
|
+
Currently, all objects that get components put into them must have a
|
9
|
+
constructor that gets a hash with symbols as keys.
|
10
|
+
Best used with constructor.rb
|
11
|
+
|
12
|
+
Auto-naming and auto-library support is done.
|
13
|
+
|
14
|
+
TEST
|
15
|
+
rake
|
16
|
+
...or ruby test/diy_context_test.rb
|
17
|
+
|
18
|
+
INSTALL
|
19
|
+
Just grab src/diy_context.rb and put it somewhere.
|
20
|
+
You might want lib/constructor.rb too, but best get it from svn/devtools/ruby/constructor, its official home.
|
21
|
+
|
22
|
+
DOC
|
23
|
+
Read SVN log
|
24
|
+
Read diy_context_test.rb
|
25
|
+
See test/files/dog/simple.yml for sample.
|
26
|
+
"rdoc src/"
|
data/vendor/diy/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
def header(s)
|
5
|
+
puts "---\n\n#{s}\n\n---\n"
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
task :default => [ :testall ]
|
10
|
+
|
11
|
+
desc "Run the unit tests in test/unit"
|
12
|
+
Rake::TestTask.new("testall") { |t|
|
13
|
+
header(t.name)
|
14
|
+
t.libs << "test"
|
15
|
+
t.pattern = 'test/**/*_test.rb'
|
16
|
+
t.verbose = true
|
17
|
+
}
|
18
|
+
|
@@ -0,0 +1,114 @@
|
|
1
|
+
class Class
|
2
|
+
#
|
3
|
+
# Declarative means to define object properties by passing a hash
|
4
|
+
# to the constructor, which will set the corresponding ivars.
|
5
|
+
# Eg,
|
6
|
+
# class Horse
|
7
|
+
# constructor :name, :breed, :weight
|
8
|
+
# end
|
9
|
+
# Horse.new :name => 'Ed', :breed => 'Mustang', :weight => 342
|
10
|
+
#
|
11
|
+
# By default the ivars do not get accessors defined.
|
12
|
+
# But you can get them auto-made if you want:
|
13
|
+
# class Horse
|
14
|
+
# constructor :name, :breed, :weight, :accessors => true
|
15
|
+
# end
|
16
|
+
# ...
|
17
|
+
# puts my_horse.weight
|
18
|
+
#
|
19
|
+
# You can enforce strict argument checking with :strict option.
|
20
|
+
# This means that the constructor will raise an error if you pass
|
21
|
+
# more or fewer arguments than declared.
|
22
|
+
# Eg,
|
23
|
+
# class Donkey
|
24
|
+
# constructor :age, :odor, :strict => true
|
25
|
+
# end
|
26
|
+
# ... this forces you to pass both an age and odor key to the Donkey constructor.
|
27
|
+
#
|
28
|
+
def constructor(*attrs)
|
29
|
+
# Look for embedded options in the listing:
|
30
|
+
opts = attrs.find { |a| a.kind_of?(Hash) and attrs.delete(a) }
|
31
|
+
do_acc = opts.nil? ? false : opts[:accessors] == true
|
32
|
+
require_args = opts.nil? ? false : opts[:strict] == true
|
33
|
+
|
34
|
+
# Incorporate superclass's constructor keys
|
35
|
+
if superclass.constructor_keys
|
36
|
+
attrs = [attrs,superclass.constructor_keys].flatten
|
37
|
+
end
|
38
|
+
# Generate ivar assigner code lines
|
39
|
+
assigns = ''
|
40
|
+
attrs.each do |k|
|
41
|
+
assigns += "@#{k.to_s} = args[:#{k.to_s}]\n"
|
42
|
+
end
|
43
|
+
|
44
|
+
# If accessors option is on, declare accessors for the attributes:
|
45
|
+
if do_acc
|
46
|
+
self.class_eval "attr_accessor " + attrs.map {|x| ":#{x.to_s}"}.join(',')
|
47
|
+
end
|
48
|
+
|
49
|
+
# If strict is on, define the constructor argument validator method,
|
50
|
+
# and setup the initializer to invoke the validator method.
|
51
|
+
# Otherwise, insert lax code into the initializer.
|
52
|
+
validation_code = "return if args.nil?"
|
53
|
+
if require_args
|
54
|
+
self.class_eval do
|
55
|
+
def _validate_constructor_args(args)
|
56
|
+
# First, make sure we've got args of some kind
|
57
|
+
unless args and args.keys and args.keys.size > 0
|
58
|
+
raise ConstructorArgumentError.new(self.class.constructor_keys)
|
59
|
+
end
|
60
|
+
# Scan for missing keys in the argument hash
|
61
|
+
a_keys = args.keys
|
62
|
+
missing = []
|
63
|
+
self.class.constructor_keys.each do |ck|
|
64
|
+
unless a_keys.member?(ck)
|
65
|
+
missing << ck
|
66
|
+
end
|
67
|
+
a_keys.delete(ck) # Delete inbound keys as we address them
|
68
|
+
end
|
69
|
+
if missing.size > 0 || a_keys.size > 0
|
70
|
+
raise ConstructorArgumentError.new(missing,a_keys)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
# Setup the code to insert into the initializer:
|
75
|
+
validation_code = "_validate_constructor_args args "
|
76
|
+
end
|
77
|
+
|
78
|
+
# Generate the initializer code
|
79
|
+
self.class_eval %{
|
80
|
+
def initialize(args=nil)
|
81
|
+
#{validation_code}
|
82
|
+
#{assigns}
|
83
|
+
setup if respond_to?(:setup)
|
84
|
+
end
|
85
|
+
}
|
86
|
+
|
87
|
+
# Remember our constructor keys
|
88
|
+
@_ctor_keys = attrs
|
89
|
+
end
|
90
|
+
|
91
|
+
# Access the constructor keys for this class
|
92
|
+
def constructor_keys; @_ctor_keys; end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Fancy validation exception, based on missing and extraneous keys.
|
96
|
+
class ConstructorArgumentError < RuntimeError
|
97
|
+
def initialize(missing,rejected=[])
|
98
|
+
err_msg = ''
|
99
|
+
if missing.size > 0
|
100
|
+
err_msg = "Missing constructor args [#{missing.join(',')}]"
|
101
|
+
end
|
102
|
+
if rejected.size > 0
|
103
|
+
# Some inbound keys were not addressed earlier; this means they're unwanted
|
104
|
+
if err_msg
|
105
|
+
err_msg << "; " # Appending to earlier message about missing items
|
106
|
+
else
|
107
|
+
err_msg = ''
|
108
|
+
end
|
109
|
+
# Enumerate the rejected key names
|
110
|
+
err_msg << "Rejected constructor args [#{rejected.join(',')}]"
|
111
|
+
end
|
112
|
+
super err_msg
|
113
|
+
end
|
114
|
+
end
|