rubybreaker 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/ABOUT.md +20 -0
  2. data/NEWS +5 -0
  3. data/README.md +16 -352
  4. data/Rakefile +30 -16
  5. data/TOPICS.md +55 -0
  6. data/TUTORIAL.md +291 -0
  7. data/VERSION +1 -1
  8. data/bin/rubybreaker +32 -14
  9. data/lib/rubybreaker/runtime/monitor.rb +1 -1
  10. data/lib/rubybreaker/runtime.rb +41 -21
  11. data/lib/rubybreaker/task.rb +15 -9
  12. data/lib/rubybreaker/test/rspec.rb +3 -3
  13. data/lib/rubybreaker/test/testcase.rb +3 -3
  14. data/lib/rubybreaker.rb +31 -16
  15. data/test/integrated/{tc_both_broken_breakable.rb → tc_both_documented_and_undocumented.rb} +3 -4
  16. data/test/integrated/tc_class_methods.rb +1 -1
  17. data/test/integrated/tc_inherit_broken.rb +1 -1
  18. data/test/integrated/tc_method_missing.rb +1 -1
  19. data/test/integrated/tc_namespace.rb +1 -1
  20. data/test/integrated/tc_simple1.rb +1 -1
  21. data/test/testtask/tc_testtask.rb +2 -2
  22. data/test/ts_integrated.rb +1 -1
  23. data/test/ts_rspec.rb +1 -1
  24. data/webpage/about.html +50 -0
  25. data/webpage/footer.html +6 -1
  26. data/webpage/header.html +9 -3
  27. data/webpage/images/logo.png +0 -0
  28. data/webpage/images/title.png +0 -0
  29. data/webpage/index.html +31 -367
  30. data/webpage/rdoc/Object.html +3 -103
  31. data/webpage/rdoc/Rake/RubyBreakerTestTask.html +80 -18
  32. data/webpage/rdoc/Rake.html +3 -7
  33. data/webpage/rdoc/RubyBreaker/Breakable.html +4 -8
  34. data/webpage/rdoc/RubyBreaker/Broken.html +4 -8
  35. data/webpage/rdoc/RubyBreaker/Context.html +3 -7
  36. data/webpage/rdoc/RubyBreaker/Errors/InternalError.html +3 -7
  37. data/webpage/rdoc/RubyBreaker/Errors/InvalidSubtypeCheck.html +3 -7
  38. data/webpage/rdoc/RubyBreaker/Errors/InvalidTypeConstruction.html +3 -7
  39. data/webpage/rdoc/RubyBreaker/Errors/SubtypeFailure.html +3 -7
  40. data/webpage/rdoc/RubyBreaker/Errors/TypeError.html +3 -7
  41. data/webpage/rdoc/RubyBreaker/Errors/UserError.html +3 -7
  42. data/webpage/rdoc/RubyBreaker/Errors.html +3 -7
  43. data/webpage/rdoc/RubyBreaker/ObjectPosition.html +3 -7
  44. data/webpage/rdoc/RubyBreaker/Position.html +3 -7
  45. data/webpage/rdoc/RubyBreaker/RDocSupport.html +3 -7
  46. data/webpage/rdoc/RubyBreaker/RubyTypeUtils.html +3 -7
  47. data/webpage/rdoc/RubyBreaker/Runtime/Inspector.html +3 -7
  48. data/webpage/rdoc/RubyBreaker/Runtime/MethodInfo.html +3 -7
  49. data/webpage/rdoc/RubyBreaker/Runtime/Monitor.html +3 -7
  50. data/webpage/rdoc/RubyBreaker/Runtime/MonitorInstaller.html +10 -14
  51. data/webpage/rdoc/RubyBreaker/Runtime/MonitorSwitch.html +3 -7
  52. data/webpage/rdoc/RubyBreaker/Runtime/MonitorUtils.html +3 -7
  53. data/webpage/rdoc/RubyBreaker/Runtime/ObjectWrapper.html +3 -7
  54. data/webpage/rdoc/RubyBreaker/Runtime/Pluggable.html +3 -7
  55. data/webpage/rdoc/RubyBreaker/Runtime/TypeSigParser.html +3 -7
  56. data/webpage/rdoc/RubyBreaker/Runtime/TypeSigUnparser.html +3 -7
  57. data/webpage/rdoc/RubyBreaker/Runtime/TypeSystem.html +3 -7
  58. data/webpage/rdoc/RubyBreaker/Runtime.html +42 -39
  59. data/webpage/rdoc/RubyBreaker/TypeComparer.html +3 -7
  60. data/webpage/rdoc/RubyBreaker/TypeDefs/AnyType.html +3 -7
  61. data/webpage/rdoc/RubyBreaker/TypeDefs/BlockType.html +3 -7
  62. data/webpage/rdoc/RubyBreaker/TypeDefs/DuckType.html +3 -7
  63. data/webpage/rdoc/RubyBreaker/TypeDefs/FusionType.html +3 -7
  64. data/webpage/rdoc/RubyBreaker/TypeDefs/MethodListType.html +3 -7
  65. data/webpage/rdoc/RubyBreaker/TypeDefs/MethodType.html +3 -7
  66. data/webpage/rdoc/RubyBreaker/TypeDefs/NilType.html +3 -7
  67. data/webpage/rdoc/RubyBreaker/TypeDefs/NominalType.html +3 -7
  68. data/webpage/rdoc/RubyBreaker/TypeDefs/OptionalType.html +3 -7
  69. data/webpage/rdoc/RubyBreaker/TypeDefs/OrType.html +3 -7
  70. data/webpage/rdoc/RubyBreaker/TypeDefs/SelfType.html +3 -7
  71. data/webpage/rdoc/RubyBreaker/TypeDefs/Type.html +3 -7
  72. data/webpage/rdoc/RubyBreaker/TypeDefs/VarLengthType.html +3 -7
  73. data/webpage/rdoc/RubyBreaker/TypeDefs.html +3 -7
  74. data/webpage/rdoc/RubyBreaker/TypeUnparser.html +3 -7
  75. data/webpage/rdoc/RubyBreaker/Typing.html +3 -7
  76. data/webpage/rdoc/RubyBreaker/Util.html +3 -7
  77. data/webpage/rdoc/RubyBreaker.html +48 -15
  78. data/webpage/rdoc/Test/Unit.html +3 -7
  79. data/webpage/rdoc/Test.html +3 -7
  80. data/webpage/rdoc/created.rid +18 -17
  81. data/webpage/rdoc/index.html +3 -7
  82. data/webpage/rdoc/js/search_index.js +1 -1
  83. data/webpage/rdoc/table_of_contents.html +28 -36
  84. data/webpage/rubybreaker.css +8 -6
  85. data/webpage/topics.html +85 -0
  86. data/webpage/tutorial.html +331 -0
  87. metadata +14 -8
  88. data/lib/rubybreaker/doc.rb +0 -3
  89. data/webpage/rdoc/Kernel.html +0 -286
  90. data/webpage/rdoc/Test/Unit/TestCase.html +0 -309
data/ABOUT.md ADDED
@@ -0,0 +1,20 @@
1
+ # About
2
+
3
+ RubyBreaker has its root in Rubydust (which stands for Ruby Dynamic
4
+ Unraveling of Static Types), an academic research project designed and
5
+ implemented at University of Maryland. However, unlike Rubydust,
6
+ RubyBreaker aims to be a practical documentation tool for Ruby rather than a
7
+ full-scale type inference tool. Although it is certainly possible that
8
+ RubyBreaker evolves into something more solid in its type system, the
9
+ primary goal of this project is to help Ruby programmers practically as much
10
+ as possible.
11
+
12
+ ## Acknowledgment
13
+
14
+ The term, "Fusion Type," is first coined by Professor Michael W. Hicks at
15
+ University of Maryland and represents an object using a structural type with
16
+ respect to a nominal type.
17
+
18
+ ## Copyright
19
+ Copyright (c) 2012 Jong-hoon (David) An. All Rights Reserved.
20
+
data/NEWS CHANGED
@@ -1,3 +1,8 @@
1
+ # VERSION 0.0.6
2
+ * Running RubyBreaker in shell mode does not require manual code change.
3
+ * Official RubyBreaker logo!
4
+ * Deprecating breakable(). Use break() instead.
5
+
1
6
  # VERSION 0.0.5
2
7
  * Rake::RubyBreakerTestTask is supported.
3
8
  * Manual modification is no longer required if run as a Rake task.
data/README.md CHANGED
@@ -1,33 +1,33 @@
1
- * * *
2
-
3
1
  # Introduction
4
2
 
5
3
  RubyBreaker is a dynamic type documentation tool written in pure Ruby. It
6
4
  provides the framework for dynamically instrumenting a Ruby program to
7
- monitor objects during executions and document the observed type
5
+ monitor objects during the execution and document the observed type
8
6
  information. In other words, RubyBreaker "breaks" Ruby code out of its
9
- obscurity and wildness (as in "code breaking" or "horse
10
- breaking") by auto-documenting type information. The type documentation
11
- generated by RubyBreaker is also an executable Ruby code that can be used as
12
- an input to subsequent analyses.
7
+ obscurity and wildness (as in "code breaking" or "horse breaking") by
8
+ auto-documenting type information. The type documentation generated by
9
+ RubyBreaker is also an executable Ruby code that can be used as an input to
10
+ subsequent analyses.
13
11
 
14
12
  The primary goal of RubyBreaker is to assign a type signature to every
15
13
  method in selected modules and classes. A type signature is written in the
16
14
  RubyBreaker Type Annotation Language which resembles the documentation style
17
- used in Ruby API Doc. Manual code change is _not_ required if used in
18
- Rakefile and is kept minimal if otherwise. Overall, this tool should help
19
- Ruby programmers document their code more rigorously and effectively.
15
+ used in Ruby Core Library Doc. No manual code change is required. Overall,
16
+ this tool should help Ruby programmers document their code more rigorously
17
+ and effectively.
20
18
 
21
- Current limitations are:
19
+ Currently, RubyBreaker *cannot*
22
20
 
23
- * Auto-documentation of block arguments (inherent)
24
- * Parametric polymorphic types
25
- * RDoc or YARD documentation support
21
+ * Auto-document block arguments (inherent)
22
+ * Perform early dynamic type checks
23
+ * Support parametric polymorphic types
24
+ * Support RDoc or YARD output format
26
25
 
27
26
  To contribute to the project, visit RubyBreaker's
28
27
  [GitHub page](http://github.com/rockalizer/rubybreaker) and
29
- [RubyGems page](http://rubygems.org/gems/rubybreaker). RubyBreaker RDoc can
30
- be found in [here](rdoc/index.html).
28
+ [RubyGems page](http://rubygems.org/gems/rubybreaker). The web version of
29
+ this document can be found
30
+ [here](http://rockalizer.webfactional.com/projects/rubybreaker).
31
31
 
32
32
  ## Requirements
33
33
 
@@ -43,339 +43,3 @@ It is as simple as running the following command:
43
43
 
44
44
  $ gem install rubybreaker
45
45
 
46
- * * *
47
-
48
- # Tutorial
49
-
50
- This tutorial will describe the basic usage of the tool, the RubyBreaker
51
- Type Annotation Language, and the RubyBreaker Type System.
52
-
53
- ## Usage
54
-
55
- RubyBreaker takes advantage of test cases that already come with the source
56
- program. It is recommended that RubyBreaker is run as a Rake task, which
57
- requires a minimum code change in the Rakefile and no code change in the
58
- source program. If not used as a Rake task, it requires a minimum code
59
- change in each test case or the source program but should not affect the
60
- development process much. Let's briefly see how RubyBreaker can be run
61
- directly as a command-line program to understand the general concept of the
62
- tool. We will explain how to use RubyBreaker in a Rakefile later.
63
-
64
- $ rubybreaker -v prog.rb
65
-
66
- This runs RubyBreaker in verbose mode on `prog.rb`. Note that RubyBreaker
67
- will actually run `prog.rb` (by simply `require`ing the program file).
68
- Somewhere in the program, there has to be a _program entry point_ to
69
- indicate where the _monitoring_ of objects starts. Let's assume `prog.rb`
70
- as the following:
71
-
72
- require "rubybreaker" # required if using "ruby" instead
73
- class A
74
- def foo(x)
75
- x.to_s
76
- end
77
- end
78
- class B
79
- def bar(y,z)
80
- y.foo(z)
81
- end
82
- end
83
- RubyBreaker.run(A, B)
84
- A.new.foo(1)
85
-
86
- This example will show how `A#foo` method is given a type by RubyBreaker.
87
- After running `rubybreaker -v prog.rb`, the following output will be
88
- generated and saved into `prog.rubybreaker.rb`.
89
-
90
- # This file is auto-generated by RubyBreaker
91
- require "rubybreaker"
92
- class A
93
- typesig("foo(fixnum[to_s]) -> string")
94
- end
95
-
96
- Here, the `typesig` method call registers `foo` as a method type that takes
97
- an object that has `Fixnum#to_s` method and returns a `String`. This
98
- method is made available by importing `rubybreaker`. Now, assume that an
99
- additional code, `B.new.bar(A.new,1)`, is added at the end of `prog.rb`. The
100
- subsequent run will generate the following result:
101
-
102
- # This file is auto-generated by RubyBreaker
103
- require "rubybreaker"
104
- class A
105
- typesig("foo(fixnum[to_s]) -> string")
106
- end
107
- class B
108
- typesig("bar(a[foo], fixnum[to_s]) -> string")
109
- end
110
-
111
- Keep in mind that RubyBreaker is designed to gather type information based
112
- on the _actual_ execution of the source program. This means the program
113
- should be equipped with test cases that have a reasonable program path
114
- coverage. Additionally, RubyBreaker assumes that test runs are correct and
115
- the program behaves correctly (for those test runs) as intended by the
116
- programmer. This assumption is not a strong requirement, but is necessary to
117
- obtain precise and accurate type information.
118
-
119
- ### Using Ruby Unit Testing Framework
120
-
121
- Instead of manually inserting the entry point indicator into the program,
122
- you can take advantage of Ruby's built-in testing framework. This is
123
- preferred to modifying the source program directly, especially for the long
124
- term program maintainability. But no worries! This method is as simple as
125
- the previous one.
126
-
127
- require "test/unit"
128
- require "rubybreaker" # This should come after test/unit.
129
- class TestClassA < Test::Unit::TestCase
130
- def setup()
131
- RubyBreaker.breakable(Class1, Class2, ...)
132
- ...
133
- end
134
- # ...tests!...
135
- end
136
-
137
- That's it! The only requirements are to indicate to RubyBreaker which modules
138
- and classes to "break" and to place `require rubybreaker` _after_
139
- `require test/unit`.
140
-
141
- ### Using RSpec
142
-
143
- The requirement is same for RSpec but use `before` instead of `setup` to
144
- specify which modules and classes to "break".
145
-
146
- require "rspec"
147
- require "rubybreaker"
148
-
149
- describe "TestClassA Test"
150
- before { RubyBreaker.breakable(Class1, Class2, ...) }
151
- ...
152
- # ...tests!...
153
- end
154
-
155
- ### Using Rakefile
156
-
157
- By running RubyBreaker along with the Rakefile, you can avoid modifying the
158
- source program at all. (You no longer need to import `rubybreaker` in the
159
- test cases neither.) Therefore, this is the recommended way to use
160
- RubyBreaker. The following code snippet describes how it can be done:
161
-
162
- require "rubybreaker/task"
163
- ...
164
- desc "Run RubyBreaker"
165
- Rake::RubyBreakerTestTask.new(:"rubybreaker") do |t|
166
- t.libs << "lib"
167
- t.test_files = ["test/foo/tc_foo1.rb"]
168
- # ...Other test task options..
169
- t.rubybreaker_opts << "-v" # run in verbose mode
170
- t.breakable = ["Class1", "Class2", ...] # specify what to monitor
171
- end
172
-
173
- Note that `RubyBrakerTestTask` can simply replace your `TestTask` block in
174
- Rakefile. In fact, the former is a subclass of the latter and includes all
175
- features supported by the latter. The only additional options are
176
- `rubybreaker_opts` which is RubyBreaker's command-line options and
177
- `breakable` which specifies which modules and classes to monitor. Since
178
- `Class1` and `Class2` are not _recognized_ by this Rakefile, you must use
179
- string literals to specify modules and classes (and with full namespace).
180
-
181
- If this is the route you are taking, there needs no editing of the source
182
- program whatsoever. This task will take care of instrumenting the specified
183
- modules and classes at proper moments.
184
-
185
- ## Type Annotation
186
-
187
- The annotation language used in RubyBreaker resembles the method
188
- documentation used by Ruby Standard Library Doc. Each type signature
189
- defines a method type using the name, argument types, block type, and return
190
- type. But, let us consider a simple case where there is one argument type
191
- and a return type.
192
-
193
- class A
194
- ...
195
- typesig("foo(fixnum) -> string")
196
- end
197
-
198
- In RubyBreaker, a type signature is recognized by the meta-class level
199
- method `typesig` which takes a string as an argument. This string is the
200
- actual type signature written in the Ruby Type Annotation Language. This
201
- language is designed to reflect the common documentation practice used by
202
- RubyDoc. It starts with the name of the method. In the above example, `foo`
203
- is currently being given a type. The rest of the signature takes a typical
204
- method type symbol, `(x) -> y` where `x` is the argument type and `y` is the
205
- return type. In the example shown above, the method takes a `Fixnum` object
206
- and returns a `String` object. Note that these types are in lowercase,
207
- indicating they are objects and not modules or classes themselves.
208
-
209
- There are several types that represent an object: nominal, duck, fusion,
210
- nil, 'any', 'or', optional, variable-length, and block. Each type signature
211
- itself represents a method type or a method list type (explained below).
212
-
213
- ### Nominal Type
214
-
215
- This is the simplest and most intuitive way to represent an object. For
216
- instance, `fixnum` is an object of type `Fixnum`. Use lower-case letters and
217
- underscores instead of _camelized_ name. `MyClass`, for example would be
218
- `my_class` in RubyBreaker type signatures. There is no particular
219
- reason for this convention other than it is the common practice used in
220
- RubyDoc. Use `/` to indicate the namespace delimiter `::`. For example,
221
- `NamspaceA::ClassB` would be represented by `namespace_a/class_b` in
222
- a RubyBreaker type signature.
223
-
224
- ### Self Type
225
-
226
- This type is similar to the nominal type but is referring to the current
227
- object--that is, the receiver of the method being typed. RubyBreaker will
228
- auto-document the return type as a self type if the return value is the same
229
- as the receiver of that call. It is also recommended to use this type over
230
- a nominal type (if the return value is `self`) since it depicts more
231
- precise return type.
232
-
233
- ### Duck Type
234
-
235
- This type is inspired by the Ruby Language's duck typing, _"if it
236
- walks like a duck and quacks like a duck, it must be a duck."_ Using this
237
- type, an object can be represented simply by a list of method names. For
238
- example `[walks, quacks]` is an object that has `walks` and `quacks`
239
- methods. Note that these method names do *not* reveal any type
240
- information for themselves.
241
-
242
- ### Fusion Type
243
-
244
- Duck type is very flexible but can be too lenient when trying to restrict
245
- the type of an object. RubyBreaker provides a type called *the fusion type*
246
- which lists method names but with respect to a nominal type. For
247
- example, `fixnum[to_f, to_s]` represents an object that has methods `to_f`
248
- and `to_s` whose types are same as those of `Fixnum`. This is more
249
- restrictive (precise) than `[to_f, to_s]` because the two methods must have
250
- the same types as `to_f` and `to_s` methods, respectively, in `Fixnum`.
251
-
252
- ### Nil Type
253
-
254
- A nil type represents a value of nil and is denoted by `nil`.
255
-
256
- ### Any Type
257
-
258
- RubyBreaker also provides a way to represent an object that is compatible with
259
- any type. This type is denoted by `?`. Use caution with this type because
260
- it should be only used for an object that requires an arbitrary yet most
261
- specific type--that is, `?` is a subtype of any other type, but any
262
- other type is not a subtype of `?`. This becomes a bit complicated for
263
- method or block argument types because of their contra-variance
264
- characteristic. Please refer to the section *Subtyping*.
265
-
266
- ### Or Type
267
-
268
- Any above types can be "or"ed together, using `||`, to represent an object
269
- that can be either one or the other. It _does_ not represent an object that
270
- has to be both (which is not supported by RubyBreaker).
271
-
272
- ### Optional Argument Type and Variable-Length Argument Type
273
-
274
- Another useful features of Ruby are the optional argument type and the
275
- variable-length argument type. The former represents an argument that has a
276
- default value (and therefore does not have to be provided). The latter
277
- represents zero or more arguments of the same type. These are denoted by
278
- suffices, `?` and `*`, respectively.
279
-
280
- ### Block Type
281
-
282
- One of the Ruby's prominent features is the block argument. It allows
283
- the caller to pass in a piece of code to be executed inside the callee. This
284
- code block can be executed by the Ruby construct, `yield`, or by directly
285
- calling the `call` method of the block object. In RubyBreaker, this type can
286
- be respresented by curly brackets. For instance, `{|fixnum,string| ->
287
- string}` represents a block that takes two arguments--one `Fixnum` and one
288
- `String`--and returns a `String`.
289
-
290
- RubyBreaker does supports nested blocks as Ruby 1.9 finally allows them.
291
- However, *keep in mind* that RubyBreaker *cannot* automatically document the
292
- block types due to `yield` being a language construct rather than a method,
293
- which means it cannot be captured by meta-programming!
294
-
295
- ### Method Type and Method List Types
296
-
297
- Method type is similar to the block type, but it represents an actual method
298
- and not a block object. It is the "root" type that the type annotation
299
- language supports, along with method list types. Method _list_ type is a
300
- collection of method types to represent more than one type information for
301
- the given method. Why would this type be needed? Consider the following Ruby
302
- code:
303
-
304
- def foo(x)
305
- case x
306
- when Fixnum
307
- 1
308
- when String
309
- "1"
310
- end
311
- end
312
-
313
- There is no way to document the type of `foo` without using a method list
314
- type. Let's try to give a method type to `foo` without a method list. The
315
- closest we can come up with would be `foo(fixnum or string) -> fixnum and
316
- string`. But RubyBreaker does not have the "and" type in the type annotation
317
- language because it gives me an headache! (By the way, it needs to be an
318
- "and" type because the caller must handle both `Fixnum` and `String` return
319
- values.)
320
-
321
- It is a dilemma because Ruby programmers actually enjoy using this kind of
322
- dynamic type checks in their code. To alleviate this headache, RubyBreaker
323
- supports the method list type to represent different scenarios depending on
324
- the argument types. Thus, the `foo` method shown above can be given the
325
- following method list type:
326
-
327
- typesig("foo(fixnum) -> fixnum")
328
- typesig("foo(string) -> string")
329
-
330
- These two type signatures simply tell RubyBreaker that `foo` has two method
331
- types--one for a `Fixnum` argument and another for a `String` argument.
332
- Depending on the argument type, the return type is determined. In this
333
- example, a `Fixnum` is returned when the argument is also a `Fixnum` and a
334
- `String` is returned when the argument is also a `String`. When
335
- automatically documenting such a type, RubyBreaker looks for the (subtyping)
336
- compatibility between the return types and "promote" the method type to a
337
- method list type by spliting the type signature into two (or more in
338
- subsequent "promotions").
339
-
340
- ## Type System
341
-
342
- RubyBreaker comes with its own type system to auto-document the type
343
- information. Each method in a "breakable" module is dynamically instrumented
344
- to be monitored during runtime. This monitoring code observes the types of
345
- the arguments, block, and return value of each method. Once this information
346
- is gathered, RubyBreaker will compare it to the information gathered so far.
347
- If these two types are "compatiable", RubyBreaker will choose more general
348
- type of the two. Otherwise, RubyBreaker will use the method list type to
349
- accommodate two "incompatible" types.
350
-
351
- ### Subtyping and Subclassing
352
-
353
- RubyBreaker uses subtyping to choose one from the two "compatible" types.
354
- Two types are "compatible" if one is subtype of another. This means that the
355
- _subtype_ can be represented using the _supertype_ instead. This is why
356
- RubyBrekaer chooses the latter to document both types. RubyBreaker relies on
357
- subclassing of Ruby to determine a subtyping relationship between two types.
358
- For example, `Fixnum` is considered to be subtype of `Numeric` since the
359
- former is subclass of the latter. (Strictly speaking, `Fixnum` is not really
360
- subtype of `Numeric` because some methods are overriden in `Fixnum` with
361
- method types that are not subtype of the counterparts in `Numeric`. But,
362
- RubyBreaker is lenient and considers them compatible--that is, `Numeric` can
363
- represent any `Fixnum`.
364
-
365
- ### Pluggable Type System (Advanced)
366
-
367
- Yes, RubyBreaker was designed with the replaceable type system in mind. In
368
- other words, anyone can write his own type system and plug it into
369
- RubyBreaker. *Technical documentation coming soon...*
370
-
371
- * * *
372
-
373
- # Acknowledgment
374
-
375
- The term, "Fusion Type," is first coined by Professor Michael W. Hicks at
376
- University of Maryland and represents an object using a structural type with
377
- respect to a nominal type.
378
-
379
- # Copyright
380
- Copyright (c) 2012 Jong-hoon (David) An. All Rights Reserved.
381
-
data/Rakefile CHANGED
@@ -19,6 +19,16 @@ rescue LoadError => e
19
19
  puts "[WARNING] No rspec-core is installed on this computer."
20
20
  end
21
21
 
22
+ # This method generates html pages with header and footer.
23
+ def gen_page(md_file, html_file)
24
+ dir = File.dirname(__FILE__)
25
+ header = File.read("#{dir}/webpage/header.html")
26
+ footer = File.read("#{dir}/webpage/footer.html")
27
+ body = RDiscount.new(File.read(md_file)).to_html
28
+ html = header + body + footer
29
+ File.open(html_file, "w") { |f| f.write(html) }
30
+ end
31
+
22
32
  # Use rake/clean to remove generated files
23
33
  CLEAN.concat(FileList["webpage/rdoc",
24
34
  "rubybreaker-*.gem",
@@ -29,38 +39,42 @@ CLEAN.concat(FileList["webpage/rdoc",
29
39
  # If no task specified, do test
30
40
  task :default => [:test, :testtask_test]
31
41
 
42
+ # The complete list of tasks
43
+ all_tasks = [:parser,
44
+ :test,
45
+ :testtask_test,
46
+ :rspec,
47
+ :rdoc,
48
+ :webpage,
49
+ :gem]
50
+
51
+ # Remove rspec if RSpec is not defined (rspec is not installed)
52
+ all_tasks.delete(:rspec) if !defined?(RSpec)
53
+
32
54
  desc "Do all"
33
- task :all => [:parser,
34
- :test,
35
- :testtask_test,
36
- :rspec,
37
- :rdoc,
38
- :webpage,
39
- :gem] do |t|
40
- end
55
+ task :all => all_tasks
41
56
 
42
57
  desc "Generate gemspec"
43
58
  task :gem do |t|
44
59
  sh "gem build rubybreaker.gemspec"
45
60
  end
46
61
 
62
+ desc "Generate RDoc"
47
63
  Rake::RDocTask.new do |rd|
48
64
  rd.rdoc_dir = "#{File.dirname(__FILE__)}/webpage/rdoc"
49
65
  rd.rdoc_files.include("lib/**/*.rb")
50
66
  rd.rdoc_files.exclude("lib/rubybreaker/type/type_grammar.rb")
67
+ rd.options << "README.md" << "TUTORIAL.md"
51
68
  end
52
69
 
53
70
  desc "Generate the webpage"
54
71
  task :webpage do |t|
55
72
  if defined?(RDiscount)
56
73
  dir = File.dirname(__FILE__)
57
- readme_md = "#{dir}/README.md"
58
- output = "#{dir}/webpage/index.html"
59
- body = RDiscount.new(File.read(readme_md)).to_html
60
- header = File.read("#{dir}/webpage/header.html")
61
- footer = File.read("#{dir}/webpage/footer.html")
62
- html = header + body + footer
63
- File.open(output, "w") { |f| f.write(html) }
74
+ gen_page("#{dir}/README.md","#{dir}/webpage/index.html")
75
+ gen_page("#{dir}/TUTORIAL.md","#{dir}/webpage/tutorial.html")
76
+ gen_page("#{dir}/TOPICS.md","#{dir}/webpage/topics.html")
77
+ gen_page("#{dir}/ABOUT.md","#{dir}/webpage/about.html")
64
78
  end
65
79
  end
66
80
 
@@ -84,7 +98,7 @@ desc "Run rubybreaker testtask test"
84
98
  Rake::RubyBreakerTestTask.new(:"testtask_test") do |t|
85
99
  t.libs << "lib" << "test/tc_testtask/sample.rb"
86
100
  t.test_files = ["test/testtask/tc_testtask.rb"]
87
- t.breakable = ["SampleClassA"]
101
+ t.break = ["SampleClassA"]
88
102
  end
89
103
 
90
104
  if defined?(RSpec)
data/TOPICS.md ADDED
@@ -0,0 +1,55 @@
1
+ # Advanced Topics
2
+
3
+ ## RubyBreaker Type System
4
+
5
+ RubyBreaker comes with its own type system to auto-document the type
6
+ information. Each method in a "breakable" module is dynamically instrumented
7
+ to be monitored during runtime. This monitoring code observes the types of
8
+ the arguments, block, and return value of each method. Once type information
9
+ for a method is gathered, RubyBreaker will compare it to the information
10
+ gathered so far for the method. If these two method types are
11
+ "compatiable", RubyBreaker will choose more general type from the two.
12
+
13
+ If two method types are not "compatible", RubyBreaker will "promote" the
14
+ method type to a method list type to accommodate more than one
15
+ "incompatible" types. Let's first understand what RubyBreaker considers two
16
+ types as "compatible".
17
+
18
+ ### Subtyping and Subclassing
19
+
20
+ RubyBreaker uses _subtyping_ to determine two "compatible" method types,
21
+ which holds true if one is subtype or supertype of another. It chooses
22
+ the supertype of the two for the method because the objective is to find (1)
23
+ the most general type of the two and (2) the least general type that can
24
+ handle both. Note that, if the objective (2) is not required, we can
25
+ always use the most general method type:
26
+
27
+ (?*) -> basic_object
28
+
29
+ A method of this type takes any number of any objects and returns a
30
+ `BasicObject`. But this is _too_ general to use for type documetation.
31
+ Instead, we want to find the most specific general type possible (and
32
+ therefore, the least upper bound of the types observed for the method).
33
+
34
+ For simplicity (and practicality), RubyBreaker uses _subclassing_ to
35
+ determine subtyping for nominal types. For instance, `Fixnum` is considered
36
+ subtype of `Numeric` because the former is subclass of the latter. However,
37
+ keep in mind this is not necessarily true in the true subtyping theory
38
+ because some methods in the former override the counterparts in the latter,
39
+ resulting in different types that no longer hold the subtyping relationship.
40
+
41
+ If a method has some type information either from the manual documentation
42
+ or from the current documentation process, this information will be used
43
+ in addition to subclassing. For example, consider method types
44
+ `foo(class1[to_s]) -> string` and `foo(class2[to_s]) -> string`. Let's also
45
+ assume that classes `Class1` and `Class2` are being auto-documented. The
46
+ method `foo` will have the type `foo(class1[to_s])` if `Class1#to_s` is a
47
+ subtype of `Class2#to_s`. (The direction is not mistaken, it is due to the
48
+ contra-variant property of a method argument.) If these classes are neither
49
+ being auto-documented nor manaully documented, this holds only if `Class1`
50
+ is subclass of `Class2`.
51
+
52
+ ## Writing a Custom Type System
53
+
54
+ _Coming soon_
55
+