tailor 1.0.1 → 1.1.0

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