wtf-tools 1.0.3 → 1.0.4
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.
- checksums.yaml +4 -4
- data/LICENSE +22 -22
- data/README.md +165 -164
- data/Rakefile +8 -8
- data/example/dump.rb +30 -30
- data/example/timing.rb +20 -20
- data/example/tracking.rb +32 -32
- data/lib/wtf-tools.rb +69 -69
- data/lib/wtf/dumper.rb +144 -113
- data/lib/wtf/method_tracker.rb +90 -90
- data/lib/wtf/query_tracker.rb +48 -48
- data/wtf-tools.gemspec +24 -24
- metadata +1 -1
data/example/timing.rb
CHANGED
@@ -1,20 +1,20 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'wtf-tools'
|
3
|
-
require 'active_support/logger'
|
4
|
-
|
5
|
-
# default: puts
|
6
|
-
WTF.time {
|
7
|
-
sleep 1.01
|
8
|
-
}
|
9
|
-
|
10
|
-
# logging time with specified precision and options
|
11
|
-
WTF.options = {
|
12
|
-
output: {
|
13
|
-
default: ActiveSupport::Logger.new('./example.log'),
|
14
|
-
}
|
15
|
-
}
|
16
|
-
result = WTF.time(4, :nl) {
|
17
|
-
sleep 3.12346
|
18
|
-
17
|
19
|
-
}
|
20
|
-
p result # => 17
|
1
|
+
require 'rubygems'
|
2
|
+
require 'wtf-tools'
|
3
|
+
require 'active_support/logger'
|
4
|
+
|
5
|
+
# default: puts
|
6
|
+
WTF.time {
|
7
|
+
sleep 1.01
|
8
|
+
}
|
9
|
+
|
10
|
+
# logging time with specified precision and options
|
11
|
+
WTF.options = {
|
12
|
+
output: {
|
13
|
+
default: ActiveSupport::Logger.new('./example.log'),
|
14
|
+
}
|
15
|
+
}
|
16
|
+
result = WTF.time(4, :nl) {
|
17
|
+
sleep 3.12346
|
18
|
+
17
|
19
|
+
}
|
20
|
+
p result # => 17
|
data/example/tracking.rb
CHANGED
@@ -1,32 +1,32 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'wtf-tools'
|
3
|
-
require 'fileutils'
|
4
|
-
require 'csv'
|
5
|
-
|
6
|
-
WTF.options = {
|
7
|
-
files: './wtf',
|
8
|
-
}
|
9
|
-
|
10
|
-
class Sample
|
11
|
-
def run
|
12
|
-
WTF.track(self)
|
13
|
-
action1
|
14
|
-
action2
|
15
|
-
action3
|
16
|
-
WTF.track_finish
|
17
|
-
end
|
18
|
-
|
19
|
-
def action1
|
20
|
-
sleep 1
|
21
|
-
end
|
22
|
-
|
23
|
-
def action2
|
24
|
-
sleep 2
|
25
|
-
end
|
26
|
-
|
27
|
-
def action3
|
28
|
-
sleep 3
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
Sample.new.run
|
1
|
+
require 'rubygems'
|
2
|
+
require 'wtf-tools'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'csv'
|
5
|
+
|
6
|
+
WTF.options = {
|
7
|
+
files: './wtf',
|
8
|
+
}
|
9
|
+
|
10
|
+
class Sample
|
11
|
+
def run
|
12
|
+
WTF.track(self)
|
13
|
+
action1
|
14
|
+
action2
|
15
|
+
action3
|
16
|
+
WTF.track_finish
|
17
|
+
end
|
18
|
+
|
19
|
+
def action1
|
20
|
+
sleep 1
|
21
|
+
end
|
22
|
+
|
23
|
+
def action2
|
24
|
+
sleep 2
|
25
|
+
end
|
26
|
+
|
27
|
+
def action3
|
28
|
+
sleep 3
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Sample.new.run
|
data/lib/wtf-tools.rb
CHANGED
@@ -1,69 +1,69 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
module WTF
|
6
|
-
class << self
|
7
|
-
def options=(value)
|
8
|
-
@options = value
|
9
|
-
end
|
10
|
-
|
11
|
-
def options
|
12
|
-
@options ||= {}
|
13
|
-
end
|
14
|
-
|
15
|
-
def files_path
|
16
|
-
if options[:files]
|
17
|
-
dirs = FileUtils.mkdir_p(options[:files])
|
18
|
-
dirs.first
|
19
|
-
else
|
20
|
-
Dir.getwd
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def output_options
|
25
|
-
Hash(options[:output])
|
26
|
-
end
|
27
|
-
|
28
|
-
# TODO: separately track ActiveRecord finders usage in the related methods
|
29
|
-
def track(*objects)
|
30
|
-
WTF::MethodTracker.start_tracking(*objects)
|
31
|
-
if block_given?
|
32
|
-
yield
|
33
|
-
track_finish
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def track_finish
|
38
|
-
WTF::MethodTracker.finish
|
39
|
-
end
|
40
|
-
|
41
|
-
def sql(*args)
|
42
|
-
WTF::QueryTracker.start_tracking(*args)
|
43
|
-
end
|
44
|
-
|
45
|
-
def time(*args)
|
46
|
-
require 'absolute_time'
|
47
|
-
|
48
|
-
precision = args.shift if args.first.is_a?(Fixnum)
|
49
|
-
precision ||= 3
|
50
|
-
before = AbsoluteTime.now
|
51
|
-
result = yield
|
52
|
-
duration = AbsoluteTime.now - before
|
53
|
-
WTF::Dumper.new(duration.round(precision), *args).call
|
54
|
-
result
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
Object.class_eval do
|
60
|
-
def WTF?(*args)
|
61
|
-
WTF::Dumper.new(*args).call
|
62
|
-
nil
|
63
|
-
end
|
64
|
-
|
65
|
-
def wtf(*args)
|
66
|
-
WTF::Dumper.new(self, *args).call
|
67
|
-
self
|
68
|
-
end
|
69
|
-
end
|
1
|
+
require_relative 'wtf/dumper'
|
2
|
+
require_relative 'wtf/method_tracker'
|
3
|
+
require_relative 'wtf/query_tracker'
|
4
|
+
|
5
|
+
module WTF
|
6
|
+
class << self
|
7
|
+
def options=(value)
|
8
|
+
@options = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def options
|
12
|
+
@options ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def files_path
|
16
|
+
if options[:files]
|
17
|
+
dirs = FileUtils.mkdir_p(options[:files])
|
18
|
+
dirs.first
|
19
|
+
else
|
20
|
+
Dir.getwd
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def output_options
|
25
|
+
Hash(options[:output])
|
26
|
+
end
|
27
|
+
|
28
|
+
# TODO: separately track ActiveRecord finders usage in the related methods
|
29
|
+
def track(*objects)
|
30
|
+
WTF::MethodTracker.start_tracking(*objects)
|
31
|
+
if block_given?
|
32
|
+
yield
|
33
|
+
track_finish
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def track_finish
|
38
|
+
WTF::MethodTracker.finish
|
39
|
+
end
|
40
|
+
|
41
|
+
def sql(*args)
|
42
|
+
WTF::QueryTracker.start_tracking(*args)
|
43
|
+
end
|
44
|
+
|
45
|
+
def time(*args)
|
46
|
+
require 'absolute_time'
|
47
|
+
|
48
|
+
precision = args.shift if args.first.is_a?(Fixnum)
|
49
|
+
precision ||= 3
|
50
|
+
before = AbsoluteTime.now
|
51
|
+
result = yield
|
52
|
+
duration = AbsoluteTime.now - before
|
53
|
+
WTF::Dumper.new(duration.round(precision), *args).call
|
54
|
+
result
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
Object.class_eval do
|
60
|
+
def WTF?(*args)
|
61
|
+
WTF::Dumper.new(*args).call
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def wtf(*args)
|
66
|
+
WTF::Dumper.new(self, *args).call
|
67
|
+
self
|
68
|
+
end
|
69
|
+
end
|
data/lib/wtf/dumper.rb
CHANGED
@@ -1,113 +1,144 @@
|
|
1
|
-
module WTF
|
2
|
-
class Dumper
|
3
|
-
PREFIX_OPTIONS = [:time, :nl, :np].freeze
|
4
|
-
FORMAT_OPTIONS = [:pp, :yaml, :json, :text, :line, :csv].freeze
|
5
|
-
MODIFY_OPTIONS = [:bare].freeze
|
6
|
-
OUTPUT_OPTIONS = [:puts, :error, :file].freeze
|
7
|
-
|
8
|
-
OPTIONS = (PREFIX_OPTIONS + FORMAT_OPTIONS + MODIFY_OPTIONS + OUTPUT_OPTIONS).freeze
|
9
|
-
|
10
|
-
attr_reader :args, :options
|
11
|
-
|
12
|
-
def initialize(*args)
|
13
|
-
@args = args
|
14
|
-
@options = {}
|
15
|
-
while is_option?(args.last)
|
16
|
-
@options[args.pop] = true
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def call
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
data
|
34
|
-
data << "
|
35
|
-
|
36
|
-
data
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
"WTF (
|
41
|
-
end
|
42
|
-
data << ': '
|
43
|
-
end
|
44
|
-
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
1
|
+
module WTF
|
2
|
+
class Dumper
|
3
|
+
PREFIX_OPTIONS = [:time, :nl, :np].freeze
|
4
|
+
FORMAT_OPTIONS = [:pp, :yaml, :json, :text, :line, :csv].freeze
|
5
|
+
MODIFY_OPTIONS = [:bare, :name].freeze
|
6
|
+
OUTPUT_OPTIONS = [:puts, :error, :file].freeze
|
7
|
+
|
8
|
+
OPTIONS = (PREFIX_OPTIONS + FORMAT_OPTIONS + MODIFY_OPTIONS + OUTPUT_OPTIONS).freeze
|
9
|
+
|
10
|
+
attr_reader :args, :options
|
11
|
+
|
12
|
+
def initialize(*args)
|
13
|
+
@args = args
|
14
|
+
@options = {}
|
15
|
+
while is_option?(args.last)
|
16
|
+
@options[args.pop] = true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def call
|
21
|
+
where, names = parse_source(caller[1])
|
22
|
+
data = prefix(where) << format(names)
|
23
|
+
output(data)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def is_option?(sym)
|
29
|
+
OPTIONS.include?(sym) or WTF.output_options.key?(sym)
|
30
|
+
end
|
31
|
+
|
32
|
+
def prefix(where)
|
33
|
+
data = ''
|
34
|
+
data << "\n" if options[:nl]
|
35
|
+
data << "[%s] " % Time.now if options[:time]
|
36
|
+
return data if options[:np]
|
37
|
+
data << if args.first.is_a?(Symbol)
|
38
|
+
args.shift.to_s.upcase
|
39
|
+
else
|
40
|
+
"WTF (#{where})"
|
41
|
+
end
|
42
|
+
data << ': '
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse_source(item)
|
46
|
+
md = item.match(%r{^(.*?([^/]+?)(?:\.rb)?):(\d+):in `(.*)'$})
|
47
|
+
where = '%s/%s:%s' % md.values_at(2, 4, 3)
|
48
|
+
names = parse_names(read_source(md[1], md[3].to_i)) if options[:name]
|
49
|
+
[where, names]
|
50
|
+
end
|
51
|
+
|
52
|
+
def read_source(file, line)
|
53
|
+
File.open(file).each_line.lazy.take(line).to_a[line-1]
|
54
|
+
end
|
55
|
+
|
56
|
+
def parse_names(source)
|
57
|
+
return nil unless source
|
58
|
+
md = source.match(/(\.wtf\(|WTF\?\(?)(.*?)\s*(?:if |unless |$)/)
|
59
|
+
return nil unless md
|
60
|
+
names = md[2].split(',').map(&:strip) # naive
|
61
|
+
names.unshift('self') if md[1] == '.wtf('
|
62
|
+
names
|
63
|
+
end
|
64
|
+
|
65
|
+
def format(names)
|
66
|
+
return format_with_names(names) if names
|
67
|
+
|
68
|
+
case
|
69
|
+
when options[:pp]
|
70
|
+
cleanup(args.pretty_inspect, options[:bare])
|
71
|
+
when options[:yaml]
|
72
|
+
YAML.dump(args)
|
73
|
+
when options[:json]
|
74
|
+
JSON::pretty_generate(args)
|
75
|
+
when options[:text]
|
76
|
+
args.map(&:to_s).join("\n")
|
77
|
+
when options[:line]
|
78
|
+
args.map(&:inspect).join("\n ")
|
79
|
+
when options[:csv]
|
80
|
+
args.first.map(&:to_csv).join
|
81
|
+
else
|
82
|
+
cleanup(args.inspect, options[:bare])
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def format_with_names(names)
|
87
|
+
len = names.map(&:length).max
|
88
|
+
args.each_with_object('').with_index do |(arg, data), i|
|
89
|
+
name = names[i] || '?'
|
90
|
+
data << "\n" << " %-#{len}s => %s" % [name, arg.inspect]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def cleanup(str, bare = false)
|
95
|
+
# remove array parentheses
|
96
|
+
str.gsub!(/^\[|\]$/,'')
|
97
|
+
# ActiveRecord no attributes
|
98
|
+
str.gsub!(/#<[A-Z]\w+ id: \d+\K.*?>/, '>') if bare
|
99
|
+
str
|
100
|
+
end
|
101
|
+
|
102
|
+
def output(data)
|
103
|
+
selected = (OUTPUT_OPTIONS + WTF.output_options.keys).select { |how| options[how] }
|
104
|
+
selected << :default if selected.empty?
|
105
|
+
proxy = Output.new(data)
|
106
|
+
selected.each do |how|
|
107
|
+
proxy.call(how)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class Output
|
112
|
+
attr_reader :data
|
113
|
+
|
114
|
+
def initialize(data)
|
115
|
+
@data = data
|
116
|
+
end
|
117
|
+
|
118
|
+
def call(meth)
|
119
|
+
if block = WTF.output_options[meth]
|
120
|
+
block.call(data)
|
121
|
+
else
|
122
|
+
send(meth)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def puts
|
129
|
+
STDOUT.puts(data)
|
130
|
+
end
|
131
|
+
alias_method :default, :puts
|
132
|
+
|
133
|
+
def file
|
134
|
+
time = Time.now.strftime('%m%d_%H%M%S')
|
135
|
+
file = File.join(WTF.files_path, "wtf_#{time}_#{rand(10000)}.txt")
|
136
|
+
File.write(file, data)
|
137
|
+
end
|
138
|
+
|
139
|
+
def error
|
140
|
+
raise StandardError, data
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|