let_it_go 0.0.1 → 0.0.2
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/README.md +19 -5
- data/lib/let_it_go/caller_line.rb +31 -0
- data/lib/let_it_go/core_ext/string.rb +1 -0
- data/lib/let_it_go/method_call.rb +85 -0
- data/lib/let_it_go/report.rb +45 -0
- data/lib/let_it_go/version.rb +1 -1
- data/lib/let_it_go/wtf_parser.rb +46 -16
- data/lib/let_it_go.rb +33 -107
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42a5bb8aaa66d8aff49ee60864cb68e81acd8789
|
4
|
+
data.tar.gz: 762339fb4d4aa69b3b39d862cd1cb932244d021e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c1145f8bd66dd5a0a8897d80467c0947f0cd7f2ef2f886f97d0660be6b65a6e72d4a02355070fa7fdb2b07844f8cd459fddd29265e01cdb1aea37f726e076dc9
|
7
|
+
data.tar.gz: 4640afbfe44d014fccefbabd2821bb7126ba9800c456b65f3ee95a47b0db4c18ac34684a0750c706b4e78726fb38af5a7ab3e7e5e9552bd79657a0a1454965d2
|
data/README.md
CHANGED
@@ -124,6 +124,23 @@ This extremely convoluted library works by watching all method calls using [Trac
|
|
124
124
|
|
125
125
|
If you can think of a better way, please open up an issue and send me a proof of concept. I know what you're thinking and no, [programatically aliasing methods won't work for 100% of the time](http://stackoverflow.com/questions/30512945/programmatically-alias-method-that-uses-global-variable).
|
126
126
|
|
127
|
+
Note: This method fails for any Ruby code that can't be parsed in 1 line. For example:
|
128
|
+
|
129
|
+
```
|
130
|
+
query = <<-SQL % known_coder_types.join(", ")
|
131
|
+
```
|
132
|
+
|
133
|
+
and
|
134
|
+
|
135
|
+
```
|
136
|
+
(attr[0] == :html && attr[1] == :attr && options[:hyphen_attrs].include?(attr[2]) &&
|
137
|
+
```
|
138
|
+
|
139
|
+
Are not valid, complete Ruby instructions. That being said this lib is still relevant. To see what you're not able to parse, run with `ENV['LET_IT_GO_RECORD_FAILED_CODE']`
|
140
|
+
|
141
|
+
|
142
|
+
|
143
|
+
|
127
144
|
## Development
|
128
145
|
|
129
146
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -141,8 +158,5 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
141
158
|
|
142
159
|
## TODO
|
143
160
|
|
144
|
-
-
|
145
|
-
-
|
146
|
-
- Implicit methods i.e. 1 + 1 and [1] << 2
|
147
|
-
- Global operators != && ==
|
148
|
-
- Subclass support. Hook into a class created TracePoint to see if a class is a subclass and add it to the list
|
161
|
+
- Global operators != && == (maybe it's good enough to only track calls to string)
|
162
|
+
- Watch receivers such as "foo".eq(variable)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module LetItGo
|
2
|
+
# Given a single line from `caller` retrieves line_number, file_name
|
3
|
+
# and can read the contents of the file
|
4
|
+
class CallerLine
|
5
|
+
attr_accessor :line_number, :file_name
|
6
|
+
def initialize(string)
|
7
|
+
file_line = string.split(":in `".freeze).first
|
8
|
+
file_line_array = file_line.split(":".freeze)
|
9
|
+
|
10
|
+
@line_number = file_line_array.pop
|
11
|
+
@file_name = file_line_array.join(":".freeze) # name may have `:` in it
|
12
|
+
end
|
13
|
+
|
14
|
+
def contents
|
15
|
+
@contents ||= read || ""
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def read
|
20
|
+
contents = ""
|
21
|
+
File.open(file_name).each_with_index do |line, index|
|
22
|
+
next unless index == Integer(line_number).pred
|
23
|
+
contents = line
|
24
|
+
break
|
25
|
+
end
|
26
|
+
contents
|
27
|
+
rescue Errno::ENOENT
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'let_it_go/wtf_parser'
|
2
|
+
|
3
|
+
module LetItGo
|
4
|
+
# Wraps logic that require knowledge of the method call
|
5
|
+
# can parse original method call's source and determine if a string literal
|
6
|
+
# was passed into the method.
|
7
|
+
class MethodCall
|
8
|
+
attr_accessor :klass, :method_name, :positions, :line_number, :file_name, :call_count
|
9
|
+
|
10
|
+
def initialize(klass: , method_name: , kaller:, positions: )
|
11
|
+
@klass = klass
|
12
|
+
@method_name = method_name.to_s
|
13
|
+
# Subclasses report method definition as caller.first via TracePoint
|
14
|
+
@key = "Method: #{klass}##{method_name} [#{kaller.first(2).inspect}]"
|
15
|
+
@caller_lines = kaller.first(2).map {|kaller_line| CallerLine.new(kaller_line) }
|
16
|
+
@positions = positions
|
17
|
+
@call_count = 0
|
18
|
+
end
|
19
|
+
|
20
|
+
def count
|
21
|
+
call_count * string_allocation_count
|
22
|
+
end
|
23
|
+
|
24
|
+
def zero?
|
25
|
+
count.zero?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Loop through each line in the caller and see if the method we're watching is being called
|
29
|
+
# This is needed due to the way TracePoint deals with inheritance
|
30
|
+
def method_array
|
31
|
+
@parser = nil
|
32
|
+
@caller_lines.each do |kaller|
|
33
|
+
code = Ripper.sexp(kaller.contents)
|
34
|
+
code ||= Ripper.sexp(kaller.contents.sub(/^\W*(if|unless)/, ''.freeze)) # if and unless "block" statements aren't valid one line ruby code
|
35
|
+
code ||= Ripper.sexp(kaller.contents.sub(/do \|.*\|$/, ''.freeze)) # remove trailing do |thing| to make valid code
|
36
|
+
code ||= Ripper.sexp(kaller.contents.sub(/(and|or)\W*$/, ''.freeze))# trailing and || or
|
37
|
+
code ||= Ripper.sexp(kaller.contents.sub(/:\W*$/, ''.freeze)) # multi line ternary statements
|
38
|
+
code ||= Ripper.sexp(kaller.contents.sub(/(^\W*)|({ \|?.*\|?)}/, ''.freeze)) # multi line blocks using {}
|
39
|
+
|
40
|
+
puts "LetItGoFailed parse (#{kaller.file_name}:#{kaller.line_number}: \n \033[0;31m"+ kaller.contents.strip + "\e[0m".freeze if ENV['LET_IT_GO_RECORD_FAILED_CODE'] && code.nil? && kaller.contents.match(/"|'/)
|
41
|
+
|
42
|
+
parser = ::LetItGo::WTFParser.new(code, contents: kaller.contents)
|
43
|
+
|
44
|
+
if parser.each_method.any? { |m| m.method_name == method_name }
|
45
|
+
@line_number = kaller.line_number
|
46
|
+
@file_name = kaller.file_name
|
47
|
+
|
48
|
+
@parser = parser
|
49
|
+
parser.each_method.each(&:arg_types)
|
50
|
+
break
|
51
|
+
else
|
52
|
+
next
|
53
|
+
end
|
54
|
+
end
|
55
|
+
@parser || []
|
56
|
+
end
|
57
|
+
|
58
|
+
def line_to_s
|
59
|
+
@line_to_s ||= contents_from_file_line(file_name, line_number)
|
60
|
+
end
|
61
|
+
|
62
|
+
def optimizable?
|
63
|
+
@optimizable ||= called_with_string_literal?
|
64
|
+
end
|
65
|
+
|
66
|
+
def string_allocation_count
|
67
|
+
@string_allocation_count
|
68
|
+
end
|
69
|
+
|
70
|
+
# Parses original method call location
|
71
|
+
# Determines if a string literal was used or not
|
72
|
+
def called_with_string_literal?
|
73
|
+
@string_allocation_count = 0
|
74
|
+
method_array.each do |m|
|
75
|
+
positions.each {|position| @string_allocation_count += 1 if m.arg_types[position] == :string_literal }
|
76
|
+
end
|
77
|
+
!@string_allocation_count.zero?
|
78
|
+
end
|
79
|
+
|
80
|
+
# Needs to be very low cost, cannot incur disk read
|
81
|
+
def key
|
82
|
+
@key
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module LetItGo
|
2
|
+
|
3
|
+
# Turns hash of keys into a semi-inteligable sorted result
|
4
|
+
class Report
|
5
|
+
def initialize(hash_of_reports)
|
6
|
+
@hash = hash_of_reports.reject {|k, obj| obj.zero? }
|
7
|
+
end
|
8
|
+
|
9
|
+
def count
|
10
|
+
@hash.inject(0) {|count, (k, obj)| count + obj.count; }
|
11
|
+
end
|
12
|
+
|
13
|
+
def report
|
14
|
+
@report = "## Un-Fozen Hotspots (#{count} total)\n\n"
|
15
|
+
|
16
|
+
file_names = @hash.values.map(&:file_name).uniq
|
17
|
+
file_name_hash = Hash.new { [] }
|
18
|
+
file_names.each do |name|
|
19
|
+
file_name_hash[name] = @hash.select {|_, obj| obj.file_name == name}.values.sort {|obj1, obj2| obj1.count <=> obj2.count }.reverse
|
20
|
+
end
|
21
|
+
|
22
|
+
file_name_hash = file_name_hash.sort {|(_, objects1), (_, objects2) |
|
23
|
+
count1 = objects1.inject(0) {|count, obj| count + obj.count }
|
24
|
+
count2 = objects2.inject(0) {|count, obj| count + obj.count }
|
25
|
+
count1 <=> count2
|
26
|
+
}.reverse
|
27
|
+
|
28
|
+
file_name_hash.each do |file_name, objects|
|
29
|
+
count = objects.inject(0) {|count, obj| count + obj.count }
|
30
|
+
@report << " #{count}) #{file_name}\n"
|
31
|
+
objects.each do |obj|
|
32
|
+
@report << " - #{obj.count}) #{obj.klass}##{obj.method_name} on line #{ obj.line_number }\n"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
@report << " (none)" if @hash.empty?
|
37
|
+
@report << "\n"
|
38
|
+
@report
|
39
|
+
end
|
40
|
+
|
41
|
+
def print
|
42
|
+
puts report
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/let_it_go/version.rb
CHANGED
data/lib/let_it_go/wtf_parser.rb
CHANGED
@@ -73,16 +73,29 @@ module LetItGo
|
|
73
73
|
# false]]]],
|
74
74
|
# false]]]
|
75
75
|
def args_add_block
|
76
|
-
args_paren.last || @raw.find {|x| x.first == :args_add_block }
|
76
|
+
args_paren.last || @raw.find {|x| x.first == :args_add_block } || []
|
77
77
|
end
|
78
78
|
|
79
79
|
def args
|
80
|
-
args_add_block.first(2).last || []
|
80
|
+
args = (args_add_block.first(2).last || [])
|
81
|
+
case args.first
|
82
|
+
when :args_add_star
|
83
|
+
args.shift
|
84
|
+
args
|
85
|
+
else
|
86
|
+
args
|
87
|
+
end
|
81
88
|
end
|
82
89
|
|
90
|
+
# [:fcall, [:@ident, "foo", [1, 6]]],
|
91
|
+
# [:arg_paren,
|
92
|
+
# [:args_add_block, [:args_add_star, [], [:array, nil]], false]]
|
93
|
+
|
94
|
+
# [:args_add_star, [], [:array, nil]], false]
|
95
|
+
|
83
96
|
# Returns argument types as an array of symbols [:regexp_literal, :string_literal]
|
84
97
|
def arg_types
|
85
|
-
args.map(&:first).map {|x| x.is_a?(Array) ? x.first : x }
|
98
|
+
args.map(&:first).map {|x| x.is_a?(Array) ? x.first : x }.compact
|
86
99
|
end
|
87
100
|
end
|
88
101
|
|
@@ -114,7 +127,7 @@ module LetItGo
|
|
114
127
|
end
|
115
128
|
|
116
129
|
def args_add_block
|
117
|
-
@raw.find {|x| x.is_a?(Array) ? x.first == :args_add_block : false }
|
130
|
+
@raw.find {|x| x.is_a?(Array) ? x.first == :args_add_block : false } || []
|
118
131
|
end
|
119
132
|
|
120
133
|
def args
|
@@ -123,7 +136,7 @@ module LetItGo
|
|
123
136
|
|
124
137
|
# Returns argument types as an array of symbols [:regexp_literal, :string_literal]
|
125
138
|
def arg_types
|
126
|
-
args.map(&:first).map {|x| x.is_a?(Array) ? x.first : x }
|
139
|
+
args.map(&:first).map {|x| x.is_a?(Array) ? x.first : x }.compact
|
127
140
|
end
|
128
141
|
end
|
129
142
|
|
@@ -151,12 +164,15 @@ module LetItGo
|
|
151
164
|
end
|
152
165
|
|
153
166
|
def arg_types
|
154
|
-
args.map(&:first).map {|x| x.is_a?(Array) ? x.first : x }
|
167
|
+
args.map(&:first).map {|x| x.is_a?(Array) ? x.first : x }.compact
|
155
168
|
end
|
156
169
|
end
|
157
170
|
|
158
|
-
|
159
|
-
|
171
|
+
attr_accessor :contents
|
172
|
+
|
173
|
+
def initialize(ripped_code, contents: "")
|
174
|
+
@contents = contents
|
175
|
+
@raw = ripped_code || []
|
160
176
|
end
|
161
177
|
|
162
178
|
# Parses raw input recursively looking for :method_add_arg blocks
|
@@ -179,22 +195,36 @@ module LetItGo
|
|
179
195
|
end
|
180
196
|
end
|
181
197
|
|
182
|
-
def
|
198
|
+
def all_methods
|
183
199
|
@method_add_array ||= begin
|
184
200
|
method_add_array = []
|
185
201
|
find_method_add_from_raw(@raw.dup, method_add_array)
|
186
202
|
method_add_array
|
187
203
|
end
|
188
204
|
end
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
205
|
+
alias :method_add :all_methods
|
206
|
+
|
207
|
+
def each
|
208
|
+
begin
|
209
|
+
if block_given?
|
210
|
+
all_methods.each do |obj|
|
211
|
+
begin
|
212
|
+
yield obj
|
213
|
+
rescue => e
|
214
|
+
end
|
215
|
+
end
|
216
|
+
else
|
217
|
+
enum_for(:each)
|
194
218
|
end
|
195
|
-
|
196
|
-
|
219
|
+
rescue => e
|
220
|
+
msg = "Could not parse seemingly valid Ruby code:\n\n"
|
221
|
+
msg << " #{ parser.contents.inspect }\n\n"
|
222
|
+
msg << e.message
|
223
|
+
raise e, msg
|
197
224
|
end
|
198
225
|
end
|
226
|
+
alias :each_method :each
|
227
|
+
|
228
|
+
include Enumerable
|
199
229
|
end
|
200
230
|
end
|
data/lib/let_it_go.rb
CHANGED
@@ -7,12 +7,19 @@ require "let_it_go/version"
|
|
7
7
|
module LetItGo
|
8
8
|
end
|
9
9
|
|
10
|
-
require 'let_it_go/wtf_parser'
|
11
|
-
|
12
10
|
module LetItGo
|
13
11
|
@mutex = Mutex.new
|
14
12
|
@watching = {}
|
15
13
|
|
14
|
+
def self.watching_klasses
|
15
|
+
@watching.keys
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.method_hash_for_klass(klass)
|
19
|
+
@watching[klass]
|
20
|
+
end
|
21
|
+
|
22
|
+
|
16
23
|
def self.watching_positions(klass, method)
|
17
24
|
@watching[klass] && @watching[klass][method]
|
18
25
|
end
|
@@ -39,68 +46,17 @@ module LetItGo
|
|
39
46
|
end
|
40
47
|
|
41
48
|
class << self
|
42
|
-
alias :cant_hold_it_back_anymore
|
43
|
-
alias :do_you_want_to_build_a_snowman
|
44
|
-
alias :turn_away_and_slam_the_door
|
49
|
+
alias :cant_hold_it_back_anymore :record
|
50
|
+
alias :do_you_want_to_build_a_snowman :record
|
51
|
+
alias :turn_away_and_slam_the_door :record
|
45
52
|
alias :the_cold_never_bothered_me_anyway :record
|
46
|
-
alias :let_it_go
|
53
|
+
alias :let_it_go :record
|
47
54
|
end
|
48
55
|
|
49
56
|
def self.recording?
|
50
57
|
Thread.current[:let_it_go_recording] == :on
|
51
58
|
end
|
52
59
|
|
53
|
-
# Wraps logic that require knowledge of the method call
|
54
|
-
# can parse original method call's source and determine if a string literal
|
55
|
-
# was passed into the method.
|
56
|
-
class MethodCall
|
57
|
-
attr_accessor :line_number, :file_name, :klass, :method_name, :kaller, :positions
|
58
|
-
|
59
|
-
def initialize(klass: , method_name: , kaller:, positions: )
|
60
|
-
@klass = klass
|
61
|
-
@method_name = method_name
|
62
|
-
@kaller = kaller
|
63
|
-
@positions = positions
|
64
|
-
|
65
|
-
file_line = kaller.split(":in `".freeze).first # can't use gsub, because global variables get messed up
|
66
|
-
file_line_array = file_line.split(":".freeze)
|
67
|
-
|
68
|
-
@line_number = file_line_array.pop
|
69
|
-
@file_name = file_line_array.join(":".freeze)
|
70
|
-
end
|
71
|
-
|
72
|
-
def line_to_s
|
73
|
-
@line_to_s ||= begin
|
74
|
-
contents = ""
|
75
|
-
File.open(file_name).each_with_index do |line, index|
|
76
|
-
next unless index == Integer(line_number).pred
|
77
|
-
contents = line
|
78
|
-
break
|
79
|
-
end
|
80
|
-
contents
|
81
|
-
rescue Errno::ENOENT
|
82
|
-
nil
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
# Parses original method call location
|
87
|
-
# Determines if a string literal was used or not
|
88
|
-
def called_with_string_literal?(parser_klass = ::LetItGo::WTFParser)
|
89
|
-
return true if line_to_s.nil?
|
90
|
-
|
91
|
-
if parsed_code = Ripper.sexp(line_to_s)
|
92
|
-
parser_klass.new(parsed_code).each_method.any? do |m|
|
93
|
-
m.method_name == method_name.to_s && positions.any? {|position| m.arg_types[position] == :string_literal }
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def key
|
99
|
-
"Method: #{klass}##{method_name} [#{kaller}]"
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
|
104
60
|
|
105
61
|
# Call to begin watching method for frozen violations
|
106
62
|
def self.watch_frozen(klass, method_name, positions:)
|
@@ -108,7 +64,6 @@ module LetItGo
|
|
108
64
|
@watching[klass][method_name] = positions
|
109
65
|
end
|
110
66
|
|
111
|
-
|
112
67
|
# If we are tracking it
|
113
68
|
# If it has positive counter
|
114
69
|
# Increment Counter
|
@@ -120,34 +75,13 @@ module LetItGo
|
|
120
75
|
# If it does not
|
121
76
|
# Set counter to
|
122
77
|
def self.watched_method_was_called(meth)
|
123
|
-
|
124
|
-
|
125
|
-
LetItGo.increment(meth.key)
|
126
|
-
end
|
127
|
-
else
|
128
|
-
if meth.called_with_string_literal?
|
129
|
-
LetItGo.store(meth.key, 1)
|
130
|
-
else
|
131
|
-
LetItGo.store(meth.key, 0)
|
132
|
-
end
|
78
|
+
unless method = Thread.current[:let_it_go_records][meth.key]
|
79
|
+
Thread.current[:let_it_go_records][meth.key] = method = meth
|
133
80
|
end
|
81
|
+
method.call_count += 1 if method.optimizable?
|
134
82
|
end
|
135
83
|
|
136
84
|
|
137
|
-
trace = TracePoint.trace(:call, :c_call) do |tp|
|
138
|
-
tp.disable
|
139
|
-
if LetItGo.recording?
|
140
|
-
if positions = watching_positions(tp.defined_class, tp.method_id)
|
141
|
-
meth = MethodCall.new(klass: tp.defined_class, method_name: tp.method_id, kaller: caller.first, positions: positions)
|
142
|
-
LetItGo.watched_method_was_called(meth)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
tp.enable
|
146
|
-
end
|
147
|
-
|
148
|
-
trace.enable
|
149
|
-
|
150
|
-
|
151
85
|
# Prevent looking
|
152
86
|
def self.record_exists?(key)
|
153
87
|
Thread.current[:let_it_go_records][key]
|
@@ -164,37 +98,29 @@ module LetItGo
|
|
164
98
|
def self.increment(key)
|
165
99
|
store(key, 1)
|
166
100
|
end
|
101
|
+
end
|
167
102
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
end
|
103
|
+
require 'let_it_go/middleware/olaf'
|
104
|
+
require 'let_it_go/caller_line'
|
105
|
+
require 'let_it_go/method_call'
|
106
|
+
require 'let_it_go/report'
|
173
107
|
|
174
|
-
def count
|
175
|
-
@hash.inject(0) {|count, (k, v)| count + v }
|
176
|
-
end
|
177
108
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
@report << " #{count}: #{name_location}\n"
|
182
|
-
end
|
183
|
-
@report << " (none)" if @hash.empty?
|
184
|
-
@report << "\n"
|
185
|
-
@report
|
186
|
-
end
|
109
|
+
Dir[File.expand_path("../let_it_go/core_ext/*.rb", __FILE__)].each do |file|
|
110
|
+
require file
|
111
|
+
end
|
187
112
|
|
188
|
-
|
189
|
-
puts report
|
190
|
-
end
|
113
|
+
RubyVM::InstructionSequence.compile_option = { specialized_instruction: false }
|
191
114
|
|
115
|
+
TracePoint.trace(:call, :c_call) do |tp|
|
116
|
+
tp.disable
|
117
|
+
if LetItGo.recording?
|
118
|
+
if positions = LetItGo.watching_positions(tp.defined_class, tp.method_id)
|
119
|
+
meth = LetItGo::MethodCall.new(klass: tp.defined_class, method_name: tp.method_id, kaller: caller, positions: positions)
|
120
|
+
LetItGo.watched_method_was_called(meth)
|
121
|
+
end
|
192
122
|
end
|
123
|
+
tp.enable
|
193
124
|
end
|
194
125
|
|
195
|
-
require 'let_it_go/middleware/olaf'
|
196
|
-
|
197
|
-
Dir[File.expand_path("../let_it_go/core_ext/*.rb", __FILE__)].each do |file|
|
198
|
-
require file
|
199
|
-
end
|
200
126
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: let_it_go
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- schneems
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-07-
|
11
|
+
date: 2015-07-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -71,10 +71,13 @@ files:
|
|
71
71
|
- bin/setup
|
72
72
|
- let_it_go.gemspec
|
73
73
|
- lib/let_it_go.rb
|
74
|
+
- lib/let_it_go/caller_line.rb
|
74
75
|
- lib/let_it_go/core_ext/array.rb
|
75
76
|
- lib/let_it_go/core_ext/pathname.rb
|
76
77
|
- lib/let_it_go/core_ext/string.rb
|
78
|
+
- lib/let_it_go/method_call.rb
|
77
79
|
- lib/let_it_go/middleware/olaf.rb
|
80
|
+
- lib/let_it_go/report.rb
|
78
81
|
- lib/let_it_go/version.rb
|
79
82
|
- lib/let_it_go/wtf_parser.rb
|
80
83
|
- lib/untitled.rb
|