rubybreaker 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/NEWS +5 -0
  2. data/NOTES +9 -0
  3. data/README.md +100 -183
  4. data/Rakefile +21 -6
  5. data/VERSION +1 -1
  6. data/bin/rubybreaker +34 -50
  7. data/lib/rubybreaker/debug/debug.rb +6 -0
  8. data/lib/rubybreaker/doc/rdoc.rb +37 -0
  9. data/lib/rubybreaker/doc.rb +3 -0
  10. data/lib/rubybreaker/runtime/inspector.rb +6 -28
  11. data/lib/rubybreaker/runtime/monitor.rb +21 -17
  12. data/lib/rubybreaker/runtime/object_wrapper.rb +7 -2
  13. data/lib/rubybreaker/runtime/type_system.rb +3 -5
  14. data/lib/rubybreaker/runtime/typesig_unparser.rb +1 -4
  15. data/lib/rubybreaker/runtime.rb +64 -105
  16. data/lib/rubybreaker/task.rb +97 -0
  17. data/lib/rubybreaker/test/rspec.rb +1 -1
  18. data/lib/rubybreaker/test/testcase.rb +13 -28
  19. data/lib/rubybreaker/type/type.rb +1 -1
  20. data/lib/rubybreaker/typing/subtyping.rb +10 -5
  21. data/lib/rubybreaker/util.rb +0 -1
  22. data/lib/rubybreaker.rb +163 -115
  23. data/test/integrated/tc_both_broken_breakable.rb +5 -4
  24. data/test/integrated/tc_class_methods.rb +4 -3
  25. data/test/integrated/tc_inherit_broken.rb +4 -3
  26. data/test/integrated/tc_method_missing.rb +4 -4
  27. data/test/integrated/tc_namespace.rb +4 -2
  28. data/test/integrated/tc_simple1.rb +4 -3
  29. data/test/runtime/tc_obj_wrapper.rb +25 -6
  30. data/test/runtime/tc_typesig_parser.rb +0 -1
  31. data/test/testtask/sample.rb +10 -0
  32. data/test/testtask/tc_testtask.rb +25 -0
  33. data/test/ts_rspec.rb +21 -15
  34. data/test/typing/tc_typing.rb +2 -3
  35. data/webpage/index.html +105 -193
  36. data/webpage/rdoc/Kernel.html +286 -0
  37. data/webpage/rdoc/Object.html +17 -11
  38. data/webpage/rdoc/Rake/RubyBreakerTestTask.html +374 -0
  39. data/webpage/rdoc/Rake.html +212 -0
  40. data/webpage/rdoc/RubyBreaker/Breakable.html +24 -40
  41. data/webpage/rdoc/RubyBreaker/Broken.html +21 -69
  42. data/webpage/rdoc/RubyBreaker/Context.html +16 -10
  43. data/webpage/rdoc/RubyBreaker/Errors/InternalError.html +16 -10
  44. data/webpage/rdoc/RubyBreaker/Errors/InvalidSubtypeCheck.html +16 -10
  45. data/webpage/rdoc/RubyBreaker/Errors/InvalidTypeConstruction.html +16 -10
  46. data/webpage/rdoc/RubyBreaker/Errors/SubtypeFailure.html +16 -10
  47. data/webpage/rdoc/RubyBreaker/Errors/TypeError.html +16 -10
  48. data/webpage/rdoc/RubyBreaker/Errors/UserError.html +16 -10
  49. data/webpage/rdoc/RubyBreaker/Errors.html +16 -10
  50. data/webpage/rdoc/RubyBreaker/ObjectPosition.html +16 -10
  51. data/webpage/rdoc/RubyBreaker/Position.html +16 -10
  52. data/webpage/rdoc/RubyBreaker/{TestCase.html → RDocSupport.html} +81 -82
  53. data/webpage/rdoc/RubyBreaker/RubyTypeUtils.html +16 -10
  54. data/webpage/rdoc/RubyBreaker/Runtime/Inspector.html +25 -44
  55. data/webpage/rdoc/RubyBreaker/Runtime/MethodInfo.html +16 -10
  56. data/webpage/rdoc/RubyBreaker/Runtime/Monitor.html +19 -13
  57. data/webpage/rdoc/RubyBreaker/Runtime/MonitorInstaller.html +37 -25
  58. data/webpage/rdoc/RubyBreaker/Runtime/MonitorSwitch.html +20 -14
  59. data/webpage/rdoc/RubyBreaker/Runtime/MonitorUtils.html +21 -15
  60. data/webpage/rdoc/RubyBreaker/Runtime/ObjectWrapper.html +23 -12
  61. data/webpage/rdoc/RubyBreaker/Runtime/Pluggable.html +16 -10
  62. data/webpage/rdoc/RubyBreaker/Runtime/TypeSigParser.html +16 -10
  63. data/webpage/rdoc/RubyBreaker/Runtime/{TypesigUnparser.html → TypeSigUnparser.html} +19 -16
  64. data/webpage/rdoc/RubyBreaker/Runtime/TypeSystem.html +18 -14
  65. data/webpage/rdoc/RubyBreaker/Runtime.html +145 -11
  66. data/webpage/rdoc/RubyBreaker/TypeComparer.html +16 -10
  67. data/webpage/rdoc/RubyBreaker/TypeDefs/AnyType.html +16 -10
  68. data/webpage/rdoc/RubyBreaker/TypeDefs/BlockType.html +16 -10
  69. data/webpage/rdoc/RubyBreaker/TypeDefs/DuckType.html +16 -10
  70. data/webpage/rdoc/RubyBreaker/TypeDefs/FusionType.html +16 -10
  71. data/webpage/rdoc/RubyBreaker/TypeDefs/MethodListType.html +16 -10
  72. data/webpage/rdoc/RubyBreaker/TypeDefs/MethodType.html +16 -10
  73. data/webpage/rdoc/RubyBreaker/TypeDefs/NilType.html +16 -10
  74. data/webpage/rdoc/RubyBreaker/TypeDefs/NominalType.html +16 -10
  75. data/webpage/rdoc/RubyBreaker/TypeDefs/OptionalType.html +16 -10
  76. data/webpage/rdoc/RubyBreaker/TypeDefs/OrType.html +16 -10
  77. data/webpage/rdoc/RubyBreaker/TypeDefs/SelfType.html +17 -11
  78. data/webpage/rdoc/RubyBreaker/TypeDefs/Type.html +17 -11
  79. data/webpage/rdoc/RubyBreaker/TypeDefs/VarLengthType.html +16 -10
  80. data/webpage/rdoc/RubyBreaker/TypeDefs.html +16 -10
  81. data/webpage/rdoc/RubyBreaker/TypeUnparser.html +16 -10
  82. data/webpage/rdoc/RubyBreaker/Typing.html +17 -11
  83. data/webpage/rdoc/RubyBreaker/Util.html +16 -10
  84. data/webpage/rdoc/RubyBreaker.html +167 -34
  85. data/webpage/rdoc/{RubyBreaker/Runtime/TypePlaceholder.html → Test/Unit/TestCase.html} +68 -39
  86. data/webpage/rdoc/Test/Unit.html +211 -0
  87. data/webpage/rdoc/Test.html +211 -0
  88. data/webpage/rdoc/created.rid +18 -17
  89. data/webpage/rdoc/index.html +16 -10
  90. data/webpage/rdoc/js/search_index.js +1 -1
  91. data/webpage/rdoc/table_of_contents.html +61 -48
  92. metadata +21 -12
  93. data/lib/rubybreaker/rubylib/core.rb +0 -2483
  94. data/lib/rubybreaker/rubylib.rb +0 -3
  95. data/lib/rubybreaker/runtime/type_placeholder.rb +0 -23
  96. data/webpage/rdoc/RubyBreaker/Broken/BrokenEigen.html +0 -305
  97. data/webpage/rdoc/RubyBreaker/Main.html +0 -458
@@ -1,6 +1,6 @@
1
1
  #--
2
2
  # This file defines the type inspector which fetches the type information
3
- # gathered or documented in a Breakable, Broken, or hybrid module.
3
+ # gathered or documented in a class.
4
4
 
5
5
  require_relative "util"
6
6
  require_relative "monitor"
@@ -9,26 +9,14 @@ module RubyBreaker
9
9
 
10
10
  module Runtime
11
11
 
12
- # This module inspects a Breakable module, a Broken module, or a hybrid
13
- # module to fetch the type information for each method.
12
+ # This module inspects type information gathered so far.
14
13
  module Inspector
15
14
 
16
15
  # This method inspects the module for the type of the specified
17
- # method. It returns the method type or method list type for the given
18
- # method, by looking at, first, the placeholder for the Breakable
19
- # side of the module, and then, the placeholder for the Broken side of
20
- # the module. If no method exists or if there is no type information
21
- # for the method, it returns nil.
16
+ # method.
22
17
  def self.inspect_meth(mod, mname)
23
18
  mname = mname.to_sym
24
- if Breakable::TYPE_PLACEHOLDER_MAP.has_key?(mod)
25
- placeholder = Breakable::TYPE_PLACEHOLDER_MAP[mod]
26
- end
27
- t = placeholder.meth_type_map[mname] if placeholder
28
- if !t && Broken::TYPE_PLACEHOLDER_MAP.has_key?(mod)
29
- placeholder = Broken::TYPE_PLACEHOLDER_MAP[mod]
30
- t = placeholder.meth_type_map[mname] if placeholder
31
- end
19
+ t = TYPE_MAP[mod][mname] if TYPE_MAP.has_key?(mod)
32
20
  return t
33
21
  end
34
22
 
@@ -52,18 +40,8 @@ module RubyBreaker
52
40
  # containing (method name, method type) pairs.
53
41
  def self.inspect_all(mod)
54
42
  mtypes = {}
55
- mm = Breakable::TYPE_PLACEHOLDER_MAP[mod]
56
- if mm
57
- mm.meth_type_map.each_pair {|im,mtype|
58
- mtypes[im] = mtype if mtype
59
- }
60
- end
61
- mm = Broken::TYPE_PLACEHOLDER_MAP[mod]
62
- if mm
63
- mm.meth_type_map.each_pair {|im,mtype|
64
- mtypes[im] = mtype if mtype
65
- }
66
- end
43
+ mm = TYPE_MAP[mod]
44
+ mm.each_pair {|im,mtype| mtypes[im] = mtype if mtype } if mm
67
45
  return mtypes
68
46
  end
69
47
 
@@ -1,14 +1,12 @@
1
1
  #--
2
2
  # This file contains the core of the runtime framework which injects the
3
- # monitoring code into Breakable classes/modules and actually monitors the
3
+ # monitoring code into breakable classes/modules and actually monitors the
4
4
  # instances of those classes/modules at runtime. It also provides some utility
5
5
  # functions for later use (after runtime).
6
6
 
7
7
  dir = File.dirname(__FILE__)
8
8
  require_relative "util"
9
9
  require_relative "../debug"
10
- require_relative "type_placeholder"
11
- require_relative "pluggable"
12
10
  require_relative "type_system"
13
11
 
14
12
  module RubyBreaker
@@ -132,11 +130,11 @@ module RubyBreaker
132
130
  mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
133
131
 
134
132
  # mm = get_module_monitor(mod) unless is_obj_mod
135
- mm = Breakable::MONITOR_MAP[mod]
133
+ mm = MONITOR_MAP[mod]
136
134
 
137
135
  # There is something wrong if there isn't a module monitor
138
136
  # associated with the call.
139
- # raise Exception if mm == nil || !mm.meth_type_map.include?(meth_name)
137
+ # raise Exception if mm == nil || !mm.include?(meth_name)
140
138
 
141
139
  meth_info = MethodInfo.new(meth_name, args, blk, nil)
142
140
 
@@ -212,24 +210,30 @@ module RubyBreaker
212
210
 
213
211
  RubyBreaker.log("Installing module monitor for #{mod}")
214
212
 
215
- Breakable::MONITOR_MAP[mod] = Monitor.new(mod, DEFAULT_TYPE_SYSTEM)
216
- Breakable::TYPE_PLACEHOLDER_MAP[mod] = TypePlaceholder.new
213
+ # Do not re-install monitor if already done so.
214
+ if MONITOR_MAP[mod]
215
+ RubyBreaker.log("Skip #{mod} as it has a monitor installed.")
216
+ return
217
+ end
218
+
219
+ MONITOR_MAP[mod] = Monitor.new(mod, DEFAULT_TYPE_SYSTEM)
217
220
 
218
- meth_type_map = []
221
+ # Create the type map if it does not exist already. Remember, this
222
+ # map could have been made by typesig().
223
+ TYPE_MAP[mod] = {} unless TYPE_MAP[mod]
224
+
225
+ # Get the list of instance methods but do not include inherited
226
+ # methods. Those are part of the owner's not this module.
219
227
  meths = mod.instance_methods(false)
220
228
 
221
- # RubyBreaker now supports the hybrid of Breakable and Broken. Here,
222
- # see if any methods are already broken.
223
- broken_meth_type_map = Inspector.inspect_all(mod)
224
- broken_meths = broken_meth_type_map.keys
229
+ # See if any method is already broken (explicitly typesig'ed)
230
+ broken_mt_map = Inspector.inspect_all(mod)
231
+ broken_meths = broken_mt_map.keys
225
232
 
226
233
  meths.each do |m|
227
- # As long as the method is not "Broken" yet, it is considered
228
- # Breakable (if the module is declared to be Breakable).
229
- unless broken_meths.include?(m)
230
- self.rename_meth(mod,m)
231
- end
234
+ self.rename_meth(mod,m) unless broken_meths.include?(m)
232
235
  end
236
+
233
237
  end
234
238
 
235
239
  end
@@ -70,11 +70,16 @@ module RubyBreaker
70
70
  def method_missing(mname,*args,&blk)
71
71
  ::RubyBreaker.log("Method_missing for #{mname}")
72
72
  if GLOBAL_MONITOR_SWITCH.switch
73
+ # Must handle send method specially (do not track them)
74
+ if [:"__send__", :send].include?(mname)
75
+ mname = args[0]
76
+ args = args[1..-1]
77
+ end
73
78
  @__rubybreaker_type.add_meth(mname)
74
- retval = @__rubybreaker_obj.send(mname,*args,&blk)
79
+ retval = @__rubybreaker_obj.send(mname, *args, &blk)
75
80
  retval = ObjectWrapper.new(retval)
76
81
  else
77
- retval = @__rubybreaker_obj.send(mname,*args,&blk)
82
+ retval = @__rubybreaker_obj.send(mname, *args, &blk)
78
83
  end
79
84
  return retval
80
85
  end
@@ -7,10 +7,10 @@
7
7
 
8
8
  require_relative "util"
9
9
  require_relative "object_wrapper"
10
- require_relative "type_placeholder"
11
10
  require_relative "../type"
12
11
  require_relative "../typing"
13
12
  require_relative "../debug"
13
+ require_relative "pluggable"
14
14
 
15
15
  module RubyBreaker
16
16
 
@@ -176,7 +176,7 @@ module RubyBreaker
176
176
  is_obj_mod = (obj.class == Class or obj.class == Module)
177
177
  mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
178
178
 
179
- meth_type_map = Breakable::TYPE_PLACEHOLDER_MAP[mod].meth_type_map
179
+ meth_type_map = TYPE_MAP[mod]
180
180
 
181
181
  # Let's take things out of the MethodInfo object
182
182
  meth_name = meth_info.meth_name
@@ -244,10 +244,8 @@ module RubyBreaker
244
244
 
245
245
  RubyBreaker.log("In module monitor_after #{meth_name}")
246
246
 
247
- meth_type_map = Breakable::TYPE_PLACEHOLDER_MAP[mod].meth_type_map
248
-
249
247
  # Compute the least upper bound
250
- lub(obj, meth_type_map,meth_name,retval,*args,&blk)
248
+ lub(obj, TYPE_MAP[mod],meth_name,retval,*args,&blk)
251
249
 
252
250
  if obj == retval
253
251
  # It is possible that the method receiver is a wrapped object if
@@ -6,7 +6,7 @@ module RubyBreaker
6
6
  module Runtime
7
7
 
8
8
  # This module handles unparsing type signatures.
9
- module TypesigUnparser
9
+ module TypeSigUnparser
10
10
 
11
11
  include TypeDefs
12
12
 
@@ -51,9 +51,6 @@ module RubyBreaker
51
51
 
52
52
  pp.text("#{keyword} #{mod.to_s}", 80)
53
53
  pp.nest(2) do
54
- pp.breakable("")
55
- pp.text("include RubyBreaker::Broken", 80)
56
-
57
54
  # See if there is any class method to show
58
55
  eigen = Runtime.eigen_class(mod)
59
56
  if !DOCUMENTED.include?(eigen)
@@ -1,8 +1,7 @@
1
1
  #--
2
- # This file defines Breakable and Broken module. Breakable module makes the
3
- # hosting module (and class) subject to type monitoring. Broken module makes
4
- # type information of the hosting module accessible.
5
-
2
+ # This file provides two methods breakable() and broken() that declares a
3
+ # module/class to be monitored
4
+ require "set"
6
5
  require_relative "runtime/overrides"
7
6
  require_relative "runtime/typesig_parser"
8
7
  require_relative "runtime/typesig_unparser"
@@ -11,122 +10,82 @@ require_relative "runtime/inspector"
11
10
 
12
11
  module RubyBreaker
13
12
 
14
- # Broken takes higher precedence than Breakable. Once a module is
15
- # "declared" to be Broken, it cannot be Breakable.
16
- #
17
- # TODO: In future, there will be a hybrid of two to allow documenting of
18
- # methods that are newly introduced in a broken class/module.
13
+ module Runtime
19
14
 
20
- # This array lists modules/classes that will be monitored.
21
- BREAKABLE = []
15
+ # This set keeps track of modules/classes that will be monitored.
16
+ # *DEPRECATED* : Use +breakable+ method instead.
17
+ BREAKABLES = Set.new
22
18
 
23
- # This array lists "broken" classes--i.e., with type signatures
24
- BROKEN = []
19
+ # This hash maps a module to a nested hash that maps a method name to a
20
+ # method type. This hash is shared between breakable modules/classes and
21
+ # non-breakable modules/classes.
22
+ TYPE_MAP = {} # module => {:meth_name => type}
25
23
 
26
- # This module should be included in classes or modules that you want to
27
- # monitor during runtime. The concept is that once a Breakable module is
28
- # monitored and its type documentation is generated, the module now becomes
29
- # a Broken module. The actual implementation is a simple trigger that
30
- # queues the target module into the list of modules to monitor. The queued
31
- # modules are then modified to be monitored dynamically.
32
- module Breakable
24
+ # This hash maps a (breakable) module to a type monitor
25
+ MONITOR_MAP = {} # module => monitor
33
26
 
34
- TYPE_PLACEHOLDER_MAP = {} # module => type_placeholder
35
- MONITOR_MAP = {} # module => monitor
27
+ # This set lists modules/classes that are actually instrumented with a
28
+ # monitor.
29
+ INSTALLED = Set.new
36
30
 
37
- # Simply keep track of this module and its eigen class so they are
38
- # monitored later on.
39
- def self.included(mod)
40
- BREAKABLE << mod
41
- BREAKABLE << Runtime.eigen_class(mod)
31
+ # This method installs a monitor for each breakable module.
32
+ # *DEPRECATED*: Use +breakable()+ method instead.
33
+ def self.instrument()
34
+ BREAKABLES.each do |mod|
35
+ # Duplicate checks in place in these calls.
36
+ MonitorInstaller.install_module_monitor(mod)
37
+ INSTALLED << mod
38
+ end
42
39
  end
43
40
 
44
- end
45
-
46
- # This module is included for "broken" classes.
47
- module Broken
48
-
49
- include TypeDefs
50
- include Runtime
51
-
52
- TYPE_PLACEHOLDER_MAP = {} # module => type_placeholder
53
-
54
- #-
55
- # This module will be "extended" to the eigen class of the class that
56
- # includes Broken module. This allows the eigen class to call 'typesig'
57
- # method to parse the type signature dynamically.
58
- #
59
- # Usage:
60
- # Class A
61
- # include RubyBreaker::Broken
62
- #
63
- # typesig("foo(fixnum) -> fixnum")
64
- # def foo(x) ... end
65
- # end
66
- #
67
- module BrokenEigen
68
-
69
- include TypeDefs
70
- include Runtime
71
-
72
- # This method can be used at the eigen level of the target module to
73
- # specify the type of a method.
74
- def typesig(str)
75
-
76
- # This MUST BE set for self type to work in type signatures.
77
- TypeDefs::SelfType.set_self(self)
78
-
79
- t = TypeSigParser.parse(str)
80
- placeholder = TYPE_PLACEHOLDER_MAP[self]
81
- if placeholder
82
- meth_type = placeholder.meth_type_map[t.meth_name]
83
- if meth_type
84
- # TODO: make a method list
85
- if meth_type.instance_of?(MethodListType)
86
- meth_type.types << t
87
- else
88
- # then upgrade it
89
- placeholder.meth_type_map[t.meth_name] =
90
- MethodListType.new([meth_type, t])
91
- end
92
- else
93
- placeholder.meth_type_map[t.meth_name] = t
41
+ # This method modifies specified modules/classes at the very moment
42
+ # (instead of registering them for later).
43
+ def self.breakable(*mods)
44
+ mods.each do |mod|
45
+ case mod
46
+ when Array
47
+ self.breakable(*mod)
48
+ when Module, Class
49
+ MonitorInstaller.install_module_monitor(mod)
50
+ eigen_class = self.eigen_class(mod)
51
+ MonitorInstaller.install_module_monitor(eigen_class)
52
+ INSTALLED << mod << eigen_class
53
+ when String, Symbol
54
+ begin
55
+ # Get the actual module and install it right now
56
+ mod = eval("#{mod}", TOPLEVEL_BINDING)
57
+ self.breakable(mod) if mod
58
+ rescue NameError => e
59
+ RubyBreaker.error("#{mod} cannot be found.")
94
60
  end
61
+ else
62
+ RubyBreaker.error("You must specify a module/class or its name.")
95
63
  end
96
- return t
97
64
  end
98
-
99
65
  end
100
-
101
- # This method is triggered when Broken module is included. This just
102
- # extends BrokenEigen into the target module so "typesig" method can be
103
- # called from the eigen level of the module. It also extends the eigen
104
- # class of the target module so that "typesig" can work for class
105
- # methods too.
106
- def self.included(mod)
66
+ end
107
67
 
108
- # Add to the list of broken modules
109
- BROKEN << mod
68
+ # *DEPRECATED*: Use +RubyBreaker.run()+ to indicate the point of entry.
69
+ def self.monitor()
70
+ end
110
71
 
111
- # Create if there is no type placeholder for this module yet
112
- placeholder = TYPE_PLACEHOLDER_MAP[mod]
113
- if !placeholder
114
- placeholder = TypePlaceholder.new()
115
- TYPE_PLACEHOLDER_MAP[mod] = placeholder
116
- end
117
- mod.extend(BrokenEigen)
72
+ # This method just redirects to Runtime's method.
73
+ def self.breakable(*mods)
74
+ Runtime.breakable(*mods)
75
+ end
118
76
 
119
- # Support up to one eigen level to support class methods
120
- eigen_class = Runtime.eigen_class(mod)
121
- BROKEN << eigen_class
122
- placeholder = TYPE_PLACEHOLDER_MAP[eigen_class]
123
- if !placeholder
124
- placeholder = TypePlaceholder.new()
125
- TYPE_PLACEHOLDER_MAP[eigen_class] = placeholder
126
- end
127
- eigen_class.extend(BrokenEigen)
77
+ # *DEPRECATED*: Use +Runtime.breakable()+ or +RubyBreaker.run()+ method
78
+ # instead.
79
+ module Breakable
80
+ def self.included(mod)
81
+ Runtime::BREAKABLES << mod << Runtime.eigen_class(mod)
128
82
  end
129
-
130
83
  end
131
84
 
85
+ # *DEPRECATED*: It has no effect.
86
+ module Broken
87
+ def self.included(mod)
88
+ # Runtime.broken(mod)
89
+ end
90
+ end
132
91
  end
@@ -0,0 +1,97 @@
1
+ require "ostruct"
2
+ require "optparse"
3
+ require "rake/testtask"
4
+ require "yaml"
5
+ require "tempfile"
6
+
7
+ module Rake
8
+
9
+ # This class can be used as a replacement for Rake::TestTask. It is a
10
+ # subclass of Rake::TestTask and maintains additional information for
11
+ # running RubyBreaker as a Rake test task.
12
+ #
13
+ # For example, the following shows how to run RubyBreaker in a test task:
14
+ #
15
+ # desc "Run testtask test"
16
+ # Rake::RubyBreakerTestTask.new(:"testtask_test") do |t|
17
+ # t.libs << "lib"
18
+ # t.test_files = ["test/testtask/tc_testtask.rb"]
19
+ # t.breakable = ["SampleClassA"]
20
+ # end
21
+ #
22
+ class RubyBreakerTestTask < Rake::TestTask
23
+
24
+ # List of Breakable modules/classes
25
+ attr_accessor :breakable
26
+
27
+ # RubyBreaker options
28
+ attr_accessor :rubybreaker_opts
29
+
30
+ # This overrides the testtask's constructor. In addition to the original
31
+ # behavior, it keeps track of RubyBreaker options and store them in a
32
+ # yaml file.
33
+ def initialize(taskname="", *args, &blk)
34
+
35
+ # Initialize extra instance variables
36
+ @rubybreaker_opts = []
37
+ @breakable = nil
38
+
39
+ # Call the original constructor first
40
+ super(taskname, *args, &blk)
41
+
42
+ # Parse the RubyBreaker options
43
+ case @rubybreaker_opts
44
+ when Array
45
+ opts = @rubybreaker_opts
46
+ when String
47
+ opts = @rubybreaker_opts.split(" ").select {|v| v != ""}
48
+ else
49
+ opts = []
50
+ end
51
+
52
+ # Construct the task configuration hash
53
+ config = {
54
+ name: taskname,
55
+ rubybreaker_opts: opts,
56
+ breakable: [], # Set doesn't work well with YAML; just use an array
57
+ test_files: @test_files,
58
+ }
59
+
60
+ # This allows a bulk declaration of Breakable modules/classes
61
+ @breakable.each { |b| config[:breakable] << b } if @breakable
62
+
63
+ # This code segment is a clever way to store yaml data in a ruby file
64
+ # that reads its own yaml data after __END__ when loaded.
65
+ code_data = <<-EOS
66
+ require "yaml"
67
+ f = File.new(__FILE__, "r")
68
+ while !(f.readline.match("^__END__.*$"))
69
+ # do nothing
70
+ end
71
+ data = f.read
72
+ $__rubybreaker_task = YAML.load(data)
73
+ __END__
74
+ #{YAML.dump(config)}
75
+ EOS
76
+
77
+ tmp_path = ""
78
+ # Tests are run different processes, so we must export this
79
+ # information to an external yaml file.
80
+ f = Tempfile.new(["#{taskname}",".rb"])
81
+ tmp_path = f.path
82
+ f.write(code_data)
83
+ f.close()
84
+
85
+ # Inject the -r option to load this yaml file
86
+ if @ruby_opts && @ruby_opts.empty?
87
+ @ruby_opts << "-r" << tmp_path
88
+ else
89
+ @ruby_opts = ["-r", tmp_path]
90
+ end
91
+
92
+ return self
93
+ end
94
+
95
+ end
96
+
97
+ end
@@ -9,7 +9,7 @@ if defined?(RSpec)
9
9
  end
10
10
 
11
11
  def describe(*args,&blk)
12
- RubyBreaker::Main.setup if defined?(RubyBreaker)
12
+ RubyBreaker.run if defined?(RubyBreaker)
13
13
  send(:"#{RUBYBREAKER_RSPEC_PREFIX}_describe", *args, &blk)
14
14
  end
15
15
 
@@ -1,38 +1,23 @@
1
1
  #--
2
- # This file mimics the Ruby testing framework. This is provided so that
3
- # RubyBreaker can be used seamlessly with the traditional Ruby framework
4
- # (supposedly :) ).
2
+ # This file overrides the test case behavior to work with RubyBreaker behind
3
+ # the scene without requiring the user to modify the code.
5
4
 
6
- module RubyBreaker
5
+ # Do this only if Test::Unit is defined
6
+ if defined?(Test) && defined?(Test::Unit)
7
7
 
8
- # This module overrides the normal behavior of Ruby Stdlib's TestCase
9
- # class.
10
- module TestCase
8
+ # This class is patched to run RubyBreaker along with the test cases.
9
+ class Test::Unit::TestCase
11
10
 
12
- def self.__rubybreaker_setup()
13
- Main.setup()
14
- end
11
+ # Save the original constructor method.
12
+ alias :__rubybreaker_initialize :initialize
15
13
 
16
- def self.__rubybreaker_teardown()
17
- # Main.output()
14
+ # This method overrides the original constructor to run RubyBreaker before
15
+ # calling the original constructor.
16
+ def initialize(*args, &blk)
17
+ RubyBreaker.run()
18
+ return send(:__rubybreaker_initialize, *args, &blk)
18
19
  end
19
20
 
20
- def self.included(mod)
21
-
22
- # hack to insert RubyBreaker's own setup and teardown methods
23
- mod.module_eval <<-EOS
24
-
25
- alias :__run :run
26
-
27
- def run(*args,&blk)
28
- RubyBreaker::TestCase.__rubybreaker_setup()
29
- __run(*args,&blk)
30
- RubyBreaker::TestCase.__rubybreaker_teardown()
31
- end
32
-
33
- EOS
34
-
35
- end
36
21
  end
37
22
  end
38
23
 
@@ -96,7 +96,7 @@ module RubyBreaker
96
96
  class SelfType < NominalType
97
97
 
98
98
  # This is a setter method for class variable mod.
99
- # NOTE: It is set every time Broken module is included.
99
+ # NOTE: It is set every time typesig() is called
100
100
  def self.set_self(mod)
101
101
  @@mod = mod
102
102
  end
@@ -9,7 +9,7 @@
9
9
  # any constraint graph to resolve subtype relations. This is the main
10
10
  # difference between Rubydust and RubyBreaker.
11
11
  #
12
- # If a module is not Broken but is Breakable (i.e., monitored), then it is
12
+ # If a module is not broken but is breakable (i.e., monitored), then it is
13
13
  # treated as non-Broken. At the end of the execution, the module will be
14
14
  # Broken--i.e., its type information is now revealed. If the user wishes to
15
15
  # use the result of the analysis, this type information will be documented
@@ -57,6 +57,11 @@ module RubyBreaker
57
57
 
58
58
  private
59
59
 
60
+ # This method determins if the module/class has its corresponding
61
+ def self.has_type_map?(mod)
62
+ return Runtime::TYPE_MAP[mod] != nil
63
+ end
64
+
60
65
  # Thie method checks if the module has all the methods specified in
61
66
  # meths array
62
67
  def self.module_has_methods?(mod, meths)
@@ -295,11 +300,11 @@ module RubyBreaker
295
300
  #
296
301
  def self.fusion_subtype_rel?(lhs,rhs)
297
302
  return false unless lhs.kind_of?(FusionType)
298
- if lhs.mod.kind_of?(Broken)
303
+ if self.has_type_map?(lhs.mod)
299
304
  if rhs.instance_of?(NominalType) # don't include self type
300
305
  if RubyTypeUtils.subclass_rel?(lhs.mod, rhs.mod)
301
306
  is_subtype = true
302
- elsif rhs.mod.kind_of?(Broken)
307
+ elsif self.has_type_map?(rhs.mod)
303
308
  # then do a type check for each method
304
309
  lhs_meths = Inspect.inspect_all(lhs.mod)
305
310
  rhs_meths = Inspect.inspect_all(rhs.mod)
@@ -311,7 +316,7 @@ module RubyBreaker
311
316
  elsif rhs.instance_of?(FusionType)
312
317
  if RubyTypeUtils.subclass_rel?(lhs.mod, rhs.mod)
313
318
  is_subtype = true
314
- elsif rhs.mod.kind_of?(Broken)
319
+ elsif self.has_type_map?(rhs.mod)
315
320
  # then do a type check for each method
316
321
  lhs_meths = Inspect.inspect_all(lhs.mod)
317
322
  rhs_meths = Inspect.inspect_meths(rhs.mod, lhs.meths.keys)
@@ -377,7 +382,7 @@ module RubyBreaker
377
382
  # If RHS is not broken, sorry no subtype relationship
378
383
  if RubyTypeUtils.subclass_rel?(lhs.mod, rhs.mod)
379
384
  is_subtype = true
380
- elsif lhs.kind_of?(Broken) && rhs.kind_of?(Broken)
385
+ elsif self.has_type_map?(lhs.mod) && self.has_type_map?(rhs.mod)
381
386
  is_subtype = true
382
387
  lhs_methods = lhs.mod.instance_methods
383
388
  rhs.meth_names.each {|m|
@@ -27,7 +27,6 @@ module RubyBreaker
27
27
  lower_case_and_underscored_word.to_s[0].chr.downcase + camelize(lower_case_and_underscored_word)[1..-1]
28
28
  end
29
29
  end
30
-
31
30
  end
32
31
 
33
32
  end