tailor 0.1.5 → 1.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,36 @@
1
+ require_relative '../ruler'
2
+
3
+
4
+ class Tailor
5
+ module Rulers
6
+ class TrailingNewlinesRuler < Tailor::Ruler
7
+
8
+ # Checks to see if the number of newlines at the end of the file is not
9
+ # equal to the value at +@config+.
10
+ #
11
+ # @param [Fixnum] trailing_newline_count The number of newlines at the end
12
+ # of the file.
13
+ def measure(trailing_newline_count)
14
+ if trailing_newline_count != @config
15
+ lineno = "<EOF>"
16
+ column = "<EOF>"
17
+ @problems << Problem.new(:trailing_newlines, lineno, column,
18
+ { actual_trailing_newlines: trailing_newline_count,
19
+ should_have: @config }
20
+ )
21
+ end
22
+ end
23
+
24
+ # Checks to see if the file's final character is a \n. If it is, it just
25
+ # returns the text that was passed in. If it's not, it adds a \n, since
26
+ # the current indentation-checking algorithm only checks indent levels when
27
+ # it parses a newline character (without this, indentation problems on the
28
+ # final line won't ever get caught).
29
+ #
30
+ # @param [Fixnum] trailing_newline_count
31
+ def file_update(trailing_newline_count)
32
+ measure(trailing_newline_count)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ class Tailor
2
+ class RuntimeError < RuntimeError; end
3
+ end
@@ -0,0 +1,88 @@
1
+ #------------------------------------------------------------------------------
2
+ # Horizontal Whitespace
3
+ #------------------------------------------------------------------------------
4
+ # allow_hard_tabs True to let hard tabs be considered a single space.
5
+ # Default: false
6
+ #
7
+ # allow_trailing_line_spaces
8
+ # True to skip detecting extra spaces at the ends of
9
+ # lines.
10
+ # Default: false
11
+ #
12
+ # indentation_spaces The number of spaces to consider a proper indent.
13
+ # Default: 2
14
+ #
15
+ # max_line_length The maximum number of characters in a line before
16
+ # tailor complains.
17
+ # Default: 80
18
+ # spaces_after_comma Number of spaces to expect after a comma.
19
+ # Default: 1
20
+ #
21
+ # spaces_before_comma Number of spaces to expect before a comma.
22
+ # Default: 0
23
+ #
24
+ # spaces_after_lbrace The number of spaces to expect after an lbrace ('{').
25
+ # Default: 1
26
+ #
27
+ # spaces_before_lbrace The number of spaces to expect before an lbrace ('{').
28
+ # Default: 1
29
+ #
30
+ # spaces_before_rbrace The number of spaces to expect before an rbrace ('}').
31
+ # Default: 1
32
+ #
33
+ # spaces_in_empty_braces The number of spaces to expect between braces when
34
+ # there's nothing in the braces (i.e. {}).
35
+ # Default: 0
36
+ #
37
+ # spaces_after_lbracket The number of spaces to expect after an
38
+ # lbracket ('[').
39
+ # Default: 0
40
+ #
41
+ # spaces_before_rbracket The number of spaces to expect before an
42
+ # rbracket (']').
43
+ # Default: 0
44
+ #
45
+ # spaces_after_lparen The number of spaces to expect after an
46
+ # lparen ('(').
47
+ # Default: 0
48
+ #
49
+ # spaces_before_rparen The number of spaces to expect before an
50
+ # rbracket (')').
51
+ # Default: 0
52
+ #
53
+ #------------------------------------------------------------------------------
54
+ # Naming
55
+ #------------------------------------------------------------------------------
56
+ # allow_camel_case_methods
57
+ # Setting to true skips detection of camel-case method
58
+ # names (i.e. def myMethod).
59
+ # Default: false
60
+ #
61
+ # allow_screaming_snake_case_classes
62
+ # Setting to true skips detection of screaming
63
+ # snake-case class names (i.e. My_Class).
64
+ # Default: false
65
+ #
66
+ #------------------------------------------------------------------------------
67
+ # Vertical Whitespace
68
+ #------------------------------------------------------------------------------
69
+ # max_code_lines_in_class The number of lines of code in a class to allow before
70
+ # tailor will warn you.
71
+ # Default: 300
72
+ #
73
+ # max_code_lines_in_method
74
+ # The number of lines of code in a method to allow
75
+ # before tailor will warn you.
76
+ # Default: 30
77
+ #
78
+ # trailing_newlines The number of newlines that should be at the end of
79
+ # the file.
80
+ # Default: 1
81
+ #
82
+ Tailor.config do |config|
83
+ config.formatters <%= formatters %>
84
+ config.file_set '<%= file_list %>' do
85
+ <% style.each do |rule, value| %><%= rule %> <%= value %>
86
+ <% end %>
87
+ end
88
+ end
@@ -1,3 +1,3 @@
1
- module Tailor
2
- VERSION = '0.1.5'
1
+ class Tailor
2
+ VERSION = '1.0.0.alpha'
3
3
  end
@@ -1,7 +1,9 @@
1
- $:.unshift(File.dirname(__FILE__) + '/../lib')
2
- require 'tailor'
3
- require 'rspec'
1
+ require 'fakefs/spec_helpers'
2
+ require 'simplecov'
4
3
 
5
- def create_file_line(string, line_number)
6
- FileLine.new(string, Pathname.new(__FILE__), line_number)
4
+ SimpleCov.start
5
+
6
+ RSpec.configure do |conf|
7
+ conf.include FakeFS::SpecHelpers
7
8
  end
9
+
@@ -0,0 +1,94 @@
1
+ require_relative '../spec_helper'
2
+ require 'tailor/cli'
3
+
4
+
5
+ describe Tailor::CLI do
6
+ let(:args) { [] }
7
+ let(:options) { double "Options", show_config: false }
8
+
9
+ let(:config) do
10
+ double "Tailor::Configuration",
11
+ file_sets: nil, formatters: nil
12
+ end
13
+
14
+ before do
15
+ Tailor::Configuration.stub(:new).and_return config
16
+ Tailor::Critic.stub(:new)
17
+ Tailor::Reporter.stub(:new)
18
+ end
19
+
20
+ after do
21
+ Tailor::Configuration.unstub(:new)
22
+ end
23
+
24
+ subject { Tailor::CLI.new(args) }
25
+
26
+ describe "::run" do
27
+ it "creates an instance of Tailor::CLI and calls that object's #execute!" do
28
+ cli = double "Tailor::CLI"
29
+ cli.should_receive(:execute!)
30
+ Tailor::CLI.should_receive(:new).and_return cli
31
+ Tailor::CLI.run([])
32
+ end
33
+ end
34
+
35
+ describe "#initialize" do
36
+ let(:args) { ['last'] }
37
+
38
+ it "uses Options to parse the args" do
39
+ Tailor::Configuration.stub(:new).and_return config
40
+ Tailor::Critic.stub(:new)
41
+ Tailor::Reporter.stub(:new)
42
+ Tailor::CLI::Options.should_receive(:parse!).with(args).and_return options
43
+
44
+ Tailor::CLI.new(args)
45
+ end
46
+
47
+ it "creates a new Configuration from the file/dir and options" do
48
+ Tailor::CLI::Options.stub(:parse!).and_return(options)
49
+ Tailor::Configuration.should_receive(:new).
50
+ with(args, options).and_return config
51
+ Tailor::Critic.stub(:new)
52
+
53
+ Tailor::CLI.new(args)
54
+ end
55
+
56
+ context "options.show_config is true" do
57
+
58
+ end
59
+
60
+ context "options.show_config is false" do
61
+
62
+ end
63
+
64
+ end
65
+
66
+ describe "#execute!" do
67
+ let(:reporter) { double "Tailor::Reporter" }
68
+ let(:critic) { double "Tailor::Critic", problem_count: 0 }
69
+
70
+ before do
71
+ Tailor::Critic.stub(:new).and_return(critic)
72
+ Tailor::Reporter.stub(:new).and_return(reporter)
73
+ subject.instance_variable_set(:@critic, critic)
74
+ subject.instance_variable_set(:@reporter, reporter)
75
+ end
76
+
77
+ after do
78
+ Tailor::Critic.unstub(:new)
79
+ Tailor::Reporter.unstub(:new)
80
+ end
81
+
82
+ it "calls @critic.critique and yields file problems and the label" do
83
+ problems_for_file = {}
84
+ label = :test
85
+ critic.stub(:problem_count).and_return 1
86
+ critic.stub(:problems)
87
+ critic.stub(:critique).and_yield(problems_for_file, label)
88
+ reporter.stub(:summary_report)
89
+ reporter.should_receive(:file_report).with(problems_for_file, label)
90
+
91
+ subject.execute!
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,147 @@
1
+ require_relative '../spec_helper'
2
+ require 'tailor/configuration'
3
+
4
+ describe Tailor::Configuration do
5
+ before { Tailor::Logger.stub(:log) }
6
+
7
+ subject do
8
+ Tailor::Configuration.new('.')
9
+ end
10
+
11
+ describe "#formatters" do
12
+ context "param is nil" do
13
+ it "returns the pre-exisiting @formatters" do
14
+ subject.instance_variable_set(:@formatters, [:blah])
15
+ subject.formatters.should == [:blah]
16
+ end
17
+ end
18
+
19
+ context "param is some value" do
20
+ it "sets @formatters to that value" do
21
+ subject.formatters "blah"
22
+ subject.instance_variable_get(:@formatters).should == ["blah"]
23
+ end
24
+ end
25
+ end
26
+
27
+ describe "#file_set" do
28
+ before do
29
+ subject.instance_variable_set(:@file_sets, {})
30
+ end
31
+
32
+ it "adds the set of stuff to @file_sets" do
33
+ subject.file_set(:bobo) do
34
+ trailing_newlines 2
35
+ end
36
+
37
+ subject.instance_variable_get(:@file_sets).should == {
38
+ bobo: {
39
+ file_list: [],
40
+ style: {
41
+ :allow_camel_case_methods=>false,
42
+ :allow_hard_tabs=>false,
43
+ :allow_screaming_snake_case_classes=>false,
44
+ :allow_trailing_line_spaces=>false,
45
+ :indentation_spaces=>2,
46
+ :max_code_lines_in_class=>300,
47
+ :max_code_lines_in_method=>30,
48
+ :max_line_length=>80,
49
+ :spaces_after_comma=>1,
50
+ :spaces_before_comma=>0,
51
+ :spaces_before_lbrace=>1,
52
+ :spaces_after_lbrace=>1,
53
+ :spaces_before_rbrace=>1,
54
+ :spaces_in_empty_braces=>0,
55
+ :spaces_after_lbracket=>0,
56
+ :spaces_before_rbracket=>0,
57
+ :spaces_after_lparen=>0,
58
+ :spaces_before_rparen=>0,
59
+ :trailing_newlines=>2
60
+ }
61
+ }
62
+ }
63
+ end
64
+
65
+ context "first param is nil" do
66
+ it "uses :default as the label" do
67
+ subject.file_set
68
+ subject.instance_variable_get(:@file_sets).should include(:default)
69
+ end
70
+ end
71
+ end
72
+
73
+ describe "#confg_file" do
74
+ context "@config_file is already set" do
75
+ it "returns @config_file" do
76
+ subject.instance_variable_set(:@config_file, 'pants')
77
+ subject.config_file
78
+ subject.instance_variable_get(:@config_file).should == 'pants'
79
+ end
80
+ end
81
+
82
+ context "@config_file is nil" do
83
+ it "returns DEFAULT_RC_FILE" do
84
+ subject.config_file
85
+ subject.instance_variable_get(:@config_file).should ==
86
+ Tailor::Configuration::DEFAULT_RC_FILE
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "#file_list" do
92
+ before do
93
+ FileUtils.mkdir_p 'one/two'
94
+ File.new('one/two/three.rb', 'w') { |f| f.write "stuff" }
95
+ end
96
+
97
+ context "glob is an Array" do
98
+ context "the Array has files" do
99
+ it "returns all files in the glob" do
100
+ results = subject.file_list(['one/two/three.rb'])
101
+ results.last.should match /one\/two\/three.rb/
102
+ end
103
+ end
104
+
105
+ context "the Array has a directory" do
106
+ context "the directory has files" do
107
+ it "returns all files in the directory" do
108
+ results = subject.file_list(['.'])
109
+ results.last.should match /one\/two\/three.rb/
110
+ end
111
+ end
112
+
113
+ context "the directory is empty" do
114
+ before do
115
+ FileUtils.mkdir 'empty'
116
+ FileUtils.rm_rf 'one'
117
+ end
118
+
119
+ it "returns an empty Array" do
120
+ results = subject.file_list(['.'])
121
+ results.should == []
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ context "glob is a glob" do
128
+ it "returns all files in the glob" do
129
+ results = subject.file_list('one/**/*.rb')
130
+ results.last.should match /one\/two\/three.rb/
131
+ end
132
+ end
133
+
134
+ context "glob is a directory" do
135
+ it "returns all files in the glob" do
136
+ results = subject.file_list('one')
137
+ results.last.should match /one\/two\/three.rb/
138
+ end
139
+ end
140
+
141
+ context "glob is a file" do
142
+ it "returns all files in the glob" do
143
+ subject.file_list('one/two/three.rb').last.should match /one\/two\/three.rb/
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,63 @@
1
+ require_relative '../spec_helper'
2
+ require 'tailor/critic'
3
+
4
+ describe Tailor::Critic do
5
+ let(:configuration) { } # empty on purpose
6
+ before { subject.stub(:log) }
7
+ subject { Tailor::Critic.new(configuration) }
8
+
9
+ describe "#check_file" do
10
+ let(:lexer) { double "Lexer" }
11
+ let(:ruler) { double "Ruler" }
12
+ let(:file_name) { "this_file.rb" }
13
+
14
+ before do
15
+ subject.stub(:init_rulers)
16
+ end
17
+
18
+ it "lexes the file" do
19
+ lexer.should_receive(:lex)
20
+ lexer.stub(:check_added_newline)
21
+ Tailor::Lexer.should_receive(:new).with(file_name).and_return lexer
22
+ subject.stub_chain(:problems, :[]=)
23
+ subject.stub_chain(:problems, :[])
24
+
25
+ subject.check_file(file_name, 1)
26
+ end
27
+
28
+ it "adds problems for the file to the main list of problems" do
29
+ lexer.stub(:lex)
30
+ lexer.stub(:check_added_newline)
31
+ Tailor::Lexer.stub(:new).and_return lexer
32
+ subject.problems.should_receive(:[]=).with(file_name, [])
33
+
34
+ subject.check_file(file_name, 1)
35
+ end
36
+ end
37
+
38
+ describe "#problems" do
39
+ specify { subject.problems.should be_a Hash }
40
+ specify { subject.problems.should be_empty }
41
+ end
42
+
43
+ describe "#problem_count" do
44
+ context "#problems is empty" do
45
+ it "returns 0" do
46
+ subject.instance_variable_set(:@problems, {})
47
+ subject.problem_count.should == 0
48
+ end
49
+ end
50
+
51
+ context "#problems contains valid values" do
52
+ it "adds the number of each problem together" do
53
+ probs = {
54
+ one: { type: :indentation, line: 1, message: "" },
55
+ two: { type: :indentation, line: 2, message: "" },
56
+ thre: { type: :indentation, line: 27, message: "" }
57
+ }
58
+ subject.instance_variable_set(:@problems, probs)
59
+ subject.problem_count.should == 3
60
+ end
61
+ end
62
+ end
63
+ end