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.
@@ -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