rubybreaker 0.0.1

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 (53) hide show
  1. data/AUTHORS +7 -0
  2. data/LICENSE +26 -0
  3. data/README.md +403 -0
  4. data/Rakefile +90 -0
  5. data/TODO +30 -0
  6. data/bin/gen_stub_rubylib +64 -0
  7. data/bin/rubybreaker +67 -0
  8. data/lib/rubybreaker/context.rb +122 -0
  9. data/lib/rubybreaker/debug.rb +48 -0
  10. data/lib/rubybreaker/error.rb +59 -0
  11. data/lib/rubybreaker/rubylib/core.rb +2316 -0
  12. data/lib/rubybreaker/rubylib.rb +3 -0
  13. data/lib/rubybreaker/runtime/inspector.rb +57 -0
  14. data/lib/rubybreaker/runtime/monitor.rb +235 -0
  15. data/lib/rubybreaker/runtime/object_wrapper.rb +77 -0
  16. data/lib/rubybreaker/runtime/overrides.rb +42 -0
  17. data/lib/rubybreaker/runtime/pluggable.rb +57 -0
  18. data/lib/rubybreaker/runtime/type_placeholder.rb +27 -0
  19. data/lib/rubybreaker/runtime/type_system.rb +228 -0
  20. data/lib/rubybreaker/runtime/typesig_parser.rb +45 -0
  21. data/lib/rubybreaker/runtime.rb +103 -0
  22. data/lib/rubybreaker/test/testcase.rb +39 -0
  23. data/lib/rubybreaker/test.rb +1 -0
  24. data/lib/rubybreaker/type/type.rb +241 -0
  25. data/lib/rubybreaker/type/type_comparer.rb +143 -0
  26. data/lib/rubybreaker/type/type_grammar.treetop +285 -0
  27. data/lib/rubybreaker/type/type_unparser.rb +142 -0
  28. data/lib/rubybreaker/type.rb +2 -0
  29. data/lib/rubybreaker/typing/rubytype.rb +47 -0
  30. data/lib/rubybreaker/typing/subtyping.rb +480 -0
  31. data/lib/rubybreaker/typing.rb +3 -0
  32. data/lib/rubybreaker/util.rb +31 -0
  33. data/lib/rubybreaker.rb +193 -0
  34. data/test/integrated/tc_method_missing.rb +30 -0
  35. data/test/integrated/tc_simple1.rb +77 -0
  36. data/test/runtime/tc_obj_wrapper.rb +73 -0
  37. data/test/runtime/tc_typesig_parser.rb +33 -0
  38. data/test/ts_integrated.rb +4 -0
  39. data/test/ts_runtime.rb +5 -0
  40. data/test/ts_type.rb +5 -0
  41. data/test/ts_typing.rb +4 -0
  42. data/test/type/tc_comparer.rb +211 -0
  43. data/test/type/tc_parser.rb +219 -0
  44. data/test/type/tc_unparser.rb +276 -0
  45. data/test/typing/tc_rubytype.rb +63 -0
  46. data/test/typing/tc_typing.rb +219 -0
  47. data/webpage/footer.html +5 -0
  48. data/webpage/generated_toc.js +319 -0
  49. data/webpage/header.html +14 -0
  50. data/webpage/images/logo.png +0 -0
  51. data/webpage/index.html +439 -0
  52. data/webpage/rubybreaker.css +53 -0
  53. metadata +119 -0
@@ -0,0 +1,228 @@
1
+ #--
2
+ # This file contains the default type system for RubyBreaker. It uses
3
+ # subtyping defined in ../typing/subtyping.rb. It is not a constraint-based
4
+ # type system and does not check type errors statically. The main purpose of
5
+ # this type system is to give a readable type signature to every method in
6
+ # designated modules and classes.
7
+
8
+ require_relative "object_wrapper"
9
+ require_relative "type_placeholder"
10
+ require_relative "../type"
11
+ require_relative "../typing"
12
+
13
+ module RubyBreaker
14
+
15
+ module Runtime
16
+
17
+ # This is the default type system for RubyBreaker. It can be overridden
18
+ # by a user specified type system. See +pluggable.rb+ for how this can
19
+ # be done.
20
+ class TypeSystem
21
+
22
+ include Pluggable # not needed but for the sake of documentation...
23
+ include TypeDefs
24
+
25
+ protected
26
+
27
+ # Check if the object is wrapped by a monitor
28
+ def is_object_wrapped?(obj)
29
+ return obj.respond_to?(WRAPPED_INDICATOR)
30
+ end
31
+
32
+ # This method is a helper for computing the least upper bound. It
33
+ # handles the case where existing method type is a method type (and
34
+ # not a method list type). If there is no compatibility of the two
35
+ # types, then it returns false.
36
+ def lub_helper(exist_meth_type, new_meth_type)
37
+
38
+ # most restrictive for the given test cases.
39
+ arg_types = []
40
+
41
+ exist_meth_type.arg_types.each_with_index do |exist_arg_type, i|
42
+ arg_type = nil
43
+ new_arg_type = new_meth_type.arg_types[i]
44
+ if !exist_arg_type
45
+ # nil means there hasn't been any type observed
46
+ arg_type = new_arg_type
47
+ elsif new_arg_type.subtype_of?(exist_arg_type)
48
+ arg_type = exist_arg_type
49
+ elsif !exist_arg_type.subtype_of?(new_arg_type)
50
+ # No subtype relation between them, so OR them
51
+ arg_type = OrType.new([new_arg_type, exist_arg_type])
52
+ end
53
+ arg_types << arg_type
54
+ end
55
+
56
+ new_ret_type = new_meth_type.ret_type
57
+ exist_ret_type = exist_meth_type.ret_type
58
+
59
+ if !exist_ret_type
60
+ ret_type = new_ret_type
61
+ resolved = true
62
+ elsif exist_ret_type.subtype_of?(new_ret_type)
63
+ ret_type = exist_ret_type
64
+ resolved = true
65
+ elsif new_ret_type.subtype_of?(exist_ret_type)
66
+ ret_type = new_ret_type
67
+ resolved = true
68
+ else
69
+ resolved = false
70
+ end
71
+
72
+ if resolved
73
+ exist_meth_type.arg_types = arg_types
74
+ exist_meth_type.ret_type = ret_type
75
+ end
76
+
77
+ return resolved
78
+ end
79
+
80
+ # This method computes the least upper bound of the existing method
81
+ # type and newly observed argument/block/return types. There are a few
82
+ # cases to consider:
83
+ #
84
+ # If the existing type is a method list type, the new observed type
85
+ # will be either "consolidated" into one of the method types in the
86
+ # list or added to the list.
87
+ #
88
+ # If there is no compatibility between the existing method type and
89
+ # the observed type, then the method type will be promoted to a method
90
+ # list type. And the newly observed type will be added to the list.
91
+ #
92
+ # For each method type,
93
+ #
94
+ # It basically consolidates the existing type information for the
95
+ # invoked method and the observed type.
96
+ #
97
+ # For arguments, we look for most general type that can handle all
98
+ # types we have seen. This means we find the super type of all types
99
+ # we have seen (excluding unknown types).
100
+ #
101
+ # For return, we look for most specific type that can handle both
102
+ # types. Therefore, if two types have no subtype relation, we AND
103
+ # them. But we do not allow AND types in the return type. We must turn
104
+ # the method type to a method list type.
105
+ #
106
+ # obj:: the receive of the method call
107
+ # inst_meths:: a hash object that maps method names to method types
108
+ # meth_name:: the name of the method being invoked
109
+ # retval:: the return value of the original method call
110
+ # args:: the arguments
111
+ # blk:: the block argument
112
+ #
113
+ def lub(obj, inst_meths, meth_name, retval, *args, &blk)
114
+
115
+ exist_meth_type = inst_meths[meth_name.to_sym]
116
+
117
+ # Construct the newly observed method type first
118
+ new_meth_type = MethodType.new(meth_name)
119
+ args.each {|arg|
120
+ if is_object_wrapped?(arg)
121
+ arg_type = arg.__rubybreaker_type
122
+ else
123
+ arg_type = NominalType.new(arg.class)
124
+ end
125
+ new_meth_type.arg_types << arg_type
126
+ }
127
+ if (obj == retval)
128
+ # the return value is same as the message receiver. This means the
129
+ # return value has the self type.
130
+ SelfType.set_self(obj.class)
131
+ ret_type = SelfType.new()
132
+ else
133
+ # Otherwise, construct a nominal type.
134
+ ret_type = NominalType.new(retval.class)
135
+ end
136
+ new_meth_type.ret_type = ret_type
137
+
138
+ resolved = false
139
+ if exist_meth_type.instance_of?(MethodListType)
140
+ exist_meth_type.types.each {|meth_type|
141
+ resolved = lub_helper(meth_type, new_meth_type)
142
+ break if resolved
143
+ }
144
+ else
145
+ resolved = lub_helper(exist_meth_type, new_meth_type)
146
+ if !resolved
147
+ # Could not resolve the types, so promote the method type to a
148
+ # method list type
149
+ exist_meth_type = MethodListType.new([exist_meth_type])
150
+ inst_meths[meth_name.to_sym] = exist_meth_type
151
+ end
152
+ end
153
+ if !resolved
154
+ exist_meth_type.types << new_meth_type
155
+ end
156
+ end
157
+
158
+ public
159
+
160
+ # This method occurs before every "monitored" method call. It wraps
161
+ # each argument with the object wrapper.
162
+ def before_method(obj, meth_info)
163
+
164
+ mod = obj.class
165
+ inst_meths = Breakable::TYPE_PLACEHOLDER_MAP[mod].inst_meths
166
+
167
+ # Let's take things out of the MethodInfo object
168
+ meth_name = meth_info.meth_name
169
+ args = meth_info.args
170
+ blk = meth_info.blk
171
+ ret = meth_info.ret
172
+
173
+ args = args.map do |arg|
174
+ if arg.kind_of?(TrueClass) || arg.kind_of?(FalseClass)
175
+ # XXX: would overrides resolve this issue?
176
+ arg
177
+ else
178
+ ObjectWrapper.new(arg)
179
+ end
180
+ end
181
+
182
+ Debug.msg("In module monitor_before #{meth_name}")
183
+
184
+ meth_type = inst_meths[meth_name]
185
+
186
+ if meth_type
187
+ # This means the method type has been created previously.
188
+ unless (blk == nil && meth_type.blk_type == nil) &&
189
+ (!blk || blk.arity == meth_type.blk_type.arg_types.length)
190
+ raise Errors::TypeError("Block usage is inconsistent")
191
+ end
192
+ else
193
+ # No method type has been created for this method yet. Create a
194
+ # blank method type (where each argument type, block type, and
195
+ # return type are all nil).
196
+ arg_types = args.map {|arg| nil }
197
+ blk_type = blk ? BlockType.new(Array.new(blk.arity), nil, nil) : nil
198
+ meth_type = MethodType.new(meth_name, arg_types, blk_type, nil)
199
+ inst_meths[meth_name] = meth_type
200
+ end
201
+
202
+ meth_info.args = args
203
+
204
+ end
205
+
206
+ # This method occurs after every "monitored" method call. It updates
207
+ # the type information.
208
+ def after_method(obj, meth_info)
209
+ mod = obj.class
210
+ # Take things out
211
+ meth_name = meth_info.meth_name
212
+ retval = meth_info.ret
213
+ args = meth_info.args
214
+ blk = meth_info.blk
215
+
216
+ Debug.msg("In module monitor_after #{meth_name}")
217
+
218
+ inst_meths = Breakable::TYPE_PLACEHOLDER_MAP[mod].inst_meths
219
+
220
+ # Compute the least upper bound
221
+ lub(obj, inst_meths,meth_name,retval,*args,&blk)
222
+
223
+ end
224
+
225
+ end
226
+ end
227
+
228
+ end
@@ -0,0 +1,45 @@
1
+ #--
2
+ # This program parses a type signature given by the Ruby programmer in the
3
+ # RubyBreaker type format.
4
+
5
+ require "treetop"
6
+ require_relative "../type"
7
+
8
+ module RubyBreaker
9
+
10
+ module Runtime
11
+
12
+ module TypeSigParser
13
+
14
+ Treetop.load "#{File.dirname(__FILE__)}/../type/type_grammar"
15
+ PARSER = TypeGrammarParser.new
16
+
17
+ public
18
+
19
+ # This is a simple redirecting method for parsing type signature. The
20
+ # only special thing about this method is that, if there are multiple
21
+ # lines in the signature, it will look at each line and construct a
22
+ # MethodListType to represent the intersection type.
23
+ def self.parse(str)
24
+ meth_types = []
25
+
26
+ # Get caller information and set the global location
27
+ my_caller = caller[1]
28
+ if my_caller
29
+ file,line,junk = my_caller.split(":")
30
+ Position.set(file,line,-1)
31
+ end
32
+
33
+ return PARSER.parse(str).value
34
+
35
+ rescue => e
36
+
37
+ puts e
38
+
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+
45
+ end
@@ -0,0 +1,103 @@
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
+
6
+ require_relative "runtime/overrides"
7
+ require_relative "runtime/typesig_parser"
8
+ require_relative "runtime/monitor"
9
+ require_relative "runtime/inspector"
10
+
11
+ module RubyBreaker
12
+
13
+ # This module should be included in classes or modules that you want to
14
+ # monitor during runtime. The concept is that once a Breakable module is
15
+ # monitored and its type documentation is generated, the module now becomes
16
+ # a Broken module. The actual implementation is a simple trigger that
17
+ # queues the target module into the list of modules to monitor. The queued
18
+ # modules are then modified to be monitored dynamically.
19
+ module Breakable
20
+
21
+ TYPE_PLACEHOLDER_MAP = {} # module => type_placeholder
22
+ MONITOR_MAP = {} # module => monitor
23
+
24
+ # when this module is included, simply keep track of this module so we
25
+ # can start monitoring
26
+ def self.included(mod)
27
+ BREAKABLE << mod
28
+ end
29
+
30
+ end
31
+
32
+ # This module is included for "broken" classes.
33
+ module Broken
34
+
35
+ include TypeDefs
36
+ include Runtime
37
+
38
+ TYPE_PLACEHOLDER_MAP = {} # module => type_placeholder
39
+
40
+ # This module will be "extended" to the meta class of the class that
41
+ # includes Broken module. This allows the meta class to call 'typesig'
42
+ # method to parse the type signature dynamically.
43
+ #
44
+ # Usage:
45
+ # Class A
46
+ # include RubyBreaker::Broken
47
+ #
48
+ # typesig("foo(fixnum) -> fixnum")
49
+ # def foo(x) ... end
50
+ # end
51
+ #
52
+ module BrokenMeta
53
+
54
+ include TypeDefs
55
+ include Runtime
56
+
57
+ # This method can be used at the meta level of the target module to
58
+ # specify the type of a method.
59
+ def typesig(str)
60
+ t = TypeSigParser.parse(str)
61
+ placeholder = TYPE_PLACEHOLDER_MAP[self]
62
+ if placeholder
63
+ meth_type = placeholder.inst_meths[t.meth_name]
64
+ if meth_type
65
+ # TODO: make a method list
66
+ if meth_type.instance_of?(MethodListType)
67
+ meth_type.types << t
68
+ else
69
+ # then upgrade it
70
+ placeholder.inst_meths[t.meth_name] = MethodListType.new([meth_type, t])
71
+ end
72
+ else
73
+ placeholder.inst_meths[t.meth_name] = t
74
+ end
75
+ end
76
+ return t
77
+ end
78
+
79
+ end
80
+
81
+ # This method is triggered when Broken module is included. This just
82
+ # extends BrokenMeta into the target module so "typesig" method can be
83
+ # called from the meta level of the module.
84
+ def self.included(mod)
85
+
86
+ # Add to the list of broken modules
87
+ BROKEN << mod
88
+
89
+ # This MUST BE set for self type to work in type signatures
90
+ SelfType.set_self(mod)
91
+
92
+ # Create if there is no type placeholder for this module yet
93
+ placeholder = TYPE_PLACEHOLDER_MAP[mod]
94
+ if !placeholder
95
+ placeholder = TypePlaceholder.new()
96
+ TYPE_PLACEHOLDER_MAP[mod] = placeholder
97
+ end
98
+ mod.extend(BrokenMeta)
99
+ end
100
+
101
+ end
102
+
103
+ end
@@ -0,0 +1,39 @@
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 :) ).
5
+
6
+ module RubyBreaker
7
+
8
+ # This module overrides the normal behavior of Ruby Stdlib's TestCase
9
+ # class.
10
+ module TestCase
11
+
12
+ def self.setup()
13
+ Main.setup()
14
+ end
15
+
16
+ def self.teardown()
17
+ # Main.output()
18
+ end
19
+
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::Utilities.rb_print("Running " + args[0].to_s)
29
+ RubyBreaker::TestCase.setup()
30
+ __run(*args,&blk)
31
+ RubyBreaker::TestCase.teardown()
32
+ end
33
+
34
+ EOS
35
+
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1 @@
1
+ require_relative "test/testcase"
@@ -0,0 +1,241 @@
1
+ #--
2
+ # This file contains the type structure used in RubyBreaker. Here we list
3
+ # types that are used (allowed) in RubyBreaker:
4
+ #
5
+ # AnyType represents basically any type in Ruby
6
+ # NilType represents a nil object
7
+ # SelfType represents "self"--the current object
8
+ # NominalType represents an object
9
+ # DuckType represents a partial object (a collection of methods)
10
+ # FusionType represents an object along with a set of methods
11
+ # MethodType represents a method
12
+ # BlockType represents a block
13
+ # OrType represents one of the many objects (i.e, OR)
14
+ # OptionalType represents an optional argument type
15
+ # VarLengthType represents a variable length argument type
16
+ # MethodListType represents one or more methods
17
+ #
18
+
19
+ require_relative "../util"
20
+ require_relative "../context.rb"
21
+
22
+ module RubyBreaker
23
+
24
+ # This module contains all RubyBreaker type definitions. This module has
25
+ # to be included to the module if you want to work with the type
26
+ # definitions that RubyBreaker provides (unless you want to add TypeDefs
27
+ # namespace in the module).
28
+ module TypeDefs
29
+
30
+ # This class is a catch-all. The constructor of this class must be
31
+ # called from children via super() in order to assign the position field
32
+ # variable.
33
+ #
34
+ # The optional arguments are args[0] = file name args[1] = line number
35
+ #
36
+ # args[2] = column position
37
+ #
38
+ # or
39
+ #
40
+ # args[0] = a Position, ObjectPosition, or Context object
41
+ #
42
+ class Type
43
+
44
+ # Speficies the context of the type.
45
+ attr_accessor :ctx
46
+
47
+ def initialize(*args)
48
+ case args[0]
49
+ when Context
50
+ @ctx = args[0]
51
+ when Position
52
+ @ctx = Context.new(args[0])
53
+ when ObjectPosition
54
+ @ctx = Context.new(args[0])
55
+ else
56
+ file = args[0]
57
+ line = args[1]
58
+ col = args[2]
59
+ pos = Position.new(file,line,col)
60
+ @ctx = Context.new(pos)
61
+ end
62
+ end
63
+ end
64
+
65
+ # This type can represent any object
66
+ class AnyType < Type
67
+ def initialize(*args)
68
+ super(*args)
69
+ end
70
+ end
71
+
72
+ # This type represents a nil
73
+ class NilType < Type
74
+ def initialize(*args)
75
+ super(*args)
76
+ end
77
+ end
78
+
79
+ # This class represents a concrete object like a Numeric or String. It
80
+ # stores the actual module in the instance variable @mod.
81
+ class NominalType < Type
82
+
83
+ # This accessor points to the actual module
84
+ attr_accessor :mod
85
+
86
+ def initialize(mod=nil,*args)
87
+ super(*args)
88
+ @mod = mod
89
+ end
90
+ end
91
+
92
+ # This type represents the self type. Note that this is a subclass of
93
+ # Nominal Type. It works just like nominal type except that it also points
94
+ # to the current object! See subtyping.rb for more detail on how this
95
+ # would impact typing.
96
+ class SelfType < NominalType
97
+
98
+ # This is a setter method for class variable mod.
99
+ # NOTE: It is set every time Broken module is included.
100
+ def self.set_self(mod)
101
+ @@mod = mod
102
+ end
103
+
104
+ # This is a getter method for class variable mod.
105
+ def self.get_self(mod)
106
+ @@mod = mod
107
+ end
108
+
109
+ def initialize(*args)
110
+ # NOTE: @@mod is not required in general, but for typing it is a must.
111
+ super(@@mod, *args)
112
+ end
113
+ end
114
+
115
+ # This class represents any object with certain methods
116
+ # Usage: [m1,m2,...] where m1...mn are method names
117
+ class DuckType < Type
118
+
119
+ # This accessor sets/gets method names in the duck type.
120
+ attr_accessor :meth_names
121
+
122
+ def initialize(meth_names=[],*args)
123
+ super(*args)
124
+ @meth_names = meth_names.map!{|n| n.to_sym}
125
+ end
126
+ def add_meth(meth_name)
127
+ @meth_names << meth_name.to_sym if !@meth_names.include?(meth_name)
128
+ end
129
+ end
130
+
131
+ # This class represents any object that has certain methods whose types
132
+ # are same as the given nominal type's counterparts.
133
+ # Usage: nominal_type[m1,m2,...]
134
+ class FusionType < DuckType
135
+
136
+ # This accessor sets/gets the nominal type to which the method names
137
+ # are bound.
138
+ attr_accessor :nom_type
139
+
140
+ def initialize(nom_type,meth_names=[],*args)
141
+ super(meth_names,*args)
142
+ @nom_type = nom_type
143
+ end
144
+
145
+ # This method gets the actual module of the nominal type for this
146
+ # fusion type. This is a shorthand for t1.nom_type.mod().
147
+ def mod()
148
+ return @nom_type.mod
149
+ end
150
+ end
151
+
152
+ # This class represents a block (in a method). It has zero or more argument
153
+ # types, nested block type (optional), and a return type.
154
+ class BlockType < Type
155
+
156
+ # This accessor sets/gets the argument types for this block type.
157
+ attr_accessor :arg_types
158
+
159
+ # This accessor sets/gets the block type for this block type.
160
+ attr_accessor :blk_type
161
+
162
+ # This accessor sets/gets the return type for this block type.
163
+ attr_accessor :ret_type
164
+
165
+ def initialize(arg_types=[],blk_type=nil,ret_type=nil,*args)
166
+ super(*args)
167
+ @arg_types = arg_types
168
+ @blk_type = blk_type
169
+ @ret_type = ret_type
170
+ end
171
+ end
172
+
173
+ # This class represents a method and is essentially same as block type
174
+ # except the method name.
175
+ class MethodType < BlockType
176
+
177
+ # This accessor sets/gets the method name for this method type.
178
+ attr_accessor :meth_name
179
+
180
+ def initialize(meth_name,arg_types=[],blk_type=nil,ret_type=nil,*args)
181
+ super(arg_types,blk_type,ret_type,*args)
182
+ @meth_name = meth_name.to_sym
183
+ end
184
+ end
185
+
186
+ # This class respresents an optional argument type
187
+ class OptionalType < Type
188
+
189
+ # This accessor sets/gets the inner type of this optional type.
190
+ attr_accessor :type
191
+
192
+ def initialize(type,*args)
193
+ super(*args)
194
+ @type = type
195
+ end
196
+ end
197
+
198
+ # This class represents a variable-length argument type
199
+ class VarLengthType < Type
200
+
201
+ # This accessor sets/gets the inner type of this variable length
202
+ # argument type.
203
+ attr_accessor :type
204
+
205
+ def initialize(type,*args)
206
+ super(*args)
207
+ @type = type
208
+ end
209
+ end
210
+
211
+ # This class represents one of many types
212
+ class OrType < Type
213
+
214
+ # This accessor sets/gets the inner types of this "or" type.
215
+ attr_accessor :types
216
+
217
+ def initialize(types=[],*args)
218
+ super(*args)
219
+ @types = types
220
+ end
221
+ end
222
+
223
+ # This class represents multiple method types.
224
+ class MethodListType < Type
225
+
226
+ # This accessor sets/gets the method types.
227
+ attr_accessor :types
228
+
229
+ def initialize(types=[],*args)
230
+ super(*args)
231
+ @types = types
232
+ end
233
+ end
234
+
235
+ end
236
+
237
+ # Include the module right away
238
+ include TypeDefs
239
+
240
+ end
241
+