rubybreaker 0.0.2 → 0.0.3
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.
- data/NEWS +6 -46
- data/README.md +30 -19
- data/TODO +22 -20
- data/VERSION +1 -1
- data/bin/rubybreaker +11 -2
- data/lib/rubybreaker.rb +31 -11
- data/lib/rubybreaker/debug.rb +5 -49
- data/lib/rubybreaker/{context.rb → debug/context.rb} +0 -0
- data/lib/rubybreaker/debug/debug.rb +61 -0
- data/lib/rubybreaker/{error.rb → debug/error.rb} +1 -1
- data/lib/rubybreaker/runtime.rb +3 -2
- data/lib/rubybreaker/runtime/inspector.rb +20 -13
- data/lib/rubybreaker/runtime/monitor.rb +21 -13
- data/lib/rubybreaker/runtime/object_wrapper.rb +3 -1
- data/lib/rubybreaker/runtime/type_system.rb +3 -2
- data/lib/rubybreaker/test/testcase.rb +0 -1
- data/lib/rubybreaker/type/type.rb +1 -1
- data/lib/rubybreaker/type/type_grammar.treetop +1 -1
- data/lib/rubybreaker/type/type_unparser.rb +1 -1
- data/lib/rubybreaker/util.rb +3 -11
- data/test/integrated/tc_both_broken_breakable.rb +27 -0
- data/test/ts_integrated.rb +1 -0
- data/webpage/index.html +30 -19
- data/webpage/rdoc/RubyBreaker.html +127 -10
- data/webpage/rdoc/RubyBreaker/Breakable.html +1 -5
- data/webpage/rdoc/RubyBreaker/Broken.html +2 -6
- data/webpage/rdoc/RubyBreaker/Broken/BrokenEigen.html +3 -6
- data/webpage/rdoc/RubyBreaker/Context.html +6 -10
- data/webpage/rdoc/RubyBreaker/Errors.html +2 -6
- data/webpage/rdoc/RubyBreaker/Errors/InternalError.html +3 -7
- data/webpage/rdoc/RubyBreaker/Errors/InvalidSubtypeCheck.html +3 -7
- data/webpage/rdoc/RubyBreaker/Errors/InvalidTypeConstruction.html +2 -6
- data/webpage/rdoc/RubyBreaker/Errors/SubtypeFailure.html +2 -6
- data/webpage/rdoc/RubyBreaker/Errors/TypeError.html +3 -7
- data/webpage/rdoc/RubyBreaker/Errors/UserError.html +3 -7
- data/webpage/rdoc/RubyBreaker/Main.html +33 -20
- data/webpage/rdoc/RubyBreaker/ObjectPosition.html +4 -8
- data/webpage/rdoc/RubyBreaker/Position.html +7 -11
- data/webpage/rdoc/RubyBreaker/RubyTypeUtils.html +1 -5
- data/webpage/rdoc/RubyBreaker/Runtime.html +1 -5
- data/webpage/rdoc/RubyBreaker/Runtime/Inspector.html +25 -18
- data/webpage/rdoc/RubyBreaker/Runtime/MethodInfo.html +1 -5
- data/webpage/rdoc/RubyBreaker/Runtime/Monitor.html +4 -8
- data/webpage/rdoc/RubyBreaker/Runtime/MonitorInstaller.html +20 -43
- data/webpage/rdoc/RubyBreaker/Runtime/MonitorSwitch.html +7 -11
- data/webpage/rdoc/RubyBreaker/Runtime/MonitorUtils.html +6 -10
- data/webpage/rdoc/RubyBreaker/Runtime/ObjectWrapper.html +7 -11
- data/webpage/rdoc/RubyBreaker/Runtime/Pluggable.html +1 -5
- data/webpage/rdoc/RubyBreaker/Runtime/TypePlaceholder.html +1 -5
- data/webpage/rdoc/RubyBreaker/Runtime/TypeSigParser.html +1 -5
- data/webpage/rdoc/RubyBreaker/Runtime/TypeSystem.html +8 -12
- data/webpage/rdoc/RubyBreaker/TestCase.html +1 -6
- data/webpage/rdoc/RubyBreaker/TypeComparer.html +1 -5
- data/webpage/rdoc/RubyBreaker/TypeDefs.html +1 -5
- data/webpage/rdoc/RubyBreaker/TypeDefs/AnyType.html +1 -5
- data/webpage/rdoc/RubyBreaker/TypeDefs/BlockType.html +1 -5
- data/webpage/rdoc/RubyBreaker/TypeDefs/DuckType.html +1 -5
- data/webpage/rdoc/RubyBreaker/TypeDefs/FusionType.html +1 -5
- data/webpage/rdoc/RubyBreaker/TypeDefs/MethodListType.html +1 -5
- data/webpage/rdoc/RubyBreaker/TypeDefs/MethodType.html +1 -5
- data/webpage/rdoc/RubyBreaker/TypeDefs/NilType.html +1 -5
- data/webpage/rdoc/RubyBreaker/TypeDefs/NominalType.html +1 -5
- data/webpage/rdoc/RubyBreaker/TypeDefs/OptionalType.html +1 -5
- data/webpage/rdoc/RubyBreaker/TypeDefs/OrType.html +1 -5
- data/webpage/rdoc/RubyBreaker/TypeDefs/SelfType.html +1 -5
- data/webpage/rdoc/RubyBreaker/TypeDefs/Type.html +1 -5
- data/webpage/rdoc/RubyBreaker/TypeDefs/VarLengthType.html +1 -5
- data/webpage/rdoc/RubyBreaker/TypeUnparser.html +1 -5
- data/webpage/rdoc/RubyBreaker/Typing.html +1 -5
- data/webpage/rdoc/RubyBreaker/{Utilities.html → Util.html} +8 -9
- data/webpage/rdoc/created.rid +15 -14
- data/webpage/rdoc/index.html +1 -5
- data/webpage/rdoc/js/search_index.js +1 -1
- data/webpage/rdoc/table_of_contents.html +22 -36
- metadata +9 -7
- data/webpage/rdoc/RubyBreaker/Debug.html +0 -411
- data/webpage/rdoc/RubyBreaker/Kernel.html +0 -259
data/NEWS
CHANGED
@@ -1,48 +1,8 @@
|
|
1
|
-
# VERSION 0.0.
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
RubyBreaker now supports class methods. Auto-documentation of class methods
|
6
|
-
is done in the eigen class scope of the target module. For example, the
|
7
|
-
consider the following:
|
8
|
-
|
9
|
-
class A
|
10
|
-
include RubyBreaker::Breakable
|
11
|
-
class << self
|
12
|
-
def foo(x); x.to_s end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
RubyBreaker.monitor()
|
16
|
-
A.foo(1)
|
17
|
-
|
18
|
-
When `foo` method is run, RubyBreaker will auto-document the type of the
|
19
|
-
method and output as the following:
|
20
|
-
|
21
|
-
class A
|
22
|
-
include RubyBreaker::Broken
|
23
|
-
class << self
|
24
|
-
typesig("foo(fixnum[to_s]) -> string")
|
25
|
-
end
|
26
|
-
end
|
1
|
+
# VERSION 0.0.3
|
2
|
+
* A class or module can be both Breakable and Broken at the same time.
|
3
|
+
* Better logging/debugging output
|
27
4
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
argument was declared with `*` prefix. For instance,
|
32
|
-
|
33
|
-
class A
|
34
|
-
include RubyBreaker::Breakable
|
35
|
-
def foo(*args)
|
36
|
-
args[0].to_s
|
37
|
-
end
|
38
|
-
end
|
39
|
-
RubyBreaker.monitor()
|
40
|
-
A.new.foo("1")
|
41
|
-
|
42
|
-
Will generate the following output:
|
43
|
-
|
44
|
-
class A
|
45
|
-
include RubyBreaker::Broken
|
46
|
-
typesig("foo(string[to_s]*) -> string")
|
47
|
-
end
|
5
|
+
# VERSION 0.0.2
|
6
|
+
* Class methods can be auto-documented or manually documented.
|
7
|
+
* Variable-length argument type can be auto-documented.
|
48
8
|
|
data/README.md
CHANGED
@@ -171,10 +171,20 @@ signature `bar(fixnum[to_s]) -> string`, which means it takes an object that
|
|
171
171
|
has `Fixnum`'s `to_s` method and returns a string. More detail on the type
|
172
172
|
annotation language will be explained in later section.
|
173
173
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
174
|
+
### Hybrid of Breakable and Broken
|
175
|
+
|
176
|
+
Starting from version 0.0.3, RubyBreaker allows a module to be declared as
|
177
|
+
`Breakable` and `Broken` at the same time. If a method has a corresponding
|
178
|
+
type signature (manually documented) somewhere, then RubyBreaker will not
|
179
|
+
monitor it during runtime. All other methods will be instrumented and
|
180
|
+
monitored by RubyBreaker.
|
181
|
+
|
182
|
+
### Class Methods
|
183
|
+
|
184
|
+
It is possible to include `Breakable` and/or `Broken` in an eigen-class to
|
185
|
+
document class methods. To make this easier, RubyBreaker will automatically
|
186
|
+
support auto-documentation and manual documentation of class methods if the
|
187
|
+
original module is declared as `Breakable` and/or `Broken`,
|
178
188
|
respectively--that is, up to immediate eigen class level of a "nominal"
|
179
189
|
module. The following example shows how class methods can be
|
180
190
|
auto-documented and manually documented, respectively.
|
@@ -194,11 +204,6 @@ auto-documented and manually documented, respectively.
|
|
194
204
|
end
|
195
205
|
end
|
196
206
|
|
197
|
-
Keep in mind that `Broken` module always wins against `Breakable`. In other
|
198
|
-
words, if a module is declared as both `Broken` and `Breakable`, it is
|
199
|
-
treated as `Broken`. Future versions of RubyBreaker will support a hybrid of
|
200
|
-
the two modules, but it remains as a limitation in the current version.
|
201
|
-
|
202
207
|
### Program Entry Point
|
203
208
|
|
204
209
|
In Ruby, as soon as a file is `require`d, the execution of that file begins.
|
@@ -271,8 +276,8 @@ and returns a `String` object. Note that these types are in lowercase,
|
|
271
276
|
indicating they are objects and not modules or classes themselves.
|
272
277
|
|
273
278
|
There are several types that represent an object: nominal, duck, fusion,
|
274
|
-
nil, 'any', and block. Each type signature
|
275
|
-
or a method list type (explained below).
|
279
|
+
nil, 'any', 'or', optional, variable-length, and block. Each type signature
|
280
|
+
itself represents a method type or a method list type (explained below).
|
276
281
|
|
277
282
|
### Nominal Type
|
278
283
|
|
@@ -325,6 +330,20 @@ other type is not a subtype of `?`. This becomes a bit complicated for
|
|
325
330
|
method or block argument types because of their contra-variance
|
326
331
|
characteristic. Please refer to the section *Subtyping*.
|
327
332
|
|
333
|
+
### Or Type
|
334
|
+
|
335
|
+
Any above types can be "or"ed together, using `||`, to represent an object
|
336
|
+
that can be either one or the other. It _does_ not represent an object that
|
337
|
+
has to be both (which is not supported by RubyBreaker).
|
338
|
+
|
339
|
+
### Optional Argument Type and Variable-Length Argument Type
|
340
|
+
|
341
|
+
Another useful features of Ruby are the optional argument type and the
|
342
|
+
variable-length argument type. The former represents an argument that has a
|
343
|
+
default value (and therefore does not have to be provided). The latter
|
344
|
+
represents zero or more arguments of the same type. These are denoted by
|
345
|
+
suffices, `?` and `*`, respectively.
|
346
|
+
|
328
347
|
### Block Type
|
329
348
|
|
330
349
|
One of the Ruby's prominent features is the block argument. It allows
|
@@ -340,14 +359,6 @@ However, *keep in mind* that RubyBreaker *cannot* automatically document the
|
|
340
359
|
block types due to `yield` being a language construct rather than a method,
|
341
360
|
which means it cannot be captured by meta-programming!
|
342
361
|
|
343
|
-
### Optional Argument Type and Variable-Length Argument Type
|
344
|
-
|
345
|
-
Another useful features of Ruby are the optional argument type and the
|
346
|
-
variable-length argument type. The former represents an argument that has a
|
347
|
-
default value (and therefore does not have to be provided). The latter
|
348
|
-
represents zero or more arguments of the same type. These are denoted by
|
349
|
-
suffices, `?` and `*`, respectively.
|
350
|
-
|
351
362
|
### Method Type and Method List Types
|
352
363
|
|
353
364
|
Method type is similar to the block type, but it represents an actual method
|
data/TODO
CHANGED
@@ -1,30 +1,32 @@
|
|
1
|
-
# Dynamic Type
|
1
|
+
# Dynamic Type Checker
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
Type documentation generated by RubyBreaker can be more useful if the types
|
4
|
+
are actually enforced during runtime. In order to do this, each method has
|
5
|
+
to be dynamically instrumented (as "breakable" methods are) and inspected
|
6
|
+
for each argument type and return type. Although this is still a dynamic
|
7
|
+
type checking, it finds type errors earlier in the program execution.
|
7
8
|
|
8
|
-
#
|
9
|
+
# More Testing Frameworks
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
The Ruby community has other testing frameworks such as RSpec and Cucumber.
|
12
|
+
RubyBreaker should be able to support these frameworks so that those test
|
13
|
+
suites can be used for RubyBreaker.
|
13
14
|
|
14
|
-
# RDoc Documentation
|
15
|
+
# RDoc and YARD Documentation Support
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
It is cool (and actually useful in a way) to output the type documentation
|
18
|
+
in an executable Ruby code. However, for documetation purpose, it would be
|
19
|
+
better to have the information in RDoc or YARD format.
|
19
20
|
|
20
|
-
#
|
21
|
+
# Core Library Documentation
|
21
22
|
|
22
|
-
|
23
|
+
The core idea behind RubyBreaker is the incremental type documentation,
|
24
|
+
starting from the core library to the application level modules.
|
25
|
+
Unfortunately, due to technical difficulties, it is not intuitive to
|
26
|
+
auto-document the core library code. Thus, it might be necessary to document
|
27
|
+
it manually and import this information for upper-level modules.
|
23
28
|
|
24
|
-
#
|
29
|
+
# Ruby on Rails Support
|
25
30
|
|
26
|
-
|
27
|
-
* Manual modification (minimal) of code is required.
|
28
|
-
* No parametric polymorphic types are supported. The lack of this type is
|
29
|
-
not a bug but a feature! Polymorphic types are just headaches!
|
31
|
+
What more can I say?
|
30
32
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
data/bin/rubybreaker
CHANGED
@@ -13,6 +13,10 @@ module RubyBreaker
|
|
13
13
|
|
14
14
|
opts.banner = "Usage: #{File.basename(__FILE__)} [options] in_file[.rb]"
|
15
15
|
|
16
|
+
opts.on("--debug", "Run in debug mode") do
|
17
|
+
OPTIONS[:debug] = true
|
18
|
+
end
|
19
|
+
|
16
20
|
opts.on("-f","--io-file FILE","Specify an input/output file") do |f|
|
17
21
|
OPTIONS[:output] = f
|
18
22
|
end
|
@@ -45,15 +49,20 @@ module RubyBreaker
|
|
45
49
|
OPTIONS[:mode] = :bin # indicate that RubyBreaker is being run as a
|
46
50
|
# binary (program).
|
47
51
|
|
48
|
-
|
49
|
-
|
52
|
+
if OPTIONS[:verbose] # Show copyright info only when verbose
|
53
|
+
puts COPYRIGHT
|
54
|
+
puts
|
55
|
+
end
|
50
56
|
|
51
57
|
# There has to be an input file
|
52
58
|
if ARGV.length < 1 then
|
59
|
+
puts "Specify a Ruby program"
|
53
60
|
puts option_parser.banner
|
54
61
|
exit(1)
|
55
62
|
end
|
56
63
|
|
64
|
+
OPTIONS[:file] = ARGV[0]
|
65
|
+
|
57
66
|
Main.run()
|
58
67
|
|
59
68
|
end
|
data/lib/rubybreaker.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
# observed at runtime and generates type annotation at the end. It can be
|
4
4
|
# run as either a stand-alone script or as a Ruby library.
|
5
5
|
|
6
|
+
require_relative "rubybreaker/debug"
|
6
7
|
require_relative "rubybreaker/runtime"
|
7
8
|
require_relative "rubybreaker/test"
|
8
9
|
|
@@ -16,12 +17,13 @@ module RubyBreaker
|
|
16
17
|
# Options for RubyBreaker
|
17
18
|
OPTIONS = {
|
18
19
|
:debug => false, # in debug mode?
|
19
|
-
:verbose =>
|
20
|
+
:verbose => false, # in RubyBreaker.verbose mode?
|
20
21
|
:mode => :lib, # bin or lib?
|
21
22
|
:io_file => nil, # generate input/output other than default?
|
22
23
|
:append => true, # append to the input file (if there is)?
|
23
24
|
:stdout => true, # also display on the screen?
|
24
25
|
:rubylib => true, # include core ruby library documentation?
|
26
|
+
:file => nil, # the input Ruby program (as typed by the user)
|
25
27
|
}
|
26
28
|
|
27
29
|
# This array lists modules/classes that are actually instrumented with a
|
@@ -48,10 +50,11 @@ module RubyBreaker
|
|
48
50
|
def self.setup()
|
49
51
|
|
50
52
|
BREAKABLE.each do |mod|
|
51
|
-
|
52
|
-
#
|
53
|
-
#
|
54
|
-
|
53
|
+
|
54
|
+
# Remember, RubyBreaker now supports a hybrid of Breakable and
|
55
|
+
# Broken module. Just check if the module has already been
|
56
|
+
# instrumented.
|
57
|
+
unless INSTALLED.include?(mod)
|
55
58
|
MonitorInstaller.install_module_monitor(mod)
|
56
59
|
INSTALLED << mod
|
57
60
|
end
|
@@ -68,6 +71,7 @@ module RubyBreaker
|
|
68
71
|
# Reads the input file if specified or exists
|
69
72
|
def self.input()
|
70
73
|
return unless OPTIONS[:io_file] && File.exist?(OPTIONS[:io_file])
|
74
|
+
RubyBreaker.verbose("RubyBreaker input file exists...loading")
|
71
75
|
eval "load \"#{OPTIONS[:io_file]}\"", TOPLEVEL_BINDING
|
72
76
|
end
|
73
77
|
|
@@ -136,9 +140,11 @@ module RubyBreaker
|
|
136
140
|
pp.breakable()
|
137
141
|
end
|
138
142
|
|
139
|
-
# This method will generate the output
|
143
|
+
# This method will generate the output.
|
140
144
|
def self.output()
|
141
145
|
|
146
|
+
RubyBreaker.verbose("Generating type documentation")
|
147
|
+
|
142
148
|
io_exist = OPTIONS[:io_file] && File.exist?(OPTIONS[:io_file])
|
143
149
|
|
144
150
|
str = ""
|
@@ -162,14 +168,24 @@ module RubyBreaker
|
|
162
168
|
end
|
163
169
|
f.puts str
|
164
170
|
end
|
171
|
+
|
172
|
+
RubyBreaker.verbose("Done generating type documentation")
|
165
173
|
end
|
166
174
|
|
167
|
-
# This method will run the
|
175
|
+
# This method will run do things in the following order:
|
176
|
+
#
|
177
|
+
# * Checks to see if the user program and an input file exists
|
178
|
+
# * Loads the documentation for Ruby Core Library (TODO)
|
179
|
+
# * Reads the input type documentation if any
|
180
|
+
# * Reads (require's) the user program
|
181
|
+
#
|
168
182
|
def self.run()
|
169
183
|
|
170
|
-
|
184
|
+
RubyBreaker.setup_logger()
|
185
|
+
RubyBreaker.verbose("Running RubyBreaker")
|
171
186
|
|
172
|
-
|
187
|
+
# First, take care of the program file.
|
188
|
+
argv0 = OPTIONS[:file]
|
173
189
|
prog_file = argv0
|
174
190
|
prog_file = File.expand_path(prog_file)
|
175
191
|
|
@@ -179,7 +195,7 @@ module RubyBreaker
|
|
179
195
|
end
|
180
196
|
|
181
197
|
if !File.exist?(prog_file)
|
182
|
-
|
198
|
+
fatal("#{argv0} is an invalid file.")
|
183
199
|
exit(1)
|
184
200
|
end
|
185
201
|
|
@@ -190,6 +206,7 @@ module RubyBreaker
|
|
190
206
|
OPTIONS[:io_file] = File.absolute_path(OPTIONS[:io_file])
|
191
207
|
|
192
208
|
if OPTIONS[:rubylib]
|
209
|
+
RubyBreaker.verbose("Loading RubyBreaker's Ruby Core Library documentation")
|
193
210
|
# Load the core library type documentation
|
194
211
|
eval("require \"rubybreaker/rubylib\"", TOPLEVEL_BINDING)
|
195
212
|
end
|
@@ -201,11 +218,14 @@ module RubyBreaker
|
|
201
218
|
# Finally, require the program file! Let it run! Wheeee!
|
202
219
|
eval("require '#{prog_file}'", TOPLEVEL_BINDING)
|
203
220
|
|
221
|
+
RubyBreaker.verbose("Done running the input program")
|
222
|
+
|
204
223
|
end
|
205
224
|
|
206
225
|
end
|
207
226
|
|
208
|
-
#
|
227
|
+
# This is the manual indicator for the program entry point. It simply
|
228
|
+
# redirects to the monitor setup code.
|
209
229
|
def self.monitor()
|
210
230
|
Main.setup()
|
211
231
|
end
|
data/lib/rubybreaker/debug.rb
CHANGED
@@ -1,52 +1,8 @@
|
|
1
1
|
#--
|
2
|
-
# This file
|
2
|
+
# This file imports all necessary modules for both debugging RubyBreaker
|
3
|
+
# internally and debugging the user program.
|
3
4
|
|
4
|
-
|
5
|
-
require_relative "
|
5
|
+
require_relative "debug/context"
|
6
|
+
require_relative "debug/error"
|
7
|
+
require_relative "debug/debug"
|
6
8
|
|
7
|
-
module RubyBreaker
|
8
|
-
|
9
|
-
# This module is for internal purpose only - to help ourselves find bugs
|
10
|
-
# and fix them with more informative error messages.
|
11
|
-
module Debug
|
12
|
-
|
13
|
-
OUTPUT = ""
|
14
|
-
|
15
|
-
def self.debug_mode?()
|
16
|
-
return defined?(RubyBreaker::OPTIONS) && RubyBreaker::OPTIONS[:debug]
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.msg(text,context=nil)
|
20
|
-
return unless self.debug_mode?
|
21
|
-
pp = PrettyPrint.new(OUTPUT)
|
22
|
-
msg = "[DEBUG] #{text}"
|
23
|
-
if context
|
24
|
-
context.format_with_msg(pp,msg)
|
25
|
-
else
|
26
|
-
pp.text(msg,79)
|
27
|
-
pp.breakable()
|
28
|
-
end
|
29
|
-
pp.flush
|
30
|
-
puts OUTPUT
|
31
|
-
OUTPUT.replace("")
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.short_msg(text)
|
35
|
-
return unless self.debug_mode?
|
36
|
-
msg = "[DEBUG] #{text}"
|
37
|
-
print msg
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.token(msg)
|
41
|
-
return unless self.debug_mode?
|
42
|
-
print msg
|
43
|
-
end
|
44
|
-
|
45
|
-
def self.feed_line()
|
46
|
-
return unless self.debug_mode?
|
47
|
-
puts ""
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
File without changes
|
@@ -0,0 +1,61 @@
|
|
1
|
+
#-
|
2
|
+
# This file contains the debug module which is exclusively used by
|
3
|
+
# RubyBreaker internally.
|
4
|
+
#
|
5
|
+
require "prettyprint"
|
6
|
+
require "logger"
|
7
|
+
require_relative "context"
|
8
|
+
|
9
|
+
module RubyBreaker
|
10
|
+
|
11
|
+
# This sets up the logger for debugging RubyBreaker
|
12
|
+
def self.setup_logger #:nodoc:
|
13
|
+
return if defined?(LOGGER)
|
14
|
+
out = if (defined?(OPTIONS) && !OPTIONS[:file].empty?)
|
15
|
+
then "#{OPTIONS[:file]}.log"
|
16
|
+
else STDOUT
|
17
|
+
end
|
18
|
+
const_set(:LOGGER, Logger.new(out))
|
19
|
+
LOGGER.level = Logger::DEBUG
|
20
|
+
end
|
21
|
+
|
22
|
+
# This method will display verbose message. It is not for debugging but to
|
23
|
+
# inform users of each stage in the analysis.
|
24
|
+
def self.verbose(str, &blk)
|
25
|
+
return unless defined?(OPTIONS) && (OPTIONS[:verbose] || OPTIONS[:debug])
|
26
|
+
if blk
|
27
|
+
msg = yield
|
28
|
+
msg = "#{str} : #{msg}" if str
|
29
|
+
else
|
30
|
+
msg = str
|
31
|
+
end
|
32
|
+
STDOUT.puts msg if OPTIONS[:verbose]
|
33
|
+
LOGGER.info msg if OPTIONS[:debug]
|
34
|
+
end
|
35
|
+
|
36
|
+
# This method is for reporting an error to the user. It will immediately
|
37
|
+
# show the error message but also log it.
|
38
|
+
def self.error(err, level=:error, &blk)
|
39
|
+
msg = err.to_s
|
40
|
+
msg = "#{msg} : #{yield}" if blk
|
41
|
+
STDOUT.puts "[#{level.to_s.upcase}] #{msg}"
|
42
|
+
LOGGER.send(level, msg) if defined?(OPTIONS) && OPTIONS[:debug]
|
43
|
+
end
|
44
|
+
|
45
|
+
# This method logs a non-error (or error) message but with the provided
|
46
|
+
# context.
|
47
|
+
def self.log(str, level=:debug, context=nil, &blk)
|
48
|
+
return unless defined?(OPTIONS) && OPTIONS[:debug]
|
49
|
+
msg = str.to_s
|
50
|
+
msg = "#{msg} : #{yield}" if blk
|
51
|
+
if context
|
52
|
+
output = ""
|
53
|
+
pp = PrettyPrint.new(output)
|
54
|
+
context.format_with_msg(pp,msg)
|
55
|
+
pp.flush
|
56
|
+
msg = output
|
57
|
+
end
|
58
|
+
LOGGER.send(level, msg)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|