flay 2.2.0 → 2.3.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.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
|