ruby-beautify 0.9.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.
- data/.gitignore +2 -0
- data/README.md +5 -0
- data/bin/rbeautify +29 -0
- data/lib/app.rb +79 -0
- data/lib/beautifier.rb +168 -0
- data/lib/cli.rb +81 -0
- data/lib/filemagic.rb +13 -0
- data/lib/rbeautify.rb +27 -0
- data/lib/rbeautify/block_end.rb +23 -0
- data/lib/rbeautify/block_matcher.rb +153 -0
- data/lib/rbeautify/block_start.rb +119 -0
- data/lib/rbeautify/config/ruby.rb +131 -0
- data/lib/rbeautify/language.rb +37 -0
- data/lib/rbeautify/line.rb +53 -0
- data/license.txt +77 -0
- data/rbeautify.gemspec +15 -0
- data/spec/fixtures/ruby.yml +408 -0
- data/spec/rbeautify/block_matcher_spec.rb +89 -0
- data/spec/rbeautify/block_start_spec.rb +51 -0
- data/spec/rbeautify/config/ruby_spec.rb +183 -0
- data/spec/rbeautify/line_spec.rb +73 -0
- data/spec/rbeautify_spec.rb +1 -0
- data/spec/spec_helper.rb +124 -0
- metadata +95 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
module RBeautify
|
2
|
+
|
3
|
+
class BlockStart
|
4
|
+
|
5
|
+
attr_reader :block_matcher, :parent, :offset, :match, :after_match, :line_number
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def first_common_ancestor(first, second)
|
9
|
+
if first.nil? || second.nil?
|
10
|
+
nil
|
11
|
+
else
|
12
|
+
(first.ancestors & second.ancestors).last
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(block_matcher, parent, line_number, offset, match, after_match)
|
18
|
+
@block_matcher = block_matcher
|
19
|
+
@parent = parent
|
20
|
+
@offset = offset
|
21
|
+
@match = match
|
22
|
+
@after_match = after_match
|
23
|
+
@line_number = line_number
|
24
|
+
end
|
25
|
+
|
26
|
+
def end_offset
|
27
|
+
offset + match.length
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse_block_end(string, offset)
|
31
|
+
block_end = parse_explicit_block_end(string, offset)
|
32
|
+
|
33
|
+
# Handle case where end is implicit
|
34
|
+
if block_end.nil? && end_is_implicit? && parent
|
35
|
+
block_end = parent.parse_block_end(string, offset)
|
36
|
+
end
|
37
|
+
|
38
|
+
block_end
|
39
|
+
end
|
40
|
+
|
41
|
+
def format_content?
|
42
|
+
block_matcher.format_content?
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse_content?
|
46
|
+
block_matcher.parse_content?
|
47
|
+
end
|
48
|
+
|
49
|
+
def indent_end_line?
|
50
|
+
block_matcher.indent_end_line?(self)
|
51
|
+
end
|
52
|
+
|
53
|
+
def total_indent_size
|
54
|
+
parent.nil? ? indent_size : parent.total_indent_size + indent_size
|
55
|
+
end
|
56
|
+
|
57
|
+
def indent_size
|
58
|
+
block_matcher.indent_size(self)
|
59
|
+
end
|
60
|
+
|
61
|
+
def end_is_implicit?
|
62
|
+
block_matcher.end_is_implicit?
|
63
|
+
end
|
64
|
+
|
65
|
+
def name
|
66
|
+
block_matcher.name
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns true if strict ancestor of
|
70
|
+
def strict_ancestor_of?(block_start)
|
71
|
+
block_start && block_start.parent && (self == block_start.parent || strict_ancestor_of?(block_start.parent))
|
72
|
+
end
|
73
|
+
|
74
|
+
def ancestors
|
75
|
+
if parent
|
76
|
+
parent.ancestors + [self]
|
77
|
+
else
|
78
|
+
[self]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
def ends?
|
84
|
+
block_matcher.ends?
|
85
|
+
end
|
86
|
+
|
87
|
+
def negate_ends_match?
|
88
|
+
block_matcher.negate_ends_match?
|
89
|
+
end
|
90
|
+
|
91
|
+
def escape_character?
|
92
|
+
block_matcher.escape_character?
|
93
|
+
end
|
94
|
+
|
95
|
+
def parse_explicit_block_end(string, offset)
|
96
|
+
block_end = nil
|
97
|
+
|
98
|
+
if ends?
|
99
|
+
|
100
|
+
if match = block_matcher.ends.match(string)
|
101
|
+
unless negate_ends_match?
|
102
|
+
if escape_character? &&
|
103
|
+
((escape_chars = match.pre_match.match(/\\*$/)) && (escape_chars[0].size % 2 == 1))
|
104
|
+
# If there are an odd number of escape characters just before
|
105
|
+
# the match then this match should be skipped
|
106
|
+
return parse_explicit_block_end(match.post_match, offset + escape_chars[0].size + match[0].length)
|
107
|
+
else
|
108
|
+
return RBeautify::BlockEnd.new(self, offset + match.begin(0), match[0], match.post_match)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
elsif negate_ends_match?
|
112
|
+
return RBeautify::BlockEnd.new(self, offset, '', string)
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# define ruby language
|
2
|
+
|
3
|
+
unless RBeautify::Language.language(:ruby)
|
4
|
+
|
5
|
+
ruby = RBeautify::Language.add_language(:ruby)
|
6
|
+
|
7
|
+
pre_keyword_boundary = '(^|[^a-z0-9A-Z:._])' # like \b but with : , . _ all added to list of exceptions
|
8
|
+
start_statement_boundary = '(^|(;|=)\s*)'
|
9
|
+
continue_statement_boundary = '(^|;\s*)'
|
10
|
+
ruby.indent_size = 2
|
11
|
+
|
12
|
+
ruby.add_matcher(:program_end, /^__END__$/, false, :format_content => false, :parse_content => false)
|
13
|
+
|
14
|
+
ruby.add_matcher(:multiline_comment, /^=begin/, /^=end/, :format_content => false, :parse_content => false)
|
15
|
+
|
16
|
+
ruby.add_matcher(:double_quote,
|
17
|
+
/"/,
|
18
|
+
/"/,
|
19
|
+
:parse_content => true,
|
20
|
+
:format_content => false,
|
21
|
+
:escape_character => true,
|
22
|
+
:nest_except => [:double_quote, :single_quote, :regex, :back_tick])
|
23
|
+
|
24
|
+
# NEED TO MODIFY DOUBLE QUOTE TO BE FORMATTED to get this to work
|
25
|
+
ruby.add_matcher(:interpolation,
|
26
|
+
/#\{/,
|
27
|
+
/\}/,
|
28
|
+
:nest_only => [:double_quote, :regex, :backtick])
|
29
|
+
|
30
|
+
ruby.add_matcher(:single_quote,
|
31
|
+
/'/,
|
32
|
+
/'/,
|
33
|
+
:parse_content => false,
|
34
|
+
:format_content => false,
|
35
|
+
:escape_character => true,
|
36
|
+
:nest_except => [:double_quote, :single_quote, :regex, :back_tick])
|
37
|
+
|
38
|
+
ruby.add_matcher(:regex,
|
39
|
+
/(^|((,|=|~)\s*))\//, # Try to distinguish it from division sign
|
40
|
+
/\//,
|
41
|
+
:format_content => false,
|
42
|
+
:escape_character => true,
|
43
|
+
:end_can_also_be_start => false,
|
44
|
+
:nest_except => [:double_quote, :single_quote, :regex, :back_tick])
|
45
|
+
|
46
|
+
ruby.add_matcher(:back_tick,
|
47
|
+
/`/,
|
48
|
+
/`/,
|
49
|
+
:format_content => false,
|
50
|
+
:escape_character => true,
|
51
|
+
:nest_except => [:double_quote, :single_quote, :regex, :back_tick])
|
52
|
+
|
53
|
+
ruby.add_matcher(:standard,
|
54
|
+
/((#{start_statement_boundary}(module|class|def))|#{pre_keyword_boundary}do)\b/,
|
55
|
+
/(((^|;|\s)end)|#{continue_statement_boundary}(rescue|ensure))\b/,
|
56
|
+
:nest_except => [:double_quote, :regex, :backtick])
|
57
|
+
|
58
|
+
ruby.add_matcher(:more,
|
59
|
+
/#{start_statement_boundary}(until|for|while)\b/,
|
60
|
+
/(((^|;|\s)end)|#{continue_statement_boundary}(rescue|ensure))\b/,
|
61
|
+
:nest_except => [:double_quote, :regex, :backtick])
|
62
|
+
|
63
|
+
ruby.add_matcher(:begin,
|
64
|
+
/((#{start_statement_boundary}begin)|(#{continue_statement_boundary}(ensure|rescue)))\b/,
|
65
|
+
/(((^|;|\s)end)|#{continue_statement_boundary}(rescue|ensure|else))\b/,
|
66
|
+
:nest_except => [:double_quote, :regex, :backtick])
|
67
|
+
|
68
|
+
ruby.add_matcher(:if,
|
69
|
+
/((#{start_statement_boundary}(if|unless))|#{continue_statement_boundary}(then|elsif|else))\b/,
|
70
|
+
/(((^|;|\s)end)|(#{continue_statement_boundary}(then|elsif|else)))\b/,
|
71
|
+
:nest_except => [:case, :double_quote, :regex, :backtick])
|
72
|
+
|
73
|
+
ruby.add_matcher(:case,
|
74
|
+
/#{pre_keyword_boundary}case\b/,
|
75
|
+
/(^|;|\s)end\b/,
|
76
|
+
:nest_except => [:double_quote, :regex, :backtick],
|
77
|
+
:indent_size => 0)
|
78
|
+
|
79
|
+
ruby.add_matcher(:inner_case,
|
80
|
+
/#{continue_statement_boundary}(when|else|then)\b/,
|
81
|
+
/#{continue_statement_boundary}(when|else|then)\b/,
|
82
|
+
:nest_only => [:case],
|
83
|
+
:end => :implicit,
|
84
|
+
:end_can_also_be_start => true,
|
85
|
+
:nest_except => [:double_quote, :regex, :backtick])
|
86
|
+
|
87
|
+
# TODO: Improve the check that this is not a block with arguments. Will
|
88
|
+
# currently match any bracket followed by spaces and |.
|
89
|
+
bracket_indent_end_line_proc = Proc.new { |block| !block.after_match.empty? && !block.after_match.match(/^\|/) }
|
90
|
+
bracket_indent_size_proc = Proc.new do |block|
|
91
|
+
if bracket_indent_end_line_proc.call(block)
|
92
|
+
strict_ancestors_on_same_line = block.ancestors.select { |a| a != block && a.line_number == block.line_number }
|
93
|
+
block.end_offset - strict_ancestors_on_same_line.inject(0) { |sum, a| sum + a.indent_size }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
ruby.add_matcher(:curly_bracket,
|
98
|
+
/\{\s*/,
|
99
|
+
/\}/,
|
100
|
+
:indent_end_line => bracket_indent_end_line_proc,
|
101
|
+
:indent_size => bracket_indent_size_proc,
|
102
|
+
:nest_except => [:double_quote, :regex, :backtick])
|
103
|
+
|
104
|
+
ruby.add_matcher(:round_bracket,
|
105
|
+
/\(\s*/,
|
106
|
+
/\)/,
|
107
|
+
:indent_end_line => bracket_indent_end_line_proc,
|
108
|
+
:indent_size => bracket_indent_size_proc,
|
109
|
+
:nest_except => [:double_quote, :regex, :backtick])
|
110
|
+
|
111
|
+
ruby.add_matcher(:square_bracket,
|
112
|
+
/\[\s*/,
|
113
|
+
/\]/,
|
114
|
+
:indent_end_line => bracket_indent_end_line_proc,
|
115
|
+
:indent_size => bracket_indent_size_proc,
|
116
|
+
:nest_except => [:double_quote, :regex, :backtick])
|
117
|
+
|
118
|
+
ruby.add_matcher(:comment, /(\s*)?#/,
|
119
|
+
/$/,
|
120
|
+
:parse_content => false,
|
121
|
+
:format_content => false,
|
122
|
+
:nest_except => [:double_quote, :single_quote, :regex, :back_tick])
|
123
|
+
|
124
|
+
ruby.add_matcher(:continuing_line,
|
125
|
+
/(,|\.|\+|-|=\>|=|&&|\|\||\\|==|\s\?|:|<<)(\s*)?(#.*)?$/,
|
126
|
+
/(^|(,|\.|\+|-|=\>|=|&&|\|\||\\|==|\s\?|:|<<)(\s*)?)(#.*)?$/,
|
127
|
+
:indent_end_line => true,
|
128
|
+
:negate_ends_match => true,
|
129
|
+
:nest_except => [:continuing_line, :curly_bracket, :round_bracket, :square_bracket, :double_quote, :single_quote, :regex, :back_tick])
|
130
|
+
|
131
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RBeautify
|
2
|
+
class Language
|
3
|
+
|
4
|
+
@@languages = {}
|
5
|
+
|
6
|
+
attr_reader :matchers
|
7
|
+
attr_accessor :indent_size
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
def language(name)
|
12
|
+
languages[name]
|
13
|
+
end
|
14
|
+
|
15
|
+
def languages
|
16
|
+
@@languages
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_language(name)
|
20
|
+
languages[name] = new()
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
@matchers = []
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_matcher(name, starts, ends, options = {})
|
29
|
+
self.matchers << BlockMatcher.new(self, name, starts, ends, options)
|
30
|
+
end
|
31
|
+
|
32
|
+
def matcher(name)
|
33
|
+
self.matchers.detect { |matcher| matcher.name == name}
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module RBeautify
|
2
|
+
class Line
|
3
|
+
|
4
|
+
attr_reader :language, :content, :line_number, :original_block, :block, :indent_character
|
5
|
+
|
6
|
+
def initialize(language, content, line_number, original_block = nil, use_tabs = false)
|
7
|
+
@language = language
|
8
|
+
@content = content
|
9
|
+
@original_block = original_block
|
10
|
+
@indent_character = use_tabs ? "\t" : " "
|
11
|
+
@block = BlockMatcher.parse(language, original_block, line_number, stripped, 0)
|
12
|
+
end
|
13
|
+
|
14
|
+
def format
|
15
|
+
if @formatted.nil?
|
16
|
+
if format?
|
17
|
+
if stripped.length == 0
|
18
|
+
@formatted = ""
|
19
|
+
else
|
20
|
+
@formatted = tab_string + stripped
|
21
|
+
end
|
22
|
+
else
|
23
|
+
@formatted = content
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
@formatted
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def format?
|
32
|
+
original_block.nil? || original_block.format_content?
|
33
|
+
end
|
34
|
+
|
35
|
+
def indent_size
|
36
|
+
if (block.nil? || block.strict_ancestor_of?(original_block)) && (original_block && original_block.indent_end_line?)
|
37
|
+
original_block.total_indent_size
|
38
|
+
else
|
39
|
+
common_ancestor = BlockStart.first_common_ancestor(original_block, block)
|
40
|
+
common_ancestor.nil? ? 0 : common_ancestor.total_indent_size
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def tab_string
|
45
|
+
indent_character * (indent_size / 2 ) + (indent_size.odd? ? ' ' : '')
|
46
|
+
end
|
47
|
+
|
48
|
+
def stripped
|
49
|
+
@stripped = content.strip
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
data/license.txt
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
All software in this package is covered by the MIT license and beerware (rev42).
|
2
|
+
|
3
|
+
Copyright (c) 2011 Ernie Brodeur
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person
|
6
|
+
obtaining a copy of this software and associated documentation
|
7
|
+
files (the "Software"), to deal in the Software without
|
8
|
+
restriction, including without limitation the rights to use,
|
9
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the
|
11
|
+
Software is furnished to do so, subject to the following
|
12
|
+
conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
19
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
21
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
22
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
23
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
24
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
25
|
+
|
26
|
+
/*
|
27
|
+
* ----------------------------------------------------------------------------
|
28
|
+
* "THE BEER-WARE LICENSE" (Revision 42):
|
29
|
+
* Ernie Brodeur wrote this package. As long as you retain this notice you
|
30
|
+
* can do whatever you want with his stuff. If we meet some day, and you think
|
31
|
+
* this stuff is worth it, you can buy me a beer in return.
|
32
|
+
* ----------------------------------------------------------------------------
|
33
|
+
*/
|
34
|
+
|
35
|
+
Further supported by: https://github.com/CraigWilliams/BeautifyRuby/blob/master/lib/rbeautify.rb
|
36
|
+
|
37
|
+
All of BeautifyRuby is licensed under the MIT license.
|
38
|
+
|
39
|
+
Copyright (c) 2011 Craig Williams <cwilliams.allancraig@gmail.com>
|
40
|
+
|
41
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
42
|
+
of this software and associated documentation files (the "Software"), to deal
|
43
|
+
in the Software without restriction, including without limitation the rights
|
44
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
45
|
+
copies of the Software, and to permit persons to whom the Software is
|
46
|
+
furnished to do so, subject to the following conditions:
|
47
|
+
|
48
|
+
The above copyright notice and this permission notice shall be included in
|
49
|
+
all copies or substantial portions of the Software.
|
50
|
+
|
51
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
52
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
53
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
54
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
55
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
56
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
57
|
+
THE SOFTWARE.
|
58
|
+
|
59
|
+
Pieces provided originally by: http://www.arachnoid.com/ruby/rubyBeautifier.html
|
60
|
+
|
61
|
+
/***************************************************************************
|
62
|
+
* Copyright (C) 2008, Joel Chippindale, Paul Lutus *
|
63
|
+
* *
|
64
|
+
* This program is free software: you can redistribute it and/or modify *
|
65
|
+
* it under the terms of the GNU General Public License as published by *
|
66
|
+
* the Free Software Foundation, either version 3 of the License, or *
|
67
|
+
* (at your option) any later version. *
|
68
|
+
* *
|
69
|
+
* This program is distributed in the hope that it will be useful, *
|
70
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
71
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
72
|
+
* GNU General Public License for more details. *
|
73
|
+
* *
|
74
|
+
* You should have received a copy of the GNU General Public License *
|
75
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
76
|
+
* *
|
77
|
+
***************************************************************************/
|
data/rbeautify.gemspec
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Gem::Specification.new do |gem|
|
2
|
+
gem.name = 'ruby-beautify'
|
3
|
+
gem.version = '0.9.0'
|
4
|
+
gem.summary = "a cli tool (and module) to beautify ruby code."
|
5
|
+
gem.description = gem.summary
|
6
|
+
gem.authors = ["Ernie Brodeur", "Craig Williams", "Joel Chippindale", "Paul Lutus"]
|
7
|
+
gem.email = 'ebrodeur@ujami.net'
|
8
|
+
gem.homepage = "https://github.com/erniebrodeur/ruby-beautify"
|
9
|
+
|
10
|
+
gem.add_development_dependency "rspec"
|
11
|
+
gem.files = `git ls-files`.split("\n")
|
12
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
13
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
14
|
+
gem.require_paths = ["lib"]
|
15
|
+
end
|
@@ -0,0 +1,408 @@
|
|
1
|
+
- name: indent if else end statement
|
2
|
+
input: |
|
3
|
+
if foo
|
4
|
+
bar = 1
|
5
|
+
elsif foo2
|
6
|
+
bar = 2
|
7
|
+
else
|
8
|
+
bar = 3
|
9
|
+
end
|
10
|
+
output: |
|
11
|
+
if foo
|
12
|
+
bar = 1
|
13
|
+
elsif foo2
|
14
|
+
bar = 2
|
15
|
+
else
|
16
|
+
bar = 3
|
17
|
+
end
|
18
|
+
|
19
|
+
- name: handle case where if begins and ends on same line
|
20
|
+
input: |
|
21
|
+
foo do
|
22
|
+
if a then b = 1 else b = 2 end
|
23
|
+
end
|
24
|
+
output: |
|
25
|
+
foo do
|
26
|
+
if a then b = 1 else b = 2 end
|
27
|
+
end
|
28
|
+
|
29
|
+
- name: indent not double indent case/when statement
|
30
|
+
input: |
|
31
|
+
case foo
|
32
|
+
when 1
|
33
|
+
bar = 'some string'
|
34
|
+
when 2
|
35
|
+
bar = 'some other string'
|
36
|
+
when 3 then bar = '3'
|
37
|
+
else
|
38
|
+
bar = '4'
|
39
|
+
end
|
40
|
+
output: |
|
41
|
+
case foo
|
42
|
+
when 1
|
43
|
+
bar = 'some string'
|
44
|
+
when 2
|
45
|
+
bar = 'some other string'
|
46
|
+
when 3 then bar = '3'
|
47
|
+
else
|
48
|
+
bar = '4'
|
49
|
+
end
|
50
|
+
|
51
|
+
- name: indent while statement
|
52
|
+
input: |
|
53
|
+
def foo
|
54
|
+
bar = 1
|
55
|
+
while bar < 3
|
56
|
+
puts bar
|
57
|
+
bar = bar.next
|
58
|
+
end
|
59
|
+
end
|
60
|
+
output: |
|
61
|
+
def foo
|
62
|
+
bar = 1
|
63
|
+
while bar < 3
|
64
|
+
puts bar
|
65
|
+
bar = bar.next
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
- name: ignore code after end of line comment
|
70
|
+
input: |
|
71
|
+
def method_containing_end_of_line_comment
|
72
|
+
a = b # Comment containing do
|
73
|
+
end
|
74
|
+
output: |
|
75
|
+
def method_containing_end_of_line_comment
|
76
|
+
a = b # Comment containing do
|
77
|
+
end
|
78
|
+
|
79
|
+
- name :not indent multineline comment:
|
80
|
+
input: |
|
81
|
+
=begin
|
82
|
+
Comment
|
83
|
+
=end
|
84
|
+
foo
|
85
|
+
|
86
|
+
- name: indent lines after first of multiline code
|
87
|
+
input: |
|
88
|
+
def method_with_multiline_method_call
|
89
|
+
multiline_method_call \
|
90
|
+
first_arg,
|
91
|
+
second_arg,
|
92
|
+
third_arg
|
93
|
+
end
|
94
|
+
output: |
|
95
|
+
def method_with_multiline_method_call
|
96
|
+
multiline_method_call \
|
97
|
+
first_arg,
|
98
|
+
second_arg,
|
99
|
+
third_arg
|
100
|
+
end
|
101
|
+
|
102
|
+
- name: indent method call with bracketed multiline arguments
|
103
|
+
input: |
|
104
|
+
def method_with_multiline_method_call
|
105
|
+
multiline_method_call(foo,
|
106
|
+
bar,
|
107
|
+
foobar)
|
108
|
+
end
|
109
|
+
output: |
|
110
|
+
def method_with_multiline_method_call
|
111
|
+
multiline_method_call(foo,
|
112
|
+
bar,
|
113
|
+
foobar)
|
114
|
+
end
|
115
|
+
|
116
|
+
- name: indent method call with bracketed multiline arguments_even_if_not_first_block_on_line
|
117
|
+
input: |
|
118
|
+
if (foo = bar(first_arg,
|
119
|
+
second_arg))
|
120
|
+
do_something
|
121
|
+
end
|
122
|
+
output: |
|
123
|
+
if (foo = bar(first_arg,
|
124
|
+
second_arg))
|
125
|
+
do_something
|
126
|
+
end
|
127
|
+
|
128
|
+
- name: indent method call with multiline arguments (implicit brackets)
|
129
|
+
input: |
|
130
|
+
def method_with_multiline_method_call
|
131
|
+
multiline_method_call first_arg,
|
132
|
+
second_arg,
|
133
|
+
# Comment in the middle of all this
|
134
|
+
third_arg
|
135
|
+
|
136
|
+
another_method_call
|
137
|
+
end
|
138
|
+
output: |
|
139
|
+
def method_with_multiline_method_call
|
140
|
+
multiline_method_call first_arg,
|
141
|
+
second_arg,
|
142
|
+
# Comment in the middle of all this
|
143
|
+
third_arg
|
144
|
+
|
145
|
+
another_method_call
|
146
|
+
end
|
147
|
+
|
148
|
+
- name: should indent multiline method call chains
|
149
|
+
input: |
|
150
|
+
def method_with_multiline_method_call_chain
|
151
|
+
multiline_method_call.
|
152
|
+
foo.
|
153
|
+
bar
|
154
|
+
|
155
|
+
another_method_call
|
156
|
+
end
|
157
|
+
output: |
|
158
|
+
def method_with_multiline_method_call_chain
|
159
|
+
multiline_method_call.
|
160
|
+
foo.
|
161
|
+
bar
|
162
|
+
|
163
|
+
another_method_call
|
164
|
+
end
|
165
|
+
|
166
|
+
- name: handle multiline code with escaped quotes in strings
|
167
|
+
input: |
|
168
|
+
def method_containing_multiline_code_with_strings
|
169
|
+
a = "foo #{method}" +
|
170
|
+
"bar"
|
171
|
+
end
|
172
|
+
output: |
|
173
|
+
def method_containing_multiline_code_with_strings
|
174
|
+
a = "foo #{method}" +
|
175
|
+
"bar"
|
176
|
+
end
|
177
|
+
|
178
|
+
- name: not change the indentation of multiline strings
|
179
|
+
input: |
|
180
|
+
def method_containing_long_string
|
181
|
+
a = "
|
182
|
+
Some text across multiple lines
|
183
|
+
And another line
|
184
|
+
"
|
185
|
+
b = 5
|
186
|
+
end
|
187
|
+
output: |
|
188
|
+
def method_containing_long_string
|
189
|
+
a = "
|
190
|
+
Some text across multiple lines
|
191
|
+
And another line
|
192
|
+
"
|
193
|
+
b = 5
|
194
|
+
end
|
195
|
+
|
196
|
+
- name: not treat divison as start of regex
|
197
|
+
input: |
|
198
|
+
def foo
|
199
|
+
a = 1/2
|
200
|
+
b = :foo
|
201
|
+
end
|
202
|
+
output: |
|
203
|
+
def foo
|
204
|
+
a = 1/2
|
205
|
+
b = :foo
|
206
|
+
end
|
207
|
+
|
208
|
+
- name: not indent multiline string even if it uses non quote delimiter
|
209
|
+
pending: implementation of block matcher for non quote delimited strings
|
210
|
+
input: |
|
211
|
+
foo = <<TEXT
|
212
|
+
some string
|
213
|
+
and more string
|
214
|
+
TEXT
|
215
|
+
|
216
|
+
- name: recognize when two blocks end on the same line
|
217
|
+
input: |
|
218
|
+
class Foo
|
219
|
+
def foobar
|
220
|
+
if a = 3
|
221
|
+
return 5
|
222
|
+
end; end
|
223
|
+
end
|
224
|
+
output: |
|
225
|
+
class Foo
|
226
|
+
def foobar
|
227
|
+
if a = 3
|
228
|
+
return 5
|
229
|
+
end; end
|
230
|
+
end
|
231
|
+
|
232
|
+
- name: indent multiline array definition
|
233
|
+
input: |
|
234
|
+
class Foo
|
235
|
+
@@bar = [1, 2,
|
236
|
+
3, 4]
|
237
|
+
end
|
238
|
+
output: |
|
239
|
+
class Foo
|
240
|
+
@@bar = [1, 2,
|
241
|
+
3, 4]
|
242
|
+
end
|
243
|
+
|
244
|
+
- name: indent multiline array definition (all on separate lines)
|
245
|
+
input: |
|
246
|
+
class Foo
|
247
|
+
@@bar = [
|
248
|
+
1,
|
249
|
+
2,
|
250
|
+
3,
|
251
|
+
4
|
252
|
+
]
|
253
|
+
end
|
254
|
+
output: |
|
255
|
+
class Foo
|
256
|
+
@@bar = [
|
257
|
+
1,
|
258
|
+
2,
|
259
|
+
3,
|
260
|
+
4
|
261
|
+
]
|
262
|
+
end
|
263
|
+
|
264
|
+
- name: indent multiline hash definition
|
265
|
+
input: |
|
266
|
+
class Foo
|
267
|
+
@@bar = { :foo => 1, :bar => 2
|
268
|
+
:c => 3, :d => 4 }
|
269
|
+
end
|
270
|
+
output: |
|
271
|
+
class Foo
|
272
|
+
@@bar = { :foo => 1, :bar => 2
|
273
|
+
:c => 3, :d => 4 }
|
274
|
+
end
|
275
|
+
|
276
|
+
- name: indent multiline block delimited with curly brackets
|
277
|
+
input: |
|
278
|
+
foo = bar.collect { |paragraph|
|
279
|
+
paragraph.strip
|
280
|
+
}.join("\n")
|
281
|
+
output: |
|
282
|
+
foo = bar.collect { |paragraph|
|
283
|
+
paragraph.strip
|
284
|
+
}.join("\n")
|
285
|
+
|
286
|
+
- name: indent method call with bracketed multiline arguments including continuing statements
|
287
|
+
pending: Implementation of support for continuing statements in bracketed multline arguments
|
288
|
+
input: |
|
289
|
+
def foo
|
290
|
+
bar(first_arg,
|
291
|
+
second_part_a +
|
292
|
+
second_part_b,
|
293
|
+
third_arg)
|
294
|
+
end
|
295
|
+
output: |
|
296
|
+
def foo
|
297
|
+
bar(first_arg,
|
298
|
+
second_part_a +
|
299
|
+
second_part_b,
|
300
|
+
third_arg)
|
301
|
+
end
|
302
|
+
|
303
|
+
- name: indent continuing lines ending in = and +
|
304
|
+
input: |
|
305
|
+
def foo
|
306
|
+
@bar ||=
|
307
|
+
1 +
|
308
|
+
2
|
309
|
+
end
|
310
|
+
output: |
|
311
|
+
def foo
|
312
|
+
@bar ||=
|
313
|
+
1 +
|
314
|
+
2
|
315
|
+
end
|
316
|
+
|
317
|
+
- name: indent block within implicit brackets
|
318
|
+
pending: Implementation of support for this feature
|
319
|
+
input: |
|
320
|
+
def foo
|
321
|
+
bar first_arg,
|
322
|
+
second_arg,
|
323
|
+
[
|
324
|
+
1,
|
325
|
+
2,
|
326
|
+
3
|
327
|
+
],
|
328
|
+
last_arg
|
329
|
+
end
|
330
|
+
output: |
|
331
|
+
def foo
|
332
|
+
bar first_arg,
|
333
|
+
second_arg,
|
334
|
+
[
|
335
|
+
1,
|
336
|
+
2,
|
337
|
+
3
|
338
|
+
],
|
339
|
+
last_arg
|
340
|
+
end
|
341
|
+
|
342
|
+
- name: "should not treat ':', '_' or '.' as word boundaries before keywords"
|
343
|
+
input: |
|
344
|
+
case params[:do]
|
345
|
+
when "update_if"
|
346
|
+
update_if.if
|
347
|
+
when "update_do"
|
348
|
+
update_do.do
|
349
|
+
end
|
350
|
+
output: |
|
351
|
+
case params[:do]
|
352
|
+
when "update_if"
|
353
|
+
update_if.if
|
354
|
+
when "update_do"
|
355
|
+
update_do.do
|
356
|
+
end
|
357
|
+
|
358
|
+
- name: should recognize interpolation and not match other content within double quotes
|
359
|
+
input: |
|
360
|
+
def foo
|
361
|
+
return "Foo#{" (#{bar})"}"
|
362
|
+
end
|
363
|
+
output: |
|
364
|
+
def foo
|
365
|
+
return "Foo#{" (#{bar})"}"
|
366
|
+
end
|
367
|
+
|
368
|
+
- name: should not non interpolated content within regexes and strings and backticks
|
369
|
+
input: |
|
370
|
+
def foo
|
371
|
+
@foo = [
|
372
|
+
/" if bar/,
|
373
|
+
`ls if`,
|
374
|
+
"if fun =",
|
375
|
+
'else'
|
376
|
+
]
|
377
|
+
end
|
378
|
+
output: |
|
379
|
+
def foo
|
380
|
+
@foo = [
|
381
|
+
/" if bar/,
|
382
|
+
`ls if`,
|
383
|
+
"if fun =",
|
384
|
+
'else'
|
385
|
+
]
|
386
|
+
end
|
387
|
+
|
388
|
+
- name: should handle one liners that include an end statement correctly
|
389
|
+
input: |
|
390
|
+
def foo; puts 'foo' end
|
391
|
+
def bar; puts 'bar' end
|
392
|
+
output: |
|
393
|
+
def foo; puts 'foo' end
|
394
|
+
def bar; puts 'bar' end
|
395
|
+
|
396
|
+
- name: should handle if and unless statements that are terminated implicitly
|
397
|
+
input: |
|
398
|
+
def foo
|
399
|
+
bar = (1 + 2) if foobar
|
400
|
+
baz unless foobaz
|
401
|
+
Boo.new(:boo) rescue raise('Houston we have a problem')
|
402
|
+
end
|
403
|
+
output: |
|
404
|
+
def foo
|
405
|
+
bar = (1 + 2) if foobar
|
406
|
+
baz unless foobaz
|
407
|
+
Boo.new(:boo) rescue raise('Houston we have a problem')
|
408
|
+
end
|