rubybreaker 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/NEWS +3 -0
  2. data/README.md +1 -2
  3. data/Rakefile +1 -0
  4. data/TODO +0 -8
  5. data/TUTORIAL.md +33 -7
  6. data/VERSION +1 -1
  7. data/lib/rubybreaker.rb +12 -4
  8. data/lib/rubybreaker/debug/error.rb +1 -1
  9. data/lib/rubybreaker/runtime.rb +16 -12
  10. data/lib/rubybreaker/runtime/monitor.rb +116 -84
  11. data/lib/rubybreaker/runtime/pluggable.rb +8 -2
  12. data/lib/rubybreaker/runtime/type_system.rb +77 -10
  13. data/lib/rubybreaker/task.rb +6 -0
  14. data/lib/rubybreaker/util.rb +23 -0
  15. data/test/integrated/tc_checking.rb +71 -0
  16. data/test/integrated/tc_class_methods.rb +14 -4
  17. data/test/testtask/sample.rb +1 -0
  18. data/test/testtask/tc_testtask.rb +14 -2
  19. data/test/ts_integrated.rb +1 -0
  20. data/webpage/index.html +1 -2
  21. data/webpage/rdoc/Object.html +0 -2
  22. data/webpage/rdoc/Rake.html +0 -2
  23. data/webpage/rdoc/Rake/RubyBreakerTestTask.html +19 -5
  24. data/webpage/rdoc/RubyBreaker.html +35 -3
  25. data/webpage/rdoc/RubyBreaker/Breakable.html +1 -3
  26. data/webpage/rdoc/RubyBreaker/Broken.html +1 -3
  27. data/webpage/rdoc/RubyBreaker/Context.html +0 -2
  28. data/webpage/rdoc/RubyBreaker/Errors.html +0 -2
  29. data/webpage/rdoc/RubyBreaker/Errors/InternalError.html +0 -2
  30. data/webpage/rdoc/RubyBreaker/Errors/InvalidSubtypeCheck.html +0 -2
  31. data/webpage/rdoc/RubyBreaker/Errors/InvalidTypeConstruction.html +0 -2
  32. data/webpage/rdoc/RubyBreaker/Errors/SubtypeFailure.html +0 -2
  33. data/webpage/rdoc/RubyBreaker/Errors/TypeError.html +0 -2
  34. data/webpage/rdoc/RubyBreaker/Errors/UserError.html +2 -4
  35. data/webpage/rdoc/RubyBreaker/ObjectPosition.html +0 -2
  36. data/webpage/rdoc/RubyBreaker/Position.html +0 -2
  37. data/webpage/rdoc/RubyBreaker/RDocSupport.html +0 -2
  38. data/webpage/rdoc/RubyBreaker/RubyTypeUtils.html +0 -2
  39. data/webpage/rdoc/RubyBreaker/Runtime.html +39 -6
  40. data/webpage/rdoc/RubyBreaker/Runtime/Inspector.html +0 -2
  41. data/webpage/rdoc/RubyBreaker/Runtime/MethodInfo.html +0 -2
  42. data/webpage/rdoc/RubyBreaker/Runtime/Monitor.html +295 -28
  43. data/webpage/rdoc/RubyBreaker/Runtime/MonitorInstaller.html +30 -43
  44. data/webpage/rdoc/RubyBreaker/Runtime/MonitorSwitch.html +4 -6
  45. data/webpage/rdoc/RubyBreaker/Runtime/ObjectWrapper.html +0 -2
  46. data/webpage/rdoc/RubyBreaker/Runtime/Pluggable.html +78 -18
  47. data/webpage/rdoc/RubyBreaker/Runtime/TypeSigParser.html +0 -2
  48. data/webpage/rdoc/RubyBreaker/Runtime/TypeSigUnparser.html +0 -2
  49. data/webpage/rdoc/RubyBreaker/Runtime/TypeSystem.html +172 -28
  50. data/webpage/rdoc/RubyBreaker/TypeComparer.html +0 -2
  51. data/webpage/rdoc/RubyBreaker/TypeDefs.html +0 -2
  52. data/webpage/rdoc/RubyBreaker/TypeDefs/AnyType.html +0 -2
  53. data/webpage/rdoc/RubyBreaker/TypeDefs/BlockType.html +0 -2
  54. data/webpage/rdoc/RubyBreaker/TypeDefs/DuckType.html +0 -2
  55. data/webpage/rdoc/RubyBreaker/TypeDefs/FusionType.html +0 -2
  56. data/webpage/rdoc/RubyBreaker/TypeDefs/MethodListType.html +0 -2
  57. data/webpage/rdoc/RubyBreaker/TypeDefs/MethodType.html +0 -2
  58. data/webpage/rdoc/RubyBreaker/TypeDefs/NilType.html +0 -2
  59. data/webpage/rdoc/RubyBreaker/TypeDefs/NominalType.html +0 -2
  60. data/webpage/rdoc/RubyBreaker/TypeDefs/OptionalType.html +0 -2
  61. data/webpage/rdoc/RubyBreaker/TypeDefs/OrType.html +0 -2
  62. data/webpage/rdoc/RubyBreaker/TypeDefs/SelfType.html +0 -2
  63. data/webpage/rdoc/RubyBreaker/TypeDefs/Type.html +0 -2
  64. data/webpage/rdoc/RubyBreaker/TypeDefs/VarLengthType.html +0 -2
  65. data/webpage/rdoc/RubyBreaker/TypeUnparser.html +0 -2
  66. data/webpage/rdoc/RubyBreaker/Typing.html +0 -2
  67. data/webpage/rdoc/RubyBreaker/Util.html +80 -4
  68. data/webpage/rdoc/Test.html +0 -2
  69. data/webpage/rdoc/Test/Unit.html +0 -2
  70. data/webpage/rdoc/created.rid +12 -12
  71. data/webpage/rdoc/index.html +0 -2
  72. data/webpage/rdoc/js/search_index.js +1 -1
  73. data/webpage/rdoc/table_of_contents.html +53 -34
  74. data/webpage/tutorial.html +36 -7
  75. metadata +8 -11
  76. data/webpage/rdoc/RubyBreaker/Runtime/MonitorUtils.html +0 -402
@@ -31,13 +31,19 @@ module RubyBreaker
31
31
  # default type system that comes with RubyBreaker.
32
32
  module Pluggable
33
33
 
34
+ def check_before_method_call(obj, meth_info)
35
+ end
36
+
37
+ def check_after_method_call(obj, meth_info)
38
+ end
39
+
34
40
  # This method will be invoked right before the actual method is
35
41
  # invoked.
36
42
  #
37
43
  # obj:: the receiver of the method call (message)
38
44
  # method_info:: a MethodInfo object containing the method call
39
45
  # information
40
- def before_method_call(obj, meth_info)
46
+ def break_before_method_call(obj, meth_info)
41
47
  end
42
48
 
43
49
  # This method will be invoked right after the actual method is
@@ -46,7 +52,7 @@ module RubyBreaker
46
52
  # obj:: the receiver of the method call (message)
47
53
  # method_info:: a MethodInfo object containing the method call
48
54
  # information
49
- def after_method_call(obj, meth_info)
55
+ def break_after_method_call(obj, meth_info)
50
56
  end
51
57
 
52
58
  end
@@ -3,7 +3,8 @@
3
3
  # subtyping defined in ../typing/subtyping.rb. It is not a constraint-based
4
4
  # type system and does not check type errors statically. The main purpose of
5
5
  # this type system is to give a readable type signature to every method in
6
- # designated modules and classes.
6
+ # modules/classes specified for "breaking" and to type check documented
7
+ # methods of modules/classes specified for "checking".
7
8
 
8
9
  require_relative "util"
9
10
  require_relative "object_wrapper"
@@ -117,7 +118,7 @@ module RubyBreaker
117
118
  exist_meth_type = meth_type_map[meth_name.to_sym]
118
119
 
119
120
  # Again, find the arity
120
- meth_obj = obj.method(MonitorUtils.get_alt_meth_name(meth_name))
121
+ meth_obj = obj.method(Monitor.get_alt_meth_name(meth_name))
121
122
  arity = meth_obj.arity
122
123
 
123
124
  # Construct the newly observed method type first
@@ -165,14 +166,79 @@ module RubyBreaker
165
166
  if !resolved
166
167
  exist_meth_type.types << new_meth_type
167
168
  end
169
+
170
+ end
171
+
172
+ # This method creates the prefix for the type error message.
173
+ def type_error_msg_prefix(mod, meth_name)
174
+ result = /#<Class:(.+)>/.match("#{mod}")
175
+ prefix = result ? "#{result[1]}." : "#{mod}#"
176
+ return "#{prefix}#{meth_name}"
168
177
  end
169
178
 
170
179
  public
180
+
181
+ # This method is invoked before the original method is executed.
182
+ def check_before_method(obj, meth_info)
183
+ is_obj_mod = (obj.class == Class or obj.class == Module)
184
+ mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
185
+
186
+ meth_type_map = TYPE_MAP[mod]
187
+ return unless meth_type_map
188
+
189
+ # Let's take things out of the MethodInfo object
190
+ meth_name = meth_info.meth_name
191
+ args = meth_info.args
192
+ blk = meth_info.blk
193
+ ret = meth_info.ret
194
+
195
+ # Get the registered method type for this method
196
+ meth_type = meth_type_map[meth_name]
197
+
198
+ args.each_with_index do |arg, i|
199
+ arg_type = NominalType.new(arg.class)
200
+ if !arg_type.subtype_of?(meth_type.arg_types[i])
201
+ msg = type_error_msg_prefix(mod, meth_name) +
202
+ "'s #{Util.ordinalize(i+1)} argument " +
203
+ "does not have type #{arg_type.unparse()}."
204
+ raise Errors::TypeError.new(msg)
205
+ end
206
+ end
207
+
208
+ end
209
+
210
+ # This method is invoked after the original method is executed.
211
+ def check_after_method(obj, meth_info)
212
+ is_obj_mod = (obj.class == Class or obj.class == Module)
213
+ mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
214
+
215
+ meth_type_map = TYPE_MAP[mod]
216
+ return unless meth_type_map
217
+
218
+ # Let's take things out of the MethodInfo object
219
+ meth_name = meth_info.meth_name
220
+ args = meth_info.args
221
+ blk = meth_info.blk
222
+ ret = meth_info.ret
223
+
224
+ # Get the registered method type for this method
225
+ meth_type = meth_type_map[meth_name]
226
+
227
+ ret_type = NominalType.new(ret.class)
228
+ if !meth_type.ret_type.subtype_of?(ret_type)
229
+ msg = type_error_msg_prefix(mod, meth_name) +
230
+ " return value does not have type #{ret_type.unparse()}."
231
+ raise Errors::TypeError.new(msg)
232
+ end
233
+ end
171
234
 
172
- # This method occurs before every "monitored" method call. It wraps
173
- # each argument with the object wrapper.
174
- def before_method(obj, meth_info)
235
+ # This method occurs before every call to a "monitored" method in a
236
+ # module/class specified for breaking. It wraps each argument with the
237
+ # object wrapper so it can be tracked of the method calls.
238
+ def break_before_method(obj, meth_info)
175
239
 
240
+ # Use the eigen class if the object is a module/class and use the
241
+ # object's class otherwise.
176
242
  is_obj_mod = (obj.class == Class or obj.class == Module)
177
243
  mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
178
244
 
@@ -201,7 +267,7 @@ module RubyBreaker
201
267
  # This means the method type has been created previously.
202
268
  unless (blk == nil && meth_type.blk_type == nil) &&
203
269
  (!blk || blk.arity == meth_type.blk_type.arg_types.length)
204
- raise Errors::TypeError("Block usage is inconsistent")
270
+ raise Errors::TypeError.new("Block usage is inconsistent")
205
271
  end
206
272
  else
207
273
  # No method type has been created for this method yet. Create a
@@ -210,7 +276,7 @@ module RubyBreaker
210
276
  #
211
277
  # First, use the orignal method's arity to find out # of
212
278
  # arguments.
213
- meth_obj = obj.method(MonitorUtils.get_alt_meth_name(meth_name))
279
+ meth_obj = obj.method(Monitor.get_alt_meth_name(meth_name))
214
280
  arity = meth_obj.arity
215
281
  arg_types = [nil] * meth_obj.arity.abs
216
282
  if blk
@@ -229,9 +295,10 @@ module RubyBreaker
229
295
 
230
296
  end
231
297
 
232
- # This method occurs after every "monitored" method call. It updates
233
- # the type information.
234
- def after_method(obj, meth_info)
298
+ # This method occurs after every call to a "monitored" method call of
299
+ # a module/class specified for "breaking". It updates the type
300
+ # information.
301
+ def break_after_method(obj, meth_info)
235
302
 
236
303
  is_obj_mod = (obj.class == Class or obj.class == Module)
237
304
  mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
@@ -24,6 +24,9 @@ module Rake
24
24
  # List of modules/classes to break
25
25
  attr_accessor :break
26
26
 
27
+ # List of modules/classes to check
28
+ attr_accessor :check
29
+
27
30
  # RubyBreaker options
28
31
  attr_accessor :rubybreaker_opts
29
32
 
@@ -41,6 +44,7 @@ module Rake
41
44
  # Initialize extra instance variables
42
45
  @rubybreaker_opts = []
43
46
  @break = nil
47
+ @check = nil
44
48
 
45
49
  # Call the original constructor first
46
50
  super(taskname, *args, &blk)
@@ -60,11 +64,13 @@ module Rake
60
64
  :name => taskname,
61
65
  :rubybreaker_opts => opts,
62
66
  :break => [], # Set doesn't work well with YAML; just use an array
67
+ :check => [],
63
68
  :test_files => @test_files,
64
69
  }
65
70
 
66
71
  # This allows a bulk declaration of Breakable modules/classes
67
72
  @break.each { |b| config[:break] << b } if @break
73
+ @check.each { |c| config[:check] << c } if @check
68
74
 
69
75
  # This code segment is a clever way to store yaml data in a ruby file
70
76
  # that reads its own yaml data after __END__ when loaded.
@@ -8,6 +8,29 @@ module RubyBreaker
8
8
  # in the project.
9
9
  module Util
10
10
 
11
+ def self.uneigen(mod_str)
12
+ result = /^#<Class:(.+)>#/.match(mod_str)
13
+ if result
14
+ return result[0]
15
+ else
16
+ return mod_str
17
+ end
18
+ end
19
+
20
+ # File lib/active_support/inflector.rb, line 295
21
+ def self.ordinalize(number)
22
+ if (11..13).include?(number.to_i % 100)
23
+ "#{number}th"
24
+ else
25
+ case number.to_i % 10
26
+ when 1; "#{number}st"
27
+ when 2; "#{number}nd"
28
+ when 3; "#{number}rd"
29
+ else "#{number}th"
30
+ end
31
+ end
32
+ end
33
+
11
34
  # File activesupport/lib/active_support/inflector/methods.rb, line 48
12
35
  def self.underscore(camel_cased_word)
13
36
  word = camel_cased_word.to_s.dup
@@ -0,0 +1,71 @@
1
+ require "test/unit"
2
+ require_relative "../../lib/rubybreaker"
3
+
4
+ class IntegratedCheckingTest < Test::Unit::TestCase
5
+ include RubyBreaker
6
+
7
+ class A
8
+
9
+ typesig("f1(fixnum) -> string")
10
+ def f1(x); x.to_s end
11
+
12
+ typesig("f2(fixnum[to_s]) -> string")
13
+ def f2(x); x.to_s end
14
+
15
+ typesig("f3(fixnum[foo, to_s]) -> string")
16
+ def f3(x); x.to_s end
17
+
18
+ typesig("f4(fixnum) -> fixnum")
19
+ def f4(x); x.to_s end
20
+
21
+ typesig("f5(fixnum, fixnum) -> fixnum")
22
+ def f5(x,y); x+y end
23
+
24
+ end
25
+
26
+ def setup()
27
+ RubyBreaker.check(A)
28
+ end
29
+
30
+ def test_nominal()
31
+ a = A.new
32
+ assert_nothing_thrown do
33
+ a.f1(2)
34
+ end
35
+ assert_raise RubyBreaker::Errors::TypeError do
36
+ a.f1("2")
37
+ end
38
+ end
39
+
40
+ def test_duck()
41
+ a = A.new
42
+ assert_nothing_thrown do
43
+ a.f2(2)
44
+ a.f3(2) # This will pass too
45
+ end
46
+ assert_raise RubyBreaker::Errors::TypeError do
47
+ a.f3("2")
48
+ end
49
+ end
50
+
51
+ def test_ret()
52
+ a = A.new
53
+ assert_raise RubyBreaker::Errors::TypeError do
54
+ a.f4(2)
55
+ end
56
+ end
57
+
58
+ def test_two_fixnums()
59
+ a = A.new
60
+ assert_nothing_thrown do
61
+ a.f5(1, 2)
62
+ end
63
+ assert_raise RubyBreaker::Errors::TypeError do
64
+ a.f5("1", 2)
65
+ end
66
+ assert_raise RubyBreaker::Errors::TypeError do
67
+ a.f5(1, "2")
68
+ end
69
+ end
70
+
71
+ end
@@ -10,13 +10,14 @@ class IntegratedClassMethodsTest < Test::Unit::TestCase
10
10
 
11
11
  class B
12
12
  class << self
13
- typesig("bar(fixnum[to_s]) -> string")
13
+ typesig("bar(fixnum[+]) -> string")
14
14
  def bar(x); x.to_s end
15
15
  end
16
16
  end
17
17
 
18
18
  def setup()
19
- RubyBreaker.break(A, B)
19
+ RubyBreaker.break(A)
20
+ RubyBreaker.check(B)
20
21
  end
21
22
 
22
23
  def test_class_methods
@@ -26,10 +27,19 @@ class IntegratedClassMethodsTest < Test::Unit::TestCase
26
27
  assert_equal("foo(fixnum[to_s]) -> string", str)
27
28
  end
28
29
 
29
- def test_broken_class_methods
30
+ def test_documented_class_methods
30
31
  b_bar_meth_type = Runtime::Inspector.inspect_class_meth(B, :bar)
31
32
  str = RubyBreaker::TypeUnparser.unparse(b_bar_meth_type)
32
- assert_equal("bar(fixnum[to_s]) -> string", str)
33
+ assert_equal("bar(fixnum[+]) -> string", str)
34
+ end
35
+
36
+ def test_type_checking
37
+ assert_nothing_thrown do
38
+ B.bar(1)
39
+ end
40
+ assert_raise Errors::TypeError do
41
+ B.bar(:abc)
42
+ end
33
43
  end
34
44
 
35
45
  end
@@ -6,5 +6,6 @@ end
6
6
 
7
7
  class SampleClassB
8
8
  def foo(x); x.to_s end
9
+ def bar(x); x.to_s end
9
10
  end
10
11
 
@@ -4,22 +4,34 @@ require "rubybreaker"
4
4
 
5
5
  class SampleClassB # re-opening
6
6
  typesig("foo(fixnum[to_s]) -> string")
7
+ typesig("bar(fixnum) -> string")
7
8
  end
8
9
 
9
10
  class RubyBreakerTestTaskTest < Test::Unit::TestCase
11
+ include RubyBreaker
10
12
 
11
13
  def test_break()
12
14
  SampleClassA.new.foo(2)
13
- t = RubyBreaker::Runtime::Inspector.inspect_meth(SampleClassA, :foo)
15
+ t = Runtime::Inspector.inspect_meth(SampleClassA, :foo)
14
16
  str = t.unparse()
15
17
  assert_equal("foo(fixnum[to_s]) -> string", str)
16
18
  end
17
19
 
18
20
  def test_documented()
19
- t = RubyBreaker::Runtime::Inspector.inspect_meth(SampleClassB, :foo)
21
+ t = Runtime::Inspector.inspect_meth(SampleClassB, :foo)
20
22
  str = t.unparse()
21
23
  assert_equal("foo(fixnum[to_s]) -> string", str)
22
24
  end
23
25
 
26
+ def test_type_checking()
27
+ b = SampleClassB.new
28
+ assert_nothing_thrown do
29
+ b.foo(1)
30
+ end
31
+ assert_raise Errors::TypeError do
32
+ b.bar(:"1")
33
+ end
34
+ end
35
+
24
36
  end
25
37
 
@@ -6,3 +6,4 @@ require_relative "integrated/tc_inherit_broken"
6
6
  require_relative "integrated/tc_class_methods"
7
7
  require_relative "integrated/tc_both_documented_and_undocumented"
8
8
  require_relative "integrated/tc_namespace"
9
+ require_relative "integrated/tc_checking"
data/webpage/index.html CHANGED
@@ -40,7 +40,6 @@ and effectively.</p>
40
40
 
41
41
  <ul>
42
42
  <li>Auto-document block arguments (inherent)</li>
43
- <li>Perform early dynamic type checks</li>
44
43
  <li>Support parametric polymorphic types</li>
45
44
  <li>Support RDoc or YARD output format</li>
46
45
  </ul>
@@ -49,7 +48,7 @@ and effectively.</p>
49
48
  <p>To contribute to the project, visit RubyBreaker's
50
49
  <a href="http://github.com/rockalizer/rubybreaker">GitHub page</a> and
51
50
  <a href="http://rubygems.org/gems/rubybreaker">RubyGems page</a>. The web version of
52
- this document can be found
51
+ this document and the tutorial can be found
53
52
  <a href="http://rockalizer.webfactional.com/projects/rubybreaker">here</a>.</p>
54
53
 
55
54
  <h2>Requirements</h2>
@@ -116,8 +116,6 @@
116
116
 
117
117
  <li><a href="./RubyBreaker/Runtime/MonitorSwitch.html">RubyBreaker::Runtime::MonitorSwitch</a>
118
118
 
119
- <li><a href="./RubyBreaker/Runtime/MonitorUtils.html">RubyBreaker::Runtime::MonitorUtils</a>
120
-
121
119
  <li><a href="./RubyBreaker/Runtime/ObjectWrapper.html">RubyBreaker::Runtime::ObjectWrapper</a>
122
120
 
123
121
  <li><a href="./RubyBreaker/Runtime/Pluggable.html">RubyBreaker::Runtime::Pluggable</a>
@@ -110,8 +110,6 @@
110
110
 
111
111
  <li><a href="./RubyBreaker/Runtime/MonitorSwitch.html">RubyBreaker::Runtime::MonitorSwitch</a>
112
112
 
113
- <li><a href="./RubyBreaker/Runtime/MonitorUtils.html">RubyBreaker::Runtime::MonitorUtils</a>
114
-
115
113
  <li><a href="./RubyBreaker/Runtime/ObjectWrapper.html">RubyBreaker::Runtime::ObjectWrapper</a>
116
114
 
117
115
  <li><a href="./RubyBreaker/Runtime/Pluggable.html">RubyBreaker::Runtime::Pluggable</a>
@@ -130,8 +130,6 @@
130
130
 
131
131
  <li><a href="../RubyBreaker/Runtime/MonitorSwitch.html">RubyBreaker::Runtime::MonitorSwitch</a>
132
132
 
133
- <li><a href="../RubyBreaker/Runtime/MonitorUtils.html">RubyBreaker::Runtime::MonitorUtils</a>
134
-
135
133
  <li><a href="../RubyBreaker/Runtime/ObjectWrapper.html">RubyBreaker::Runtime::ObjectWrapper</a>
136
134
 
137
135
  <li><a href="../RubyBreaker/Runtime/Pluggable.html">RubyBreaker::Runtime::Pluggable</a>
@@ -248,6 +246,19 @@ t.break = [&quot;SampleClassA&quot;]</pre>
248
246
  </div>
249
247
  </div>
250
248
 
249
+ <div id="attribute-i-check" class="method-detail">
250
+ <div class="method-heading attribute-method-heading">
251
+ <span class="method-name">check</span><span
252
+ class="attribute-access-type">[RW]</span>
253
+ </div>
254
+
255
+ <div class="method-description">
256
+
257
+ <p>List of modules/classes to check</p>
258
+
259
+ </div>
260
+ </div>
261
+
251
262
  <div id="attribute-i-rubybreaker_opts" class="method-detail">
252
263
  <div class="method-heading attribute-method-heading">
253
264
  <span class="method-name">rubybreaker_opts</span><span
@@ -288,12 +299,13 @@ options and store them in a yaml file.</p>
288
299
 
289
300
 
290
301
  <div class="method-source-code" id="new-source">
291
- <pre><span class="ruby-comment"># File lib/rubybreaker/task.rb, line 39</span>
302
+ <pre><span class="ruby-comment"># File lib/rubybreaker/task.rb, line 42</span>
292
303
  <span class="ruby-keyword">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">taskname</span>=<span class="ruby-string">&quot;&quot;</span>, *<span class="ruby-identifier">args</span>, &amp;<span class="ruby-identifier">blk</span>)
293
304
 
294
305
  <span class="ruby-comment"># Initialize extra instance variables</span>
295
306
  <span class="ruby-ivar">@rubybreaker_opts</span> = []
296
307
  <span class="ruby-ivar">@break</span> = <span class="ruby-keyword">nil</span>
308
+ <span class="ruby-ivar">@check</span> = <span class="ruby-keyword">nil</span>
297
309
 
298
310
  <span class="ruby-comment"># Call the original constructor first</span>
299
311
  <span class="ruby-keyword">super</span>(<span class="ruby-identifier">taskname</span>, *<span class="ruby-identifier">args</span>, &amp;<span class="ruby-identifier">blk</span>)
@@ -313,11 +325,13 @@ options and store them in a yaml file.</p>
313
325
  <span class="ruby-value">:name</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">taskname</span>,
314
326
  <span class="ruby-value">:rubybreaker_opts</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">opts</span>,
315
327
  <span class="ruby-value">:break</span> =<span class="ruby-operator">&gt;</span> [], <span class="ruby-comment"># Set doesn't work well with YAML; just use an array</span>
328
+ <span class="ruby-value">:check</span> =<span class="ruby-operator">&gt;</span> [],
316
329
  <span class="ruby-value">:test_files</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-ivar">@test_files</span>,
317
330
  }
318
331
 
319
332
  <span class="ruby-comment"># This allows a bulk declaration of Breakable modules/classes</span>
320
333
  <span class="ruby-ivar">@break</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">b</span><span class="ruby-operator">|</span> <span class="ruby-identifier">config</span>[<span class="ruby-value">:break</span>] <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">b</span> } <span class="ruby-keyword">if</span> <span class="ruby-ivar">@break</span>
334
+ <span class="ruby-ivar">@check</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">c</span><span class="ruby-operator">|</span> <span class="ruby-identifier">config</span>[<span class="ruby-value">:check</span>] <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">c</span> } <span class="ruby-keyword">if</span> <span class="ruby-ivar">@check</span>
321
335
 
322
336
  <span class="ruby-comment"># This code segment is a clever way to store yaml data in a ruby file</span>
323
337
  <span class="ruby-comment"># that reads its own yaml data after __END__ when loaded.</span>
@@ -381,7 +395,7 @@ __END__
381
395
 
382
396
 
383
397
  <div class="method-source-code" id="breakable-source">
384
- <pre><span class="ruby-comment"># File lib/rubybreaker/task.rb, line 31</span>
398
+ <pre><span class="ruby-comment"># File lib/rubybreaker/task.rb, line 34</span>
385
399
  <span class="ruby-keyword">def</span> <span class="ruby-identifier">breakable</span>(); <span class="ruby-ivar">@break</span> <span class="ruby-keyword">end</span></pre>
386
400
  </div><!-- breakable-source -->
387
401
 
@@ -409,7 +423,7 @@ __END__
409
423
 
410
424
 
411
425
  <div class="method-source-code" id="breakable-3D-source">
412
- <pre><span class="ruby-comment"># File lib/rubybreaker/task.rb, line 34</span>
426
+ <pre><span class="ruby-comment"># File lib/rubybreaker/task.rb, line 37</span>
413
427
  <span class="ruby-keyword">def</span> <span class="ruby-identifier">breakable=</span>(*<span class="ruby-identifier">args</span>); <span class="ruby-keyword">self</span>.<span class="ruby-identifier">break</span>(*<span class="ruby-identifier">args</span>) <span class="ruby-keyword">end</span></pre>
414
428
  </div><!-- breakable-3D-source -->
415
429