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.
Files changed (128) hide show
  1. data/.document +2 -0
  2. data/CHANGES +2 -0
  3. data/LICENSE +19 -0
  4. data/README +107 -0
  5. data/Rakefile +145 -0
  6. data/config/environment.rb +15 -0
  7. data/config/objects.yml +22 -0
  8. data/lib/analog_io.rb +30 -0
  9. data/lib/digital_auxport_io.rb +49 -0
  10. data/lib/digital_configuration.rb +66 -0
  11. data/lib/digital_port_io.rb +68 -0
  12. data/lib/extension/extconf.rb +4 -0
  13. data/lib/extension/minilab_hardware.c +235 -0
  14. data/lib/extension/minilab_hardware.so +0 -0
  15. data/lib/library_translator.rb +48 -0
  16. data/lib/minilab.rb +149 -0
  17. data/lib/minilab_context.rb +39 -0
  18. data/lib/result_verifier.rb +14 -0
  19. data/test/integration/analog_input_output_test.rb +43 -0
  20. data/test/integration/connect_to_hardware_test.rb +13 -0
  21. data/test/integration/digital_input_output_test.rb +114 -0
  22. data/test/integration/integration_test.rb +53 -0
  23. data/test/integration/require_minilab_test.rb +9 -0
  24. data/test/system/analog_input.test +3 -0
  25. data/test/system/analog_output.test +37 -0
  26. data/test/system/digital_port_input.test +5 -0
  27. data/test/system/digital_port_output.test +39 -0
  28. data/test/system/digital_port_read_byte.test +26 -0
  29. data/test/system/digital_screw_terminals_input.test +2 -0
  30. data/test/system/digital_screw_terminals_output.test +11 -0
  31. data/test/system/minilab_driver.rb +85 -0
  32. data/test/test_helper.rb +11 -0
  33. data/test/unit/analog_io_test.rb +87 -0
  34. data/test/unit/digital_auxport_io_test.rb +114 -0
  35. data/test/unit/digital_configuration_test.rb +136 -0
  36. data/test/unit/digital_port_io_test.rb +117 -0
  37. data/test/unit/library_translator_test.rb +100 -0
  38. data/test/unit/minilab_context_test.rb +82 -0
  39. data/test/unit/minilab_hardware_test.rb +83 -0
  40. data/test/unit/minilab_test.rb +131 -0
  41. data/test/unit/result_verifier_test.rb +33 -0
  42. data/vendor/behaviors/lib/behaviors.rb +50 -0
  43. data/vendor/behaviors/tasks/behaviors_tasks.rake +140 -0
  44. data/vendor/behaviors/test/behaviors_tasks_test.rb +71 -0
  45. data/vendor/behaviors/test/behaviors_test.rb +50 -0
  46. data/vendor/behaviors/test/tasks_test/Rakefile +16 -0
  47. data/vendor/behaviors/test/tasks_test/doc/behaviors.html +55 -0
  48. data/vendor/behaviors/test/tasks_test/lib/user.rb +2 -0
  49. data/vendor/behaviors/test/tasks_test/test/user_test.rb +17 -0
  50. data/vendor/constructor/Rakefile +44 -0
  51. data/vendor/constructor/config/environment.rb +12 -0
  52. data/vendor/constructor/lib/constructor.rb +132 -0
  53. data/vendor/constructor/test/constructor_test.rb +366 -0
  54. data/vendor/constructor/test/helper.rb +3 -0
  55. data/vendor/diy/README +26 -0
  56. data/vendor/diy/Rakefile +18 -0
  57. data/vendor/diy/lib/constructor.rb +114 -0
  58. data/vendor/diy/lib/diy.rb +329 -0
  59. data/vendor/diy/proto/context.rb +117 -0
  60. data/vendor/diy/proto/context.yml +20 -0
  61. data/vendor/diy/test/diy_test.rb +370 -0
  62. data/vendor/diy/test/files/broken_construction.yml +7 -0
  63. data/vendor/diy/test/files/cat/cat.rb +4 -0
  64. data/vendor/diy/test/files/cat/extra_conflict.yml +5 -0
  65. data/vendor/diy/test/files/cat/heritage.rb +2 -0
  66. data/vendor/diy/test/files/cat/needs_input.yml +3 -0
  67. data/vendor/diy/test/files/cat/the_cat_lineage.rb +1 -0
  68. data/vendor/diy/test/files/dog/dog_model.rb +4 -0
  69. data/vendor/diy/test/files/dog/dog_presenter.rb +4 -0
  70. data/vendor/diy/test/files/dog/dog_view.rb +2 -0
  71. data/vendor/diy/test/files/dog/file_resolver.rb +2 -0
  72. data/vendor/diy/test/files/dog/other_thing.rb +2 -0
  73. data/vendor/diy/test/files/dog/simple.yml +11 -0
  74. data/vendor/diy/test/files/donkey/foo.rb +8 -0
  75. data/vendor/diy/test/files/donkey/foo/bar/qux.rb +7 -0
  76. data/vendor/diy/test/files/fud/objects.yml +13 -0
  77. data/vendor/diy/test/files/fud/toy.rb +15 -0
  78. data/vendor/diy/test/files/gnu/objects.yml +14 -0
  79. data/vendor/diy/test/files/gnu/thinger.rb +8 -0
  80. data/vendor/diy/test/files/goat/base.rb +8 -0
  81. data/vendor/diy/test/files/goat/can.rb +6 -0
  82. data/vendor/diy/test/files/goat/goat.rb +6 -0
  83. data/vendor/diy/test/files/goat/objects.yml +12 -0
  84. data/vendor/diy/test/files/goat/paper.rb +6 -0
  85. data/vendor/diy/test/files/goat/plane.rb +8 -0
  86. data/vendor/diy/test/files/goat/shirt.rb +6 -0
  87. data/vendor/diy/test/files/goat/wings.rb +8 -0
  88. data/vendor/diy/test/files/horse/holder_thing.rb +4 -0
  89. data/vendor/diy/test/files/horse/objects.yml +7 -0
  90. data/vendor/diy/test/files/yak/core_model.rb +4 -0
  91. data/vendor/diy/test/files/yak/core_presenter.rb +4 -0
  92. data/vendor/diy/test/files/yak/core_view.rb +1 -0
  93. data/vendor/diy/test/files/yak/data_source.rb +1 -0
  94. data/vendor/diy/test/files/yak/fringe_model.rb +4 -0
  95. data/vendor/diy/test/files/yak/fringe_presenter.rb +4 -0
  96. data/vendor/diy/test/files/yak/fringe_view.rb +1 -0
  97. data/vendor/diy/test/files/yak/my_objects.yml +21 -0
  98. data/vendor/diy/test/test_helper.rb +40 -0
  99. data/vendor/hardmock/CHANGES +8 -0
  100. data/vendor/hardmock/LICENSE +7 -0
  101. data/vendor/hardmock/README +48 -0
  102. data/vendor/hardmock/Rakefile +100 -0
  103. data/vendor/hardmock/TODO +7 -0
  104. data/vendor/hardmock/config/environment.rb +12 -0
  105. data/vendor/hardmock/homepage/demo.rb +21 -0
  106. data/vendor/hardmock/homepage/hardmock_sample.png +0 -0
  107. data/vendor/hardmock/homepage/index.html +65 -0
  108. data/vendor/hardmock/init.rb +3 -0
  109. data/vendor/hardmock/lib/hardmock.rb +634 -0
  110. data/vendor/hardmock/lib/method_cleanout.rb +14 -0
  111. data/vendor/hardmock/rcov.rake +18 -0
  112. data/vendor/hardmock/test/functional/assert_error_test.rb +52 -0
  113. data/vendor/hardmock/test/functional/auto_verify_test.rb +192 -0
  114. data/vendor/hardmock/test/functional/direct_mock_usage_test.rb +396 -0
  115. data/vendor/hardmock/test/functional/hardmock_test.rb +380 -0
  116. data/vendor/hardmock/test/test_helper.rb +23 -0
  117. data/vendor/hardmock/test/unit/expectation_builder_test.rb +18 -0
  118. data/vendor/hardmock/test/unit/expector_test.rb +56 -0
  119. data/vendor/hardmock/test/unit/method_cleanout_test.rb +35 -0
  120. data/vendor/hardmock/test/unit/mock_control_test.rb +172 -0
  121. data/vendor/hardmock/test/unit/mock_test.rb +273 -0
  122. data/vendor/hardmock/test/unit/simple_expectation_test.rb +345 -0
  123. data/vendor/hardmock/test/unit/trapper_test.rb +60 -0
  124. data/vendor/hardmock/test/unit/verify_error_test.rb +34 -0
  125. data/vendor/systir/systir.rb +403 -0
  126. data/vendor/systir/test/unit/ui/xml/testrunner.rb +192 -0
  127. data/vendor/systir/test/unit/ui/xml/xmltestrunner.xslt +109 -0
  128. metadata +235 -0
@@ -0,0 +1,329 @@
1
+ require 'yaml'
2
+
3
+ #
4
+ # DIY (Dependency Injection in Yaml) is a simple dependency injection library
5
+ # which focuses on declarative composition of objects through setter injection.
6
+ #
7
+ # == Examples
8
+ #
9
+ # === A Simple Context
10
+ #
11
+ # The context is a hash specified in in a yaml file. Each top-level key identifies
12
+ # an object. When the context is created and queried for an object, by default,
13
+ # the context will require a file with the same name:
14
+ # require 'foo'
15
+ # next, by default, it will call new on a class from the camel-cased name of the key:
16
+ # Foo.new
17
+ #
18
+ # foo.rb:
19
+ # class Foo; end
20
+ #
21
+ # context.yml:
22
+ # ---
23
+ # foo:
24
+ # bar:
25
+ #
26
+ # c = DIY::Context.from_file('context.yml')
27
+ # c[:foo] #=> #<Foo:0x81eb0>
28
+ #
29
+ # === Specifying Class Name
30
+ #
31
+ # If the class name isn't the camel-cased key:
32
+ #
33
+ # foo.rb:
34
+ # class MyFoo; end
35
+ #
36
+ # context.yml:
37
+ # ---
38
+ # foo:
39
+ # class: MyFoo
40
+ # bar:
41
+ #
42
+ # === Specifying Ruby File to Require
43
+ #
44
+ # If the file the class resides in isn't named after they key:
45
+ #
46
+ # fun_stuff.rb:
47
+ # class Foo; end
48
+ #
49
+ # context.yml:
50
+ # ---
51
+ # foo:
52
+ # lib: fun_stuff
53
+ # bar:
54
+ #
55
+ # === Constructor Arguments
56
+ #
57
+ # DIY allows specification of constructor arguments as hash key-value pairs
58
+ # using the <tt>compose</tt> directive.
59
+ #
60
+ # foo.rb:
61
+ # class Foo
62
+ # def initialize(args)
63
+ # @bar = args[:bar]
64
+ # @other = args[:other]
65
+ # end
66
+ # end
67
+ #
68
+ # context.yml:
69
+ # ---
70
+ # foo:
71
+ # compose: bar, other
72
+ # bar:
73
+ # other:
74
+ #
75
+ # To make constructor definition easier use constructor:
76
+ #
77
+ # foo.rb:
78
+ # class Foo
79
+ # constructor :bar, :other
80
+ # end
81
+ #
82
+ # If the constructor argument names don't match up with the object keys
83
+ # in the context, they can be mapped explicitly.
84
+ #
85
+ # foo.rb:
86
+ # class Foo
87
+ # constructor :bar, :other
88
+ # end
89
+ #
90
+ # context.yml:
91
+ # ---
92
+ # foo:
93
+ # bar: my_bar
94
+ # other: the_other_one
95
+ # my_bar:
96
+ # the_other_one:
97
+ #
98
+ module DIY
99
+ class Context
100
+ def initialize(context_hash, extra_inputs={})
101
+ raise "Nil context hash" unless context_hash
102
+ raise "Need a hash" unless context_hash.kind_of?(Hash)
103
+ [ "[]", "keys" ].each do |mname|
104
+ unless extra_inputs.respond_to?(mname)
105
+ raise "Extra inputs must respond to hash-like [] operator and methods #keys and #each"
106
+ end
107
+ end
108
+
109
+ # store extra inputs
110
+ if extra_inputs.kind_of?(Hash)
111
+ @extra_inputs = {}
112
+ extra_inputs.each { |k,v| @extra_inputs[k.to_s] = v } # smooth out the names
113
+ else
114
+ @extra_inputs = extra_inputs
115
+ end
116
+
117
+ # Collect object and subcontext definitions
118
+ @defs = {}
119
+ @sub_context_defs = {}
120
+ context_hash.each do |name,info|
121
+ name = name.to_s
122
+ case name
123
+ when /^\+/
124
+ # subcontext
125
+ @sub_context_defs[name.gsub(/^\+/,'')] = info
126
+ else
127
+ # normal object def
128
+ if extra_inputs_has(name)
129
+ raise ConstructionError.new(name, "Object definition conflicts with parent context")
130
+ end
131
+ @defs[name] = ObjectDef.new(name,info)
132
+ end
133
+ end
134
+
135
+
136
+ # init the cache
137
+ @cache = {}
138
+ @cache['this_context'] = self
139
+ end
140
+
141
+ def self.from_yaml(io_or_string, extra_inputs={})
142
+ raise "nil input to YAML" unless io_or_string
143
+ Context.new(YAML.load(io_or_string), extra_inputs)
144
+ end
145
+
146
+ def self.from_file(fname, extra_inputs={})
147
+ raise "nil file name" unless fname
148
+ self.from_yaml(File.read(fname), extra_inputs)
149
+ end
150
+
151
+ def get_object(obj_name)
152
+ key = obj_name.to_s
153
+ obj = @cache[key]
154
+ unless obj
155
+ if extra_inputs_has(key)
156
+ obj = @extra_inputs[key]
157
+ end
158
+ end
159
+ unless obj
160
+ obj = construct_object(key)
161
+ @cache[key] = obj
162
+ end
163
+ obj
164
+ end
165
+ alias :[] :get_object
166
+
167
+ def set_object(obj_name,obj)
168
+ key = obj_name.to_s
169
+ raise "object '#{key}' already exists in context" if @cache.keys.include?(key)
170
+ @cache[key] = obj
171
+ end
172
+ alias :[]= :set_object
173
+
174
+ def keys
175
+ @defs.keys
176
+ end
177
+
178
+ # Instantiate and yield the named subcontext
179
+ def within(sub_context_name)
180
+ # Find the subcontext definitaion:
181
+ context_def = @sub_context_defs[sub_context_name.to_s]
182
+ raise "No sub-context named #{sub_context_name}" unless context_def
183
+ # Instantiate a new context using self as parent:
184
+ context = Context.new( context_def, self )
185
+
186
+ yield context
187
+ end
188
+
189
+ def contains_object(obj_name)
190
+ key = obj_name.to_s
191
+ @defs.keys.member?(key) or extra_inputs_has(key)
192
+ end
193
+
194
+ def build_everything
195
+ @defs.keys.each { |k| self[k] }
196
+ end
197
+ alias :build_all :build_everything
198
+ alias :preinstantiate_singletons :build_everything
199
+
200
+ private
201
+ def construct_object(key)
202
+ # Find the object definition
203
+ obj_def = @defs[key]
204
+ raise "No object definition for '#{key}'" unless obj_def
205
+
206
+ # If object def mentions a library, load it
207
+ require obj_def.library if obj_def.library
208
+
209
+ # Resolve all components for the object
210
+ arg_hash = {}
211
+ obj_def.components.each do |name,value|
212
+ case value
213
+ when Lookup
214
+ arg_hash[name.to_sym] = get_object(value.name)
215
+ when StringValue
216
+ arg_hash[name.to_sym] = value.literal_value
217
+ else
218
+ raise "Cannot cope with component definition '#{value.inspect}'"
219
+ end
220
+ end
221
+ # Get a reference to the class for the object
222
+ big_c = get_class_for_name_with_module_delimeters(obj_def.class_name)
223
+ # Make and return the instance
224
+ if arg_hash.keys.size > 0
225
+ return big_c.new(arg_hash)
226
+ else
227
+ return big_c.new
228
+ end
229
+ rescue Exception => oops
230
+ cerr = ConstructionError.new(key,oops)
231
+ cerr.set_backtrace(oops.backtrace)
232
+ raise cerr
233
+ end
234
+
235
+ def get_class_for_name_with_module_delimeters(class_name)
236
+ class_name.split(/::/).inject(Object) do |mod,const_name| mod.const_get(const_name) end
237
+ end
238
+
239
+ def extra_inputs_has(key)
240
+ if key.nil? or key.strip == ''
241
+ raise ArgumentError.new("Cannot lookup objects with nil keys")
242
+ end
243
+ @extra_inputs.keys.member?(key) or @extra_inputs.keys.member?(key.to_sym)
244
+ end
245
+ end
246
+
247
+ class Lookup #:nodoc:
248
+ attr_reader :name
249
+ def initialize(obj_name)
250
+ @name = obj_name
251
+ end
252
+ end
253
+
254
+ class ObjectDef #:nodoc:
255
+ attr_accessor :name, :class_name, :library, :components
256
+ def initialize(name,info=nil)
257
+ if info
258
+ info = info.clone
259
+ else
260
+ info = {}
261
+ end
262
+
263
+ @components = {}
264
+
265
+ # Object name
266
+ @name = name
267
+
268
+ # Class name
269
+ @class_name = info.delete 'class'
270
+ @class_name ||= info.delete 'type'
271
+ @class_name ||= camelize(@name)
272
+
273
+ # Library
274
+ @library = info.delete 'library'
275
+ @library ||= info.delete 'lib'
276
+ @library ||= underscore(@class_name)
277
+
278
+ # Auto-compose
279
+ compose = info.delete 'compose'
280
+ if compose
281
+ case compose
282
+ when Array
283
+ auto_names = compose.map { |x| x.to_s }
284
+ when String
285
+ auto_names = compose.split(',').map { |x| x.to_s.strip }
286
+ when Symbol
287
+ auto_names = [ compose.to_s ]
288
+ else
289
+ raise "Cannot auto compose object #{@name}, bad 'compose' format: #{compose.inspect}"
290
+ end
291
+ end
292
+ auto_names ||= []
293
+ auto_names.each do |cname|
294
+ @components[cname] = Lookup.new(cname)
295
+ end
296
+
297
+ # Remaining keys
298
+ info.each do |key,val|
299
+ @components[key.to_s] = Lookup.new(val.to_s)
300
+ end
301
+ end
302
+
303
+ private
304
+ # Ganked this from Inflector:
305
+ def camelize(lower_case_and_underscored_word)
306
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
307
+ end
308
+ # Ganked this from Inflector:
309
+ def underscore(camel_cased_word)
310
+ camel_cased_word.to_s.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
311
+ end
312
+ end
313
+
314
+ # Exception raised when an object can't be created which is defined in the context.
315
+ class ConstructionError < RuntimeError
316
+ def initialize(object_name, cause=nil) #:nodoc:
317
+ object_name = object_name
318
+ cause = cause
319
+ m = "Failed to construct '#{object_name}'"
320
+ if cause
321
+ m << "\n ...caused by:\n >>> #{cause}"
322
+ end
323
+ super m
324
+ end
325
+ end
326
+ end
327
+
328
+
329
+
@@ -0,0 +1,117 @@
1
+ require 'rubygems'
2
+ require 'active_support/inflector'
3
+ require 'yaml'
4
+
5
+ class DiyContext
6
+ def initialize(context_hash)
7
+ @defs = {}
8
+ context_hash.each do |name,info|
9
+ @defs[name.to_s] = ObjectDef.new(name,info)
10
+ end
11
+ @cache = {}
12
+ end
13
+
14
+ def self.from_yaml(text)
15
+ DiyContext.new(YAML.load(text))
16
+ end
17
+
18
+ def self.from_file(fname)
19
+ self.from_yaml(File.read(fname))
20
+ end
21
+
22
+ def get_object(obj_name)
23
+ key = obj_name.to_s
24
+ obj = @cache[key]
25
+ unless obj
26
+ obj = construct_object(key)
27
+ @cache[key] = obj
28
+ end
29
+ obj
30
+ end
31
+
32
+ def contains_object(obj_name)
33
+ !@defs[obj_name].nil?
34
+ end
35
+
36
+ private
37
+ def construct_object(key)
38
+ # Find the object definition
39
+ obj_def = @defs[key]
40
+ raise "No object definition for '#{key}'"
41
+
42
+ # If object def mentions a library, load it
43
+ require obj_def.library if obj_def.library
44
+
45
+ # Resolve all components for the object
46
+ arg_hash = {}
47
+ obj_def.components.each do |name,value|
48
+ case value
49
+ when Lookup
50
+ arg_hash[name.to_sym] = get_object(value.name)
51
+ when StringValue
52
+ arg_hash[name.to_sym] = value.literal_value
53
+ else
54
+ raise "Cannot cope with component definition '#{value.inspect}'"
55
+ end
56
+ end
57
+ # Get a reference to the class for the object
58
+ big_c = self.class.const_get(obj_def.class_name)
59
+ # Make and return the instance
60
+ big_c.new(arg_hash)
61
+ end
62
+
63
+ class Lookup
64
+ attr_reader :name
65
+ def initialize(obj_name)
66
+ @name = @obj_name
67
+ end
68
+ end
69
+
70
+ class ObjectDef
71
+ attr_accessor :name, :class_name, :library, :components
72
+ def initialize(name,info={})
73
+ info ||= {}
74
+
75
+ @components = {}
76
+
77
+ # Object name
78
+ @name = name
79
+
80
+ # Class name
81
+ @class_name = info.delete 'class'
82
+ @class_name ||= info.delete 'type'
83
+ @class_name ||= Inflector.camelize(@name)
84
+
85
+ # Library
86
+ @library = info.delete 'library'
87
+ @library ||= info.delete 'lib'
88
+ @library ||= Inflector.underscore(@class_name)
89
+
90
+ # Auto-compose
91
+ compose = info.delete 'compose'
92
+ if compose
93
+ case compose
94
+ when Array
95
+ auto_names = compose.map { |x| x.to_s }
96
+ when String
97
+ auto_names = compose.split(',').map { |x| x.to_s }
98
+ when Symbol
99
+ auto_names = [ compose.to_s ]
100
+ else
101
+ raise "Cannot auto compose object #{@name}, bad 'compose' format: #{compose.inspect}"
102
+ end
103
+ end
104
+ auto_names ||= []
105
+ auto_names.each do |cname|
106
+ @components[cname] = Lookup.new(cname)
107
+ end
108
+
109
+ # Remaining keys
110
+ info.each do |key,val|
111
+ @components[key.to_s] = Lookup.new(val.to_s)
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+
@@ -0,0 +1,20 @@
1
+ app_form:
2
+ class: MainAppForm
3
+
4
+ file_resolver:
5
+ class: FileResolver
6
+ lib: tools/happy_stuff
7
+
8
+ bep_host_config:
9
+ ini_file: (value) config.ini
10
+ compose: file_resolver
11
+
12
+ basic_dialog_shower:
13
+ compose:
14
+ - open_file_dialog
15
+ - error_dialog
16
+
17
+ hoss:
18
+ my_shower: basic_dialog_shower
19
+
20
+ boss: