Indentinator 0.0.2 → 0.0.3
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/bin/indentinator +87 -25
- data/lib/indentinator.rb +33 -29
- data/test/tests.rb +139 -9
- 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
|
-
|
7
|
-
|
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']
|
21
|
+
@verbose = opts['v'] || @very_verbose
|
22
|
+
@replace = opts['r'] && !@from_stdin
|
10
23
|
@files = ARGV
|
11
|
-
|
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
|
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
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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 =
|
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
|
-
|
8
|
-
diff =
|
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 =
|
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
|
-
|
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
|
-
|
35
|
-
|
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
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
indent
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
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:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
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-
|
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:
|