rmtools 1.0.0 → 1.1.0
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/History.txt +5 -0
- data/Manifest.txt +84 -26
- data/Rakefile +7 -4
- data/ext/extconf.rb +1 -1
- data/ext/rmtools.cpp +27 -12
- data/ext/rmtools.h +6 -5
- data/lib/rmtools/b.rb +18 -0
- data/lib/rmtools/console/coloring.rb +72 -0
- data/lib/rmtools/console/highlight.rb +13 -0
- data/lib/rmtools/{printing.rb → console/printing.rb} +17 -2
- data/lib/rmtools/console.rb +1 -0
- data/lib/rmtools/conversions/enum.rb +23 -0
- data/lib/rmtools/conversions/int.rb +47 -0
- data/lib/rmtools/conversions/string.rb +26 -0
- data/lib/rmtools/conversions.rb +1 -0
- data/lib/rmtools/core/arguments.rb +52 -0
- data/lib/rmtools/{boolean.rb → core/boolean.rb} +0 -13
- data/lib/rmtools/core/class.rb +41 -0
- data/lib/rmtools/core/js.rb +45 -0
- data/lib/rmtools/core/kernel.rb +28 -0
- data/lib/rmtools/{module.rb → core/module.rb} +0 -41
- data/lib/rmtools/core/numeric.rb +35 -0
- data/lib/rmtools/{object.rb → core/object.rb} +2 -23
- data/lib/rmtools/core/proc.rb +18 -0
- data/lib/rmtools/core/regexp.rb +11 -0
- data/lib/rmtools/core/string_compliance.rb +31 -0
- data/lib/rmtools/core.rb +1 -0
- data/lib/rmtools/db/active_record.rb +54 -0
- data/lib/rmtools/db.rb +7 -0
- data/lib/rmtools/debug/binding.rb +56 -0
- data/lib/rmtools/debug/highlight.rb +23 -0
- data/lib/rmtools/debug/logging.rb +176 -0
- data/lib/rmtools/debug/present.rb +38 -0
- data/lib/rmtools/debug/timer.rb +19 -0
- data/lib/rmtools/debug/traceback.rb +92 -0
- data/lib/rmtools/debug.rb +1 -0
- data/lib/rmtools/debug_notrace.rb +1 -0
- data/lib/rmtools/enumerable/array.rb +134 -0
- data/lib/rmtools/enumerable/array_iterators.rb +33 -0
- data/lib/rmtools/enumerable/common.rb +49 -0
- data/lib/rmtools/{hash.rb → enumerable/hash.rb} +8 -8
- data/lib/rmtools/enumerable/object_space.rb +19 -0
- data/lib/rmtools/enumerable/range.rb +201 -0
- data/lib/rmtools/enumerable.rb +1 -0
- data/lib/rmtools/experimental/blackhole.rb +12 -0
- data/lib/rmtools/experimental/deprecation.rb +36 -0
- data/lib/rmtools/experimental/dumps.rb +28 -0
- data/lib/rmtools/{numeric.rb → experimental/numeric.rb} +22 -51
- data/lib/rmtools/experimental/rails_backtrace.rb +29 -0
- data/lib/rmtools/experimental/string.rb +56 -0
- data/lib/rmtools/{tree.rb → experimental/tree.rb} +0 -0
- data/lib/rmtools/experimental.rb +1 -0
- data/lib/rmtools/fs/dir.rb +89 -0
- data/lib/rmtools/fs/file.rb +104 -0
- data/lib/rmtools/fs/io.rb +58 -0
- data/lib/rmtools/fs/tools.rb +49 -0
- data/lib/rmtools/fs.rb +1 -0
- data/lib/rmtools/functional/fold.rb +32 -0
- data/lib/rmtools/{string_to_proc.rb → functional/string_to_proc.rb} +2 -22
- data/lib/rmtools/functional/unfold.rb +16 -0
- data/lib/rmtools/functional.rb +1 -0
- data/lib/rmtools/ip/numeric.rb +35 -0
- data/lib/rmtools/ip/string.rb +45 -0
- data/lib/rmtools/ip.rb +1 -0
- data/lib/rmtools/lang/ansi.rb +17 -0
- data/lib/rmtools/lang/cyrillic.rb +106 -0
- data/lib/rmtools/lang/regexp.rb +8 -0
- data/lib/rmtools/lang/shortcuts.rb +20 -0
- data/lib/rmtools/lang.rb +1 -0
- data/lib/rmtools/rand/array.rb +39 -0
- data/lib/rmtools/rand/enum.rb +26 -0
- data/lib/rmtools/rand/range.rb +13 -0
- data/lib/rmtools/{random.rb → rand/string.rb} +13 -107
- data/lib/rmtools/rand.rb +1 -0
- data/lib/rmtools/require.rb +13 -0
- data/lib/rmtools/setup.rb +6 -5
- data/lib/rmtools/text/string_parse.rb +60 -0
- data/lib/rmtools/{stringscanner.rb → text/string_scanner.rb} +3 -2
- data/lib/rmtools/text/string_simple.rb +75 -0
- data/lib/rmtools/text/string_split.rb +148 -0
- data/lib/rmtools/text/textilize.rb +44 -0
- data/lib/rmtools/text.rb +1 -0
- data/lib/rmtools/time/global.rb +17 -0
- data/lib/rmtools/time/russian.rb +47 -0
- data/lib/rmtools/time.rb +1 -32
- data/lib/rmtools/xml/document.rb +28 -0
- data/lib/rmtools/xml/finders.rb +84 -0
- data/lib/rmtools/xml/libxml.rb +11 -0
- data/lib/rmtools/xml/node.rb +196 -0
- data/lib/rmtools/xml/string.rb +43 -0
- data/lib/rmtools/xml/xpath.rb +32 -0
- data/lib/rmtools/xml.rb +7 -0
- data/lib/rmtools.rb +8 -44
- metadata +97 -72
- data/lib/rmtools/arguments.rb +0 -24
- data/lib/rmtools/array.rb +0 -189
- data/lib/rmtools/binding.rb +0 -23
- data/lib/rmtools/coloring.rb +0 -82
- data/lib/rmtools/cyr-time.rb +0 -49
- data/lib/rmtools/cyrilic.rb +0 -124
- data/lib/rmtools/dumps.rb +0 -192
- data/lib/rmtools/enum.rb +0 -90
- data/lib/rmtools/io.rb +0 -303
- data/lib/rmtools/js.rb +0 -25
- data/lib/rmtools/limited_string.rb +0 -17
- data/lib/rmtools/logging.rb +0 -158
- data/lib/rmtools/proc.rb +0 -25
- data/lib/rmtools/range.rb +0 -100
- data/lib/rmtools/string.rb +0 -276
- data/lib/rmtools/traceback.rb +0 -106
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Kernel
|
|
2
|
+
|
|
3
|
+
# re-require
|
|
4
|
+
def require!(file)
|
|
5
|
+
%w{.rb .so .dll}.each {|ext| $".delete "#{file}#{ext}"}
|
|
6
|
+
require file
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def obtained(obj, &func)
|
|
10
|
+
if obj.is Proc
|
|
11
|
+
if obj.arity == 0
|
|
12
|
+
func.call obj.call
|
|
13
|
+
else # obj is a function receiving another function
|
|
14
|
+
obj.call &func
|
|
15
|
+
end
|
|
16
|
+
else func.call obj
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def TypeError! given, *expected
|
|
21
|
+
"invalid argument type #{given.class.name}, expected #{expected*' or '}"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def executing? file=$0
|
|
25
|
+
caller(0)[0] =~ /^#{file}:/
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
@@ -70,44 +70,3 @@ private
|
|
|
70
70
|
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
class Class
|
|
74
|
-
|
|
75
|
-
# define python-like initializer form
|
|
76
|
-
def __init__
|
|
77
|
-
modname, classname = name.rsplit('::', 2)
|
|
78
|
-
classname ||= modname
|
|
79
|
-
mod = '::'.in(name) ? eval(modname) : RMTools
|
|
80
|
-
mod.module_eval "def #{classname} *args; #{name}.new *args end
|
|
81
|
-
module_function :#{classname}"
|
|
82
|
-
if mod != RMTools
|
|
83
|
-
mod.each_child {|c| c.class_eval "include #{mod}; extend #{mod}" if !c.in c.children}
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def method_proxy *vars
|
|
88
|
-
buffered_missing = instance_methods.grep(/method_missing/).sort.last || 'method_missing'
|
|
89
|
-
# next arg overrides previous
|
|
90
|
-
vars.each {|v|
|
|
91
|
-
class_eval "
|
|
92
|
-
alias #{buffered_missing.bump! '_'} method_missing
|
|
93
|
-
def method_missing *args, &block
|
|
94
|
-
#{v}.send *args, &block
|
|
95
|
-
rescue NoMethodError
|
|
96
|
-
#{buffered_missing} *args, &block
|
|
97
|
-
end"
|
|
98
|
-
}
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def personal_methods filter=//
|
|
102
|
-
(self.singleton_methods - self.superclass.singleton_methods).sort!.grep(filter)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def my_instance_methods filter=//
|
|
106
|
-
(self.public_instance_methods - Object.public_instance_methods).sort!.grep(filter)
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def personal_instance_methods filter=//
|
|
110
|
-
(self.public_instance_methods - self.superclass.public_instance_methods).sort!.grep(filter)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
class Numeric
|
|
3
|
+
|
|
4
|
+
def ceil_to(i)
|
|
5
|
+
self + i - self%i
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def floor_to(i)
|
|
9
|
+
self - self%i
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def round_to(i)
|
|
13
|
+
[ceil_to(i), floor_to(i)].max
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def between(min, max)
|
|
17
|
+
min < self and self < max
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def mult_of(subj)
|
|
21
|
+
self%subj == 0
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def hex
|
|
25
|
+
sprintf "%x", self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
module Math
|
|
31
|
+
|
|
32
|
+
def logb(b, x) log(x)/log(b) end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
class Object
|
|
3
3
|
alias :resto :respond_to?
|
|
4
|
-
|
|
5
|
-
def requrie file
|
|
6
|
-
require file
|
|
7
|
-
end
|
|
8
|
-
#alias :requrie :require # most frequent typo, lol
|
|
4
|
+
alias :requrie :require # most frequent typo, lol
|
|
9
5
|
|
|
10
6
|
def is klass
|
|
11
7
|
if Array === klass
|
|
@@ -50,25 +46,8 @@ class Object
|
|
|
50
46
|
self
|
|
51
47
|
end
|
|
52
48
|
|
|
53
|
-
def in
|
|
49
|
+
def in(*container)
|
|
54
50
|
container.size == 1 ? container[0].include?(self) : container.include?(self)
|
|
55
51
|
end
|
|
56
52
|
|
|
57
|
-
def require! file
|
|
58
|
-
%w{.rb .so .dll}.each {|ext| $".delete "#{file}#{ext}"}
|
|
59
|
-
require file
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def b; self end
|
|
63
|
-
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
class BlackHole
|
|
67
|
-
|
|
68
|
-
# Think twice before use it. It may devour your code!
|
|
69
|
-
def method_missing *args
|
|
70
|
-
BlackHole.new
|
|
71
|
-
end
|
|
72
|
-
|
|
73
53
|
end
|
|
74
|
-
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
class Proc
|
|
3
|
+
NULL = lambda {} unless defined? Proc::NULL
|
|
4
|
+
attr_accessor :string
|
|
5
|
+
|
|
6
|
+
def when
|
|
7
|
+
Thread.new do
|
|
8
|
+
sleep 0.001 until yield
|
|
9
|
+
call
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.eval string, binding=nil
|
|
14
|
+
(proc = (binding || Kernel).eval "lambda {#{string}}").string = string
|
|
15
|
+
proc
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class String
|
|
2
|
+
|
|
3
|
+
if RUBY_VERSION < "1.9"
|
|
4
|
+
def ord; self[0] end
|
|
5
|
+
else
|
|
6
|
+
# BUGFIX?
|
|
7
|
+
alias :sub19 :sub
|
|
8
|
+
alias :sub19! :sub!
|
|
9
|
+
alias :gsub19 :gsub
|
|
10
|
+
alias :gsub19! :gsub!
|
|
11
|
+
|
|
12
|
+
def sub! a,b=nil,&c
|
|
13
|
+
if b
|
|
14
|
+
if b=~/\\\d/
|
|
15
|
+
b = b.sub19!(/\\\d/) {|m| "\#{$#{m[1,1]}}"}
|
|
16
|
+
sub19!(a) {eval "\"#{b}\""}
|
|
17
|
+
else sub19!(a) {b} end
|
|
18
|
+
else sub19! a,&c end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def sub a,b=nil,&c
|
|
22
|
+
if b
|
|
23
|
+
if b=~/\\\d/
|
|
24
|
+
b = b.sub19(/\\\d/) {|m| "\#{$#{m[1,1]}}"}
|
|
25
|
+
sub19(a) {eval "\"#{b}\""}
|
|
26
|
+
else sub19(a) {b} end
|
|
27
|
+
else sub19 a,&c end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
data/lib/rmtools/core.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require_with_path __FILE__, '*'
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'active_record'
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
|
|
5
|
+
def self.establish_connection_with config
|
|
6
|
+
c = case config
|
|
7
|
+
when String
|
|
8
|
+
c = if config.inline
|
|
9
|
+
if c = RMTools.read(config) then c
|
|
10
|
+
else return; nil
|
|
11
|
+
end
|
|
12
|
+
else config
|
|
13
|
+
end
|
|
14
|
+
YAML.load c
|
|
15
|
+
when IO then YAML.load config
|
|
16
|
+
else config
|
|
17
|
+
end
|
|
18
|
+
Base.establish_connection(c) rescue(false)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class Base
|
|
22
|
+
|
|
23
|
+
def self.establish_connection_with config
|
|
24
|
+
ActiveRecord.establish_connection_with config
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_hash
|
|
28
|
+
serializer = Serializer.new(self)
|
|
29
|
+
serializer.respond_to?(:attributes_hash) ?
|
|
30
|
+
serializer.attributes_hash :
|
|
31
|
+
serializer.serializable_record
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
alias :delete_with_id :delete
|
|
35
|
+
# a problem was: model.delete() won't work if it has no id. Just delete() it if has
|
|
36
|
+
def delete
|
|
37
|
+
id ? delete_with_id : self.class.delete_all(attributes)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.merge_conditions(*conditions)
|
|
41
|
+
segments = conditions.map {|condition|
|
|
42
|
+
sanitize_sql condition
|
|
43
|
+
}.reject {|condition|
|
|
44
|
+
condition.blank?
|
|
45
|
+
}
|
|
46
|
+
"(#{segments.join(') AND (')})" unless segments.empty?
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
data/lib/rmtools/db.rb
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
class Binding
|
|
2
|
+
|
|
3
|
+
def inspect_local_variables
|
|
4
|
+
vars = self.eval('local_variables') # ['a', 'b']
|
|
5
|
+
values = self.eval "[#{vars * ','}]" # ["a's value", "b's value"]
|
|
6
|
+
Hash[vars.zip(values)]
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def inspect_instance_variables
|
|
10
|
+
vars = self.eval('instance_variables') # ['@a', '@b']
|
|
11
|
+
values = self.eval "[#{vars * ','}]" # ["@a's value", "@b's value"]
|
|
12
|
+
Hash[vars.zip(values)]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def inspect_env
|
|
16
|
+
self.eval("{'self' => self}").merge(inspect_local_variables).merge(inspect_instance_variables)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def valid_types(pattern_ary)
|
|
20
|
+
self.eval("[#{self.eval('local_variables')*','}]").valid_types(pattern_ary)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def report(obj)
|
|
24
|
+
if Array === obj
|
|
25
|
+
obj.map {|s| self.eval "\"#{s.gsub('"'){'\"'}} = \#{(#{s}).inspect}\""} * '; '
|
|
26
|
+
else
|
|
27
|
+
obj.to_s.split(' ').map {|s| self.eval "\"#{s.gsub('"'){'\"'}} = \#{(#{s}).inspect}\""} * '; '
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# it's supposed to be called during TDD in an IRB session
|
|
32
|
+
# $__MAIN__ must be `self' or root IRB session, i.e. `main' object
|
|
33
|
+
# def tested_function
|
|
34
|
+
# blah blah blah
|
|
35
|
+
# rescue => err
|
|
36
|
+
# binding.start_interaction
|
|
37
|
+
# raise err
|
|
38
|
+
# end
|
|
39
|
+
def start_interaction(sandbox=true)
|
|
40
|
+
$__env__ = inspect_env
|
|
41
|
+
Kernel.puts RMTools.format_trace(caller(2)).join("\n")
|
|
42
|
+
$env.present
|
|
43
|
+
$__binding__ = self
|
|
44
|
+
|
|
45
|
+
$log << "entering irb"
|
|
46
|
+
$__MAIN__.irb
|
|
47
|
+
# Now input "irb_change_binding$__binding__" and have fun with debug
|
|
48
|
+
$log << "exiting irb"
|
|
49
|
+
|
|
50
|
+
if sandbox
|
|
51
|
+
self.eval($env.keys.map {|k, v| "#{k} = $env[#{k.inspect}]"} * '; ')
|
|
52
|
+
end
|
|
53
|
+
$__env__ = nil
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require_with_path 'console/coloring'
|
|
2
|
+
|
|
3
|
+
module RMTools
|
|
4
|
+
|
|
5
|
+
def highlighted_line(file, line)
|
|
6
|
+
if defined? SCRIPT_LINES__
|
|
7
|
+
" >> #{Painter.green SCRIPT_LINES__[file][line.to_i - 1].chop}" if SCRIPT_LINES__[file]
|
|
8
|
+
else
|
|
9
|
+
file = Readline::TEMPLOG if file == '(irb)' and defined? Readline::TEMPLOG
|
|
10
|
+
" >> #{Painter.green read_lines(file, line.to_i).chop}" if File.file? file
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module_function :highlighted_line
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class Proc
|
|
18
|
+
|
|
19
|
+
def inspect
|
|
20
|
+
"#{str=to_s}: #{@string ? Painter.green(@string) : "\n"+RMTools.highlighted_line(*str.match(/([^@]+):(\d+)>$/)[1..2])}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require_with_path 'console/coloring'
|
|
3
|
+
require_with_path 'text/string_parse'
|
|
4
|
+
|
|
5
|
+
module RMTools
|
|
6
|
+
|
|
7
|
+
# lazy logger
|
|
8
|
+
# with caller processing and highlighting
|
|
9
|
+
class RMLogger
|
|
10
|
+
__init__
|
|
11
|
+
attr_accessor :mute_info, :mute_warn, :mute_log, :mute_debug
|
|
12
|
+
attr_reader :default_format
|
|
13
|
+
|
|
14
|
+
Modes = %w{debug log info warn}.to_syms
|
|
15
|
+
NOPRINT = 4
|
|
16
|
+
NOLOG = 2
|
|
17
|
+
INLINE = 1
|
|
18
|
+
|
|
19
|
+
def initialize format={}
|
|
20
|
+
@clr = Coloring.new
|
|
21
|
+
@highlight = {
|
|
22
|
+
:warn => @clr.red_bold("WARN"),
|
|
23
|
+
:log => @clr.cyan("INFO"),
|
|
24
|
+
:info => @clr.cyan_bold("INFO"),
|
|
25
|
+
:debug => @clr.gray_bold("DEBUG")
|
|
26
|
+
}
|
|
27
|
+
@file_formats = Hash.new(@default_format = {})
|
|
28
|
+
set_format :global, format
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def _set_format file, format
|
|
32
|
+
file.print = !format.q
|
|
33
|
+
file.out = format.out
|
|
34
|
+
|
|
35
|
+
file.path_format = '%'.in file.out if file.out
|
|
36
|
+
file.tf = format.time.to_a
|
|
37
|
+
file.cf0 = format.caller
|
|
38
|
+
file.cf = file.cf0.sub('%p'){'\1'}.sub('%f'){'\2'}.sub('%l'){'\3'}.sub('%m'){'\4'}
|
|
39
|
+
file.fmt = format.format
|
|
40
|
+
file._time, file._caller = '%time'.in(file.fmt), '%caller'.in(file.fmt)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def defaults
|
|
44
|
+
puts %{ :q => false, # not print
|
|
45
|
+
:out => false, # output to file, may have strftime's %H%M%Y for filename
|
|
46
|
+
:time => ["%H:%M:%S", "%03d"], # strftime, [msecs]
|
|
47
|
+
:caller => "#{@clr.gray('%f:%l')} #{@clr.red_bold(':%m')}", # file:line :method
|
|
48
|
+
:format => "%time %mode [%caller]: %text" # no comments}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# set any needed params, the rest will be set by default
|
|
52
|
+
def set_format *args
|
|
53
|
+
global, format = args.fetch_opts [nil],
|
|
54
|
+
:time => ["%H:%M:%S", "%03d"],
|
|
55
|
+
:caller => "#{@clr.gray('%f:%l')} #{@clr.red_bold(':%m')}",
|
|
56
|
+
:format => "%time %mode [%caller]: %text"
|
|
57
|
+
if global
|
|
58
|
+
_set_format @default_format, format
|
|
59
|
+
else
|
|
60
|
+
_set_format(file_format={}, format)
|
|
61
|
+
@file_formats[File.expand_path(caller[0].till ':')] = file_format
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def get_format file=nil
|
|
66
|
+
cfg = @file_formats[file && File.expand_path(file)]
|
|
67
|
+
modes = Modes.reject {|m| send :"mute_#{m}"}
|
|
68
|
+
%{<Logger #{cfg.fmt.sub('%time', "%time(#{cfg.tf*'.'})").sub('%caller', "%caller(#{cfg.cf0})")}#{' -> '+cfg.out if cfg.out} #{modes.b ? modes.inspect : 'muted'}>}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def _print mode, text, opts, caler, bind, cfg
|
|
72
|
+
log_ = opts&NOLOG==0
|
|
73
|
+
print_ = opts&NOPRINT==0
|
|
74
|
+
str = cfg.fmt.dup
|
|
75
|
+
str.sub! "%mode", @highlight[mode]
|
|
76
|
+
if bind
|
|
77
|
+
text = bind.report text
|
|
78
|
+
elsif !text.is String
|
|
79
|
+
text = text.inspect
|
|
80
|
+
end
|
|
81
|
+
str.sub! "%text", text
|
|
82
|
+
str << "\n" if opts&INLINE==0
|
|
83
|
+
out = cfg.out
|
|
84
|
+
if cfg._time or cfg.path_format
|
|
85
|
+
now = Time.now
|
|
86
|
+
if cfg._time
|
|
87
|
+
time = now.strftime cfg.tf[0]
|
|
88
|
+
time << ".#{cfg.tf[1]%[now.usec/1000]}" if cfg.tf[1]
|
|
89
|
+
str.sub! "%time", time
|
|
90
|
+
end
|
|
91
|
+
out = now.strftime cfg.out if cfg.path_format
|
|
92
|
+
end
|
|
93
|
+
str.sub! "%caller", caler.sub(String::CALLER_RE, cfg.cf) if caler
|
|
94
|
+
log_str = @clr.clean str
|
|
95
|
+
RMTools.write out, log_str if log_
|
|
96
|
+
Kernel.print str if print_
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def check_binding a
|
|
100
|
+
a[0].is(Binding) ? [a[0], a[1] || 0] : [nil, a[0] || 0]
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def get_config!
|
|
104
|
+
@file_formats.empty? ? @default_format : @file_formats[File.expand_path(caller(2)[0].till ':')]
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# controllers:
|
|
108
|
+
# - $panic: print debug messages
|
|
109
|
+
# - $verbose: print log messages
|
|
110
|
+
# - $quiet: print only warn messages regardless of other globals
|
|
111
|
+
# - @mute_warn, @mute_info, @mute_log: do not print
|
|
112
|
+
# this messages regardless of any globals
|
|
113
|
+
# - @out_all: write to file any messages
|
|
114
|
+
|
|
115
|
+
def warn text="\b\b ", *a
|
|
116
|
+
cfg = get_config!
|
|
117
|
+
if (cfg.out or cfg.print) && !@mute_warn
|
|
118
|
+
bind, opts = check_binding a
|
|
119
|
+
opts |= NOLOG if !cfg.out
|
|
120
|
+
opts |= NOPRINT if !cfg.print
|
|
121
|
+
text ||= yield if block_given?
|
|
122
|
+
_print(:warn, text, opts, cfg._caller && caller[0], bind, cfg)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def log text="\b\b ", *a
|
|
127
|
+
cfg = get_config!
|
|
128
|
+
if (cfg.out or cfg.print && !$quiet && $verbose) && !@mute_log
|
|
129
|
+
bind, opts = check_binding a
|
|
130
|
+
opts |= NOLOG if !cfg.out
|
|
131
|
+
opts |= NOPRINT if !(cfg.print && !$quiet && $verbose)
|
|
132
|
+
text ||= yield if block_given?
|
|
133
|
+
_print(:log, text, opts, cfg._caller && caller[0], bind, cfg)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def info text="\b\b ", *a
|
|
138
|
+
cfg = get_config!
|
|
139
|
+
if (cfg.print && !$quiet or cfg.out && cfg.out_all) && !@mute_info
|
|
140
|
+
bind, opts = check_binding a
|
|
141
|
+
opts |= NOLOG if !(cfg.out && cfg.out_all)
|
|
142
|
+
opts |= NOPRINT if !(cfg.print && !$quiet)
|
|
143
|
+
text ||= yield if block_given?
|
|
144
|
+
_print(:info, text, opts, cfg._caller && caller[0], bind, cfg)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def debug text="\b\b ", *a
|
|
149
|
+
cfg = get_config!
|
|
150
|
+
if (cfg.print && $panic && !$quiet or cfg.out && cfg.out_all) && !@mute_debug
|
|
151
|
+
bind, opts = check_binding a
|
|
152
|
+
opts |= NOLOG if !(cfg.out && cfg.out_all)
|
|
153
|
+
opts |= NOPRINT if !(cfg.print && $panic && !$quiet)
|
|
154
|
+
text ||= yield if block_given?
|
|
155
|
+
_print(:debug, text, opts, cfg._caller && caller[0], bind, cfg)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
alias << info
|
|
160
|
+
alias < warn
|
|
161
|
+
|
|
162
|
+
Modes.each {|m| define_method("#{m}=") {|mute| send :"mute_#{m}=", !mute}}
|
|
163
|
+
|
|
164
|
+
def outall=(x) @default_format.out_all = x end
|
|
165
|
+
def print=(x) @default_format.print = x end
|
|
166
|
+
def out=(x) @default_format.out = x end
|
|
167
|
+
|
|
168
|
+
def out_all() @default_format.out_all end
|
|
169
|
+
def print() @default_format.print end
|
|
170
|
+
def out() @default_format.out end
|
|
171
|
+
|
|
172
|
+
def inspect() get_format end
|
|
173
|
+
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
class Object
|
|
3
|
+
|
|
4
|
+
def present
|
|
5
|
+
Hash[readable_variables.map {|v| [":#{v}", __send__(v)]}].present
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class Array
|
|
11
|
+
|
|
12
|
+
def present(inspect_string=nil)
|
|
13
|
+
res = "[ "
|
|
14
|
+
indent = (size-1).to_s.size
|
|
15
|
+
res << map_with_index {|k,i|
|
|
16
|
+
"#{i.to_s.rjust(indent)}: #{(k.is String and !inspect_string) ? k : k.inspect}"
|
|
17
|
+
}*"\n "
|
|
18
|
+
res << "]"
|
|
19
|
+
puts res
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class Hash
|
|
25
|
+
|
|
26
|
+
def present(inspect_string=nil)
|
|
27
|
+
str = "{ "
|
|
28
|
+
sorted = sort rescue to_a.sort_by_to_s
|
|
29
|
+
str << sorted.map {|k,v|
|
|
30
|
+
"#{(k.is String and !inspect_string) ? k : k.inspect} => #{(v.is String and !inspect_string) ? v : v.inspect},"
|
|
31
|
+
}*"\n "
|
|
32
|
+
str << "}"
|
|
33
|
+
puts str
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require_with_path 'console/coloring'
|
|
2
|
+
|
|
3
|
+
module RMTools
|
|
4
|
+
|
|
5
|
+
def timer(ts=1, output=true)
|
|
6
|
+
timez = ts - 1
|
|
7
|
+
panic, verbose = $panic, $verbose
|
|
8
|
+
$panic = $verbose = false
|
|
9
|
+
t1 = Time.now
|
|
10
|
+
timez.times {yield}
|
|
11
|
+
res = yield
|
|
12
|
+
t2 = (Time.now.to_f*1000).round
|
|
13
|
+
t1 = (t1.to_f*1000).round
|
|
14
|
+
$panic, $verbose = panic, verbose
|
|
15
|
+
res = res.inspect
|
|
16
|
+
puts "#{output ? "res: #{res.size > 1000 ? res[0...1000]+"…" : res}\n" : "size of res string: #{res.to_s.size}, "}one: #{Painter.gray '%0.4fms'%[(t2-t1).to_f/ts]}, total: #{Painter.gray "#{(t2-t1).to_f}ms"}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
require_with_path 'debug/highlight'
|
|
2
|
+
module Kernel
|
|
3
|
+
|
|
4
|
+
# Python-like traceback for exceptions; uses ANSI coloring.
|
|
5
|
+
# In case of any low-level ruby error it may hang up interpreter
|
|
6
|
+
# (although you must have done creepy things for that). If you find
|
|
7
|
+
# interpreter in hanging up, require 'rmtools_notrace' instead of 'rmtools'
|
|
8
|
+
# or run "Exception.trace_format false" right after require
|
|
9
|
+
#
|
|
10
|
+
# 1:0> def divbyzero
|
|
11
|
+
# 2:1< 10/0 end
|
|
12
|
+
# => nil
|
|
13
|
+
# 3:0> divbyzero
|
|
14
|
+
# ZeroDivisionError: divided by 0
|
|
15
|
+
# from (irb):2:in `divbyzero' <- `/'
|
|
16
|
+
# >> 10/0 end
|
|
17
|
+
# from (irb):3
|
|
18
|
+
# >> divbyzero
|
|
19
|
+
def format_trace a
|
|
20
|
+
bt, calls, i = [], [], 0
|
|
21
|
+
# $log.info 'a.size', binding
|
|
22
|
+
m = a[0].parse:caller
|
|
23
|
+
while i < a.size
|
|
24
|
+
# $log.info i
|
|
25
|
+
m2 = a[i+1] && a[i+1].parse(:caller)
|
|
26
|
+
# $log.info 'm', binding
|
|
27
|
+
# $log.info 'm2', binding
|
|
28
|
+
# $log.info 'm[3] m[1..2]==m2[1..2]', binding if m and m2
|
|
29
|
+
# $log.info 'm[1] m[2]', binding if m
|
|
30
|
+
# $log.info highlighted_line(*m[1..2]) if m
|
|
31
|
+
if m and m.func and m2 and [m.path, m.line] == [m2.path, m2.line]
|
|
32
|
+
calls << "`#{m.func}' -> "
|
|
33
|
+
elsif m and m.line != 0 and line = highlighted_line(m.path, m.line)
|
|
34
|
+
bt << "#{a[i]}#{calls.join}\n#{line}"
|
|
35
|
+
calls = []
|
|
36
|
+
else bt << a[i]
|
|
37
|
+
end
|
|
38
|
+
i += 1
|
|
39
|
+
m = m2
|
|
40
|
+
end
|
|
41
|
+
# $log << Painter.r("FORMAT DONE! #{bt.size} lines formatted")
|
|
42
|
+
bt
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class Class
|
|
48
|
+
|
|
49
|
+
def trace_format method
|
|
50
|
+
if Exception.in ancestors
|
|
51
|
+
class_eval(method ? %{
|
|
52
|
+
def set_backtrace src
|
|
53
|
+
src = #{method} src
|
|
54
|
+
set_bt src
|
|
55
|
+
end
|
|
56
|
+
} : %{
|
|
57
|
+
def set_backtrace src
|
|
58
|
+
set_bt src
|
|
59
|
+
end
|
|
60
|
+
})
|
|
61
|
+
else
|
|
62
|
+
raise NoMethodError, "undefined method `trace_format' for class #{self}"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# 1.9 may hung up processing IO while generating traceback
|
|
69
|
+
if RUBY_VERSION < '1.9'
|
|
70
|
+
class Exception
|
|
71
|
+
alias :set_bt :set_backtrace
|
|
72
|
+
|
|
73
|
+
# to use trace formatting ensure that you have SCRIPT_LINES__ constant set
|
|
74
|
+
# SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
|
|
75
|
+
#
|
|
76
|
+
# If you also set (e.g. in irbrc file)
|
|
77
|
+
# module Readline
|
|
78
|
+
# alias :orig_readline :readline
|
|
79
|
+
# def readline(*args)
|
|
80
|
+
# ln = orig_readline(*args)
|
|
81
|
+
# SCRIPT_LINES__['(irb)'] << "#{ln}\n"
|
|
82
|
+
# ln
|
|
83
|
+
# end
|
|
84
|
+
# end
|
|
85
|
+
# it will be possible to get the lines entered in IRB
|
|
86
|
+
# else it reads only ordinal require'd files
|
|
87
|
+
|
|
88
|
+
trace_format :format_trace
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
SystemStackError.trace_format false
|
|
92
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require_with_path __FILE__, '*'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require_with_path 'debug', '{binding,logging,present,timer}'
|