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.
Files changed (7) hide show
  1. data.tar.gz.sig +0 -0
  2. data/History.txt +11 -0
  3. data/README.txt +12 -6
  4. data/lib/flay.rb +39 -25
  5. data/test/test_flay.rb +152 -1
  6. metadata +11 -11
  7. metadata.gz.sig +0 -0
data.tar.gz.sig CHANGED
Binary file
@@ -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
- repo :: https://github.com/seattlerb/flay
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. javascript and others will be available separately.
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
@@ -15,7 +15,7 @@ class File
15
15
  end
16
16
 
17
17
  class Flay
18
- VERSION = "2.2.0" # :nodoc:
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
- all_hashes = {}
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
- all_hashes[h] = true
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,_| all_hashes[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
- all_hashes = Hash.new { |h,k| h[k] = [] }
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
- all_hashes[subhash] << subnode
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 all_hashes[h]
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
- data.each_with_index do |s, i|
368
- c = (?A.ord + i).chr
369
- s.group = c
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
- max = data.map { |s| s.scan(/^.*/).size }.max
379
+ comments = collapse_and_label pad_with_empty_strings comments
380
+ codes = collapse_and_label pad_with_empty_strings codes
373
381
 
374
- data.map! { |s| # FIX: this is tarded, but I'm out of brain
375
- c = s.group
376
- s = s.scan(/^.*/)
377
- s.push(*([""] * (max - s.size))) # pad
378
- s.each do |o|
379
- o.group = c
380
- end
381
- s
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
- groups = data[0].zip(*data[1..-1])
385
- groups.map! { |lines|
386
- collapsed = lines.uniq
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
  ##
@@ -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: 7
4
+ hash: 3
5
5
  prerelease:
6
6
  segments:
7
7
  - 2
8
- - 2
8
+ - 3
9
9
  - 0
10
- version: 2.2.0
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-04-10 00:00:00 Z
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: 21
79
+ hash: 31
80
80
  segments:
81
- - 4
82
- - 7
83
- version: "4.7"
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: 13
109
+ hash: 11
110
110
  segments:
111
111
  - 3
112
- - 5
113
- version: "3.5"
112
+ - 6
113
+ version: "3.6"
114
114
  type: :development
115
115
  version_requirements: *id005
116
116
  description: |-
metadata.gz.sig CHANGED
Binary file