debride 1.4.0 → 1.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a6fb60e6abb914cdca253c8f91a87ee9f29b9573
4
- data.tar.gz: c277e27c75a4a571e22cc647fe4d98063f944256
3
+ metadata.gz: 8f2ef4f667b2008a96704a15a62f41bc993f0872
4
+ data.tar.gz: 68ee77d6fd2c8687ef8392cbbd910ae959b251c5
5
5
  SHA512:
6
- metadata.gz: dc8279ae3e71097d6b57ade1054d80c596b76e6b47878b8269fd931abca6b497da3780cf85cff3860563b307a2c01f727fe11f1bc03a11287242e3bd376c75d7
7
- data.tar.gz: 560722e6f9d07d1dff4bab14e912cec2d9a019046ee4a5dcfc7a6394e98c9f933e0ff1c4c9dc9b85f2cdd1ad2093889acd2926fb05246bfc96c3bd89bbf477a7
6
+ metadata.gz: 4f226eb6901be45033201a3ceb29498d253b13fe20c998bdbe8c1200d6401f3785111690437e47f10ecb87919c2c0c73b057a68a8d9a0a630d92ab6e4f067276
7
+ data.tar.gz: ad86dccb33825e6157c33ec72f919dc9f2e3d9730b6a67c35664814fdf4517c27b3f1ca214579c83c4b1a448e4e38a97b1d2282e0215148c21426cdcd57cded0
@@ -1,3 +1,2 @@
1
- qX4R�uDGV���B����gN
2
- SL&�:�;ˑL����Z�ȝ�2��d�=&|�)H��6�KB���V�.�y�^Ӹ�>��2!{H?�K�ųf8t8Z4̀`�h3sMD�������uh��u۔�E<�.�*�(C��F���L|H��"�*�[��K
3
- ��Jc���}����
1
+ ̸H+
2
+ �n:Tၑ��k,!m �h#xk:dd!���L�ȱC���R�8��(�#=��Bsaq�_����(K8����i���B`��;�׳���O�|�vU%�i�&QWwaωޞ�7x�o]��������iiK�4���1B���-/��*���9������:�Ғ��3X��V>0n�>-����3 ���˾bI���Q �5#� �h�meǗ��2�a ,�k:��N,x��9.�4��}�6;~t
data.tar.gz.sig CHANGED
Binary file
@@ -1,3 +1,20 @@
1
+ === 1.5.0 / 2015-06-14
2
+
3
+ * 6 minor enhancements:
4
+
5
+ * Added --focus <path> to filter report on focused path. (phiggins)
6
+ * Added debride_rails_whitelist to help generate emperical whitelists from logs.
7
+ * Added validate to rails methods. (jeremyf)
8
+ * Extended debride to understand attr_* methods. (jeremyf)
9
+ * Extended debride_rails_whitelist to be able to scan compressed logs (gzip/bzip)
10
+ * Improved output of debride_rails_whitelist so you know what's going on. (amerine)
11
+
12
+ * 3 bug fixes:
13
+
14
+ * Fixed handling of uncalled attr_* methods in reports.
15
+ * Fixed improper recording of locations of consts and alias_method_chain.
16
+ * Fixed recording of method names.
17
+
1
18
  === 1.4.0 / 2015-05-27
2
19
 
3
20
  * 1 major enhancement:
@@ -4,5 +4,6 @@ Manifest.txt
4
4
  README.rdoc
5
5
  Rakefile
6
6
  bin/debride
7
+ bin/debride_rails_whitelist
7
8
  lib/debride.rb
8
9
  test/test_debride.rb
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ route = ARGV.shift
4
+ routes = {}
5
+ verbs = "(?:GET|POST|PUT|PATCH|DELETE)"
6
+
7
+ unless route then
8
+ cmd = File.basename $0
9
+ warn "error: no files given"
10
+ warn "usage:"
11
+ warn " rake routes > routes.txt"
12
+ warn " #{cmd} routes.txt logfiles... | sort -u > whitelist.txt"
13
+ abort
14
+ end
15
+
16
+ File.foreach route do |line|
17
+ case line.chomp
18
+ when /^\s+Prefix/, "" then
19
+ # ignore
20
+ when /^Routes for /
21
+ break
22
+ when /^\s*(\w+) (#{verbs})\s+(\S+)\s+([\w\/]+#\w+)/ then
23
+ _, verb, path, action = $1, $2, $3, $4
24
+ path.sub!(/..:format./, '\\/?')
25
+ path.sub!(/:id/, '\\d+')
26
+ routes[/^#{verb} #{path}$/] = action.split(/#/).last
27
+ when /^\s*(GET|POST|PUT|PATCH|DELETE)\s+(\S+)\s+([\w\/]+#\w+)/ then
28
+ verb, path, action = $1, $2, $3
29
+ path.sub!(/..:format./, '')
30
+ path.sub!(/:id/, '\\d+')
31
+ routes[/^#{verb} #{path}$/] = action.split(/#/).last
32
+ else
33
+ # warn "unparsed: #{line.chomp}"
34
+ end
35
+ end
36
+
37
+ warn "NOTE: No logs provided. Scanning stdin." if ARGV.empty?
38
+
39
+ ARGV.each do |path|
40
+ warn path
41
+ cmd = case path
42
+ when /\.gz$/ then
43
+ "gzcat"
44
+ when /\.bz2?$/ then
45
+ "bzcat"
46
+ else
47
+ "cat"
48
+ end
49
+
50
+ IO.popen [cmd, path] do |io|
51
+ io.each_line do |line|
52
+ $stderr.print "." if $. % 10_000 == 0
53
+ case line
54
+ when /Processing by (\w+)#(\w+) as/ then
55
+ _, action = $1, $2
56
+ puts action
57
+ when /Started (#{verbs}) \"([^"]+)\"/, /method=(#{verbs}) path="([^"]+)"/ then
58
+ verb, path = $1, $2
59
+
60
+ _, action = routes.find { |k,v| "#{verb} #{path}" =~ k }
61
+
62
+ puts action if action
63
+ else
64
+ # warn "unparsed: #{line.chomp}"
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ warn "done"
@@ -19,7 +19,7 @@ end
19
19
  # A static code analyzer that points out possible dead methods.
20
20
 
21
21
  class Debride < MethodBasedSexpProcessor
22
- VERSION = "1.4.0" # :nodoc:
22
+ VERSION = "1.5.0" # :nodoc:
23
23
  PROJECT = "debride"
24
24
 
25
25
  def self.expand_dirs_to_files *dirs # TODO: push back up to sexp_processor
@@ -100,7 +100,7 @@ class Debride < MethodBasedSexpProcessor
100
100
 
101
101
  def process_rb path_or_io
102
102
  begin
103
- warn "processing: #{path}" if option[:verbose]
103
+ warn "Processing ruby: #{path_or_io}" if option[:verbose]
104
104
 
105
105
  case path_or_io
106
106
  when String then
@@ -147,6 +147,16 @@ class Debride < MethodBasedSexpProcessor
147
147
  options[:whitelist] = File.read(s).split(/\n+/) rescue []
148
148
  end
149
149
 
150
+ opts.on("-f", "--focus PATH", String, "Only report against this path") do |s|
151
+ unless File.exist? s then
152
+ abort "ERROR: --focus path #{s} doesn't exist."
153
+ end
154
+
155
+ s = "#{s.chomp "/"}/*" if File.directory?(s)
156
+
157
+ options[:focus] = s
158
+ end
159
+
150
160
  opts.on("-r", "--rails", "Add some rails call conversions.") do
151
161
  options[:rails] = true
152
162
  end
@@ -154,13 +164,18 @@ class Debride < MethodBasedSexpProcessor
154
164
  opts.on("-v", "--verbose", "Verbose. Show progress processing files.") do
155
165
  options[:verbose] = true
156
166
  end
157
-
158
- opts.parse! args
159
167
  end
160
168
 
169
+ op.parse! args
170
+
161
171
  abort op.to_s if args.empty?
162
172
 
163
173
  options
174
+ rescue OptionParser::InvalidOption => e
175
+ warn op.to_s
176
+ warn ""
177
+ warn e.message
178
+ exit 1
164
179
  end
165
180
 
166
181
  ##
@@ -194,17 +209,111 @@ class Debride < MethodBasedSexpProcessor
194
209
  super.to_s
195
210
  end
196
211
 
197
- def method_name # :nodoc:
198
- super.to_s.sub(/^::|#/, "").to_sym
212
+ def plain_method_name # :nodoc:
213
+ method_name.to_s.sub(/^::|#/, "").to_sym
214
+ end
215
+
216
+ def process_attrasgn(sexp)
217
+ method_name = sexp[2]
218
+ method_name = method_name.last if Sexp === method_name
219
+ called << method_name
220
+ process_until_empty sexp
221
+ sexp
222
+ end
223
+
224
+ def record_method name, file, line
225
+ signature = "#{klass_name}##{name}"
226
+ method_locations[signature] = "#{file}:#{line}"
227
+ map[klass_name][name] = signature
228
+ known[name] << klass_name
229
+ end
230
+
231
+ def process_call sexp # :nodoc:
232
+ method_name = sexp[2]
233
+
234
+ case method_name
235
+ when :new then
236
+ method_name = :initialize
237
+ when :alias_method_chain then
238
+ # s(:call, nil, :alias_method_chain, s(:lit, :royale), s(:lit, :cheese))
239
+ _, _, _, (_, new_name), _ = sexp
240
+ if option[:rails] then
241
+ file, line = sexp.file, sexp.line
242
+ record_method new_name, file, line
243
+ end
244
+ when :attr_accessor then
245
+ # s(:call, nil, :attr_accessor, s(:lit, :a1), ...)
246
+ _, _, _, *args = sexp
247
+ file, line = sexp.file, sexp.line
248
+ args.each do |(_, name)|
249
+ record_method name, file, line
250
+ record_method "#{name}=".to_sym, file, line
251
+ end
252
+ when :attr_writer then
253
+ # s(:call, nil, :attr_writer, s(:lit, :w1), ...)
254
+ _, _, _, *args = sexp
255
+ file, line = sexp.file, sexp.line
256
+ args.each do |(_, name)|
257
+ record_method "#{name}=".to_sym, file, line
258
+ end
259
+ when :attr_reader then
260
+ # s(:call, nil, :attr_reader, s(:lit, :r1), ...)
261
+ _, _, _, *args = sexp
262
+ file, line = sexp.file, sexp.line
263
+ args.each do |(_, name)|
264
+ record_method name, file, line
265
+ end
266
+ when :send, :public_send, :__send__ then
267
+ # s(:call, s(:const, :Seattle), :send, s(:lit, :raining?))
268
+ _, _, _, msg_arg, * = sexp
269
+ if Sexp === msg_arg && [:lit, :str].include?(msg_arg.sexp_type) then
270
+ called << msg_arg.last.to_sym
271
+ end
272
+ when *RAILS_VALIDATION_METHODS then
273
+ if option[:rails]
274
+ possible_hash = sexp.last
275
+ if Sexp === possible_hash && possible_hash.sexp_type == :hash
276
+ possible_hash.sexp_body.each_slice(2) do |key, val|
277
+ called << val.last if val.first == :lit
278
+ called << val.last.to_sym if val.first == :str
279
+ end
280
+ end
281
+ end
282
+ when *RAILS_DSL_METHODS then
283
+ if option[:rails]
284
+ # s(:call, nil, :before_save, s(:lit, :save_callback), s(:hash, ...))
285
+ _, _, _, (_, new_name), possible_hash = sexp
286
+ called << new_name
287
+ if Sexp === possible_hash && possible_hash.sexp_type == :hash
288
+ possible_hash.sexp_body.each_slice(2) do |key, val|
289
+ next unless Sexp === val
290
+ called << val.last if val.first == :lit
291
+ called << val.last.to_sym if val.first == :str
292
+ end
293
+ end
294
+ end
295
+ when /_path$/ then
296
+ method_name = method_name.to_s[0..-6].to_sym if option[:rails]
297
+ end
298
+
299
+ called << method_name
300
+
301
+ process_until_empty sexp
302
+
303
+ sexp
199
304
  end
200
305
 
201
306
  def process_cdecl exp # :nodoc:
202
307
  _, name, val = exp
203
308
  process val
204
309
 
205
- map[klass_name][name] = "#{klass_name}::#{name}"
310
+ signature = "#{klass_name}::#{name}"
311
+ map[klass_name][name] = signature
206
312
  known[name] << klass_name
207
313
 
314
+ file, line = exp.file, exp.line
315
+ method_locations[signature] = "#{file}:#{line}"
316
+
208
317
  exp
209
318
  end
210
319
 
@@ -235,70 +344,20 @@ class Debride < MethodBasedSexpProcessor
235
344
 
236
345
  def process_defn sexp # :nodoc:
237
346
  super do
238
- map[klass_name][method_name] = signature
239
- known[method_name] << klass_name
347
+ map[klass_name][plain_method_name] = signature
348
+ known[plain_method_name] << klass_name
240
349
  process_until_empty sexp
241
350
  end
242
351
  end
243
352
 
244
353
  def process_defs sexp # :nodoc:
245
354
  super do
246
- map[klass_name][method_name] = signature
247
- known[method_name] << klass_name
355
+ map[klass_name][plain_method_name] = signature
356
+ known[plain_method_name] << klass_name
248
357
  process_until_empty sexp
249
358
  end
250
359
  end
251
360
 
252
- def process_call sexp # :nodoc:
253
- method_name = sexp[2]
254
-
255
- case method_name
256
- when :new then
257
- method_name = :initialize
258
- when :alias_method_chain then
259
- new_name = sexp[3]
260
- new_name = new_name.last if Sexp === new_name # when is this NOT the case?
261
- known[new_name] << klass_name if option[:rails]
262
- when :send, :public_send, :__send__ then
263
- sent_method = sexp[3]
264
- if Sexp === sent_method && [:lit, :str].include?(sent_method.first)
265
- called << sent_method.last.to_sym
266
- end
267
- when *RAILS_VALIDATION_METHODS then
268
- if option[:rails]
269
- possible_hash = sexp.last
270
- if Sexp === possible_hash && possible_hash.first == :hash
271
- possible_hash[1..-1].each_slice(2) do |key, val|
272
- called << val.last if val.first == :lit
273
- called << val.last.to_sym if val.first == :str
274
- end
275
- end
276
- end
277
- when *RAILS_DSL_METHODS then
278
- if option[:rails]
279
- new_name = sexp[3]
280
- new_name = new_name.last if Sexp === new_name # when is this NOT the case?
281
- called << new_name
282
- possible_hash = sexp.last
283
- if Sexp === possible_hash && possible_hash.first == :hash
284
- possible_hash[1..-1].each_slice(2) do |key, val|
285
- next unless Sexp === val
286
- called << val.last if val.first == :lit
287
- called << val.last.to_sym if val.first == :str
288
- end
289
- end
290
- end
291
- when /_path$/ then
292
- method_name = method_name.to_s[0..-6].to_sym if option[:rails]
293
- end
294
-
295
- called << method_name
296
-
297
- process_until_empty sexp
298
-
299
- sexp
300
- end
301
-
302
361
  ##
303
362
  # Calculate the difference between known methods and called methods.
304
363
 
@@ -338,14 +397,30 @@ class Debride < MethodBasedSexpProcessor
338
397
  # Print out a report of suspects.
339
398
 
340
399
  def report
400
+ focus = option[:focus]
401
+
402
+ if focus then
403
+ puts "Focusing on #{focus}"
404
+ puts
405
+ end
406
+
341
407
  puts "These methods MIGHT not be called:"
342
408
 
343
409
  missing.each do |klass, meths|
410
+ bad = meths.map { |meth|
411
+ location = method_locations[map[klass][meth]]
412
+ path = location[/(.+):\d+$/, 1]
413
+
414
+ next if focus and not File.fnmatch(focus, path)
415
+
416
+ " %-35s %s" % [meth, location]
417
+ }
418
+ bad.compact!
419
+ next if bad.empty?
420
+
344
421
  puts
345
422
  puts klass
346
- meths.each do |meth|
347
- puts " %-35s %s" % [meth, method_locations[map[klass][meth]]]
348
- end
423
+ puts bad.join "\n"
349
424
  end
350
425
  end
351
426
 
@@ -374,6 +449,9 @@ class Debride < MethodBasedSexpProcessor
374
449
  :before_save,
375
450
  :before_update,
376
451
  :before_validation,
452
+
453
+ # http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validate
454
+ :validate,
377
455
  ]
378
456
 
379
457
  # http://api.rubyonrails.org/v4.2.1/classes/ActiveModel/Validations/HelperMethods.html
@@ -23,6 +23,7 @@ class TestDebride < Minitest::Test
23
23
  debride.process debride.process_rb io
24
24
 
25
25
  assert_equal exp, debride.missing
26
+ debride
26
27
  end
27
28
 
28
29
  def test_sanity
@@ -35,7 +36,9 @@ class TestDebride < Minitest::Test
35
36
  end
36
37
 
37
38
  exp = [["Debride",
38
- [:process_call, :process_defn, :process_defs, :process_rb, :report]]]
39
+ [:process_attrasgn, :process_call, :process_cdecl, :process_colon2,
40
+ :process_colon3, :process_const, :process_defn, :process_defs,
41
+ :process_rb, :report]]]
39
42
 
40
43
  assert_equal exp, debride.missing
41
44
  end
@@ -65,6 +68,17 @@ class TestDebride < Minitest::Test
65
68
  assert_option %w[-e moot,moot.rb lib], %w[lib], :exclude => %w[moot moot.rb]
66
69
  end
67
70
 
71
+ def test_parse_options_focus
72
+ assert_option %w[-f lib lib], %w[lib], :focus => "lib/*"
73
+ assert_option %w[--focus lib lib], %w[lib], :focus => "lib/*"
74
+
75
+ e = assert_raises RuntimeError do
76
+ assert_option %w[-f missing lib], %w[], :verbose => true
77
+ end
78
+
79
+ assert_includes e.message, "ERROR: --focus path missing doesn't exist."
80
+ end
81
+
68
82
  def test_parse_options_whitelist
69
83
  exp = File.readlines("Manifest.txt").map(&:chomp) # omg dumb
70
84
  assert_option %w[--whitelist Manifest.txt lib], %w[lib], :whitelist => exp
@@ -76,7 +90,9 @@ class TestDebride < Minitest::Test
76
90
  debride = Debride.run %w[--exclude test lib]
77
91
 
78
92
  exp = [["Debride",
79
- [:process_call, :process_defn, :process_defs, :process_rb, :report]]]
93
+ [:process_attrasgn, :process_call, :process_cdecl, :process_colon2,
94
+ :process_colon3, :process_const, :process_defn, :process_defs,
95
+ :process_rb, :report]]]
80
96
 
81
97
  assert_equal exp, debride.missing
82
98
  end
@@ -199,12 +215,14 @@ class TestDebride < Minitest::Test
199
215
  def action_condition ; 1 ; end
200
216
  def string_condition ; 1 ; end
201
217
  def validation_condition ; 1 ; end
218
+ def some_validation_method; 1 ; end
202
219
 
203
220
  before_save :save_callback, unless: :callback_condition
204
221
  before_save :save_callback, if: 'string_condition'
205
222
  before_action :action_filter, if: :action_condition, only: :new
206
223
  after_save :save_callback, if: lambda {|r| true }
207
224
  validates :database_column, if: :validation_condition
225
+ validate :some_validation_method
208
226
  end
209
227
  RUBY
210
228
 
@@ -230,4 +248,86 @@ class TestDebride < Minitest::Test
230
248
 
231
249
  assert_process [["Constants", [:UNUSED]]], ruby
232
250
  end
251
+
252
+ def test_attr_accessor
253
+ ruby = <<-RUBY.strip
254
+ class AttributeAccessor
255
+ attr_accessor :a1, :a2, :a3
256
+ attr_writer :w1, :w2
257
+ attr_reader :r1, :r2
258
+ def initialize
259
+ self.a2 = 'Bar'
260
+ self.w1 = 'W'
261
+ end
262
+ end
263
+
264
+ object = AttributeAccessor.new
265
+ object.a1
266
+ object.r1
267
+ object.a3 = 'Baz'
268
+ RUBY
269
+
270
+ d = assert_process [["AttributeAccessor", [:a1=, :a2, :a3, :r2, :w2=]]], ruby
271
+
272
+ exp = {
273
+ "AttributeAccessor" => {
274
+ :a1 => "AttributeAccessor#a1",
275
+ :a1= => "AttributeAccessor#a1=",
276
+ :a2 => "AttributeAccessor#a2",
277
+ :a2= => "AttributeAccessor#a2=",
278
+ :a3 => "AttributeAccessor#a3",
279
+ :a3= => "AttributeAccessor#a3=",
280
+ :w1= => "AttributeAccessor#w1=",
281
+ :w2= => "AttributeAccessor#w2=",
282
+ :r1 => "AttributeAccessor#r1",
283
+ :r2 => "AttributeAccessor#r2",
284
+ :initialize => "AttributeAccessor#initialize"
285
+ }
286
+ }
287
+
288
+ assert_equal exp, d.map
289
+
290
+ exp = {
291
+ "AttributeAccessor#a1" => "(io):2",
292
+ "AttributeAccessor#a1=" => "(io):2",
293
+ "AttributeAccessor#a2" => "(io):2",
294
+ "AttributeAccessor#a2=" => "(io):2",
295
+ "AttributeAccessor#a3" => "(io):2",
296
+ "AttributeAccessor#a3=" => "(io):2",
297
+ "AttributeAccessor#w1=" => "(io):3",
298
+ "AttributeAccessor#w2=" => "(io):3",
299
+ "AttributeAccessor#r1" => "(io):4",
300
+ "AttributeAccessor#r2" => "(io):4",
301
+ "AttributeAccessor#initialize" => "(io):5",
302
+ }
303
+
304
+ assert_equal exp, d.method_locations
305
+
306
+ out, err = capture_io do
307
+ d.report
308
+ end
309
+
310
+ assert_match(/AttributeAccessor/, out)
311
+ assert_match(/a1=/, out)
312
+ assert_empty err
313
+ end
314
+
315
+ def test_attr_accessor_with_hash_default_value
316
+ ruby = <<-RUBY.strip
317
+ class AttributeAccessor
318
+ attr_accessor :a1
319
+ def initialize(options = {})
320
+ self.a1 = options.fetch(:a1) { default_a1 }
321
+ end
322
+
323
+ def default_a1
324
+ 'the default_a1'
325
+ end
326
+ end
327
+
328
+ object = AttributeAccessor.new
329
+ RUBY
330
+
331
+ assert_process [["AttributeAccessor", [:a1]]], ruby
332
+ end
233
333
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: debride
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Davis
@@ -29,7 +29,7 @@ cert_chain:
29
29
  xJcC6UN6NHMOVMyAXsr2HR0gRRx4ofN1LoP2KhXzSr8UMvQYlwPmE0N5GQv1b5AO
30
30
  VpzF30vNaJK6ZT7xlIsIlwmH
31
31
  -----END CERTIFICATE-----
32
- date: 2015-05-27 00:00:00.000000000 Z
32
+ date: 2015-06-15 00:00:00.000000000 Z
33
33
  dependencies:
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: sexp_processor
@@ -65,14 +65,14 @@ dependencies:
65
65
  requirements:
66
66
  - - ~>
67
67
  - !ruby/object:Gem::Version
68
- version: '5.6'
68
+ version: '5.7'
69
69
  type: :development
70
70
  prerelease: false
71
71
  version_requirements: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ~>
74
74
  - !ruby/object:Gem::Version
75
- version: '5.6'
75
+ version: '5.7'
76
76
  - !ruby/object:Gem::Dependency
77
77
  name: rdoc
78
78
  requirement: !ruby/object:Gem::Requirement
@@ -106,6 +106,7 @@ email:
106
106
  - ryand-ruby@zenspider.com
107
107
  executables:
108
108
  - debride
109
+ - debride_rails_whitelist
109
110
  extensions: []
110
111
  extra_rdoc_files:
111
112
  - History.rdoc
@@ -119,6 +120,7 @@ files:
119
120
  - README.rdoc
120
121
  - Rakefile
121
122
  - bin/debride
123
+ - bin/debride_rails_whitelist
122
124
  - lib/debride.rb
123
125
  - test/test_debride.rb
124
126
  homepage: https://github.com/seattlerb/debride
metadata.gz.sig CHANGED
@@ -1 +1 @@
1
- ��S��m=X��?t]���<�8R�I��BKC?ʓ�g����ʯ���1
1
+ ��Q����|�u�I;常EE�`��}������,���0�Y_�O���S7a����N=IvaYMB��c/���1��0��l���̻N��oq5u���g�-z���@k6�}