rubybreaker 0.0.6 → 0.0.7

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 (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