di 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/HISTORY +14 -0
  2. data/di.gemspec +3 -3
  3. data/lib/di.rb +67 -69
  4. metadata +5 -5
data/HISTORY CHANGED
@@ -1,3 +1,17 @@
1
+ == 0.3.0 2012-05-14
2
+
3
+ * Fix pagerizing with Ruby 1.9+ and turn it on by default.
4
+
5
+ * Complement a missing implementation of --unidirectional-new-file.
6
+
7
+ * Complement a missing implementation of -S/--starting-file=FILE.
8
+
9
+ * Add support for --suppress-blank-empty.
10
+
11
+ * Fix handling of -T/--initial-tab.
12
+
13
+ * Remove -L which use has long been deprecated.
14
+
1
15
  == 0.2.3 2012-03-29
2
16
 
3
17
  * Fix the case where comparing two directories fails when the latter
data/di.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "di"
8
- s.version = "0.2.3"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Akinori MUSHA"]
12
- s.date = "2012-03-29"
12
+ s.date = "2012-05-14"
13
13
  s.description = "The di(1) command wraps around GNU diff(1) to provide reasonable\ndefault settings and some original features.\n"
14
14
  s.email = "knu@idaemons.org"
15
15
  s.executables = ["di"]
@@ -32,7 +32,7 @@ Gem::Specification.new do |s|
32
32
  s.homepage = "https://github.com/knu/di"
33
33
  s.require_paths = ["lib"]
34
34
  s.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
35
- s.rubygems_version = "1.8.15"
35
+ s.rubygems_version = "1.8.23"
36
36
  s.summary = "A wrapper around GNU diff(1)"
37
37
 
38
38
  if s.respond_to? :specification_version then
data/lib/di.rb CHANGED
@@ -28,13 +28,12 @@
28
28
  # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
29
  # SUCH DAMAGE.
30
30
 
31
- MYVERSION = "0.2.3"
31
+ MYVERSION = "0.3.0"
32
32
  MYNAME = File.basename($0)
33
33
  MYCOPYRIGHT = "Copyright (c) 2008, 2009, 2010, 2011, 2012 Akinori MUSHA"
34
34
 
35
35
  DIFF_CMD = ENV.fetch('DIFF', 'diff')
36
36
  ENV_NAME = "#{MYNAME.tr('-a-z', '_A-Z')}_OPTIONS"
37
- EMPTYFILE = '/dev/null'
38
37
 
39
38
  RSYNC_EXCLUDE_FILE_GLOBS = [
40
39
  'tags', 'TAGS', 'GTAGS', 'GRTAGS', 'GSYMS', 'GPATH',
@@ -58,6 +57,8 @@ FIGNORE_GLOBS = ENV.fetch('FIGNORE', '').split(':').map { |pat|
58
57
  '*' + pat
59
58
  }
60
59
 
60
+ IO::NULL = '/dev/null' unless defined? IO::NULL
61
+
61
62
  def main(args)
62
63
  setup
63
64
 
@@ -116,31 +117,31 @@ usage: #{MYNAME} [flags] [files]
116
117
  }
117
118
 
118
119
  opts.on('--[no-]pager',
119
- 'Pipe output into pager if stdout is a terminal. [!][*]') { |val|
120
- $diff.use_pager = val if $stdout.tty? && RUBY_VERSION < "1.9"
120
+ 'Pipe output into pager if stdout is a terminal. [+][*]') { |val|
121
+ $diff.use_pager = val if $stdout.tty?
121
122
  }
122
123
  opts.on('--[no-]color',
123
- 'Colorize output if stdout is a terminal and the format is unified or context. [!][*]') { |val|
124
+ 'Colorize output if stdout is a terminal and the format is unified or context. [+][*]') { |val|
124
125
  $diff.colorize = val if $stdout.tty?
125
126
  }
126
127
  opts.on('--[no-]highlight-whitespace',
127
- 'Highlight suspicious whitespace differences in colorized output. [!][*]') { |val|
128
+ 'Highlight suspicious whitespace differences in colorized output. [+][*]') { |val|
128
129
  $diff.highlight_whitespace = val
129
130
  }
130
131
  opts.on('--[no-]rsync-exclude', '--[no-]cvs-exclude',
131
- 'Exclude some kinds of files and directories a la rsync(1). [!][*]') { |val|
132
+ 'Exclude some kinds of files and directories a la rsync(1). [+][*]') { |val|
132
133
  $diff.rsync_exclude = val
133
134
  }
134
135
  opts.on('--[no-]ignore-cvs-lines',
135
- 'Ignore CVS/RCS keyword lines. [!][*]') { |val|
136
+ 'Ignore CVS/RCS keyword lines. [+][*]') { |val|
136
137
  $diff.ignore_cvs_lines = val
137
138
  }
138
139
  opts.on('--[no-]fignore-exclude',
139
- 'Ignore files having suffixes specified in FIGNORE. [!][*]') { |val|
140
+ 'Ignore files having suffixes specified in FIGNORE. [+][*]') { |val|
140
141
  $diff.fignore_exclude = val
141
142
  }
142
143
  opts.on('-R', '--relative[=-]', miniTrueClass,
143
- 'Use relative path names. [*]') { |val|
144
+ 'Use relative path names.') { |val|
144
145
  $diff.relative = val
145
146
  }
146
147
  opts.on('-i', '--ignore-case[=-]', miniTrueClass,
@@ -189,19 +190,19 @@ usage: #{MYNAME} [flags] [files]
189
190
  set_format_flag('-C', val.to_s)
190
191
  }
191
192
  opts.on('-u[NUM]', '--unified[=NUM]', Integer,
192
- 'Output NUM (default 3) lines of unified context. [!]') { |val|
193
+ 'Output NUM (default 3) lines of unified context. [+]') { |val|
193
194
  set_format_flag('-U', val ? val.to_s : '3')
194
195
  }
195
196
  opts.on('-U NUM', Integer,
196
197
  'Output NUM lines of unified context.') { |val|
197
198
  set_format_flag('-U', val.to_s)
198
199
  }
199
- opts.on('-L LABEL', '--label=LABEL',
200
+ opts.on('--label=LABEL',
200
201
  'Use LABEL instead of file name.') { |val|
201
- set_flag('-L', val)
202
+ set_flag('--label', val)
202
203
  }
203
204
  opts.on('-p', '--show-c-function[=-]', miniTrueClass,
204
- 'Show which C function each change is in. [!]') { |val|
205
+ 'Show which C function each change is in. [+]') { |val|
205
206
  set_flag('-p', val)
206
207
  }
207
208
  opts.on('-F RE', '--show-function-line=RE',
@@ -252,37 +253,21 @@ usage: #{MYNAME} [flags] [files]
252
253
  'Output merged file to show `#ifdef NAME\' diffs.') { |val|
253
254
  set_format_flag('-D', val)
254
255
  }
255
- opts.on('--old-group-format=GFMT',
256
- 'Format old input groups with GFMT.') { |val|
257
- set_custom_format_flag('--old-group-format', val)
258
- }
259
- opts.on('--new-group-format=GFMT',
260
- 'Format new input groups with GFMT.') { |val|
261
- set_custom_format_flag('--new-group-format', val)
262
- }
263
- opts.on('--changed-group-format=GFMT',
264
- 'Format changed input groups with GFMT.') { |val|
265
- set_custom_format_flag('--changed-group-format', val)
266
- }
267
- opts.on('--unchanged-group-format=GFMT',
268
- 'Format unchanged input groups with GFMT.') { |val|
269
- set_custom_format_flag('--unchanged-group-format', val)
256
+ %w[old new changed unchanged].each { |gtype|
257
+ opts.on("--#{gtype}-group-format=GFMT",
258
+ "Format #{gtype} input groups with GFMT.") { |val|
259
+ set_custom_format_flag("--#{gtype}-group-format", val)
260
+ }
270
261
  }
271
262
  opts.on('--line-format=LFMT',
272
263
  'Format all input lines with LFMT.') { |val|
273
264
  set_custom_format_flag('--line-format', val)
274
265
  }
275
- opts.on('--old-line-format=LFMT',
276
- 'Format old input lines with LFMT.') { |val|
277
- set_custom_format_flag('--old-line-format', val)
278
- }
279
- opts.on('--new-line-format=LFMT',
280
- 'Format new input lines with LFMT.') { |val|
281
- set_custom_format_flag('--new-line-format', val)
282
- }
283
- opts.on('--unchanged-line-format=LFMT',
284
- 'Format unchanged input lines with LFMT.') { |val|
285
- set_custom_format_flag('--unchanged-line-format', val)
266
+ %w[old new changed unchanged].each { |ltype|
267
+ opts.on("--#{ltype}-line-format=LFMT",
268
+ "Format #{ltype} input lines with LFMT.") { |val|
269
+ set_custom_format_flag("--#{ltype}-line-format", val)
270
+ }
286
271
  }
287
272
  opts.on('-l', '--paginate[=-]', miniTrueClass,
288
273
  'Pass the output through `pr\' to paginate it.') { |val|
@@ -294,25 +279,30 @@ usage: #{MYNAME} [flags] [files]
294
279
  }
295
280
  opts.on('-T', '--initial-tab[=-]', miniTrueClass,
296
281
  'Make tabs line up by prepending a tab.') { |val|
297
- set_flag('-T', '--initial-tab', val)
282
+ set_flag('-T', val)
298
283
  }
299
284
  opts.on('--tabsize=NUM', Integer,
300
285
  'Tab stops are every NUM (default 8) print columns.') { |val|
301
286
  set_flag('--tabsize', val.to_s)
302
287
  }
288
+ opts.on('--suppress-blank-empty[=-]', miniTrueClass,
289
+ 'Suppress space or tab before empty output lines.') { |val|
290
+ set_flag('--suppress-blank-empty', val)
291
+ }
303
292
  opts.on('-r', '--recursive[=-]', miniTrueClass,
304
- 'Recursively compare any subdirectories found. [!]') { |val|
293
+ 'Recursively compare any subdirectories found. [+]') { |val|
305
294
  set_flag('-r', val)
306
295
  $diff.recursive = val
307
296
  }
308
297
  opts.on('-N', '--[no-]new-file[=-]', miniTrueClass,
309
- 'Treat absent files as empty. [!]') { |val|
298
+ 'Treat absent files as empty. [+]') { |val|
310
299
  set_flag('-N', val)
311
- $diff.new_file = val
300
+ $diff.new_file = val ? :bidirectional : val
312
301
  }
313
302
  opts.on('--unidirectional-new-file[=-]', miniTrueClass,
314
303
  'Treat absent first files as empty.') { |val|
315
304
  set_flag('--unidirectional-new-file', val)
305
+ $diff.new_file = val ? :unidirectional : val
316
306
  }
317
307
  opts.on('-s', '--report-identical-files[=-]', miniTrueClass,
318
308
  'Report when two files are the same.') { |val|
@@ -336,7 +326,7 @@ usage: #{MYNAME} [flags] [files]
336
326
  }
337
327
  opts.on('-S FILE', '--starting-file=FILE',
338
328
  'Start with FILE when comparing directories.') { |val|
339
- set_flag('-S', val)
329
+ $diff.starting_file = val
340
330
  }
341
331
  opts.on('--from-file=FILE1',
342
332
  'Compare FILE1 to all operands. FILE1 can be a directory.') { |val|
@@ -351,7 +341,7 @@ usage: #{MYNAME} [flags] [files]
351
341
  set_flag('--horizon-lines', val.to_s)
352
342
  }
353
343
  opts.on('-d', '--minimal[=-]', miniTrueClass,
354
- 'Try hard to find a smaller set of changes. [!]') { |val|
344
+ 'Try hard to find a smaller set of changes. [+]') { |val|
355
345
  set_flag('-d', val)
356
346
  }
357
347
  opts.on('--speed-large-files[=-]', miniTrueClass,
@@ -373,8 +363,8 @@ usage: #{MYNAME} [flags] [files]
373
363
  'Output this help.') { |val|
374
364
  invoke_pager
375
365
  print opts, <<EOS
376
- Options without the [*] sign will be passed through to diff(1).
377
- Options marked as [!] sign are turned on by default. To turn them off,
366
+ Options marked with [*] are this wrapper's original features.
367
+ Options marked with [+] are turned on by default. To turn them off,
378
368
  specify -?- for short options and --no-??? for long options, respectively.
379
369
 
380
370
  Environment variables:
@@ -466,23 +456,21 @@ def invoke_pager!
466
456
  pr.close
467
457
  pw.close
468
458
  IO.select([$stdin], nil, [$stdin])
469
- if system(ENV['PAGER'] || 'more')
470
- Process.kill(:TERM, ppid)
471
- else
459
+ begin
460
+ exec(ENV['PAGER'] || 'more')
461
+ rescue
472
462
  $stderr.puts "Pager failed."
473
- Process.kill(:INT, ppid)
474
463
  end
475
464
  }
476
- trap(:TERM) { exit(0) }
477
- trap(:INT) { exit(130) }
465
+
478
466
  $stdout.reopen(pw)
479
467
  $stderr.reopen(pw) if $stderr.tty?
480
468
  pw.close
481
469
  at_exit {
482
470
  $stdout.flush
483
471
  $stderr.flush
484
- $stdout.close
485
- $stderr.close
472
+ $stdout.reopen(IO::NULL)
473
+ $stderr.reopen(IO::NULL)
486
474
  Process.waitpid(pid)
487
475
  }
488
476
  end
@@ -543,7 +531,7 @@ def diff_main
543
531
  to_file = File.expand_path(from_file, to_file)
544
532
  end
545
533
 
546
- diff_dirs(from_file, to_file)
534
+ diff_dirs(from_file, to_file, true)
547
535
  else
548
536
  if $diff.relative
549
537
  from_file = File.expand_path(to_file, from_file)
@@ -607,9 +595,9 @@ def call_diff(*args)
607
595
  return status
608
596
  end
609
597
 
610
- def diff_dirs(dir1, dir2)
611
- entries1 = diff_entries(dir1)
612
- entries2 = diff_entries(dir2)
598
+ def diff_dirs(dir1, dir2, toplevel_p = false)
599
+ entries1 = diff_entries(dir1, toplevel_p)
600
+ entries2 = diff_entries(dir2, toplevel_p)
613
601
 
614
602
  common = entries1 & entries2
615
603
  missing1 = entries2 - entries1
@@ -635,15 +623,20 @@ def diff_dirs(dir1, dir2)
635
623
  end
636
624
 
637
625
  if $diff.reversed
638
- [[dir1, missing2], [dir2, missing1]]
626
+ [[dir1, missing2, true], [dir2, missing1, false]]
639
627
  else
640
- [[dir2, missing1], [dir1, missing2]]
641
- end.each { |dir, missing|
628
+ [[dir2, missing1, true], [dir1, missing2, false]]
629
+ end.each { |dir, missing, direction|
642
630
  new_files = []
631
+ case $diff.new_file
632
+ when :bidirectional
633
+ new_file = true
634
+ when :unidirectional
635
+ new_file = direction
636
+ end
643
637
  missing.each { |entry|
644
638
  file = File.join(dir, entry)
645
-
646
- if $diff.new_file
639
+ if new_file
647
640
  if File.directory?(file)
648
641
  if dir.equal?(dir1)
649
642
  diff_dirs(file, nil)
@@ -660,16 +653,21 @@ def diff_dirs(dir1, dir2)
660
653
  end
661
654
  }
662
655
  if dir.equal?(dir1)
663
- diff_files(new_files, EMPTYFILE)
656
+ diff_files(new_files, IO::NULL)
664
657
  else
665
- diff_files(EMPTYFILE, new_files)
658
+ diff_files(IO::NULL, new_files)
666
659
  end
667
660
  }
668
661
  end
669
662
 
670
- def diff_entries(dir)
663
+ def diff_entries(dir, toplevel_p)
671
664
  return [] if dir.nil?
672
- return Dir.entries(dir).reject { |file| diff_exclude?(dir, file) }
665
+ Dir.entries(dir).tap { |entries|
666
+ entries.reject! { |file| diff_exclude?(dir, file) }
667
+ if toplevel_p && (starting_file = $diff.starting_file)
668
+ entries.reject! { |file| file < starting_file }
669
+ end
670
+ }
673
671
  rescue => e
674
672
  warn "#{dir}: #{e}"
675
673
  return []
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: di
3
3
  version: !ruby/object:Gem::Version
4
- hash: 17
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 2
9
8
  - 3
10
- version: 0.2.3
9
+ - 0
10
+ version: 0.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Akinori MUSHA
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-03-29 00:00:00 Z
18
+ date: 2012-05-14 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: thoughtbot-shoulda
@@ -85,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
85
85
  requirements: []
86
86
 
87
87
  rubyforge_project:
88
- rubygems_version: 1.8.15
88
+ rubygems_version: 1.8.23
89
89
  signing_key:
90
90
  specification_version: 3
91
91
  summary: A wrapper around GNU diff(1)