tailor 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
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}