flay 2.2.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/History.txt +11 -0
- data/README.txt +12 -6
- data/lib/flay.rb +39 -25
- data/test/test_flay.rb +152 -1
- metadata +11 -11
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/History.txt
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
=== 2.3.0 / 2013-05-10
|
2
|
+
|
3
|
+
* 2 minor enhancements:
|
4
|
+
|
5
|
+
* Refactored n_way_diff into split_and_group, collapse_and_label, and pad_with_empty_strings.
|
6
|
+
* n_way_diff now does leading comments separately from the code, to better align diffs.
|
7
|
+
|
8
|
+
* 1 bug fix:
|
9
|
+
|
10
|
+
* Fixed code/home urls in readme/gem.
|
11
|
+
|
1
12
|
=== 2.2.0 / 2013-04-09
|
2
13
|
|
3
14
|
Semantic versioning doesn't take into account how AWESOME a release
|
data/README.txt
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
= flay
|
2
2
|
|
3
3
|
home :: http://ruby.sadi.st/
|
4
|
-
|
4
|
+
code :: https://github.com/seattlerb/flay
|
5
5
|
rdoc :: http://seattlerb.rubyforge.org/flay
|
6
6
|
|
7
7
|
== DESCRIPTION:
|
@@ -22,10 +22,16 @@ braces vs do/end, etc are all ignored. Making this totally rad.
|
|
22
22
|
* Provides conservative (default) and --liberal pruning options.
|
23
23
|
* Provides --fuzzy duplication detection.
|
24
24
|
* Language independent: Plugin system allows other languages to be flayed.
|
25
|
-
* Ships with .rb and .erb.
|
25
|
+
* Ships with .rb and .erb.
|
26
|
+
* javascript and others will be available separately.
|
26
27
|
* Includes FlayTask for Rakefiles.
|
27
28
|
* Totally rad.
|
28
29
|
|
30
|
+
== KNOWN EXTENSIONS:
|
31
|
+
|
32
|
+
* flay-haml :: Flay your HAML source.
|
33
|
+
* flay-persistence :: Persist results across runs. Great for multi-project analysis.
|
34
|
+
|
29
35
|
== TODO:
|
30
36
|
|
31
37
|
* Editor integration (emacs, textmate, other contributions welcome).
|
@@ -34,11 +40,11 @@ braces vs do/end, etc are all ignored. Making this totally rad.
|
|
34
40
|
|
35
41
|
% flay -v --diff ~/Work/svn/ruby/ruby_1_8/lib/cgi.rb
|
36
42
|
Processing /Users/ryan/Work/svn/ruby/ruby_1_8/lib/cgi.rb...
|
37
|
-
|
43
|
+
|
38
44
|
Matches found in :defn (mass = 184)
|
39
45
|
A: /Users/ryan/Work/svn/ruby/ruby_1_8/lib/cgi.rb:1470
|
40
46
|
B: /Users/ryan/Work/svn/ruby/ruby_1_8/lib/cgi.rb:1925
|
41
|
-
|
47
|
+
|
42
48
|
A: def checkbox_group(name = "", *values)
|
43
49
|
B: def radio_group(name = "", *values)
|
44
50
|
if name.kind_of?(Hash) then
|
@@ -60,11 +66,11 @@ braces vs do/end, etc are all ignored. Making this totally rad.
|
|
60
66
|
end
|
61
67
|
end.to_s
|
62
68
|
end
|
63
|
-
|
69
|
+
|
64
70
|
IDENTICAL Matches found in :for (mass*2 = 144)
|
65
71
|
A: /Users/ryan/Work/svn/ruby/ruby_1_8/lib/cgi.rb:2160
|
66
72
|
B: /Users/ryan/Work/svn/ruby/ruby_1_8/lib/cgi.rb:2217
|
67
|
-
|
73
|
+
|
68
74
|
for element in ["HTML", "BODY", "P", "DT", "DD", "LI", "OPTION", "THEAD", "TFOOT", "TBODY", "COLGROUP", "TR", "TH", "TD", "HEAD"] do
|
69
75
|
methods = (methods + ((" def #{element.downcase}(attributes = {})\n" + nO_element_def(element)) + " end\n"))
|
70
76
|
end
|
data/lib/flay.rb
CHANGED
@@ -15,7 +15,7 @@ class File
|
|
15
15
|
end
|
16
16
|
|
17
17
|
class Flay
|
18
|
-
VERSION = "2.
|
18
|
+
VERSION = "2.3.0" # :nodoc:
|
19
19
|
|
20
20
|
##
|
21
21
|
# Returns the default options.
|
@@ -311,17 +311,17 @@ class Flay
|
|
311
311
|
# subnode element of a node in another bucket.
|
312
312
|
|
313
313
|
def prune_conservatively
|
314
|
-
|
314
|
+
hashes_to_prune = {}
|
315
315
|
|
316
316
|
# extract all subtree hashes from all nodes
|
317
317
|
self.hashes.values.each do |nodes|
|
318
318
|
nodes.first.all_structural_subhashes.each do |h|
|
319
|
-
|
319
|
+
hashes_to_prune[h] = true
|
320
320
|
end
|
321
321
|
end
|
322
322
|
|
323
323
|
# nuke subtrees so we show the biggest matching tree possible
|
324
|
-
self.hashes.delete_if { |h,_|
|
324
|
+
self.hashes.delete_if { |h,_| hashes_to_prune[h] }
|
325
325
|
end
|
326
326
|
|
327
327
|
##
|
@@ -331,7 +331,7 @@ class Flay
|
|
331
331
|
def prune_liberally
|
332
332
|
update_masses
|
333
333
|
|
334
|
-
|
334
|
+
hashes_to_prune = Hash.new { |h,k| h[k] = [] }
|
335
335
|
|
336
336
|
# record each subtree by subhash, but skip if subtree mass > parent mass
|
337
337
|
self.hashes.values.each do |nodes|
|
@@ -345,14 +345,14 @@ class Flay
|
|
345
345
|
|
346
346
|
next if subscore and subscore > topscore
|
347
347
|
|
348
|
-
|
348
|
+
hashes_to_prune[subhash] << subnode
|
349
349
|
end
|
350
350
|
end
|
351
351
|
end
|
352
352
|
|
353
353
|
# nuke only individual items by object identity
|
354
354
|
self.hashes.each do |h,v|
|
355
|
-
v.delete_eql
|
355
|
+
v.delete_eql hashes_to_prune[h]
|
356
356
|
end
|
357
357
|
|
358
358
|
# nuke buckets we happened to fully empty
|
@@ -364,34 +364,48 @@ class Flay
|
|
364
364
|
# given.
|
365
365
|
|
366
366
|
def n_way_diff *data
|
367
|
-
|
368
|
-
|
369
|
-
|
367
|
+
comments = []
|
368
|
+
codes = []
|
369
|
+
|
370
|
+
split_and_group(data).each do |subdata|
|
371
|
+
n = subdata.find_index { |s| s !~ /^#/ }
|
372
|
+
|
373
|
+
comment, code = subdata[0..n-1], subdata[n..-1]
|
374
|
+
|
375
|
+
comments << comment
|
376
|
+
codes << code
|
370
377
|
end
|
371
378
|
|
372
|
-
|
379
|
+
comments = collapse_and_label pad_with_empty_strings comments
|
380
|
+
codes = collapse_and_label pad_with_empty_strings codes
|
373
381
|
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
+
(comments + codes).flatten.join("\n")
|
383
|
+
end
|
384
|
+
|
385
|
+
def split_and_group ary # :nodoc:
|
386
|
+
ary.each_with_index.map { |s, i|
|
387
|
+
c = (?A.ord + i).chr
|
388
|
+
s.scan(/^.*/).map { |s2|
|
389
|
+
s2.group = c
|
390
|
+
s2
|
391
|
+
}
|
382
392
|
}
|
393
|
+
end
|
394
|
+
|
395
|
+
def pad_with_empty_strings ary # :nodoc:
|
396
|
+
max = ary.map { |s| s.size }.max
|
397
|
+
|
398
|
+
ary.map { |a| a + ([""] * (max - a.size)) }
|
399
|
+
end
|
383
400
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
if collapsed.size == 1 then
|
401
|
+
def collapse_and_label ary # :nodoc:
|
402
|
+
ary[0].zip(*ary[1..-1]).map { |lines|
|
403
|
+
if lines.uniq.size == 1 then
|
388
404
|
" #{lines.first}"
|
389
405
|
else
|
390
|
-
# TODO: make r2r have a canonical mode (doesn't make 1-liners)
|
391
406
|
lines.reject { |l| l.empty? }.map { |l| "#{l.group}: #{l}" }
|
392
407
|
end
|
393
408
|
}
|
394
|
-
groups.flatten.join("\n")
|
395
409
|
end
|
396
410
|
|
397
411
|
##
|
data/test/test_flay.rb
CHANGED
@@ -65,11 +65,21 @@ class TestSexp < MiniTest::Unit::TestCase
|
|
65
65
|
end
|
66
66
|
|
67
67
|
DOG_AND_CAT = Ruby18Parser.new.process <<-RUBY
|
68
|
+
##
|
69
|
+
# I am a dog.
|
70
|
+
|
68
71
|
class Dog
|
69
72
|
def x
|
70
73
|
return "Hello"
|
71
74
|
end
|
72
75
|
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# I
|
79
|
+
# am
|
80
|
+
# a
|
81
|
+
# cat.
|
82
|
+
|
73
83
|
class Cat
|
74
84
|
def y
|
75
85
|
return "Hello"
|
@@ -198,6 +208,38 @@ class TestSexp < MiniTest::Unit::TestCase
|
|
198
208
|
end
|
199
209
|
|
200
210
|
def test_report
|
211
|
+
# make sure we run through options parser
|
212
|
+
$*.clear
|
213
|
+
$* << "--mass=1"
|
214
|
+
$* << "-v"
|
215
|
+
|
216
|
+
opts = nil
|
217
|
+
capture_io do # ignored
|
218
|
+
opts = Flay.parse_options
|
219
|
+
end
|
220
|
+
|
221
|
+
flay = Flay.new opts
|
222
|
+
|
223
|
+
flay.process_sexp DOG_AND_CAT.deep_clone
|
224
|
+
flay.analyze
|
225
|
+
|
226
|
+
out, err = capture_io do
|
227
|
+
flay.report nil
|
228
|
+
end
|
229
|
+
|
230
|
+
exp = <<-END.gsub(/\d+/, "N").gsub(/^ {6}/, "")
|
231
|
+
Total score (lower is better) = 16
|
232
|
+
|
233
|
+
1) Similar code found in :class (mass = 16)
|
234
|
+
(string):1
|
235
|
+
(string):6
|
236
|
+
END
|
237
|
+
|
238
|
+
assert_equal '', err
|
239
|
+
assert_equal exp, out.gsub(/\d+/, "N")
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_report_diff
|
201
243
|
# make sure we run through options parser
|
202
244
|
$*.clear
|
203
245
|
$* << "-d"
|
@@ -225,6 +267,13 @@ class TestSexp < MiniTest::Unit::TestCase
|
|
225
267
|
A: (string):1
|
226
268
|
B: (string):6
|
227
269
|
|
270
|
+
##
|
271
|
+
A: # I am a dog.
|
272
|
+
B: # I
|
273
|
+
B: # am
|
274
|
+
B: # a
|
275
|
+
B: # cat.
|
276
|
+
|
228
277
|
A: class Dog
|
229
278
|
B: class Cat
|
230
279
|
A: def x
|
@@ -235,6 +284,108 @@ class TestSexp < MiniTest::Unit::TestCase
|
|
235
284
|
END
|
236
285
|
|
237
286
|
assert_equal '', err
|
238
|
-
assert_equal exp, out.gsub(/\d+/, "N")
|
287
|
+
assert_equal exp, out.gsub(/\d+/, "N").gsub(/^ {3}$/, "")
|
288
|
+
end
|
289
|
+
|
290
|
+
def test_n_way_diff
|
291
|
+
dog_and_cat = ["##\n# I am a dog.\n\nclass Dog\n def x\n return \"Hello\"\n end\nend",
|
292
|
+
"##\n# I\n#\n# am\n# a\n# cat.\n\nclass Cat\n def y\n return \"Hello\"\n end\nend"]
|
293
|
+
|
294
|
+
flay = Flay.new
|
295
|
+
|
296
|
+
exp = <<-EOM.gsub(/\d+/, "N").gsub(/^ {6}/, "").chomp
|
297
|
+
##
|
298
|
+
A: # I am a dog.
|
299
|
+
B: # I
|
300
|
+
B: #
|
301
|
+
B: # am
|
302
|
+
B: # a
|
303
|
+
B: # cat.
|
304
|
+
|
305
|
+
A: class Dog
|
306
|
+
B: class Cat
|
307
|
+
A: def x
|
308
|
+
B: def y
|
309
|
+
return \"Hello\"
|
310
|
+
end
|
311
|
+
end
|
312
|
+
EOM
|
313
|
+
|
314
|
+
assert_equal exp, flay.n_way_diff(*dog_and_cat).gsub(/^ {3}$/, "")
|
315
|
+
end
|
316
|
+
|
317
|
+
def test_split_and_group
|
318
|
+
flay = Flay.new
|
319
|
+
|
320
|
+
act = flay.split_and_group ["a\nb\nc", "d\ne\nf"]
|
321
|
+
exp = [%w(a b c), %w(d e f)]
|
322
|
+
|
323
|
+
assert_equal exp, act
|
324
|
+
assert_equal [%w(A A A), %w(B B B)], act.map { |a| a.map { |s| s.group } }
|
325
|
+
end
|
326
|
+
|
327
|
+
def test_pad_with_empty_strings
|
328
|
+
flay = Flay.new
|
329
|
+
|
330
|
+
a = %w(a b c)
|
331
|
+
b = %w(d)
|
332
|
+
|
333
|
+
assert_equal [a, ["d", "", ""]], flay.pad_with_empty_strings([a, b])
|
334
|
+
end
|
335
|
+
|
336
|
+
def test_pad_with_empty_strings_same
|
337
|
+
flay = Flay.new
|
338
|
+
|
339
|
+
a = %w(a b c)
|
340
|
+
b = %w(d e f)
|
341
|
+
|
342
|
+
assert_equal [a, b], flay.pad_with_empty_strings([a, b])
|
343
|
+
end
|
344
|
+
|
345
|
+
def test_collapse_and_label
|
346
|
+
flay = Flay.new
|
347
|
+
|
348
|
+
a = %w(a b c).map { |s| s.group = "A"; s }
|
349
|
+
b = %w(d b f).map { |s| s.group = "B"; s }
|
350
|
+
|
351
|
+
exp = [["A: a", "B: d"], " b", ["A: c", "B: f"]]
|
352
|
+
|
353
|
+
assert_equal exp, flay.collapse_and_label([a, b])
|
354
|
+
end
|
355
|
+
|
356
|
+
def test_collapse_and_label_same
|
357
|
+
flay = Flay.new
|
358
|
+
|
359
|
+
a = %w(a b c).map { |s| s.group = "A"; s }
|
360
|
+
b = %w(a b c).map { |s| s.group = "B"; s }
|
361
|
+
|
362
|
+
exp = [" a", " b", " c"]
|
363
|
+
|
364
|
+
assert_equal exp, flay.collapse_and_label([a, b])
|
365
|
+
end
|
366
|
+
|
367
|
+
def test_n_way_diff_methods
|
368
|
+
dog_and_cat = ["##\n# I am a dog.\n\ndef x\n return \"Hello\"\nend",
|
369
|
+
"##\n# I\n#\n# am\n# a\n# cat.\n\ndef y\n return \"Hello\"\nend"]
|
370
|
+
|
371
|
+
opts = Flay.parse_options
|
372
|
+
flay = Flay.new opts
|
373
|
+
|
374
|
+
exp = <<-EOM.gsub(/\d+/, "N").gsub(/^ {6}/, "").chomp
|
375
|
+
##
|
376
|
+
A: # I am a dog.
|
377
|
+
B: # I
|
378
|
+
B: #
|
379
|
+
B: # am
|
380
|
+
B: # a
|
381
|
+
B: # cat.
|
382
|
+
|
383
|
+
A: def x
|
384
|
+
B: def y
|
385
|
+
return \"Hello\"
|
386
|
+
end
|
387
|
+
EOM
|
388
|
+
|
389
|
+
assert_equal exp, flay.n_way_diff(*dog_and_cat).gsub(/^ {3}$/, "")
|
239
390
|
end
|
240
391
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flay
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 3
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 2
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 2.
|
10
|
+
version: 2.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ryan Davis
|
@@ -36,7 +36,7 @@ cert_chain:
|
|
36
36
|
FBHgymkyj/AOSqKRIpXPhjC6
|
37
37
|
-----END CERTIFICATE-----
|
38
38
|
|
39
|
-
date: 2013-
|
39
|
+
date: 2013-05-10 00:00:00 Z
|
40
40
|
dependencies:
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: sexp_processor
|
@@ -76,11 +76,11 @@ dependencies:
|
|
76
76
|
requirements:
|
77
77
|
- - ~>
|
78
78
|
- !ruby/object:Gem::Version
|
79
|
-
hash:
|
79
|
+
hash: 31
|
80
80
|
segments:
|
81
|
-
-
|
82
|
-
-
|
83
|
-
version: "
|
81
|
+
- 5
|
82
|
+
- 0
|
83
|
+
version: "5.0"
|
84
84
|
type: :development
|
85
85
|
version_requirements: *id003
|
86
86
|
- !ruby/object:Gem::Dependency
|
@@ -106,11 +106,11 @@ dependencies:
|
|
106
106
|
requirements:
|
107
107
|
- - ~>
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
hash:
|
109
|
+
hash: 11
|
110
110
|
segments:
|
111
111
|
- 3
|
112
|
-
-
|
113
|
-
version: "3.
|
112
|
+
- 6
|
113
|
+
version: "3.6"
|
114
114
|
type: :development
|
115
115
|
version_requirements: *id005
|
116
116
|
description: |-
|
metadata.gz.sig
CHANGED
Binary file
|