flay 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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