tailor 0.1.5 → 1.0.0.alpha

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 (124) hide show
  1. data/.gitignore +9 -1
  2. data/.rspec +2 -1
  3. data/.tailor +6 -0
  4. data/Gemfile.lock +47 -78
  5. data/{ChangeLog.rdoc → History.rdoc} +0 -0
  6. data/README.rdoc +157 -24
  7. data/Rakefile +0 -9
  8. data/bin/tailor +16 -69
  9. data/features/configurable.feature +78 -0
  10. data/features/horizontal_spacing.feature +262 -0
  11. data/features/indentation.feature +17 -21
  12. data/features/indentation/bad_files_with_no_trailing_newline.feature +90 -0
  13. data/features/indentation/good_files_with_no_trailing_newline.feature +206 -0
  14. data/features/name_detection.feature +72 -0
  15. data/features/step_definitions/indentation_steps.rb +10 -133
  16. data/features/support/env.rb +7 -15
  17. data/features/support/file_cases/horizontal_spacing_cases.rb +265 -0
  18. data/features/support/file_cases/indentation_cases.rb +972 -0
  19. data/features/support/file_cases/naming_cases.rb +52 -0
  20. data/features/support/file_cases/vertical_spacing_cases.rb +70 -0
  21. data/features/support/hooks.rb +8 -0
  22. data/features/support/{1_file_with_bad_operator_spacing → legacy}/bad_op_spacing.rb +0 -0
  23. data/features/support/{1_file_with_bad_ternary_colon_spacing → legacy}/bad_ternary_colon_spacing.rb +0 -0
  24. data/features/support/{1_long_file_with_indentation/my_project.rb → legacy/long_file_with_indentation.rb} +1 -1
  25. data/features/support/world.rb +14 -0
  26. data/features/vertical_spacing.feature +114 -0
  27. data/lib/ext/string_ext.rb +5 -0
  28. data/lib/tailor.rb +6 -252
  29. data/lib/tailor/cli.rb +49 -0
  30. data/lib/tailor/cli/options.rb +251 -0
  31. data/lib/tailor/composite_observable.rb +56 -0
  32. data/lib/tailor/configuration.rb +263 -0
  33. data/lib/tailor/critic.rb +162 -0
  34. data/lib/tailor/formatters/text.rb +126 -0
  35. data/lib/tailor/lexed_line.rb +246 -0
  36. data/lib/tailor/lexer.rb +428 -0
  37. data/lib/tailor/lexer/token.rb +103 -0
  38. data/lib/tailor/lexer_constants.rb +75 -0
  39. data/lib/tailor/logger.rb +28 -0
  40. data/lib/tailor/problem.rb +100 -0
  41. data/lib/tailor/reporter.rb +48 -0
  42. data/lib/tailor/ruler.rb +39 -0
  43. data/lib/tailor/rulers.rb +7 -0
  44. data/lib/tailor/rulers/allow_camel_case_methods_ruler.rb +30 -0
  45. data/lib/tailor/rulers/allow_hard_tabs_ruler.rb +22 -0
  46. data/lib/tailor/rulers/allow_screaming_snake_case_classes_ruler.rb +32 -0
  47. data/lib/tailor/rulers/allow_trailing_line_spaces_ruler.rb +33 -0
  48. data/lib/tailor/rulers/indentation_spaces_ruler.rb +199 -0
  49. data/lib/tailor/rulers/indentation_spaces_ruler/indentation_manager.rb +362 -0
  50. data/lib/tailor/rulers/max_code_lines_in_class_ruler.rb +84 -0
  51. data/lib/tailor/rulers/max_code_lines_in_method_ruler.rb +84 -0
  52. data/lib/tailor/rulers/max_line_length_ruler.rb +31 -0
  53. data/lib/tailor/rulers/spaces_after_comma_ruler.rb +83 -0
  54. data/lib/tailor/rulers/spaces_after_lbrace_ruler.rb +114 -0
  55. data/lib/tailor/rulers/spaces_after_lbracket_ruler.rb +123 -0
  56. data/lib/tailor/rulers/spaces_after_lparen_ruler.rb +116 -0
  57. data/lib/tailor/rulers/spaces_before_comma_ruler.rb +67 -0
  58. data/lib/tailor/rulers/spaces_before_lbrace_ruler.rb +93 -0
  59. data/lib/tailor/rulers/spaces_before_rbrace_ruler.rb +98 -0
  60. data/lib/tailor/rulers/spaces_before_rbracket_ruler.rb +70 -0
  61. data/lib/tailor/rulers/spaces_before_rparen_ruler.rb +70 -0
  62. data/lib/tailor/rulers/spaces_in_empty_braces_ruler.rb +94 -0
  63. data/lib/tailor/rulers/trailing_newlines_ruler.rb +36 -0
  64. data/lib/tailor/runtime_error.rb +3 -0
  65. data/lib/tailor/tailorrc.erb +88 -0
  66. data/lib/tailor/version.rb +2 -2
  67. data/spec/spec_helper.rb +7 -5
  68. data/spec/tailor/cli_spec.rb +94 -0
  69. data/spec/tailor/configuration_spec.rb +147 -0
  70. data/spec/tailor/critic_spec.rb +63 -0
  71. data/spec/tailor/lexed_line_spec.rb +569 -0
  72. data/spec/tailor/lexer/token_spec.rb +46 -0
  73. data/spec/tailor/lexer_spec.rb +181 -0
  74. data/spec/tailor/options_spec.rb +6 -0
  75. data/spec/tailor/problem_spec.rb +74 -0
  76. data/spec/tailor/reporter_spec.rb +53 -0
  77. data/spec/tailor/ruler_spec.rb +56 -0
  78. data/spec/tailor/rulers/indentation_spaces_ruler/indentation_manager_spec.rb +454 -0
  79. data/spec/tailor/rulers/indentation_spaces_ruler_spec.rb +128 -0
  80. data/spec/tailor/rulers/spaces_after_comma_spec.rb +31 -0
  81. data/spec/tailor/rulers/spaces_after_lbrace_ruler_spec.rb +145 -0
  82. data/spec/tailor/rulers/spaces_before_lbrace_ruler_spec.rb +63 -0
  83. data/spec/tailor/rulers/spaces_before_rbrace_ruler_spec.rb +63 -0
  84. data/spec/tailor/rulers_spec.rb +9 -0
  85. data/spec/tailor/version_spec.rb +6 -0
  86. data/spec/tailor_spec.rb +9 -21
  87. data/tailor.gemspec +22 -35
  88. data/tasks/features.rake +7 -0
  89. data/tasks/roodi.rake +9 -0
  90. data/tasks/roodi_config.yaml +14 -0
  91. data/tasks/spec.rake +16 -0
  92. data/tasks/yard.rake +14 -0
  93. metadata +224 -77
  94. data/features/case_checking.feature +0 -38
  95. data/features/spacing.feature +0 -97
  96. data/features/spacing/commas.feature +0 -44
  97. data/features/step_definitions/case_checking_steps.rb +0 -42
  98. data/features/step_definitions/spacing_steps.rb +0 -156
  99. data/features/support/1_file_with_bad_comma_spacing/bad_comma_spacing.rb +0 -43
  100. data/features/support/1_file_with_bad_curly_brace_spacing/bad_curly_brace_spacing.rb +0 -60
  101. data/features/support/1_file_with_bad_parenthesis/bad_parenthesis.rb +0 -4
  102. data/features/support/1_file_with_bad_square_brackets/bad_square_brackets.rb +0 -62
  103. data/features/support/1_file_with_camel_case_class/camel_case_class.rb +0 -5
  104. data/features/support/1_file_with_camel_case_method/camel_case_method.rb +0 -3
  105. data/features/support/1_file_with_hard_tabs/hard_tab.rb +0 -3
  106. data/features/support/1_file_with_long_lines/long_lines.rb +0 -5
  107. data/features/support/1_file_with_snake_case_class/snake_case_class.rb +0 -5
  108. data/features/support/1_file_with_snake_case_method/snake_case_method.rb +0 -3
  109. data/features/support/1_file_with_trailing_whitespace/trailing_whitespace.rb +0 -5
  110. data/features/support/1_good_simple_file/simple_project.rb +0 -5
  111. data/features/support/common.rb +0 -102
  112. data/features/support/matchers.rb +0 -11
  113. data/lib/tailor/file_line.rb +0 -220
  114. data/lib/tailor/indentation.rb +0 -245
  115. data/lib/tailor/spacing.rb +0 -237
  116. data/spec/file_line_spec.rb +0 -70
  117. data/spec/indentation_spec.rb +0 -259
  118. data/spec/spacing/colon_spacing_spec.rb +0 -71
  119. data/spec/spacing/comma_spacing_spec.rb +0 -159
  120. data/spec/spacing/curly_brace_spacing_spec.rb +0 -257
  121. data/spec/spacing/parentheses_spacing_spec.rb +0 -28
  122. data/spec/spacing/square_bracket_spacing_spec.rb +0 -116
  123. data/spec/spacing_spec.rb +0 -167
  124. data/tasks/metrics.rake +0 -23
@@ -1,245 +0,0 @@
1
- require 'tailor/spacing'
2
-
3
- module Tailor
4
-
5
- # Provides methods for checking indentation problems in a FileLine.
6
- module Indentation
7
- include Tailor::Spacing
8
-
9
- INDENT_SIZE = 2
10
- HARD_TAB_SIZE = 4
11
-
12
- INDENT_EXPRESSIONS = [
13
- /^class\b/,
14
- /^module\b/,
15
- /^def\b/,
16
- /(=\s*|^)if\b/,
17
- /(=\s*|^)until\b/,
18
- /(=\s*|^)for\b/,
19
- /(=\s*|^)unless\b/,
20
- /(=\s*|^)while\b/,
21
- /(=\s*|^)begin\b/,
22
- /(=\s*|^)case\b/,
23
- /\bthen\b/,
24
- # /^rescue\b/,
25
- /\bdo\b/,
26
- # /^else\b/,
27
- # /^elsif\b/,
28
- # /^ensure\b/,
29
- # /\bwhen\b/,
30
- /\{[^\}]*$/,
31
- /\[[^\]]*$/
32
- ]
33
-
34
- OUTDENT_EXPRESSIONS = [
35
- /^rescue\b/,
36
- /^ensure\b/,
37
- /^elsif\b/,
38
- # /^end\b/,
39
- /^else\b/,
40
- /\bwhen\b/,
41
- # /^[^\{]*\}/, # matches and end } when no { appears
42
- # /^[^\[]*\]/
43
- ]
44
-
45
- END_EXPRESSIONS = [
46
- /^end\b/,
47
- /^[^\{]*\}/, # matches and end } when no { appears
48
- /^[^\[]*\]/ # matches and end ] when no [ appears
49
- ]
50
-
51
- # Determines the number of spaces the line is indented.
52
- #
53
- # @return [Number] Returns the number of spaces the line is indented.
54
- def indented_spaces
55
- # Find out how many spaces exist at the beginning of the line
56
- spaces = self.scan(/^\x20+/).first
57
-
58
- unless spaces.nil?
59
- return spaces.length
60
- end
61
-
62
- 0
63
- end
64
-
65
- # Determines the level to which the line is indented. For Ruby, this
66
- # should be 2 spaces. Note that this treats lines that are indented an
67
- # odd number of spaces as a multiple of 0.5 levels of indentation.
68
- #
69
- # @return [Float] The level.
70
- def is_at_level
71
- spaces = indented_spaces
72
-
73
- if spaces.eql? 0
74
- return 0.0
75
- end
76
-
77
- spaces.to_f / 2.0
78
- end
79
-
80
- # Checks to see if the line contains a statement that should be indented.
81
- #
82
- # @return [Boolean] True if the line contains one of the statements and
83
- # does not contain 'end'.
84
- def indent?
85
- return false if self.comment_line?
86
-
87
- INDENT_EXPRESSIONS.each do |regexp|
88
- result = self.strip.scan(regexp)
89
-
90
- if(self.strip =~ regexp && !(self =~ /\s+end\s*$/))
91
- return true
92
- end
93
- end
94
-
95
- false
96
- end
97
-
98
- # Checks to see if the line contains a statement that should be outdented.
99
- #
100
- # @return [Boolean] True if the line contains one of the statements.
101
- def outdent?
102
- return false if self.comment_line?
103
-
104
- OUTDENT_EXPRESSIONS.each do |regexp|
105
- result = self.strip.scan(regexp)
106
-
107
- # If it does contain an expression, set the proper level to be out 1.0.
108
- unless result.empty?
109
- return true
110
- end
111
- end
112
-
113
- false
114
- end
115
-
116
- # Checks to see if the line contains a statement that ends a code chunk:
117
- # end, ], or }.
118
- #
119
- # @return [Boolean] True if the line contains one of the statements.
120
- def contains_end?
121
- return false if self.comment_line?
122
-
123
- END_EXPRESSIONS.each do |regexp|
124
- result = self.strip.scan(regexp)
125
-
126
- # If it does contain an expression, set the proper level to be out 1.0.
127
- unless result.empty?
128
- #@logger.debug "Found match: #{regexp}"
129
- return true
130
- end
131
- end
132
-
133
- false
134
- end
135
-
136
- # Simply compares the level the line is at to the parameter that's passed
137
- # in. The proper level is maintained outside of this module.
138
- #
139
- # @return [Boolean] True if level of the line doesn't match the level
140
- # passed in. Also returns true if the line is an empty line, since that
141
- # line doesn't need to be checked.
142
- def at_improper_level? proper_level
143
- current_level = self.is_at_level
144
-
145
- if current_level == proper_level or self.empty_line?
146
- return false
147
- end
148
-
149
- message = "Line is at level #{current_level}, "
150
- message += "but should be at level #{proper_level}:"
151
- @line_problem_count += 1
152
- print_problem message
153
-
154
- true
155
- end
156
-
157
- def ends_with_operator?
158
- if self.comment_line?
159
- return false
160
- end
161
-
162
- result = false
163
-
164
- OPERATORS.each_pair do |op_family, op_values|
165
- op_values.each do |op|
166
- match = self.scan(/.*#{Regexp.escape(op)}\s*$/)
167
-
168
- next if op == '?' and self.question_mark_method?
169
-
170
- unless match.empty?
171
- logger = Logger.new(STDOUT)
172
- logger.debug "Matched on op: #{op}"
173
- result = true
174
- end
175
- end
176
- end
177
-
178
- result
179
- end
180
-
181
- def ends_with_comma?
182
- if self.comment_line?
183
- return false
184
- end
185
-
186
- unless self.scan(/.*,\s*$/).empty?
187
- puts "Ends with comma."
188
- return true
189
- end
190
-
191
- false
192
- end
193
-
194
- def ends_with_backslash?
195
- if self.comment_line?
196
- return false
197
- end
198
-
199
- unless self.scan(/.*\\\s*$/).empty?
200
- puts "Ends with backslash."
201
- return true
202
- end
203
-
204
- false
205
- end
206
-
207
- def unclosed_parenthesis?
208
- if self.comment_line?
209
- return false
210
- end
211
-
212
- unless self.scan(/\([^\)]*(?!=\))\s*$/).empty?
213
- puts "Ends with unclosed parenthesis."
214
- return true
215
- end
216
-
217
- false
218
- end
219
-
220
- def only_closed_parenthesis?
221
- if self.comment_line?
222
- return false
223
- end
224
-
225
- unless self.scan(/^\s*[^\(](\w*|\s*)\)/).empty?
226
- return true
227
- end
228
-
229
- false
230
- end
231
-
232
- def multi_line_statement?
233
- if self.comment_line?
234
- return false
235
- end
236
-
237
- if self.ends_with_operator? or self.ends_with_comma? or
238
- self.ends_with_backslash? or self.unclosed_parenthesis?
239
- return true
240
- end
241
-
242
- false
243
- end
244
- end
245
- end
@@ -1,237 +0,0 @@
1
- require 'tailor'
2
- require 'tailor/file_line'
3
-
4
- module Tailor
5
-
6
- # This module provides methods for detecting spacing problems on a single
7
- # line in a file. The real intent here is to mix in to the FileLine class.
8
- module Spacing
9
- # TODO: Add skipping of comment lines.
10
- SPACING_CONDITIONS = {
11
- :more_than_one_space_after_comma => [
12
- /,\x20{2,}(\w|'|"|:).*((?:(?!#\s*)).)*$/,
13
- "[Spacing] Line has a comma with > 1 space after it"
14
- ],
15
- :no_space_after_comma => [
16
- /,\x20{0}\S/,
17
- "[Spacing] Line has a comma with 0 spaces after it"
18
- ],
19
- :space_before_comma => [
20
- /\S\x20+,/,
21
- "[Spacing] Line has at least one space before a comma"
22
- ],
23
- :space_after_open_parenthesis => [
24
- /\(\x20+/,
25
- "[Spacing] Line has a '(' with spaces after it"
26
- ],
27
- :space_before_closed_parenthesis => [
28
- /^\s*[^#]\w+.*\x20+\)/,
29
- "[Spacing] Line has a ')' with spaces before it"
30
- ],
31
- :space_around_open_bracket => [
32
- /^\s*[^#](\w+\x20+\[|.*\[\x20+)/,
33
- "[Spacing] Line has a '[' with at least 1 space around it"
34
- ],
35
- :space_before_closed_bracket => [
36
- /^\s*[^#]\w+.*\x20+\]/,
37
- "[Spacing] Line has a ']' with spaces before it"
38
- ],
39
- :hard_tabbed => [
40
- /\t+/,
41
- "[Spacing] Line contains hard tabs"
42
- ],
43
- :trailing_whitespace => [
44
- /(\x20+|\x09+)$/,
45
- #"[Spacing] Line contains #{trailing_whitespace_count} " +
46
- "[Spacing] Line contains trailing whitespaces"
47
- ],
48
- :no_space_around_open_curly_brace => [
49
- /^\s*((?:(?!def).)*)(=|\w)\x20{0}\{|\{\x20{0}(\||:|"|')/,
50
- "[Spacing] Line contains 0 spaces on at least one side of a '{'"
51
- ],
52
- :no_space_before_closed_curly_brace => [
53
- /^\s*((?:(?!#\{).)*)(?:(?!\{)\S)\x20{0}\}/,
54
- "[Spacing] Line contains 0 spaces before a '}'"
55
- ],
56
- :more_than_one_space_around_open_curly_brace => [
57
- /\w\x20{2,}\{|\{\x20{2,}\|/,
58
- "[Spacing] Line contains >1 spaces around a '{'"
59
- ],
60
- :more_than_one_space_before_closed_curly_brace => [
61
- /\w\x20{2,}\}\s*$/,
62
- "[Spacing] Line contains >1 spaces before a '}'"
63
- ],
64
- :not_one_space_around_ternary_colon => [
65
- /^.*\?.*\w((\x20{0}|\x20{2,}):(?!:)|[^:|\[]:(\x20{0}|\x20{2,})\w)/,
66
- "[Spacing] Line contains ternary ':' with not 1 space around it"
67
- ]
68
- }
69
-
70
- # Detect spacing problems around all predefined bad cases.
71
- #
72
- # @return [Number] The number of problems discovered during detection.
73
- def spacing_problems
74
- problem_count = 0
75
-
76
- # Disregard text in regexps
77
- self.gsub!(/\/.*?\//, "''")
78
- self.gsub!(/'.*?'/, "''")
79
-
80
- SPACING_CONDITIONS.each_pair do |condition, values|
81
- unless self.scan(values.first).empty?
82
- problem_count += 1
83
- @line_problem_count += 1
84
- print_problem values[1]
85
- end
86
- end
87
-
88
- problem_count
89
- end
90
-
91
- # Checks to see if there's whitespace at the end of the line. Prints the
92
- # number of whitespaces at the end of the line.
93
- #
94
- # @return [Boolean] Returns true if there's whitespace at the end of the
95
- # line.
96
- =begin
97
- def trailing_whitespace?
98
- count = self.trailing_whitespace_count
99
-
100
- if count > 0
101
- @line_problem_count += 1
102
- print_problem "Line contains #{count} trailing whitespace(s):"
103
- return true
104
- end
105
-
106
- return false
107
- end
108
- =end
109
- # Checks to see if the line has trailing whitespace at the end of it. Note
110
- # that this excludes empty lines that have spaces on them!
111
- #
112
- # @return [Number] Returns the number of trailing spaces at the end of the
113
- # line.
114
- def trailing_whitespace_count
115
- spaces = self.scan(/(\x20+|\x09+)$/)
116
-
117
- if spaces.first.eql? nil
118
- return 0
119
- end
120
-
121
- spaces.first.first.length
122
- end
123
- module_function :trailing_whitespace_count
124
-
125
- # Checks to see if there's no spaces before a given string. If the line
126
- # being checked is a method with a question mark at the end of it, this
127
- # skips checking the line.
128
- #
129
- # @param [String] string The string to check for spaces before.
130
- # @return [Boolean] True if there are no spaces before the string.
131
- def no_space_before? string
132
- # Get out if the check is for a '?' and that's part of a method name.
133
- if self.question_mark_method?
134
- return false
135
- end
136
-
137
- # Get out if this line is a comment line
138
- if self.comment_line?
139
- return false
140
- end
141
-
142
- # Get out if the string is within another string
143
- if word_is_in_string? string
144
- return false
145
- end
146
-
147
- counts = []
148
- spaces_before(string).each { |s| counts << s }
149
-
150
- result = false
151
- counts.each do |count|
152
- if count == 0
153
- @line_problem_count += 1
154
- print_problem "Line has a '#{string}' with 0 spaces before it:"
155
- result = true
156
- end
157
- end
158
-
159
- result
160
- end
161
-
162
- # Checks to see if there's no spaces after a given string.
163
- #
164
- # @param [String] string The string to check for spaces after.
165
- # @return [Boolean] True if there are no spaces after the string.
166
- def no_space_after? string
167
- # Get out if the check is for a '?' and that's part of a method name.
168
- if self.question_mark_method?
169
- return false
170
- end
171
-
172
- # Get out if this line is a comment line
173
- if self.comment_line?
174
- return false
175
- end
176
-
177
- # Get out if the string is within another string
178
- if word_is_in_string? string
179
- return false
180
- end
181
-
182
- # Get out if the string is within another string
183
- if word_is_in_regexp? string
184
- return false
185
- end
186
-
187
- counts = []
188
- spaces_after(string).each { |s| counts << s }
189
-
190
- result = false
191
- counts.each do |count|
192
- if count == 0
193
- @line_problem_count += 1
194
- print_problem "Line has a '#{string}' with 0 spaces after it:"
195
- result = true
196
- end
197
- end
198
-
199
- result
200
- end
201
-
202
- # Gets the number of spaces after a string.
203
- #
204
- # @param [String] string The string to check for spaces after.
205
- # @return [Array<Number>] An array that holds the number of spaces after
206
- # every time the given string appears in a line.
207
- def spaces_after string
208
- # Get out if this line is a comment line
209
- if self.comment_line?
210
- return false
211
- end
212
-
213
- right_side_match = Regexp.new(Regexp.escape(string) + '\x20*')
214
-
215
- occurrences = self.scan(right_side_match)
216
-
217
- results = []
218
- occurrences.each do |o|
219
- string_spaces = o.sub(string, '')
220
- results << string_spaces.size
221
- end
222
-
223
- results
224
- end
225
-
226
- # Checks to see if the line contains a method name with a ?.
227
- #
228
- # @return [Boolean] True if the line contains a method line include?.
229
- def question_mark_method?
230
- if self.scan(/[a-zA-Z|_]\w*\?/).empty?
231
- return false
232
- end
233
-
234
- true
235
- end
236
- end
237
- end