tailor 1.0.1 → 1.1.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 (69) hide show
  1. data/.tailor +1 -0
  2. data/Gemfile.lock +1 -1
  3. data/History.rdoc +34 -0
  4. data/README.rdoc +17 -1
  5. data/features/valid_ruby.feature +1 -1
  6. data/lib/ext/string_ext.rb +0 -4
  7. data/lib/tailor/cli/options.rb +9 -2
  8. data/lib/tailor/configuration.rb +103 -150
  9. data/lib/tailor/configuration/file_set.rb +110 -0
  10. data/lib/tailor/formatters/text.rb +108 -79
  11. data/lib/tailor/rake_task.rb +148 -0
  12. data/lib/tailor/tailorrc.erb +1 -1
  13. data/lib/tailor/version.rb +1 -1
  14. data/spec/functional/configuration_spec.rb +244 -0
  15. data/spec/functional/horizontal_spacing/braces_spec.rb +238 -0
  16. data/spec/functional/horizontal_spacing/brackets_spec.rb +88 -0
  17. data/spec/functional/horizontal_spacing/comma_spacing_spec.rb +68 -0
  18. data/spec/functional/horizontal_spacing/hard_tabs_spec.rb +110 -0
  19. data/spec/functional/horizontal_spacing/long_lines_spec.rb +51 -0
  20. data/spec/functional/horizontal_spacing/parens_spec.rb +102 -0
  21. data/spec/functional/horizontal_spacing/trailing_whitespace_spec.rb +66 -0
  22. data/spec/functional/horizontal_spacing_spec.rb +59 -0
  23. data/spec/functional/indentation_spacing/bad_indentation_spec.rb +372 -0
  24. data/spec/functional/indentation_spacing_spec.rb +85 -0
  25. data/spec/functional/naming/camel_case_methods_spec.rb +56 -0
  26. data/spec/functional/naming/screaming_snake_case_classes_spec.rb +83 -0
  27. data/spec/functional/naming_spec.rb +35 -0
  28. data/spec/functional/vertical_spacing/class_length_spec.rb +67 -0
  29. data/spec/functional/vertical_spacing/method_length_spec.rb +61 -0
  30. data/spec/functional/vertical_spacing_spec.rb +35 -0
  31. data/spec/support/bad_indentation_cases.rb +265 -0
  32. data/{features/support/file_cases/indentation_cases.rb → spec/support/good_indentation_cases.rb} +6 -266
  33. data/spec/support/horizontal_spacing_cases.rb +136 -0
  34. data/spec/support/naming_cases.rb +26 -0
  35. data/{features/support/file_cases → spec/support}/vertical_spacing_cases.rb +0 -33
  36. data/spec/{tailor → unit/tailor}/cli_spec.rb +1 -1
  37. data/spec/{tailor → unit/tailor}/composite_observable_spec.rb +1 -1
  38. data/spec/unit/tailor/configuration/file_set_spec.rb +65 -0
  39. data/spec/{tailor → unit/tailor}/configuration/style_spec.rb +1 -1
  40. data/spec/{tailor → unit/tailor}/configuration_spec.rb +1 -59
  41. data/spec/{tailor → unit/tailor}/critic_spec.rb +1 -1
  42. data/spec/{tailor → unit/tailor}/formatter_spec.rb +1 -1
  43. data/spec/{tailor → unit/tailor}/lexed_line_spec.rb +1 -1
  44. data/spec/{tailor → unit/tailor}/lexer/token_spec.rb +1 -1
  45. data/spec/{tailor → unit/tailor}/lexer_spec.rb +1 -2
  46. data/spec/{tailor → unit/tailor}/options_spec.rb +1 -1
  47. data/spec/{tailor → unit/tailor}/problem_spec.rb +1 -1
  48. data/spec/{tailor → unit/tailor}/reporter_spec.rb +1 -1
  49. data/spec/{tailor → unit/tailor}/ruler_spec.rb +1 -1
  50. data/spec/{tailor → unit/tailor}/rulers/indentation_spaces_ruler/indentation_manager_spec.rb +1 -1
  51. data/spec/{tailor → unit/tailor}/rulers/indentation_spaces_ruler_spec.rb +1 -1
  52. data/spec/{tailor → unit/tailor}/rulers/spaces_after_comma_ruler_spec.rb +1 -1
  53. data/spec/{tailor → unit/tailor}/rulers/spaces_after_lbrace_ruler_spec.rb +1 -1
  54. data/spec/{tailor → unit/tailor}/rulers/spaces_before_lbrace_ruler_spec.rb +1 -1
  55. data/spec/{tailor → unit/tailor}/rulers/spaces_before_rbrace_ruler_spec.rb +1 -1
  56. data/spec/{tailor → unit/tailor}/rulers_spec.rb +1 -1
  57. data/spec/unit/tailor/version_spec.rb +6 -0
  58. data/spec/{tailor_spec.rb → unit/tailor_spec.rb} +1 -1
  59. data/tasks/spec.rake +8 -3
  60. metadata +121 -93
  61. data/features/horizontal_spacing.feature +0 -263
  62. data/features/indentation/bad_files_with_no_trailing_newline.feature +0 -91
  63. data/features/indentation/good_files_with_no_trailing_newline.feature +0 -219
  64. data/features/name_detection.feature +0 -72
  65. data/features/support/file_cases/horizontal_spacing_cases.rb +0 -266
  66. data/features/support/file_cases/naming_cases.rb +0 -51
  67. data/features/vertical_spacing.feature +0 -135
  68. data/m.rb +0 -15
  69. data/spec/tailor/version_spec.rb +0 -6
data/.tailor CHANGED
@@ -7,6 +7,7 @@ Tailor.config do |config|
7
7
  end
8
8
 
9
9
  config.file_set 'spec/**/*.rb', :spec do |style|
10
+ style.max_line_length 105, level: :warn
10
11
  style.spaces_after_lbrace 1, level: :warn
11
12
  style.spaces_before_lbrace 1, level: :warn
12
13
  style.spaces_before_rbrace 1, level: :warn
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tailor (1.0.0)
4
+ tailor (1.1.0)
5
5
  log_switch (>= 0.3.0)
6
6
  term-ansicolor (>= 1.0.5)
7
7
  text-table (>= 1.2.2)
data/History.rdoc CHANGED
@@ -1,3 +1,37 @@
1
+ === 1.1.0 2012-05-07
2
+
3
+ * gh-89[https://github.com/turboladen/tailor/issues/89]
4
+ * You can now use {Tailor::RakeTask} to create a Rake task.
5
+ * gh-100[https://github.com/turboladen/tailor/issues/100]
6
+ * Added {Tailor::Configuration#recursive_file_set}. This lets you do the
7
+ following in your config file, which will recursively match all files in
8
+ your current path that end with '_spec.rb':
9
+
10
+ Tailor.config do |config|
11
+ config.recursive_file_set '*_spec.rb', :unit_tests do |style|
12
+ style.max_line_length 90, level: :warn
13
+ end
14
+ end
15
+
16
+ ...which is equivalent to:
17
+
18
+ Tailor.config do |config|
19
+ config.file_set '*/**/*_spec.rb', :unit_tests do |style|
20
+ style.max_line_length 90, level: :warn
21
+ end
22
+ end
23
+
24
+ * gh-107[https://github.com/turboladen/tailor/issues/107]
25
+ * Fixed --no-color option.
26
+ * gh-108[https://github.com/turboladen/tailor/issues/108]
27
+ * Fixed --create-config, which created style level options with a missing ':'
28
+ for the Hash value.
29
+ * Configuration files now don't force you to use the :default file set. If you
30
+ don't specify any file sets, then the default is used; if you specify file
31
+ sets, it uses what you specify.
32
+ * CLI options now override config file options for all file sets (previously,
33
+ only the :default file set's option would get overridden by the CLI option).
34
+
1
35
  === 1.0.1 2012-04-23
2
36
 
3
37
  * gh-104: Fixed incorrect rendering of config file when using
data/README.rdoc CHANGED
@@ -92,6 +92,12 @@ Check only files ending in .rb under the 'test' directory:
92
92
  Check defaults (lib/**/*.rb):
93
93
 
94
94
  $ tailor
95
+
96
+ Use defaults via a Rake task:
97
+
98
+ require 'tailor/rake_task'
99
+
100
+ Tailor::RakeTask.new
95
101
 
96
102
  ==== On style...
97
103
 
@@ -224,7 +230,7 @@ rulers caused the problem to be found.
224
230
  Tailor.config do |config|
225
231
 
226
232
  # All defaults; implies "default" label
227
- config.file_set 'lib/**/*.rb
233
+ config.file_set 'lib/**/*.rb'
228
234
 
229
235
  config.file_set 'app/**/*.rb', :rails_app do |style|
230
236
  style.max_line_length 100
@@ -242,6 +248,16 @@ rulers caused the problem to be found.
242
248
  end
243
249
  end
244
250
 
251
+ If it suits you better, use "recursive file sets" to get all matching files
252
+ in your current path. If you wanted to critique all .rb files:
253
+
254
+ # .tailor
255
+ Tailor.config do |config|
256
+
257
+ # All defaults; implies "default" label
258
+ config.recursive_file_set '*.rb'
259
+ end
260
+
245
261
  Similarly to the CLI, if you want to turn off a default Ruler, set its problem
246
262
  level to +:off+:
247
263
 
@@ -13,5 +13,5 @@ Feature: Valid Ruby
13
13
 
14
14
  """
15
15
  When I run `tailor -d extra_end.rb`
16
- Then the output should match /Total Problems.*1/
16
+ Then the output should match /TOTAL.*1/
17
17
  And the output should match /File contains invalid Ruby/
@@ -1,8 +1,4 @@
1
- require 'term/ansicolor'
2
-
3
1
  class String
4
- include Term::ANSIColor
5
-
6
2
  # Borrowed from ActiveSupport, this converts camel-case Strings to
7
3
  # snake-case.
8
4
  #
@@ -1,6 +1,7 @@
1
1
  require 'erb'
2
2
  require 'optparse'
3
3
  require 'ostruct'
4
+ require 'term/ansicolor'
4
5
  require 'text-table'
5
6
  require_relative '../version'
6
7
  require_relative '../configuration'
@@ -193,11 +194,17 @@ class Tailor
193
194
  end
194
195
 
195
196
  opts.parse!(args)
196
- require_relative '../../ext/string_ext' if @output_color
197
+ colorize
197
198
 
198
199
  options
199
200
  end
200
201
 
202
+ # Sets colors based on --[no-]color. If the terminal doesn't support
203
+ # colors, it turns colors off, despite the CLI setting.
204
+ def self.colorize
205
+ Term::ANSIColor.coloring = @output_color ? STDOUT.isatty : false
206
+ end
207
+
201
208
  # @return [String]
202
209
  def self.banner
203
210
  ruler + about + "\r\n" + usage + "\r\n"
@@ -251,7 +258,7 @@ tailor --show-config
251
258
  File.dirname(__FILE__) + '/../tailorrc.erb')
252
259
  formatters = Tailor::Configuration.default.formatters
253
260
  file_list = 'lib/**/*.rb'
254
- style = Tailor::Configuration.default.file_sets[:default][:style]
261
+ style = Tailor::Configuration::Style.new.to_hash
255
262
  default_config_file = ERB.new(File.read(erb_file)).result(binding)
256
263
  File.open('.tailor', 'w') { |f| f.write default_config_file }
257
264
  end
@@ -2,6 +2,7 @@ require_relative '../tailor'
2
2
  require_relative 'logger'
3
3
  require_relative 'runtime_error'
4
4
  require_relative 'configuration/style'
5
+ require_relative 'configuration/file_set'
5
6
 
6
7
  class Tailor
7
8
 
@@ -12,10 +13,13 @@ class Tailor
12
13
  #
13
14
  # It then basically represents a list of "file sets" and the rulers that
14
15
  # should be applied against each file set.
16
+ #
17
+ # If a file list is given from the CLI _and_ a configuration file is
18
+ # given/found, tailor uses the style settings for the default file set and
19
+ # only checks the default file set.
15
20
  class Configuration
16
21
  include Tailor::Logger::Mixin
17
22
 
18
- DEFAULT_GLOB = 'lib/**/*.rb'
19
23
  DEFAULT_RC_FILE = Dir.home + '/.tailorrc'
20
24
  DEFAULT_PROJECT_CONFIG = Dir.pwd + '/.tailor'
21
25
 
@@ -33,110 +37,138 @@ class Tailor
33
37
  # @option options [Array] formatters
34
38
  # @option options [Hash] style
35
39
  def initialize(runtime_file_list=nil, options=nil)
36
- @style = Style.new
37
40
  @formatters = ['text']
38
- @file_sets = {
39
- default: {
40
- file_list: file_list(DEFAULT_GLOB),
41
- style: @style.to_hash
42
- }
43
- }
44
-
41
+ @file_sets = {}
45
42
  @runtime_file_list = runtime_file_list
46
43
  log "Got runtime file list: #{@runtime_file_list}"
44
+
47
45
  @options = options
48
46
  log "Got options: #{@options}"
47
+
48
+ unless @options.nil?
49
+ @config_file = @options.config_file unless @options.config_file.empty?
50
+ end
49
51
  end
50
52
 
51
53
  # Call this to load settings from the config file and from CLI options.
52
54
  def load!
53
- # Get config file settings
54
- @config_file = @options.config_file unless @options.config_file.empty?
55
- load_from_config_file(config_file) if config_file
55
+ if config_file
56
+ load_from_config_file(config_file)
56
57
 
57
- if @config_file
58
- if @rc_file_config
58
+ if @config_from_file
59
59
  get_formatters_from_config_file
60
- get_files_sets_from_config_file
60
+ #get_file_sets_from_config_file unless @runtime_file_list
61
+ get_file_sets_from_config_file
61
62
  end
63
+ else
64
+ log "Creating default file set..."
65
+ @file_sets = { default: FileSet.new(@runtime_file_list) }
62
66
  end
63
67
 
64
68
  get_formatters_from_cli_opts
65
- get_files_sets_from_cli_opts
69
+ get_file_sets_from_cli_opts
66
70
  get_style_from_cli_opts
71
+ end
72
+
73
+ # Tries to open the file at the path given at +config_file+ and read in
74
+ # the configuration given there.
75
+ #
76
+ # @param [String] config_file Path to the config file to use.
77
+ def load_from_config_file(config_file)
78
+ user_config_file = File.expand_path(config_file)
67
79
 
68
- if @file_sets[:default][:file_list].empty?
69
- @file_sets[:default][:file_list] = file_list(DEFAULT_GLOB)
80
+ if File.exists? user_config_file
81
+ log "Loading config from file: #{user_config_file}"
82
+
83
+ begin
84
+ @config_from_file = instance_eval(File.read(user_config_file), user_config_file)
85
+ log "Got new config from file: #{user_config_file}"
86
+ rescue LoadError => ex
87
+ raise Tailor::RuntimeError,
88
+ "Couldn't load config file: #{user_config_file}"
89
+ end
90
+ else
91
+ log "No config file found at #{user_config_file}."
70
92
  end
71
93
  end
72
94
 
73
- def get_files_sets_from_config_file
74
- unless @rc_file_config.file_sets.empty?
75
- @rc_file_config.file_sets.each do |label, file_set|
76
- log "file set: #{file_set}"
95
+ # @return [String] Name of the config file to use.
96
+ def config_file
97
+ return @config_file if @config_file
77
98
 
78
- if @file_sets[label]
79
- @file_sets[label][:file_list].concat file_set[:file_list]
80
- @file_sets[label][:file_list].uniq!
81
- @file_sets[label][:style].merge! file_set[:style]
82
- else
83
- @file_sets[label] = {
84
- file_list: file_set[:file_list],
85
- style: @style.to_hash.merge(file_set[:style])
86
- }
87
- end
99
+ if File.exists?(DEFAULT_PROJECT_CONFIG)
100
+ return @config_file = DEFAULT_PROJECT_CONFIG
101
+ end
102
+
103
+ if File.exists?(DEFAULT_RC_FILE)
104
+ return @config_file = DEFAULT_RC_FILE
105
+ end
106
+ end
107
+
108
+ def get_file_sets_from_config_file
109
+ return if @config_from_file.file_sets.empty?
110
+
111
+ @config_from_file.file_sets.each do |label, file_set|
112
+ log "label: #{label}"
113
+ log "file set file list: #{file_set[:file_list]}"
114
+ log "file set style: #{file_set[:style]}"
115
+
116
+ if @file_sets[label]
117
+ log "label already exists. Updating..."
118
+ @file_sets[label].update_file_list(file_set[:file_list])
119
+ @file_sets[label].update_style(file_set[:style])
120
+ else
121
+ log "Creating new label..."
122
+ @file_sets[label] =
123
+ FileSet.new(file_set[:file_list], file_set[:style])
88
124
  end
89
125
  end
90
126
  end
91
127
 
92
128
  def get_formatters_from_config_file
93
- unless @rc_file_config.formatters.empty?
94
- @formatters = @rc_file_config.formatters
95
- log "@formatters is now #{@formatters}"
96
- end
129
+ return if @config_from_file.formatters.empty?
130
+
131
+ @formatters = @config_from_file.formatters
132
+ log "@formatters is now #{@formatters}"
97
133
  end
98
134
 
99
135
  def get_style_from_cli_opts
100
- if @options.style
101
- @options.style.each do |property, value|
136
+ return unless @options && @options.style
137
+
138
+ @options.style.each do |property, value|
139
+ @file_sets.keys.each do |label|
102
140
  if value == :off || value == "off"
103
- @file_sets[:default][:style][property][1] = { level: :off }
141
+ @file_sets[label].style[property][1] = { level: :off }
104
142
  else
105
- @file_sets[:default][:style][property][0] = value
143
+ @file_sets[label].style[property][0] = value
106
144
  end
107
145
  end
108
146
  end
109
147
  end
110
148
 
111
- def get_files_sets_from_cli_opts
112
- unless @runtime_file_list.nil? || @runtime_file_list.empty?
113
- # Only use options set for the :default file set because the user gave
114
- # a different set of files to measure.
115
- @file_sets.delete_if { |k, v| k != :default }
116
- @file_sets[:default][:file_list] = file_list(@runtime_file_list)
149
+ # If any files are given from the CLI, this gets that list of files and
150
+ # replaces those in any :default file set.
151
+ def get_file_sets_from_cli_opts
152
+ return if @runtime_file_list.nil? || @runtime_file_list.empty?
153
+
154
+ # Only use options set for the :default file set because the user gave
155
+ # a different set of files to measure.
156
+ @file_sets.delete_if { |k, v| k != :default }
157
+
158
+ if @file_sets.include? :default
159
+ @file_sets[:default].file_list = @runtime_file_list
160
+ else
161
+ @file_sets = { default: FileSet.new(@runtime_file_list) }
117
162
  end
118
163
  end
119
164
 
120
165
  def get_formatters_from_cli_opts
121
- unless @options.formatters.empty? || @options.formatters.nil?
166
+ unless @options.nil? || @options.formatters.empty? || @options.formatters.nil?
122
167
  @formatters = @options.formatters
123
168
  log "@formatters is now #{@formatters}"
124
169
  end
125
170
  end
126
171
 
127
- # @return [String] Name of the config file to use.
128
- def config_file
129
- return @config_file if @config_file
130
-
131
- if File.exists?(DEFAULT_PROJECT_CONFIG)
132
- return @config_file = DEFAULT_PROJECT_CONFIG
133
- end
134
-
135
- if File.exists?(DEFAULT_RC_FILE)
136
- return @config_file = DEFAULT_RC_FILE
137
- end
138
- end
139
-
140
172
  # @return [Array] The list of formatters.
141
173
  def formatters(*new_formatters)
142
174
  @formatters = new_formatters unless new_formatters.empty?
@@ -146,106 +178,27 @@ class Tailor
146
178
 
147
179
  # Adds a file set to the list of file sets in the Configuration object.
148
180
  #
149
- # @param [String] file_glob The String that represents the file set. This
150
- # can be a file, directory, or a glob.
181
+ # @param [String] file_expression The String that represents the file set. This
182
+ # can be a file, directory, or a (Ruby Dir) glob.
151
183
  # @param [Symbol] label The label that represents the file set.
152
- def file_set(file_glob=DEFAULT_GLOB, label=:default)
184
+ def file_set(file_expression='lib/**/*.rb', label=:default)
153
185
  log "file sets before: #{@file_sets}"
154
186
  log "file set label #{label}"
155
-
156
187
  new_style = Style.new
157
188
 
158
- if block_given?
159
- yield new_style
160
-
161
- if @file_sets[label]
162
- @file_sets[label][:style].merge! new_style
163
- end
164
- end
165
-
166
- if @file_sets[label]
167
- @file_sets[label][:file_list].concat file_list(file_glob)
168
- @file_sets[label][:file_list].uniq!
169
- else
170
- @file_sets[label] = {
171
- file_list: file_list(file_glob),
172
- style: @style.to_hash.merge(new_style)
173
- }
174
- end
189
+ yield new_style if block_given?
175
190
 
191
+ @file_sets[label] = FileSet.new(file_expression, new_style)
176
192
  log "file sets after: #{@file_sets}"
177
193
  end
178
194
 
179
- # Tries to open the file at the path given at +config_file+ and read in
180
- # the configuration given there.
181
- #
182
- # @param [String] config_file Path to the config file to use.
183
- def load_from_config_file(config_file)
184
- user_config_file = File.expand_path(config_file)
185
-
186
- if File.exists? user_config_file
187
- log "Loading config from file: #{user_config_file}"
188
-
189
- begin
190
- config = instance_eval File.read(user_config_file)
191
- rescue LoadError => ex
192
- raise Tailor::RuntimeError,
193
- "Couldn't load config file: #{user_config_file}"
194
- end
195
- else
196
- log "No config file found at #{user_config_file}."
197
- end
198
-
199
- if config
200
- log "Got new config from file: #{config}"
201
- @rc_file_config = config
202
- end
203
- end
204
-
205
- # Gets a list of only files that are in +base_dir+.
206
- #
207
- # @param [String] base_dir The directory to get the file list for.
208
- # @return [Array<String>] The List of files.
209
- def all_files_in_dir(base_dir)
210
- files = Dir.glob(File.join(base_dir, '**', '*')).find_all do |file|
211
- file if File.file?(file)
212
- end
213
-
214
- files
215
- end
216
-
217
- # The list of the files in the project to check.
195
+ # A helper to #file_set that allows you to specify '*.rb' to get all files
196
+ # ending with +.rb+ in your current path and deeper.
218
197
  #
219
- # @param [String] glob Path to the file, directory or glob to check.
220
- # @return [Array] The list of files to check.
221
- def file_list(glob)
222
- files_in_project = if glob.is_a? Array
223
- log "Configured glob is an Array: #{glob}"
224
-
225
- glob.map do |e|
226
- if File.directory?(e)
227
- all_files_in_dir(e)
228
- else
229
- e
230
- end
231
- end.flatten.uniq
232
- elsif File.directory? glob
233
- log "Configured glob is an directory: #{glob}"
234
- all_files_in_dir(glob)
235
- else
236
- log "Configured glob is a glob/single-file: #{glob}"
237
- Dir.glob glob
238
- end
239
-
240
- list_with_absolute_paths = []
241
-
242
- files_in_project.each do |file|
243
- list_with_absolute_paths << File.expand_path(file)
244
- end
245
-
246
- log "All files: #{list_with_absolute_paths}"
247
-
248
- list_with_absolute_paths.sort
198
+ # @param [String] file_expression The expression to match recursively.
199
+ # @param [Symbol] label The file set label to use.
200
+ def recursive_file_set(file_expression, label=:default)
201
+ file_set("*/**/#{file_expression}", label)
249
202
  end
250
203
 
251
204
  # Displays the current configuration as a text table.