rubybreaker 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|