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
@@ -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