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,4 +0,0 @@
1
- # Spaces after open and before closed parentheses in a comment: ( me, you )
2
- def do_something( hello, and_hi=[ "me", "you" ] )
3
- File.expand_path( File.dirname (__FILE__) )
4
- end
@@ -1,62 +0,0 @@
1
- # Arrays...
2
- # Perfect
3
- thing = []
4
-
5
- # 1 space after [
6
- thing = [ ]
7
-
8
- # Perfect with element
9
- one = 'won'
10
- thing = [one]
11
-
12
- # 1 space after [ with element
13
- thing = [ one]
14
-
15
- # 1 space before ] with element
16
- thing = [one ]
17
-
18
- # 1 space before and after [ and ]
19
- thing = [ one ]
20
-
21
- # Perfect element reference
22
- thing[0]
23
-
24
- # 1 space after [ with element reference
25
- thing[ 0]
26
-
27
- # 1 space before [ with element reference
28
- thing [0]
29
-
30
- # 1 space before ] with element reference
31
- thing[0 ]
32
-
33
- # Perfect multi-line
34
- two = 'too'
35
- thing = [
36
- one,
37
- two
38
- ]
39
-
40
- # Perfect multi-line, indented
41
- def thing
42
- a_thing = [
43
- one,
44
- two
45
- ]
46
- end
47
-
48
-
49
- # Hash references...
50
- thing = { :one => 1 }
51
-
52
- # Perfect element reference
53
- thing[:one]
54
-
55
- # 1 space after [ with element reference
56
- thing[ :one]
57
-
58
- # 1 space before [ with element reference
59
- thing [:one]
60
-
61
- # 1 space before ] with element reference
62
- thing[:one ]
@@ -1,5 +0,0 @@
1
- class CamelCase
2
- def my_method
3
- return
4
- end
5
- end
@@ -1,3 +0,0 @@
1
- def doSomething
2
- return
3
- end
@@ -1,3 +0,0 @@
1
- def my_method
2
- return
3
- end
@@ -1,5 +0,0 @@
1
- # This method has a line in it that is way too freaking long. Seriously, why would you do
2
- # something like this?
3
- def do_something and_stuff
4
- this_is_a_long_variable_name = Hash.new(:thing1 => 'something', :thing2 => 'something')
5
- end
@@ -1,5 +0,0 @@
1
- class A_Class
2
- def do_something
3
- return
4
- end
5
- end
@@ -1,3 +0,0 @@
1
- def do_something
2
- return
3
- end
@@ -1,5 +0,0 @@
1
- class MyClass
2
- def do_something
3
- return
4
- end
5
- end
@@ -1,5 +0,0 @@
1
- class Something
2
- def a_method
3
- puts "hi"
4
- end
5
- end
@@ -1,102 +0,0 @@
1
- $:.unshift(File.dirname(__FILE__) + '/../../lib')
2
-
3
- require 'tailor'
4
-
5
- include Tailor
6
-
7
- module CommonHelpers
8
- def in_tmp_folder(&block)
9
- FileUtils.chdir(@tmp_root, &block)
10
- end
11
-
12
- def in_project_folder(&block)
13
- project_folder = @active_project_folder || @tmp_root
14
- FileUtils.chdir(project_folder, &block)
15
- end
16
-
17
- def in_home_folder(&block)
18
- FileUtils.chdir(@home_path, &block)
19
- end
20
-
21
- def force_local_lib_override(project_name = @project_name)
22
- rakefile = File.read(File.join(project_name, 'Rakefile'))
23
- File.open(File.join(project_name, 'Rakefile'), "w+") do |f|
24
- f << "$:.unshift('#{@lib_path}')\n"
25
- f << rakefile
26
- end
27
- end
28
-
29
- def setup_active_project_folder project_name
30
- @active_project_folder = File.join(@tmp_root, project_name)
31
- @project_name = project_name
32
- end
33
- end
34
-
35
- World(CommonHelpers)
36
-
37
- # Counts keywords in the file provided.
38
- #
39
- # @param [String] file Path to the file to check
40
- # @param [String] keyword Keyword to count
41
- # @return [Number] Number of keywords counted
42
- def count_keywords file, keyword
43
- ruby_source = File.open(file, 'r')
44
-
45
- count = 0
46
- ruby_source.each_line do |line|
47
- if line =~ /^#{keyword}/
48
- count =+ 1
49
- end
50
- end
51
- ruby_source.close
52
- count
53
- end
54
-
55
- def check_file
56
- ruby_source = File.open(@file_list[0], 'r')
57
-
58
- ruby_source.each_line do |line|
59
- yield(line)
60
- end
61
- end
62
-
63
- # Prep for the testing
64
- Before do
65
- @tailor = "#{File.dirname(__FILE__)}/../../bin/tailor"
66
- end
67
-
68
- #-----------------------------------------------------------------------------
69
- # "Given" statements
70
- #-----------------------------------------------------------------------------
71
- Given /^I have a project directory "([^\"]*)"$/ do |project_dir|
72
- project_dir = "#{@features_path}/support/#{project_dir}"
73
- File.exists?(project_dir).should be_true
74
- File.directory?(project_dir).should be_true
75
- @project_dir = project_dir
76
- end
77
-
78
- Given /^the file contains only "([^\"]*)" "([^\"]*)" statement$/ do
79
- |count_in_spec, keyword|
80
- #count_in_file = count_keywords(@ruby_source, keyword)
81
- count_in_file = count_keywords(@file_list[0], keyword)
82
- count_in_file.should == count_in_spec.to_i
83
- end
84
-
85
- Given /^I have 1 file in my project$/ do
86
- @file_list = Dir.glob("#{@project_dir}/*")
87
- @file_list.length.should == 1
88
- end
89
-
90
- Given /^that file does not contain any "([^\"]*)" statements$/ do |keyword|
91
- ruby_source = File.open(@file_list[0], 'r')
92
-
93
- count = count_keywords(ruby_source, keyword)
94
- count.should == 0
95
- end
96
-
97
- #-----------------------------------------------------------------------------
98
- # "When" statements
99
- #-----------------------------------------------------------------------------
100
- When "I run the checker on the project" do
101
- @result = `#{@tailor} #{@project_dir}`
102
- end
@@ -1,11 +0,0 @@
1
- module Matchers
2
- def contain(expected)
3
- simple_matcher("contain #{expected.inspect}") do |given, matcher|
4
- matcher.failure_message = "expected #{given.inspect} to contain #{expected.inspect}"
5
- matcher.negative_failure_message = "expected #{given.inspect} not to contain #{expected.inspect}"
6
- given.index expected
7
- end
8
- end
9
- end
10
-
11
- World(Matchers)
@@ -1,220 +0,0 @@
1
- require 'logger'
2
- require 'rubygems'
3
- require 'tailor/spacing'
4
- require 'tailor/indentation'
5
- require 'term/ansicolor'
6
-
7
- module Tailor
8
-
9
- # Calling modules will get the Ruby file to check, then read by line. This
10
- # class allows for checking of line-specific style by Represents a single
11
- # line of a file of Ruby code. Inherits from String so "self" can be used.
12
- #
13
- # Methods are named such that they check for bad style conditions, and return
14
- # true and print the associated error message when the bad style condition
15
- # is discovered in the file line.
16
- class FileLine < String
17
- include Tailor::Spacing
18
- include Tailor::Indentation
19
- include Term::ANSIColor
20
-
21
- LINE_LENGTH_MAX = 80
22
-
23
- # This passes the line of code to String (the parent) so that it can act
24
- # like a standard string.
25
- #
26
- # @param [String] line_of_code Line from a Ruby file that will be checked
27
- # for styling.
28
- # @param [Pathname] file_path Path to the file the line is in.
29
- # @param [Number] line_number Line number in the file that contains the
30
- # line.
31
- # @return [String] Returns a String that includes all of the methods
32
- # defined here.
33
- def initialize(line_of_code, file_path, line_number)
34
- super line_of_code
35
- @file_path = file_path
36
- @line_number = line_number
37
- @line_problem_count = 0
38
- @logger = ::Logger.new(STDOUT)
39
- #@logger.datetime_format = "%H:%M:%S"
40
- @logger.datetime_format = ""
41
- end
42
-
43
- # Checks to see if the method name is using camel case.
44
- #
45
- # @return [Boolean] Returns true if the method name is camel case.
46
- # Returns nil if this line doesn't contain a method definition.
47
- def camel_case_method?
48
- words = self.split(/ /)
49
-
50
- # If we're not dealing with a method, get outta here.
51
- unless self.method_line?
52
- return nil
53
- end
54
-
55
- # The 2nd word is the method name, so evaluate that for caps chars.
56
- if words[1] =~ /[A-Z]/
57
- @line_problem_count += 1
58
- print_problem "Method name uses camel case"
59
- return true
60
- end
61
-
62
- false
63
- end
64
-
65
- # Checks to see if the class name is using snake case.
66
- #
67
- # @return [Boolean] Returns true if the class name is snake case.
68
- # Returns nil if this line doesn't contain a class definition.
69
- def snake_case_class?
70
- words = self.split(/ /)
71
-
72
- # If we're dealing with a class, check for an underscore.
73
- unless self.class_line?
74
- return nil
75
- end
76
-
77
- # The 2nd word is the class name, so check that.
78
- if words[1] =~ /_/
79
- @line_problem_count += 1
80
- print_problem "Class name does NOT use camel case"
81
- return true
82
- end
83
-
84
- false
85
- end
86
-
87
- # Checks to see if the line is the start of a method's definition.
88
- #
89
- # @return [Boolean] Returns true if the line starts with 'def'.
90
- def method_line?
91
- words = self.strip.split(/ /)
92
- if words[0].eql? "def"
93
- return true
94
- end
95
-
96
- false
97
- end
98
-
99
- # Returns the name of the method if the line is one that contains a method
100
- # definition.
101
- #
102
- # @return [String] The method name.
103
- def method_name
104
- unless self.method_line?
105
- return nil
106
- end
107
-
108
- words = self.strip.split(/ /)
109
- words[1]
110
- end
111
-
112
- # Checks to see if the line is the start of a class's definition.
113
- #
114
- # @return [Boolean] Returns true if the line contains 'class' and the
115
- # second word begins with a uppercase letter.
116
- def class_line?
117
- words = self.split(/ /)
118
- if words[0].eql? "class" and starts_with_uppercase?(words[1])
119
- return true
120
- end
121
-
122
- false
123
- end
124
-
125
- # Checks to see if the line is a regular statement (not a class, method, or
126
- # comment).
127
- #
128
- # @return [Boolean] Returns true if the line is not a class, method or
129
- # comment.
130
- def statement_line?
131
- if self.method_line? or self.class_line? or self.comment_line?
132
- return false
133
- end
134
-
135
- true
136
- end
137
-
138
- # Checks to see if the whole line is a basic comment line. This doesn't
139
- # check for trailing-line comments (@see #trailing_comment?).
140
- #
141
- # @return [Boolean] Returns true if the line begins with a pound symbol.
142
- def comment_line?
143
- unless self.scan(/^\s*#/).empty?
144
- return true
145
- end
146
-
147
- false
148
- end
149
-
150
- # Checks to see if the whole line is only space characters.
151
- #
152
- # @return [Boolean] Returns true if the line is only space characters.
153
- def empty_line?
154
- if self.scan(/^\s*$/).empty?
155
- return false
156
- end
157
-
158
- true
159
- end
160
-
161
- # Checks to see if the line is greater than the defined max (80 chars is
162
- # default).
163
- #
164
- # @return [Boolean] Returns true if the line length exceeds the allowed
165
- # length.
166
- def too_long?
167
- length = self.length
168
- if length > LINE_LENGTH_MAX
169
- @line_problem_count += 1
170
- print_problem "Line is >#{LINE_LENGTH_MAX} characters (#{length})"
171
- return true
172
- end
173
-
174
- false
175
- end
176
-
177
- #-----------------------------------------------------------------
178
- # Private methods
179
- #-----------------------------------------------------------------
180
- private
181
-
182
- # Prints the file name and line number that the problem occurred on.
183
- #
184
- # @param [String] Error message to print.
185
- def print_problem message
186
- if @line_problem_count == 1
187
- line_info = "Problems in"
188
- line_info += " #{@file_path.relative_path_from(Pathname.pwd)}"
189
- line_info += " [#{@line_number}]:"
190
-
191
- puts ""
192
- puts line_info
193
- end
194
-
195
- puts red("\t"+ message)
196
- end
197
-
198
- # Checks to see if a word begins with a lowercase letter.
199
- #
200
- # @param [String] word The word to check case on.
201
- def starts_with_lowercase? word
202
- if word =~ /^[a-z]/
203
- return true
204
- end
205
-
206
- false
207
- end
208
-
209
- # Checks to see if a word begins with an uppercase letter.
210
- #
211
- # @param [String] word The word to check case on.
212
- def starts_with_uppercase? word
213
- if word =~ /^[A-Z]/
214
- return true
215
- end
216
-
217
- false
218
- end
219
- end
220
- end