rubybreaker 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/NEWS +6 -0
  2. data/VERSION +1 -1
  3. data/bin/rubybreaker +3 -3
  4. data/lib/rubybreaker.rb +15 -11
  5. data/lib/rubybreaker/doc/rdoc.rb +1 -1
  6. data/lib/rubybreaker/runtime/monitor.rb +8 -6
  7. data/lib/rubybreaker/runtime/object_wrapper.rb +38 -16
  8. data/lib/rubybreaker/runtime/overrides.rb +42 -30
  9. data/lib/rubybreaker/runtime/type_system.rb +45 -14
  10. data/lib/rubybreaker/type/type_unparser.rb +4 -8
  11. data/lib/rubybreaker/typing/subtyping.rb +1 -0
  12. data/test/integrated/tc_original_behavior.rb +38 -0
  13. data/test/integrated/tc_simple1.rb +20 -0
  14. data/test/integrated/tc_simple_algorithms.rb +135 -0
  15. data/test/runtime/tc_obj_wrapper.rb +3 -3
  16. data/test/ts_integrated.rb +1 -0
  17. data/test/type/tc_parser.rb +24 -0
  18. data/webpage/rdoc/Object.html +0 -2
  19. data/webpage/rdoc/Rake.html +0 -2
  20. data/webpage/rdoc/Rake/RubyBreakerTestTask.html +0 -2
  21. data/webpage/rdoc/RubyBreaker.html +1 -3
  22. data/webpage/rdoc/RubyBreaker/Breakable.html +0 -2
  23. data/webpage/rdoc/RubyBreaker/Broken.html +0 -2
  24. data/webpage/rdoc/RubyBreaker/Context.html +0 -2
  25. data/webpage/rdoc/RubyBreaker/Errors.html +0 -2
  26. data/webpage/rdoc/RubyBreaker/Errors/ArgumentTypeError.html +0 -2
  27. data/webpage/rdoc/RubyBreaker/Errors/ArityError.html +0 -2
  28. data/webpage/rdoc/RubyBreaker/Errors/InternalError.html +0 -2
  29. data/webpage/rdoc/RubyBreaker/Errors/InvalidSubtypeCheck.html +0 -2
  30. data/webpage/rdoc/RubyBreaker/Errors/InvalidTypeConstruction.html +0 -2
  31. data/webpage/rdoc/RubyBreaker/Errors/ReturnTypeError.html +0 -2
  32. data/webpage/rdoc/RubyBreaker/Errors/TypeError.html +0 -2
  33. data/webpage/rdoc/RubyBreaker/Errors/UserError.html +0 -2
  34. data/webpage/rdoc/RubyBreaker/ObjectPosition.html +0 -2
  35. data/webpage/rdoc/RubyBreaker/Position.html +0 -2
  36. data/webpage/rdoc/RubyBreaker/RubyTypeUtils.html +0 -2
  37. data/webpage/rdoc/RubyBreaker/Runtime.html +7 -3
  38. data/webpage/rdoc/RubyBreaker/Runtime/Inspector.html +0 -2
  39. data/webpage/rdoc/RubyBreaker/Runtime/MethodInfo.html +0 -2
  40. data/webpage/rdoc/RubyBreaker/Runtime/Monitor.html +12 -13
  41. data/webpage/rdoc/RubyBreaker/Runtime/MonitorInstaller.html +6 -7
  42. data/webpage/rdoc/RubyBreaker/Runtime/MonitorSwitch.html +4 -6
  43. data/webpage/rdoc/RubyBreaker/Runtime/ObjectWrapper.html +21 -19
  44. data/webpage/rdoc/RubyBreaker/Runtime/Pluggable.html +0 -2
  45. data/webpage/rdoc/RubyBreaker/Runtime/TypeSigParser.html +0 -2
  46. data/webpage/rdoc/RubyBreaker/Runtime/TypeSigUnparser.html +0 -2
  47. data/webpage/rdoc/RubyBreaker/Runtime/TypeSystem.html +52 -23
  48. data/webpage/rdoc/RubyBreaker/TypeComparer.html +0 -2
  49. data/webpage/rdoc/RubyBreaker/TypeDefs.html +0 -2
  50. data/webpage/rdoc/RubyBreaker/TypeDefs/AnyType.html +0 -2
  51. data/webpage/rdoc/RubyBreaker/TypeDefs/BlockType.html +0 -2
  52. data/webpage/rdoc/RubyBreaker/TypeDefs/DuckType.html +0 -2
  53. data/webpage/rdoc/RubyBreaker/TypeDefs/FusionType.html +0 -2
  54. data/webpage/rdoc/RubyBreaker/TypeDefs/MethodListType.html +0 -2
  55. data/webpage/rdoc/RubyBreaker/TypeDefs/MethodType.html +0 -2
  56. data/webpage/rdoc/RubyBreaker/TypeDefs/NilType.html +0 -2
  57. data/webpage/rdoc/RubyBreaker/TypeDefs/NominalType.html +0 -2
  58. data/webpage/rdoc/RubyBreaker/TypeDefs/OptionalType.html +0 -2
  59. data/webpage/rdoc/RubyBreaker/TypeDefs/OrType.html +0 -2
  60. data/webpage/rdoc/RubyBreaker/TypeDefs/SelfType.html +0 -2
  61. data/webpage/rdoc/RubyBreaker/TypeDefs/Type.html +2 -4
  62. data/webpage/rdoc/RubyBreaker/TypeDefs/VarLengthType.html +0 -2
  63. data/webpage/rdoc/RubyBreaker/TypeUnparser.html +1 -3
  64. data/webpage/rdoc/RubyBreaker/Typing.html +1 -3
  65. data/webpage/rdoc/RubyBreaker/Util.html +0 -2
  66. data/webpage/rdoc/Test.html +0 -2
  67. data/webpage/rdoc/Test/Unit.html +0 -2
  68. data/webpage/rdoc/created.rid +10 -10
  69. data/webpage/rdoc/index.html +0 -2
  70. data/webpage/rdoc/js/search_index.js +1 -1
  71. data/webpage/rdoc/table_of_contents.html +31 -38
  72. metadata +3 -3
  73. data/webpage/rdoc/RubyBreaker/RDocSupport.html +0 -328
data/NEWS CHANGED
@@ -1,3 +1,9 @@
1
+ # VERSION 0.0.9
2
+ * More critical bug fixes
3
+
4
+ # VERSION 0.0.8
5
+ * Bug fixes
6
+
1
7
  # VERSION 0.0.7
2
8
  * Early dynamic type check is implemented.
3
9
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.8
1
+ 0.0.9
@@ -9,10 +9,10 @@ module RubyBreaker
9
9
  exit(1)
10
10
  end
11
11
 
12
- # This method prepares shell mode execution of RubyBreaker.
12
+ # This method prepares the command mode execution of RubyBreaker.
13
13
  def self.main()
14
14
  RubyBreaker.setup_logger()
15
- RubyBreaker.verbose("Running RubyBreaker in shell mode")
15
+ RubyBreaker.verbose("Running RubyBreaker in the command mode")
16
16
 
17
17
  # parse the command-line arguments
18
18
  OPTION_PARSER.parse!
@@ -60,7 +60,7 @@ module RubyBreaker
60
60
  self.verbose("Done importing #{lib}")
61
61
  end
62
62
 
63
- # Now, RubyBreaker shell mode will run this
63
+ # Runs the main library code at this point
64
64
  RubyBreaker.run()
65
65
 
66
66
  # Run the program file!
@@ -133,18 +133,22 @@ module RubyBreaker
133
133
  if fname && OPTIONS[:save_output]
134
134
  # Check if the file already exists--that is, if it was used for input
135
135
  io_exist = File.exists?(fname)
136
- RubyBreaker.verbose("Saving it to #{fname}")
137
- # Append the result to the input file (or create a new file)
138
- fmode = OPTIONS[:append] ? "a" : "w"
139
- open(fname, fmode) do |f|
140
- # When append, do not write the header
141
- unless OPTIONS[:append]
142
- f.puts "# This file is auto-generated by RubyBreaker"
136
+ if File.writable?(fname)
137
+ RubyBreaker.verbose("Saving it to #{fname}")
138
+ # Append the result to the input file (or create a new file)
139
+ fmode = OPTIONS[:append] ? "a" : "w"
140
+ open(fname, fmode) do |f|
141
+ # When append, do not write the header
142
+ unless OPTIONS[:append]
143
+ f.puts "# This file is auto-generated by RubyBreaker"
144
+ end
145
+ # But time stamp always
146
+ f.puts "# Last modified: #{Time.now}"
147
+ f.puts "require \"rubybreaker\"" unless OPTIONS[:append]
148
+ f.print code
143
149
  end
144
- # But time stamp always
145
- f.puts "# Last modified: #{Time.now}"
146
- f.puts "require \"rubybreaker\"" unless OPTIONS[:append]
147
- f.print code
150
+ else
151
+ RubyBreaker.verbose("Cannot write to #{fname}.")
148
152
  end
149
153
  end
150
154
 
@@ -5,7 +5,7 @@ module RubyBreaker
5
5
 
6
6
  # This module has functionalities that are necessary for supporting RDoc
7
7
  # output
8
- module RDocSupport
8
+ module RDocSupport #:nodoc:
9
9
 
10
10
  include TypeDefs
11
11
 
@@ -94,14 +94,13 @@ module RubyBreaker
94
94
  mm.check_before_method(obj, meth_info)
95
95
  end
96
96
  rescue ::Exception => e
97
+ RubyBreaker.log("Exception #{e.class} has been raised.", :debug, CONTEXT)
97
98
  # Trap it, turn on the global monitor and then re-raise the
98
99
  # exception
99
100
  GLOBAL_MONITOR_SWITCH.turn_on()
100
101
  raise e
101
102
  end
102
103
 
103
- RubyBreaker.log("break_before_method ended")
104
-
105
104
  # we are going to turn the switch back on
106
105
  GLOBAL_MONITOR_SWITCH.turn_on()
107
106
 
@@ -109,9 +108,10 @@ module RubyBreaker
109
108
  retval = obj.send(stub_meth_name.to_sym, *meth_info.args,
110
109
  &meth_info.blk)
111
110
 
112
- # turn it off
111
+ # turn the switch off again
113
112
  GLOBAL_MONITOR_SWITCH.turn_off()
114
113
 
114
+ # Remember the return value in the method info object.
115
115
  meth_info.ret = retval
116
116
 
117
117
  begin
@@ -124,6 +124,7 @@ module RubyBreaker
124
124
  rescue ::Exception => e
125
125
  # Trap it, turn on the global monitor and then re-raise the
126
126
  # exception
127
+ RubyBreaker.log("Exception #{e.class} has been raised.", :debug, CONTEXT)
127
128
  GLOBAL_MONITOR_SWITCH.turn_on()
128
129
  raise e
129
130
  end
@@ -143,7 +144,7 @@ module RubyBreaker
143
144
 
144
145
  # This method returns the alternative (renamed) method name
145
146
  def self.get_alt_meth_name(meth_name)
146
- return "__#{meth_name}"
147
+ return "__rubybreaker_#{meth_name}"
147
148
  end
148
149
 
149
150
  # This method returns the original method name
@@ -237,11 +238,11 @@ module RubyBreaker
237
238
  # Installs an module (class) monitor to the object.
238
239
  def self.install_monitor(monitor_type, mod)
239
240
 
240
- RubyBreaker.log("Installing module monitor for #{mod}")
241
+ RubyBreaker.log("Installing #{monitor_type} monitor for #{mod} started.")
241
242
 
242
243
  # Do not re-install monitor if already done so.
243
244
  if MONITOR_MAP[mod]
244
- RubyBreaker.log("Skip #{mod} as it has a monitor installed.")
245
+ RubyBreaker.log("#{mod} already has a monitor installed.")
245
246
  return
246
247
  end
247
248
 
@@ -266,6 +267,7 @@ module RubyBreaker
266
267
  end
267
268
  end
268
269
 
270
+ RubyBreaker.log("Installing #{monitor_type} monitor for #{mod} ended.")
269
271
  end
270
272
 
271
273
  end
@@ -35,13 +35,25 @@ module RubyBreaker
35
35
  return @__rubybreaker_type
36
36
  end
37
37
 
38
+ # This method computes the wrap level of any given wrapped object. In
39
+ # theory, this should always be 1.
40
+ #
41
+ # Used for internal debugging purpose only
42
+ def __rubybreaker_wrap_level() #:nodoc:
43
+ val = 1
44
+ if @__rubybreaker_obj.respond_to?(WRAPPED_INDICATOR)
45
+ val += @__rubybreaker_obj.__rubybreaker_wrap_level
46
+ end
47
+ return val
48
+ end
49
+
38
50
  #--
39
51
  # The following code generates the "serious problem" warning which is
40
52
  # suppressed by the hack using $VERBOSE. This is ok. This meta
41
53
  # programming code block re-defines BasicObject's methods to redirect
42
54
  # to the actual object.
43
55
  [:"!", :"!=", :"==", :"equal?", :"eql?", :"__id__", :"object_id",
44
- :"send", :"__send__", :"instance_eval",
56
+ :"send", :"__send__", :"instance_eval", :class,
45
57
  :"instance_exec"].each do |meth|
46
58
 
47
59
  orig_verbose = $VERBOSE
@@ -65,14 +77,20 @@ module RubyBreaker
65
77
  return true if mname.to_sym == WRAPPED_INDICATOR
66
78
  return @__rubybreaker_obj.respond_to?(mname)
67
79
  end
80
+
81
+ # # Keep track of methods that MUST NOT take wrapped arguments.
82
+ # WRAP_BLACKLIST = {
83
+ # ::Array => [:[], :[]=],
84
+ # ::Hash => [:[], :[]=],
85
+ # }
68
86
 
69
87
  # This method missing method redirects all other method calls.
70
88
  def method_missing(mname,*args,&blk)
71
- ::RubyBreaker.log("Method_missing for #{mname}")
72
89
  if GLOBAL_MONITOR_SWITCH.switch
73
90
 
74
91
  # Be safe and turn the switch off
75
92
  GLOBAL_MONITOR_SWITCH.turn_off
93
+ ::RubyBreaker.log("Object wrapper method_missing for #{mname} started")
76
94
 
77
95
  # Must handle send method specially (do not track them)
78
96
  if [:"__send__", :send].include?(mname)
@@ -88,16 +106,18 @@ module RubyBreaker
88
106
  is_obj_mod = (obj.class == ::Class or obj.class == ::Module)
89
107
  mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
90
108
 
91
- # Monitor map doesn't exist MEANS it's not being monitored.
92
- unless MONITOR_MAP[mod]
93
- args.map! do |arg|
94
- if arg.respond_to?(WRAPPED_INDICATOR)
95
- arg.__rubybreaker_obj
96
- else
97
- arg
98
- end
99
- end
100
- end
109
+ # # There are certain methods that should not take wrapped
110
+ # # argument(s) whatsoever. Use WRAP_BLACKLIST for these.
111
+ # if !MONITOR_MAP[mod] && WRAP_BLACKLIST[mod] &&
112
+ # WRAP_BLACKLIST[mod].include?(mname)
113
+ # args.map! do |arg|
114
+ # if arg.respond_to?(WRAPPED_INDICATOR)
115
+ # arg.__rubybreaker_obj
116
+ # else
117
+ # arg
118
+ # end
119
+ # end
120
+ # end
101
121
 
102
122
  # Turn on the global switch again
103
123
  GLOBAL_MONITOR_SWITCH.turn_on
@@ -105,13 +125,15 @@ module RubyBreaker
105
125
  # And call the original method
106
126
  retval = @__rubybreaker_obj.send(mname, *args, &blk)
107
127
 
108
- # No need to wrap the object again...if it's wrapped already
109
- unless retval.respond_to?(WRAPPED_INDICATOR)
110
- retval = ObjectWrapper.new(retval)
111
- end
128
+ # # No need to wrap the object again...if it's wrapped already
129
+ # unless retval.respond_to?(WRAPPED_INDICATOR)
130
+ # retval = ObjectWrapper.new(retval)
131
+ # end
112
132
  else
133
+ ::RubyBreaker.log("Object wrapper method_missing for #{mname} started")
113
134
  retval = @__rubybreaker_obj.send(mname, *args, &blk)
114
135
  end
136
+ ::RubyBreaker.log("Object wrapper method_missing for #{mname} ended")
115
137
  return retval
116
138
  end
117
139
  end
@@ -19,19 +19,31 @@ module RubyBreaker
19
19
  # indicate overridden methods.
20
20
  OVERRIDE_PREFIX = "__rubybreaker"
21
21
 
22
- # Prohibit these module/class+method from being overriden
22
+ # Prohibit these module/class+method from being overriden.
23
23
  BLACKLIST = {
24
24
  String => [:to_s, :<<, :concat, :gsub],
25
25
  }
26
26
 
27
+ # Allow certain methods of these classes/modules to be overrriden. That
28
+ # is, they will take unwrapped arguments whatsoever.
29
+ WHITELIST = {
30
+ Kernel => [:puts, :putc, :gets, :print, :printf, :raise],
31
+ IO => [:getc, :gets, :putc, :puts, :print, :printf,
32
+ :readlines, :readline, :read],
33
+ Object => [:"==", :equal?, :eql?, :"!="],
34
+ Enumerable => [:"==", :equal?, :eql?, :"!="],
35
+ Array => [:"==", :equal?, :eql?, :"!=", :[], :[]=],
36
+ Hash => [:"==", :equal?, :eql?, :"!=", :[], :[]=],
37
+ }
38
+
27
39
  end
28
40
 
29
41
  end
30
42
 
31
43
  # TODO: More IO related stuff need to be overriden!
32
- [Kernel, IO].each do |mod|
44
+ RubyBreaker::Runtime::WHITELIST.each_pair do |mod, mlist|
33
45
 
34
- [:"puts", :"putc", :"printf", :print].each do |meth_name|
46
+ mlist.each do |meth_name|
35
47
 
36
48
  mod.module_eval <<-EOS
37
49
 
@@ -58,7 +70,7 @@ end
58
70
 
59
71
  end
60
72
 
61
- [Symbol, Numeric, Fixnum, Float, Integer, Bignum, String].each do |mod|
73
+ [Exception, StandardError, ArgumentError, Symbol, Numeric, Fixnum, Float, Integer, Bignum, String].each do |mod|
62
74
  mod.instance_methods(false).each do |meth_name|
63
75
  black_list = RubyBreaker::Runtime::BLACKLIST
64
76
  next if black_list[mod] && black_list[mod].include?(meth_name)
@@ -83,32 +95,32 @@ end
83
95
  end
84
96
  end
85
97
 
86
- # TODO: add more modules here as necessary!
87
- [Object, Enumerable, Array, Hash].each do |mod|
88
-
89
- [:"==", :equal?, :eql?].each do |meth_name|
90
-
91
- # Create a unique alias name for each module. (It causes some issue when
92
- # not done this way.)
93
- alias_name = "RubyBreaker::Runtime::OVERRIDE_PREFIX_#{mod.object_id}" +
94
- "_#{meth_name}"
95
-
96
- mod.module_eval <<-EOS
97
-
98
- alias :"#{alias_name}" :"#{meth_name}"
99
-
100
- def #{meth_name}(other)
101
- if other.respond_to?(RubyBreaker::Runtime::WRAPPED_INDICATOR)
102
- other = other.__rubybreaker_obj
103
- end
104
- return self.send(:"#{alias_name}",other)
105
- end
106
-
107
- EOS
108
-
109
- end
110
-
111
- end
98
+ # # TODO: add more modules here as necessary!
99
+ # [Object, Enumerable, Array, Hash].each do |mod|
100
+ #
101
+ # [:"==", :equal?, :eql?, :"!="].each do |meth_name|
102
+ #
103
+ # # Create a unique alias name for each module. (It causes some issue when
104
+ # # not done this way.)
105
+ # alias_name = "RubyBreaker::Runtime::OVERRIDE_PREFIX_#{mod.object_id}" +
106
+ # "_#{meth_name}"
107
+ #
108
+ # mod.module_eval <<-EOS
109
+ #
110
+ # alias :"#{alias_name}" :"#{meth_name}"
111
+ #
112
+ # def #{meth_name}(other)
113
+ # if other.respond_to?(RubyBreaker::Runtime::WRAPPED_INDICATOR)
114
+ # other = other.__rubybreaker_obj
115
+ # end
116
+ # return self.send(:"#{alias_name}",other)
117
+ # end
118
+ #
119
+ # EOS
120
+ #
121
+ # end
122
+ #
123
+ # end
112
124
 
113
125
 
114
126
 
@@ -41,21 +41,31 @@ module RubyBreaker
41
41
  # most restrictive for the given test cases.
42
42
  arg_types = []
43
43
 
44
+ # Resolve the argument types first.
44
45
  exist_meth_type.arg_types.each_with_index do |exist_arg_type, i|
45
46
  arg_type = nil
46
47
  new_arg_type = new_meth_type.arg_types[i]
47
48
  if !exist_arg_type
48
- # nil means there hasn't been any type observed
49
+ # nil means there hasn't been any type observed so use the new
50
+ # argument type as "resolved".
49
51
  arg_type = new_arg_type
50
52
  elsif new_arg_type.subtype_of?(exist_arg_type)
53
+ # Pick the subtype argument since we are resolving in
54
+ # contra-variance
55
+ arg_type = new_arg_type
56
+ elsif exist_arg_type.subtype_of?(new_arg_type)
57
+ # Pick the subtype argument since we are resolving in
58
+ # contra-variance
51
59
  arg_type = exist_arg_type
52
- elsif !exist_arg_type.subtype_of?(new_arg_type)
53
- # No subtype relation between them, so OR them
60
+ else
61
+ # No subtype relation between them, so OR them.
54
62
  arg_type = OrType.new([new_arg_type, exist_arg_type])
55
63
  end
56
64
  arg_types << arg_type
57
65
  end
58
66
 
67
+ # Now, resolve the return type
68
+
59
69
  new_ret_type = new_meth_type.ret_type
60
70
  exist_ret_type = exist_meth_type.ret_type
61
71
 
@@ -63,10 +73,12 @@ module RubyBreaker
63
73
  ret_type = new_ret_type
64
74
  resolved = true
65
75
  elsif exist_ret_type.subtype_of?(new_ret_type)
66
- ret_type = exist_ret_type
76
+ # Co-variance
77
+ ret_type = new_ret_type
67
78
  resolved = true
68
79
  elsif new_ret_type.subtype_of?(exist_ret_type)
69
- ret_type = new_ret_type
80
+ # Co-variance
81
+ ret_type = exist_ret_type
70
82
  resolved = true
71
83
  else
72
84
  resolved = false
@@ -213,6 +225,8 @@ module RubyBreaker
213
225
  args = meth_info.args
214
226
  # blk = meth_info.blk
215
227
 
228
+ RubyBreaker.log("check_before_method #{mod}##{meth_name} started")
229
+
216
230
  # Get the registered method type for this method
217
231
  meth_type = meth_type_map[meth_name]
218
232
 
@@ -263,6 +277,7 @@ module RubyBreaker
263
277
  end
264
278
  end
265
279
 
280
+ RubyBreaker.log("check_before_method #{mod}##{meth_name} ended")
266
281
  end
267
282
 
268
283
  # This method is invoked after the original method is executed.
@@ -270,13 +285,16 @@ module RubyBreaker
270
285
  is_obj_mod = (obj.class == Class or obj.class == Module)
271
286
  mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
272
287
 
288
+ # Get the method type map for the module/class from the global map.
273
289
  meth_type_map = TYPE_MAP[mod]
274
- return unless meth_type_map
290
+ return unless meth_type_map
275
291
 
276
292
  # Let's take things out of the MethodInfo object
277
293
  meth_name = meth_info.meth_name
278
294
  ret = meth_info.ret
279
295
 
296
+ RubyBreaker.log("check_after_method #{mod}##{meth_name} started")
297
+
280
298
  # Get the registered method type for this method
281
299
  meth_type = meth_type_map[meth_name]
282
300
 
@@ -286,6 +304,8 @@ module RubyBreaker
286
304
  " return value does not have type #{ret_type.unparse()}."
287
305
  raise Errors::ReturnTypeError.new(msg)
288
306
  end
307
+
308
+ RubyBreaker.log("check_after_method #{mod}##{meth_name} started")
289
309
  end
290
310
 
291
311
  # This method occurs before every call to a "monitored" method in a
@@ -298,30 +318,37 @@ module RubyBreaker
298
318
  is_obj_mod = (obj.class == Class or obj.class == Module)
299
319
  mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
300
320
 
301
- meth_type_map = TYPE_MAP[mod]
302
-
303
321
  # Let's take things out of the MethodInfo object
304
322
  meth_name = meth_info.meth_name
305
323
  args = meth_info.args
306
324
  blk = meth_info.blk
307
325
  ret = meth_info.ret
308
326
 
327
+ RubyBreaker.log("break_before_method #{mod}##{meth_name} started")
328
+
309
329
  args = args.map do |arg|
310
330
  if arg == nil || arg.kind_of?(TrueClass) || arg.kind_of?(FalseClass)
311
331
  # XXX: would overrides resolve this issue?
312
332
  arg
333
+ elsif arg.respond_to?(WRAPPED_INDICATOR)
334
+ # Don't need to wrap an object that is already wrapped
335
+ arg
313
336
  else
314
337
  ObjectWrapper.new(arg)
315
338
  end
316
339
  end
317
340
 
318
- RubyBreaker.log("In module monitor_before #{meth_name}")
319
-
341
+ # Using this module object, retrieve the method type map which
342
+ # maps method names to method types.
343
+ meth_type_map = TYPE_MAP[mod]
344
+
345
+ # Using the method name, get the type of this method from the map.
320
346
  meth_type = meth_type_map[meth_name]
321
347
 
322
348
  if meth_type
323
349
  # This means the method type has been created previously.
324
- unless (blk == nil && meth_type.blk_type == nil) &&
350
+ unless !meth_type.instance_of?(MethodType) ||
351
+ (blk == nil && meth_type.blk_type == nil) &&
325
352
  (!blk || blk.arity == meth_type.blk_type.arg_types.length)
326
353
  raise Errors::TypeError.new("Block usage is inconsistent")
327
354
  end
@@ -349,6 +376,8 @@ module RubyBreaker
349
376
 
350
377
  meth_info.args = args
351
378
 
379
+ RubyBreaker.log("break_before_method #{mod}##{meth_name} ended")
380
+
352
381
  end
353
382
 
354
383
  # This method occurs after every call to a "monitored" method call of
@@ -359,16 +388,16 @@ module RubyBreaker
359
388
  is_obj_mod = (obj.class == Class or obj.class == Module)
360
389
  mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
361
390
 
362
- # Take things out
391
+ # Take things out of the method info object
363
392
  meth_name = meth_info.meth_name
364
393
  retval = meth_info.ret
365
394
  args = meth_info.args
366
395
  blk = meth_info.blk
367
396
 
368
- RubyBreaker.log("In module monitor_after #{meth_name}")
397
+ RubyBreaker.log("break_after_method #{mod}##{meth_name} started")
369
398
 
370
399
  # Compute the least upper bound
371
- lub(obj, TYPE_MAP[mod],meth_name,retval,*args,&blk)
400
+ lub(obj, TYPE_MAP[mod], meth_name, retval, *args, &blk)
372
401
 
373
402
  if obj == retval
374
403
  # It is possible that the method receiver is a wrapped object if
@@ -378,6 +407,8 @@ module RubyBreaker
378
407
  meth_info.ret = obj
379
408
  end
380
409
 
410
+ RubyBreaker.log("break_after_method #{mod}##{meth_name} ended")
411
+
381
412
  end
382
413
 
383
414
  end