tailor 1.3.1 → 1.4.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/Gemfile.lock +27 -25
  4. data/History.md +36 -0
  5. data/README.md +10 -4
  6. data/Rakefile +6 -6
  7. data/features/support/env.rb +2 -2
  8. data/features/support/legacy/bad_ternary_colon_spacing.rb +1 -1
  9. data/features/support/legacy/long_file_with_indentation.rb +2 -2
  10. data/features/support/world.rb +1 -1
  11. data/features/valid_ruby.feature +1 -1
  12. data/lib/tailor/cli/options.rb +19 -1
  13. data/lib/tailor/configuration.rb +2 -2
  14. data/lib/tailor/configuration/style.rb +6 -0
  15. data/lib/tailor/lexed_line.rb +2 -2
  16. data/lib/tailor/lexer/lexer_constants.rb +1 -0
  17. data/lib/tailor/lexer/token.rb +2 -2
  18. data/lib/tailor/logger.rb +2 -2
  19. data/lib/tailor/rake_task.rb +2 -2
  20. data/lib/tailor/ruler.rb +0 -1
  21. data/lib/tailor/rulers/allow_camel_case_methods_ruler.rb +0 -1
  22. data/lib/tailor/rulers/allow_conditional_parentheses.rb +65 -0
  23. data/lib/tailor/rulers/allow_unnecessary_double_quotes_ruler.rb +61 -0
  24. data/lib/tailor/rulers/allow_unnecessary_interpolation_ruler.rb +87 -0
  25. data/lib/tailor/rulers/indentation_spaces_ruler.rb +40 -50
  26. data/lib/tailor/rulers/indentation_spaces_ruler/argument_alignment.rb +63 -0
  27. data/lib/tailor/rulers/indentation_spaces_ruler/ast_xml.rb +89 -0
  28. data/lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb +2 -14
  29. data/lib/tailor/rulers/indentation_spaces_ruler/line_continuations.rb +58 -0
  30. data/lib/tailor/rulers/max_code_lines_in_class_ruler.rb +3 -3
  31. data/lib/tailor/rulers/max_code_lines_in_method_ruler.rb +3 -3
  32. data/lib/tailor/rulers/spaces_after_comma_ruler.rb +3 -3
  33. data/lib/tailor/rulers/spaces_after_conditional_ruler.rb +3 -3
  34. data/lib/tailor/rulers/spaces_after_lbrace_ruler.rb +3 -3
  35. data/lib/tailor/rulers/spaces_after_lbracket_ruler.rb +3 -3
  36. data/lib/tailor/rulers/spaces_after_lparen_ruler.rb +3 -3
  37. data/lib/tailor/rulers/spaces_before_comma_ruler.rb +3 -3
  38. data/lib/tailor/rulers/spaces_before_rbrace_ruler.rb +2 -2
  39. data/lib/tailor/rulers/spaces_in_empty_braces_ruler.rb +2 -2
  40. data/lib/tailor/tailorrc.erb +28 -0
  41. data/lib/tailor/version.rb +1 -1
  42. data/spec/functional/conditional_parentheses_spec.rb +325 -0
  43. data/spec/functional/conditional_spacing_spec.rb +66 -42
  44. data/spec/functional/configuration_spec.rb +1 -1
  45. data/spec/functional/horizontal_spacing/braces_spec.rb +10 -9
  46. data/spec/functional/horizontal_spacing/hard_tabs_spec.rb +4 -4
  47. data/spec/functional/horizontal_spacing_spec.rb +5 -5
  48. data/spec/functional/indentation_spacing/argument_alignment_spec.rb +511 -0
  49. data/spec/functional/indentation_spacing/line_continuations_spec.rb +181 -0
  50. data/spec/functional/indentation_spacing_spec.rb +17 -0
  51. data/spec/functional/string_interpolation_spec.rb +117 -0
  52. data/spec/functional/string_quoting_spec.rb +97 -0
  53. data/spec/functional/vertical_spacing/class_length_spec.rb +1 -1
  54. data/spec/spec_helper.rb +8 -2
  55. data/spec/support/argument_alignment_cases.rb +93 -0
  56. data/spec/support/bad_indentation_cases.rb +20 -20
  57. data/spec/support/conditional_parentheses_cases.rb +60 -0
  58. data/spec/support/good_indentation_cases.rb +31 -31
  59. data/spec/support/horizontal_spacing_cases.rb +1 -1
  60. data/spec/support/line_indentation_cases.rb +71 -0
  61. data/spec/support/string_interpolation_cases.rb +45 -0
  62. data/spec/support/string_quoting_cases.rb +25 -0
  63. data/spec/unit/tailor/configuration/file_set_spec.rb +3 -3
  64. data/spec/unit/tailor/configuration/style_spec.rb +24 -21
  65. data/spec/unit/tailor/configuration_spec.rb +4 -1
  66. data/spec/unit/tailor/formatter_spec.rb +10 -10
  67. data/spec/unit/tailor/reporter_spec.rb +0 -1
  68. data/spec/unit/tailor/rulers/indentation_spaces_ruler/indentation_manager_spec.rb +0 -11
  69. data/spec/unit/tailor/rulers/indentation_spaces_ruler_spec.rb +1 -1
  70. data/spec/unit/tailor/version_spec.rb +1 -1
  71. data/tailor.gemspec +1 -0
  72. metadata +72 -33
  73. data/.infinity_test +0 -4
@@ -0,0 +1,181 @@
1
+ require 'spec_helper'
2
+ require_relative '../../support/line_indentation_cases'
3
+ require 'tailor/critic'
4
+ require 'tailor/configuration/style'
5
+
6
+ describe 'Line continuation indentation' do
7
+ def file_name
8
+ self.class.description
9
+ end
10
+
11
+ def contents
12
+ LINE_INDENT[file_name] || begin
13
+ raise "Example not found: #{file_name}"
14
+ end
15
+ end
16
+
17
+ before do
18
+ Tailor::Logger.stub(:log)
19
+ FakeFS.activate!
20
+ FileUtils.touch file_name
21
+ File.open(file_name, 'w') { |f| f.write contents }
22
+ end
23
+
24
+ let(:critic) { Tailor::Critic.new }
25
+
26
+ let(:style) do
27
+ style = Tailor::Configuration::Style.new
28
+ style.trailing_newlines 0, level: :off
29
+ style.allow_invalid_ruby true, level: :off
30
+ style.allow_unnecessary_double_quotes true, level: :off
31
+
32
+ style
33
+ end
34
+
35
+ context :line_continues_further_indented do
36
+
37
+ it 'warns when line continuation spacing is not specified' do
38
+ critic.check_file(file_name, style.to_hash)
39
+ expect(critic.problems[file_name]).to eql [{
40
+ type: 'indentation_spaces',
41
+ line: 2,
42
+ column: 4,
43
+ message: "Line is indented to column 4, but should be at 2.",
44
+ level: :error
45
+ }]
46
+ end
47
+
48
+ it 'warns when line continuation spacing is disabled' do
49
+ style.indentation_spaces 2, level: :error, line_continuations: :off
50
+ critic.check_file(file_name, style.to_hash)
51
+ expect(critic.problems[file_name]).to eql [{
52
+ type: 'indentation_spaces',
53
+ line: 2,
54
+ column: 4,
55
+ message: "Line is indented to column 4, but should be at 2.",
56
+ level: :error
57
+ }]
58
+ end
59
+
60
+ it 'does not warn when line continuation spacing is enabled' do
61
+ style.indentation_spaces 2, level: :error, line_continuations: true
62
+ critic.check_file(file_name, style.to_hash)
63
+ expect(critic.problems[file_name]).to be_empty
64
+ end
65
+
66
+ end
67
+
68
+ context :line_continues_at_same_indentation do
69
+
70
+ it 'does not warn when line continuation spacing is not specified' do
71
+ critic.check_file(file_name, style.to_hash)
72
+ expect(critic.problems[file_name]).to be_empty
73
+ end
74
+
75
+ it 'does not warn when line continuation spacing is disabled' do
76
+ style.indentation_spaces 2, level: :error, line_continuations: :off
77
+ critic.check_file(file_name, style.to_hash)
78
+ expect(critic.problems[file_name]).to be_empty
79
+ end
80
+
81
+ it 'warns when line continuation spacing is enabled' do
82
+ style.indentation_spaces 2, level: :error, line_continuations: true
83
+ critic.check_file(file_name, style.to_hash)
84
+ expect(critic.problems[file_name]).to eql [{
85
+ type: 'indentation_spaces',
86
+ line: 2,
87
+ column: 2,
88
+ message: "Line is indented to column 2, but should be at 4.",
89
+ level: :error
90
+ }]
91
+ end
92
+
93
+ end
94
+
95
+ context :parameters_continuation_indent_across_lines do
96
+ it 'warns when line continuation spacing is not specified' do
97
+ critic.check_file(file_name, style.to_hash)
98
+ expect(critic.problems[file_name]).to eql [{
99
+ type: 'indentation_spaces',
100
+ line: 2,
101
+ column: 4,
102
+ message: "Line is indented to column 4, but should be at 2.",
103
+ level: :error
104
+ }]
105
+ end
106
+
107
+ it 'warns when line continuation spacing is disabled' do
108
+ style.indentation_spaces 2, level: :error, line_continuations: :off
109
+ critic.check_file(file_name, style.to_hash)
110
+ expect(critic.problems[file_name]).to eql [{
111
+ type: 'indentation_spaces',
112
+ line: 2,
113
+ column: 4,
114
+ message: "Line is indented to column 4, but should be at 2.",
115
+ level: :error
116
+ }]
117
+ end
118
+
119
+ it 'warns when line continuation spacing is enabled' do
120
+ style.indentation_spaces 2, level: :error, line_continuations: true
121
+ critic.check_file(file_name, style.to_hash)
122
+ expect(critic.problems[file_name]).to be_empty
123
+ end
124
+
125
+ end
126
+
127
+ context :parameters_no_continuation_indent_across_lines do
128
+ it 'warns when line continuation spacing is not specified' do
129
+ critic.check_file(file_name, style.to_hash)
130
+ expect(critic.problems[file_name]).to be_empty
131
+ end
132
+
133
+ it 'warns when line continuation spacing is disabled' do
134
+ style.indentation_spaces 2, level: :error, line_continuations: :off
135
+ critic.check_file(file_name, style.to_hash)
136
+ expect(critic.problems[file_name]).to be_empty
137
+ end
138
+
139
+ it 'warns when line continuation spacing is enabled' do
140
+ style.indentation_spaces 2, level: :error, line_continuations: true
141
+ critic.check_file(file_name, style.to_hash)
142
+ expect(critic.problems[file_name]).to eql [{
143
+ type: 'indentation_spaces',
144
+ line: 2,
145
+ column: 2,
146
+ message: "Line is indented to column 2, but should be at 4.",
147
+ level: :error
148
+ }]
149
+ end
150
+
151
+ end
152
+
153
+ [
154
+ :hash_spans_lines,
155
+ :if_else,
156
+ :line_continues_without_nested_statements,
157
+ :minitest_test_cases,
158
+ :nested_blocks,
159
+ :one_assignment_per_line
160
+ ].each do |never_warns_example|
161
+ context never_warns_example do
162
+
163
+ it 'does not warn when line continuation spacing is not specified' do
164
+ critic.check_file(file_name, style.to_hash)
165
+ expect(critic.problems[file_name]).to be_empty
166
+ end
167
+
168
+ it 'does not warn when line continuation spacing is disabled' do
169
+ style.indentation_spaces 2, level: :error, line_continuations: :off
170
+ critic.check_file(file_name, style.to_hash)
171
+ expect(critic.problems[file_name]).to be_empty
172
+ end
173
+
174
+ it 'does not warn when line continuation spacing is enabled' do
175
+ style.indentation_spaces 2, level: :error, line_continuations: true
176
+ critic.check_file(file_name, style.to_hash)
177
+ expect(critic.problems[file_name]).to be_empty
178
+ end
179
+ end
180
+ end
181
+ end
@@ -83,4 +83,21 @@ end}
83
83
  pending
84
84
  end
85
85
  end
86
+
87
+ context 'block chained on a block' do
88
+ let(:file_name) { 'block_chain' }
89
+
90
+ let(:contents) do
91
+ %Q{{
92
+ a: 1
93
+ }.each do |k, v|
94
+ puts k, v
95
+ end}
96
+ end
97
+
98
+ it 'is OK' do
99
+ critic.check_file(file_name, style.to_hash)
100
+ critic.problems.should == { file_name => [] }
101
+ end
102
+ end
86
103
  end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+ require_relative '../support/string_interpolation_cases'
3
+ require 'tailor/critic'
4
+ require 'tailor/configuration/style'
5
+
6
+ describe 'String interpolation cases' do
7
+ def file_name
8
+ self.class.description
9
+ end
10
+
11
+ def contents
12
+ INTERPOLATION[file_name] || begin
13
+ raise "Example not found: #{file_name}"
14
+ end
15
+ end
16
+
17
+ before do
18
+ Tailor::Logger.stub(:log)
19
+ FakeFS.activate!
20
+ FileUtils.touch file_name
21
+ File.open(file_name, 'w') { |f| f.write contents }
22
+ end
23
+
24
+ let(:critic) { Tailor::Critic.new }
25
+
26
+ let(:style) do
27
+ style = Tailor::Configuration::Style.new
28
+ style.trailing_newlines 0, level: :off
29
+ style.allow_invalid_ruby true, level: :off
30
+ style.allow_unnecessary_double_quotes true, level: :off
31
+
32
+ style
33
+ end
34
+
35
+ context :one_variable_interpolated_only do
36
+ it 'warns when interpolation is used unnecessarily' do
37
+ critic.check_file(file_name, style.to_hash)
38
+ expect(critic.problems[file_name]).to eql [{
39
+ type: 'unnecessary_string_interpolation',
40
+ line: 1,
41
+ column: 6,
42
+ message: 'Variable interpolated unnecessarily',
43
+ level: :warn
44
+ }]
45
+ end
46
+ end
47
+
48
+ context :mixed_content_and_expression do
49
+ it 'does not warn' do
50
+ critic.check_file(file_name, style.to_hash)
51
+ expect(critic.problems[file_name]).to be_empty
52
+ end
53
+ end
54
+
55
+ context :no_string do
56
+ it 'does not warn' do
57
+ critic.check_file(file_name, style.to_hash)
58
+ expect(critic.problems[file_name]).to be_empty
59
+ end
60
+ end
61
+
62
+ context :two_variables do
63
+ it 'does not warn' do
64
+ critic.check_file(file_name, style.to_hash)
65
+ expect(critic.problems[file_name]).to be_empty
66
+ end
67
+ end
68
+
69
+ context :two_strings_with_unnecessary_interpolation do
70
+ it 'warns against both strings' do
71
+ critic.check_file(file_name, style.to_hash)
72
+ expect(critic.problems[file_name]).to eql [
73
+ {
74
+ type: 'unnecessary_string_interpolation',
75
+ line: 1,
76
+ column: 6,
77
+ message: 'Variable interpolated unnecessarily',
78
+ level: :warn
79
+ },
80
+ {
81
+ type: 'unnecessary_string_interpolation',
82
+ line: 1,
83
+ column: 17,
84
+ message: 'Variable interpolated unnecessarily',
85
+ level: :warn
86
+ }
87
+ ]
88
+ end
89
+ end
90
+
91
+ context :multiline_string_with_unnecessary_interpolation do
92
+ it 'warns against the first line' do
93
+ critic.check_file(file_name, style.to_hash)
94
+ expect(critic.problems[file_name]).to eql [{
95
+ type: 'unnecessary_string_interpolation',
96
+ line: 1,
97
+ column: 6,
98
+ message: 'Variable interpolated unnecessarily',
99
+ level: :warn
100
+ }]
101
+ end
102
+ end
103
+
104
+ context :multiline_word_list do
105
+ it 'does not warn' do
106
+ critic.check_file(file_name, style.to_hash)
107
+ expect(critic.problems[file_name]).to be_empty
108
+ end
109
+ end
110
+
111
+ context :nested_interpolation do
112
+ it 'does not warn' do
113
+ critic.check_file(file_name, style.to_hash)
114
+ expect(critic.problems[file_name]).to be_empty
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+ require_relative '../support/string_quoting_cases'
3
+ require 'tailor/critic'
4
+ require 'tailor/configuration/style'
5
+
6
+ describe 'String Quoting' do
7
+
8
+ def file_name
9
+ self.class.description
10
+ end
11
+
12
+ def contents
13
+ QUOTING[file_name] || begin
14
+ raise "Example not found: #{file_name}"
15
+ end
16
+ end
17
+
18
+ before do
19
+ Tailor::Logger.stub(:log)
20
+ FakeFS.activate!
21
+ FileUtils.touch file_name
22
+ File.open(file_name, 'w') { |f| f.write contents }
23
+ end
24
+
25
+ let(:critic) { Tailor::Critic.new }
26
+
27
+ let(:style) do
28
+ style = Tailor::Configuration::Style.new
29
+ style.trailing_newlines 0, level: :off
30
+ style.allow_invalid_ruby true, level: :off
31
+ style
32
+ end
33
+
34
+ context :single_quotes_no_interpolation do
35
+ it 'does not warn' do
36
+ critic.check_file(file_name, style.to_hash)
37
+ expect(critic.problems[file_name]).to be_empty
38
+ end
39
+ end
40
+
41
+ context :double_quotes_with_interpolation do
42
+ it 'does not warn' do
43
+ critic.check_file(file_name, style.to_hash)
44
+ expect(critic.problems[file_name]).to be_empty
45
+ end
46
+ end
47
+
48
+ context :double_quotes_no_interpolation do
49
+ it 'warns that double quotes are unnecessary' do
50
+ critic.check_file(file_name, style.to_hash)
51
+ expect(critic.problems[file_name]).to eql [{
52
+ type: 'unnecessary_double_quotes',
53
+ line: 1,
54
+ column: 6,
55
+ message: 'Unnecessary double quotes at column 6, expected single quotes.',
56
+ level: :warn
57
+ }]
58
+ end
59
+ end
60
+
61
+ context :double_quotes_no_interpolation_twice do
62
+ it 'warns that double quotes are unnecessary' do
63
+ critic.check_file(file_name, style.to_hash)
64
+ expect(critic.problems[file_name]).to eql [
65
+ {
66
+ type: 'unnecessary_double_quotes',
67
+ line: 1,
68
+ column: 6,
69
+ message: 'Unnecessary double quotes at column 6, expected single quotes.',
70
+ level: :warn
71
+ },
72
+ {
73
+ type: 'unnecessary_double_quotes',
74
+ line: 1,
75
+ column: 14,
76
+ message: 'Unnecessary double quotes at column 14, expected single quotes.',
77
+ level: :warn
78
+ }
79
+ ]
80
+ end
81
+ end
82
+
83
+ context :nested_quotes do
84
+ it 'does not warn' do
85
+ critic.check_file(file_name, style.to_hash)
86
+ expect(critic.problems[file_name]).to be_empty
87
+ end
88
+ end
89
+
90
+ context :escape_sequence do
91
+ it 'does not warn when a double quoted string contains a newline' do
92
+ critic.check_file(file_name, style.to_hash)
93
+ expect(critic.problems[file_name]).to be_empty
94
+ end
95
+ end
96
+
97
+ end
@@ -10,7 +10,7 @@ CLASS_LENGTH['class_too_long'] =
10
10
  include Pizza
11
11
 
12
12
  def barrel_roll
13
- puts "DOABARRELROLL!"
13
+ puts 'DOABARRELROLL!'
14
14
  end
15
15
  end}
16
16
 
@@ -3,6 +3,12 @@ require 'simplecov'
3
3
 
4
4
  SimpleCov.start
5
5
 
6
- RSpec.configure do |conf|
7
- conf.include FakeFS::SpecHelpers
6
+ RSpec.configure do |config|
7
+ config.include FakeFS::SpecHelpers
8
+
9
+ # Run specs in random order to surface order dependencies. If you find an
10
+ # order dependency and want to debug it, you can fix the order by providing
11
+ # the seed, which is printed after each run.
12
+ # --seed 1234
13
+ config.order = 'random'
8
14
  end
@@ -0,0 +1,93 @@
1
+ ARG_INDENT = {}
2
+
3
+ ARG_INDENT['def_no_arguments'] =
4
+ %q{def foo
5
+ true
6
+ end}
7
+
8
+ ARG_INDENT['def_arguments_fit_on_one_line'] =
9
+ %q{def foo(foo, bar, baz)
10
+ true
11
+ end}
12
+
13
+ ARG_INDENT['def_arguments_aligned'] =
14
+ %q{def something(waka, baka, bing,
15
+ bla, goop, foop)
16
+ stuff
17
+ end
18
+ }
19
+
20
+ ARG_INDENT['def_arguments_indented'] =
21
+ %q{def something(waka, baka, bing,
22
+ bla, goop, foop)
23
+ stuff
24
+ end
25
+ }
26
+
27
+ ARG_INDENT['call_no_arguments'] =
28
+ %q{bla = method()}
29
+
30
+ ARG_INDENT['call_arguments_fit_on_one_line'] =
31
+ %q{bla = method(foo, bar, baz, bing, ding)}
32
+
33
+ ARG_INDENT['call_arguments_aligned'] =
34
+ %q{bla = Something::SomethingElse::SomeClass.method(foo, bar, baz,
35
+ bing, ding)
36
+ }
37
+
38
+ ARG_INDENT['call_arguments_aligned_args_are_integer_literals'] =
39
+ %q{bla = Something::SomethingElse::SomeClass.method(1, 2, 3,
40
+ 4, 5)
41
+ }
42
+
43
+ ARG_INDENT['call_arguments_aligned_args_are_string_literals'] =
44
+ %q{bla = Something::SomethingElse::SomeClass.method('foo', 'bar', 'baz',
45
+ 'bing', 'ding')
46
+ }
47
+
48
+ ARG_INDENT['call_arguments_aligned_args_have_parens'] =
49
+ %q{bla = Something::SomethingElse::SomeClass.method(foo, bar(), baz,
50
+ bing, ding)
51
+ }
52
+
53
+ ARG_INDENT['call_arguments_aligned_no_parens'] =
54
+ %q{bla = Something::SomethingElse::SomeClass.method foo, bar, baz,
55
+ bing, ding
56
+ }
57
+
58
+ ARG_INDENT['call_arguments_aligned_multiple_lines'] =
59
+ %q{bla = Something::SomethingElse::SomeClass.method(foo, bar, baz,
60
+ bing, ding,
61
+ ginb, gind)
62
+ }
63
+
64
+ ARG_INDENT['call_arguments_indented'] =
65
+ %q{bla = Something::SomethingElse::SomeClass.method(foo, bar, baz,
66
+ bing, ding)
67
+ }
68
+
69
+ ARG_INDENT['call_arguments_indented_separate_line'] =
70
+ %q{bla = Something::SomethingElse::SomeClass.method(
71
+ foo, bar, baz,
72
+ bing, ding
73
+ )}
74
+
75
+ ARG_INDENT['call_arguments_on_next_line'] =
76
+ %q{some_long_method_that_goes_out_to_the_end_of_the_line(
77
+ foo, bar)
78
+ }
79
+
80
+ ARG_INDENT['call_arguments_on_next_line_nested'] =
81
+ %q{if some_long_method_that_goes_out_to_the_end_of_the_line(
82
+ foo, bar)
83
+ my_nested_expression
84
+ end}
85
+
86
+ ARG_INDENT['call_arguments_on_next_line_multiple'] =
87
+ %q{some_long_method_that_goes_out_to_the_end_of_the_line(
88
+ foo, bar)
89
+
90
+ if diff_long_method_that_goes_out_to_the_end_of_the_line(
91
+ foo, bar)
92
+ my_nested_expression
93
+ end}