Indentinator 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/bin/indentinator +87 -25
  2. data/lib/indentinator.rb +33 -29
  3. data/test/tests.rb +139 -9
  4. metadata +33 -6
data/bin/indentinator CHANGED
@@ -1,50 +1,112 @@
1
1
  #! /usr/bin/env ruby
2
+ $:.unshift(File.expand_path('../../lib', __FILE__)) if $0 == __FILE__
2
3
  require 'getopt/std'
3
4
  require 'indentinator'
4
5
  include Indentinator
5
6
 
6
- opts = Getopt::Std.getopts('c:vV')
7
- @to_amount = opts['c']
7
+ def parse_amount(val)
8
+ return nil if val.nil?
9
+ if val.to_i.to_s == val # is a number
10
+ ' ' * val.to_i
11
+ elsif val.downcase == 'tab'
12
+ "\t"
13
+ end
14
+ end
15
+
16
+ opts = Getopt::Std.getopts('ic:a:vVr')
17
+ @from_stdin = opts['i']
18
+ @amount = parse_amount(opts['a'])
19
+ @to_amount = parse_amount(opts['c'])
8
20
  @very_verbose = opts['V']
9
- @verbose = opts['v'] or @very_verbose
21
+ @verbose = opts['v'] || @very_verbose
22
+ @replace = opts['r'] && !@from_stdin
10
23
  @files = ARGV
11
- if @files.size == 0
24
+
25
+ if @files.size == 0 and not @from_stdin
12
26
  puts "Usage:
13
27
 
14
28
  indentinator [-c INDENT_AMOUNT] <file> [<file2>...]
15
29
 
16
30
  Options:
17
31
 
18
- -c Modify the indentation amount to INDENT_AMOUNT
32
+ -c INDENT_AMOUNT
33
+ Modify the indentation amount to INDENT_AMOUNT. The value is either
34
+ a number - in which case it indicates the number of spaces to use;
35
+ or TAB - which indicates to use tabs.
36
+
37
+ -a AMOUNT
38
+ Tell me the original AMOUNT of indentation to use
39
+ when converting the file's indentation.
40
+ Normally, this value is inferred by looking at the input.
41
+ This option takes the same values as -c.
42
+
43
+ -i Read input from stdin. This will ignore any file arguments.
44
+
45
+ -r Replace the original file. Please back up your file or make sure you
46
+ are using version control. Indentinator is not responsible for
47
+ any damages; it just indents.
48
+
19
49
  -v Verbose output
50
+
20
51
  -V Very verbose output
21
52
 
22
53
  "
23
54
  exit(0)
24
55
  end
25
56
 
26
- @files.each do |path|
27
- begin
28
- if File.directory?(path)
29
- puts "#{path} is a directory."
30
- next
57
+ def process_input(text, path)
58
+ lines = text.split("\n")
59
+ if @to_amount.nil? or @amount.nil?
60
+ @amount = indent_amount(lines)
61
+ end
62
+ if @to_amount.nil?
63
+ if @amount == ''
64
+ puts "#{path} has no indentation."
65
+ elsif @amount.match(/^ *$/)
66
+ puts "#{path} uses #{@amount.size} spaces."
67
+ elsif @amount == "\t"
68
+ puts "#{path} uses tabs."
69
+ else
70
+ puts "#{path} uses #{@amount.gsub(' ', 'SPACE ').gsub("\t", 'TAB ').strip}. WTF?"
71
+ end
72
+ else
73
+ output = convert_lines(lines, @amount, @to_amount).join("\n")
74
+ if @replace
75
+ write_file(path, output)
76
+ else
77
+ puts output
31
78
  end
32
- File.open(path) do |file|
33
- lines = file.read.split("\n")
34
- amount = indent_amount(lines)
35
- if @to_amount.nil?
36
- if amount == 0
37
- puts "#{path} has no indentation."
38
- else
39
- puts "#{path} uses #{amount} spaces."
40
- end
41
- else
42
- puts convert_lines(lines, amount, @to_amount).join("\n")
79
+ end
80
+ end
81
+
82
+ def read_file(path)
83
+ f = open(path, 'r')
84
+ text = f.read
85
+ f.close
86
+ text
87
+ end
88
+
89
+ def write_file(path, text)
90
+ f = open(path, 'w')
91
+ f.write(text)
92
+ f.close
93
+ end
94
+
95
+ if @from_stdin
96
+ process_file(STDIN, 'Input')
97
+ else
98
+ @files.each do |path|
99
+ begin
100
+ if File.directory?(path)
101
+ puts "#{path} is a directory."
102
+ next
43
103
  end
104
+ text = read_file(path)
105
+ process_input(text, path)
106
+ rescue Errno::ENOENT
107
+ puts "Can't open #{path}"
108
+ rescue ArgumentError
109
+ puts "Failed for #{path}. Is it binary?"
44
110
  end
45
- rescue Errno::ENOENT
46
- puts "Can't open #{path}"
47
- rescue ArgumentError
48
- puts "Failed for #{path}. Is it binary?"
49
111
  end
50
112
  end
data/lib/indentinator.rb CHANGED
@@ -1,28 +1,37 @@
1
+ class String
2
+ def -(other)
3
+ self.index(other) == 0 ? self[other.size..self.size] : nil
4
+ end
5
+ end
6
+
1
7
  module Indentinator
2
8
 
3
9
  def indent_amount(lines)
4
- curr = 0
10
+ curr = ''
5
11
  diffs = {}
12
+ # loop through the lines and count each indent difference
13
+ # between prev and current line in `diffs`
6
14
  lines.each_with_index do |line, idx|
7
- spaces = line.match(/^( *)/)[0]
8
- diff = spaces.size - curr
15
+ whites = line.match(/^([ \t]*)/)[0]
16
+ diff = whites - curr
9
17
  if @very_verbose
10
- puts "#{'%- 5d' % (idx + 1)}: #{diff}"
18
+ puts "#{'%- 5d' % (idx + 1)}: #{diff.size}" if diff
11
19
  end
12
- if diff > 0
20
+ if diff and diff.size > 0
13
21
  diffs[diff] ||= 0
14
22
  diffs[diff] = diffs[diff] + 1
15
23
  end
16
- curr = spaces.size
24
+ curr = whites
17
25
  end
26
+ # sort and pick the one w highest frequency
18
27
  if diffs.size > 0
19
28
  sorted = diffs.sort{|a, b| b[1] - a[1]}
20
29
  if @verbose
21
- puts sorted.map{|p| ('%- 5d=> ' % p[0]) + p[1].to_s}.join("\n")
30
+ puts sorted.map{|p| ('%- 5d=> ' % p[0].size) + p[1].to_s}.join("\n")
22
31
  end
23
32
  sorted[0][0]
24
33
  else
25
- 0
34
+ ''
26
35
  end
27
36
  end
28
37
 
@@ -31,30 +40,25 @@ def convert_indentation(text, from, to)
31
40
  end
32
41
 
33
42
  def convert_lines(lines, from, to)
34
- ratio = to.to_f / from
35
- curr_indent_org = 0
36
- curr_indent = 0
43
+ indents = [] # indentation stack
44
+ # loop through and convert line by line
37
45
  lines.map do |line|
38
- if line.empty?
39
- line
40
- else
41
- m = line.match(/^( *)(.*)$/)
42
- spaces = m[1]
43
- rest = m[2]
44
- indent = spaces.size - curr_indent_org
45
- curr_indent_org = spaces.size
46
- if indent == from # standard indent
47
- curr_indent += (indent * ratio).to_i
48
- elsif indent > 0 # non-standard indent
49
- curr_indent += indent
50
- elsif indent == 0 # no indent
51
-
52
- else # de-indent
53
- # reset back to use original indentation
54
- curr_indent = (curr_indent_org * ratio).round
46
+ next line if line.strip.empty?
47
+ m = line.match(/^([ \t]*)(.*)$/)
48
+ whites = m[1]
49
+ rest = m[2]
50
+ diff = whites - indents.join
51
+ if diff.nil?
52
+ # no match indent, could be a de-indent or a different indent pattern
53
+ # find longest matching indent in stack, and pop till that point
54
+ indents.pop
55
+ while indents.size > 0 and diff.nil?
56
+ indents.pop
57
+ diff = whites - indents.join
55
58
  end
56
- ' ' * curr_indent + rest
57
59
  end
60
+ indents.push(diff)
61
+ indents.map{|i| (i == from or i == "\t") ? to : i }.join + rest
58
62
  end
59
63
  end
60
64
 
data/test/tests.rb CHANGED
@@ -1,5 +1,61 @@
1
1
  require 'rspec'
2
- require 'indentinator.rb'
2
+ require 'indentinator'
3
+ include Indentinator
4
+
5
+ describe 'indent_amount' do
6
+ it "sniffs indent amount 2" do
7
+ text = "
8
+ line 1
9
+ line 2"
10
+ indent_amount(text.split("\n")).should == " " * 2
11
+ text = "
12
+ line 1
13
+ line 2"
14
+ indent_amount(text.split("\n")).should == " " * 4
15
+ end
16
+
17
+ it "should pick most frequent indentation" do
18
+ text = "
19
+ line 1
20
+ line 2
21
+ line 3
22
+ line 4"
23
+ indent_amount(text.split("\n")).should == " " * 4
24
+ end
25
+
26
+ it "should support tabs" do
27
+ lines = [
28
+ "line 1",
29
+ "\tline 2",
30
+ "\t\tline 3"
31
+ ]
32
+ indent_amount(lines).should == "\t"
33
+ end
34
+
35
+ it "should support tabs - adheres to frequency principle" do
36
+ lines = [
37
+ "line 1",
38
+ "\tline 2",
39
+ "\t\tline 3",
40
+ " line 4"
41
+ ]
42
+ indent_amount(lines).should == "\t"
43
+ end
44
+
45
+ it "should support tabs - adheres to frequency principle(2)" do
46
+ lines = [
47
+ "line 1",
48
+ "\tline 2",
49
+ "\t\tline 3",
50
+ "line 4",
51
+ " line 5",
52
+ " line 6",
53
+ " line 7"
54
+ ]
55
+ indent_amount(lines).should == " "
56
+ end
57
+ end
58
+
3
59
  describe 'convert_file' do
4
60
  it "converts basic indentation" do
5
61
  text = "
@@ -7,7 +63,7 @@ line 1
7
63
  line 2
8
64
  line 3
9
65
  line 4"
10
- convert_indentation(text, 2, 4).should == "
66
+ convert_indentation(text, ' ' * 2, ' ' * 4).should == "
11
67
  line 1
12
68
  line 2
13
69
  line 3
@@ -19,7 +75,7 @@ line 4"
19
75
  text = "
20
76
  line 1
21
77
  line 2"
22
- convert_indentation(text, 2, 4).should == text
78
+ convert_indentation(text, ' ' * 2, ' ' * 4).should == text
23
79
  end
24
80
 
25
81
  it "retains non-standard indentation even when is
@@ -29,7 +85,7 @@ line 1
29
85
  line 2
30
86
  line 3
31
87
  line 2"
32
- convert_indentation(text, 2, 4).should == "
88
+ convert_indentation(text, ' ' * 2, ' ' * 4).should == "
33
89
  line 1
34
90
  line 2
35
91
  line 3
@@ -42,7 +98,7 @@ line 1
42
98
  line 2
43
99
  line 3
44
100
  line 4"
45
- convert_indentation(text, 4, 2).should == "
101
+ convert_indentation(text, ' ' * 4, ' ' * 2).should == "
46
102
  line 1
47
103
  line 2
48
104
  line 3
@@ -56,7 +112,7 @@ line 0
56
112
  line 2
57
113
  line 3
58
114
  line 4"
59
- convert_indentation(text, 4, 2).should == "
115
+ convert_indentation(text, ' ' * 4, ' ' * 2).should == "
60
116
  line 0
61
117
  line 1
62
118
  line 2
@@ -70,7 +126,7 @@ line 0
70
126
  line 2
71
127
  line 3
72
128
  line 4"
73
- convert_indentation(text, 2, 4).should == "
129
+ convert_indentation(text, ' ' * 2, ' ' * 4).should == "
74
130
  line 0
75
131
  line 2
76
132
  line 3
@@ -85,7 +141,7 @@ line 0
85
141
  line 3
86
142
 
87
143
  line 4"
88
- convert_indentation(text, 4, 2).should == "
144
+ convert_indentation(text, ' ' * 4, ' ' * 2).should == "
89
145
  line 0
90
146
  line 1
91
147
  line 2
@@ -101,11 +157,85 @@ line 1
101
157
  line 3
102
158
 
103
159
  line 4"
104
- convert_indentation(text, 4, 2).should == "
160
+ convert_indentation(text, ' ' * 4, ' ' * 2).should == "
105
161
  line 1
106
162
  line 2
107
163
  line 3
108
164
 
109
165
  line 4"
110
166
  end
167
+
168
+ it "should de-indent property(ex 3)" do
169
+ text = "
170
+ line 2
171
+ line 3
172
+ line 4
173
+ line 5"
174
+ convert_indentation(text, ' ' * 2, ' ' * 4).should == "
175
+ line 2
176
+ line 3
177
+ line 4
178
+ line 5"
179
+ end
180
+
181
+ it "should de-indent property(ex 4)" do
182
+ text = "
183
+ line 2
184
+ line 3
185
+ line 4
186
+ line 5"
187
+ convert_indentation(text, ' ' * 2, ' ' * 4).should == text
188
+ end
189
+
190
+ it "should de-indent property(ex 5)" do
191
+ text = "
192
+ line 1
193
+ line 2
194
+ line 3
195
+ line 4
196
+ line 5
197
+ line 6"
198
+ convert_indentation(text, ' ' * 2, ' ' * 4).should == text
199
+ end
200
+
201
+ it "should support tabs" do
202
+ lines = [
203
+ "line 1",
204
+ "\tline 2",
205
+ "\tline 3",
206
+ "\t\tline 4"
207
+ ]
208
+ convert_lines(lines, "\t", " " * 4).should == [
209
+ "line 1",
210
+ " line 2",
211
+ " line 3",
212
+ " line 4"
213
+ ]
214
+ end
215
+
216
+ it "should support tabs (ex 2)" do
217
+ text = "
218
+ line 1
219
+ line 2
220
+ line 3
221
+ line 4"
222
+ convert_indentation(text, ' ' * 2, "\t").should == "
223
+ line 1
224
+ \tline 2
225
+ \t\tline 3
226
+ line 4"
227
+ end
228
+
229
+ it "tabs should be converted always" do
230
+ lines = [
231
+ "line 1",
232
+ " line 2",
233
+ "\tline 3"
234
+ ]
235
+ convert_lines(lines, ' ' * 2, ' ' * 4).should == [
236
+ "line 1",
237
+ " line 2",
238
+ " line 3"
239
+ ]
240
+ end
111
241
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: Indentinator
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 2
10
- version: 0.0.2
9
+ - 3
10
+ version: 0.0.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Toby Ho
@@ -15,10 +15,37 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-03-24 00:00:00 -04:00
18
+ date: 2011-03-26 00:00:00 -04:00
19
19
  default_executable:
20
- dependencies: []
21
-
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: getopt
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rspec
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id002
22
49
  description:
23
50
  email: airportyh@gmail.com
24
51
  executables: