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,46 @@
1
+ require_relative '../../spec_helper'
2
+ require 'tailor/lexer/token'
3
+
4
+ describe Tailor::Lexer::Token do
5
+ before do
6
+ Tailor::Logger.stub(:log)
7
+ end
8
+
9
+ describe "#modifier_keyword?" do
10
+ subject do
11
+ options = { full_line_of_text: full_line_of_text }
12
+ Tailor::Lexer::Token.new("if", options)
13
+ end
14
+
15
+ context "the current line has a keyword that is also a modifier" do
16
+ context "the keyword is acting as a modifier" do
17
+ let!(:full_line_of_text) { %q{puts "hi" if true == true} }
18
+
19
+ it "returns true" do
20
+ subject.modifier_keyword?.should be_true
21
+ end
22
+ end
23
+
24
+ context "they keyword is NOT acting as a modifier" do
25
+ let!(:full_line_of_text) { %q{if true == true; puts "hi"; end} }
26
+
27
+ it "returns false" do
28
+ subject.modifier_keyword?.should be_false
29
+ end
30
+ end
31
+ end
32
+
33
+ context "the current line doesn't have a keyword" do
34
+ let!(:full_line_of_text) { %q{puts true} }
35
+
36
+ subject do
37
+ options = { full_line_of_text: full_line_of_text }
38
+ Tailor::Lexer::Token.new("puts", options)
39
+ end
40
+
41
+ it "returns false" do
42
+ subject.modifier_keyword?.should be_false
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,181 @@
1
+ require 'fakefs/spec_helpers'
2
+ require_relative '../spec_helper'
3
+ require 'tailor/lexer'
4
+
5
+ describe Tailor::Lexer do
6
+ let!(:file_text) { "" }
7
+ let(:style) { {} }
8
+ let(:indentation_ruler) { double "IndentationSpacesRuler" }
9
+
10
+ subject do
11
+ r = Tailor::Lexer.new(file_text)
12
+ r.instance_variable_set(:@buf, [])
13
+ r.stub(:log)
14
+
15
+ r
16
+ end
17
+
18
+ before do
19
+ Tailor::Lexer.any_instance.stub(:ensure_trailing_newline).and_return(file_text)
20
+ end
21
+
22
+ describe "#initialize" do
23
+ context "name of file is passed in" do
24
+ let(:file_name) { "test" }
25
+
26
+ before do
27
+ File.open(file_name, 'w') { |f| f.write "some text" }
28
+ end
29
+
30
+ it "opens and reads the file by the name passed in" do
31
+ file = double "File"
32
+ file.should_receive(:read).and_return file_text
33
+ File.should_receive(:open).with("test", 'r').and_return file
34
+ Tailor::Lexer.new(file_name)
35
+ end
36
+ end
37
+
38
+ context "text to lex is passed in" do
39
+ let(:text) { "some text" }
40
+
41
+ it "doesn't try to open a file" do
42
+ File.should_not_receive(:open)
43
+ Tailor::Lexer.new(text)
44
+ end
45
+ end
46
+ end
47
+
48
+ describe "#on_ignored_nl" do
49
+ it "calls #current_line_lex" do
50
+ pending
51
+ subject.stub(:only_spaces?).and_return true
52
+ subject.should_receive(:current_line_lex)
53
+ subject.on_ignored_nl("\n")
54
+ end
55
+
56
+ context "#only_spaces? is true" do
57
+ pending
58
+ before { subject.stub(:only_spaces?).and_return true }
59
+
60
+ it "does not call #update_actual_indentation" do
61
+ pending
62
+ end
63
+ end
64
+ end
65
+
66
+ describe "#on_sp" do
67
+ context "@config says to disallow hard tabs" do
68
+ before do
69
+ config = { horizontal_spacing: { allow_hard_tabs: false } }
70
+ subject.instance_variable_set(:@config, config)
71
+ end
72
+
73
+ context "token contains a hard tab" do
74
+ it "adds a new problem to @problems" do
75
+ pending "This behavior moved to indent_sp_ruler--move there."
76
+
77
+ subject.instance_variable_set(:@problems, [])
78
+
79
+ expect { subject.on_sp("\t") }.
80
+ to change{subject.instance_variable_get(:@problems).size}.
81
+ from(0).to 1
82
+ end
83
+ end
84
+
85
+ context "token does not contain a hard tab" do
86
+ it "does not add a new problem to @problems" do
87
+ pending "This behavior moved to indent_sp_ruler--move there."
88
+
89
+ subject.instance_variable_set(:@problems, [])
90
+
91
+ expect { subject.on_sp("\x20") }.
92
+ to_not change{subject.instance_variable_get(:@problems).size}.
93
+ from(0).to 1
94
+ end
95
+ end
96
+ end
97
+
98
+ context "@config says to allow hard tabs" do
99
+ before do
100
+ config = { horizontal_spacing: { allow_hard_tabs: true } }
101
+ subject.instance_variable_set(:@config, config)
102
+ end
103
+
104
+ it "does not check the token" do
105
+ token = double "token"
106
+ token.stub(:size)
107
+ token.should_not_receive(:=~)
108
+ subject.on_sp(token)
109
+ end
110
+ end
111
+ end
112
+
113
+ describe "#current_line_of_text" do
114
+ before do
115
+ subject.instance_variable_set(:@file_text, file_text)
116
+ subject.stub(:lineno).and_return 1
117
+ end
118
+
119
+ context "@file_text is 1 line with 0 \\ns" do
120
+ let(:file_text) { "puts 'code'" }
121
+
122
+ it "returns the line" do
123
+ subject.current_line_of_text.should == file_text
124
+ end
125
+ end
126
+
127
+ context "@file_text is 1 empty line with 0 \\ns" do
128
+ let(:file_text) { "" }
129
+
130
+ it "returns the an empty string" do
131
+ subject.current_line_of_text.should == file_text
132
+ end
133
+ end
134
+
135
+ context "@file_text is 1 empty line with 1 \\n" do
136
+ let(:file_text) { "\n" }
137
+
138
+ it "returns an empty string" do
139
+ subject.current_line_of_text.should == ""
140
+ end
141
+ end
142
+ end
143
+
144
+ describe "#count_trailing_newlines" do
145
+ context "text contains 0 trailing \\n" do
146
+ let(:text) { "text" }
147
+ specify { subject.count_trailing_newlines(text).should be_zero }
148
+ end
149
+
150
+ context "text contains 1 trailing \\n" do
151
+ let(:text) { "text\n" }
152
+ specify { subject.count_trailing_newlines(text).should == 1 }
153
+ end
154
+ end
155
+
156
+ describe "#ensure_trailing_newline" do
157
+ before do
158
+ Tailor::Lexer.any_instance.unstub(:ensure_trailing_newline)
159
+ end
160
+
161
+ context "text contains a trailing newline already" do
162
+ let!(:text) { "text\n" }
163
+
164
+ before do
165
+ subject.stub(:count_trailing_newlines).and_return 1
166
+ end
167
+
168
+ it "doesn't alter the text" do
169
+ subject.ensure_trailing_newline(text).should == text
170
+ end
171
+ end
172
+
173
+ context "text does not contain a trailing newline" do
174
+ let!(:text) { "text" }
175
+
176
+ it "adds a newline at the end" do
177
+ subject.ensure_trailing_newline(text).should == text + "\n"
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,6 @@
1
+ require_relative '../spec_helper'
2
+ require 'tailor/cli/options'
3
+
4
+ describe Tailor::CLI::Options do
5
+
6
+ end
@@ -0,0 +1,74 @@
1
+ require_relative '../spec_helper'
2
+ require 'tailor/problem'
3
+
4
+ describe Tailor::Problem do
5
+ before do
6
+ Tailor::Problem.any_instance.stub(:log)
7
+ end
8
+
9
+ let(:lineno) { 10 }
10
+ let(:column) { 11 }
11
+
12
+ describe "#set_values" do
13
+ before do
14
+ Tailor::Problem.any_instance.stub(:message)
15
+ end
16
+
17
+ it "sets self[:type] to the type param" do
18
+ Tailor::Problem.new(:test, lineno, column).should include(type: :test)
19
+ end
20
+
21
+ it "sets self[:line] to the lineno param" do
22
+ Tailor::Problem.new(:test, lineno, column).should include(line: lineno)
23
+ end
24
+
25
+ it "sets self[:column] to 'column' from the binding" do
26
+ Tailor::Problem.new(:test, lineno, column).should include(column: column)
27
+ end
28
+
29
+ it "sets self[:message] to what's returned from #message for @type" do
30
+ Tailor::Problem.any_instance.should_receive(:message).with(:test).
31
+ and_return("test message")
32
+
33
+ problem = Tailor::Problem.new(:test, lineno, column)
34
+ problem.should include(message: "test message")
35
+ end
36
+ end
37
+
38
+ describe "#message" do
39
+ before do
40
+ Tailor::Problem.any_instance.stub(:set_values)
41
+ end
42
+
43
+ context "type is :indentation" do
44
+ it "builds a successful message" do
45
+ options = { actual_indentation: 10, should_be_at: 97 }
46
+ problem = Tailor::Problem.new(:test, lineno, column, options)
47
+ problem.message(:indentation).should match /10.*97/
48
+ end
49
+ end
50
+
51
+ context "type is :trailing_newlines" do
52
+ it "builds a successful message" do
53
+ options = { actual_trailing_newlines: 123, should_have: 777 }
54
+ problem = Tailor::Problem.new(:test, lineno, column, options)
55
+ problem.message(:trailing_newlines).should match /123.*777/
56
+ end
57
+ end
58
+
59
+ context "type is :hard_tab" do
60
+ it "builds a successful message" do
61
+ problem = Tailor::Problem.new(:test, lineno, column)
62
+ problem.message(:hard_tab).should match /Hard tab found./
63
+ end
64
+ end
65
+
66
+ context "type is :line_length" do
67
+ it "builds a successful message" do
68
+ options = { actual_length: 88, should_be_at: 77 }
69
+ problem = Tailor::Problem.new(:test, lineno, column, options)
70
+ problem.message(:line_length).should match /88.*77/
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,53 @@
1
+ require_relative '../spec_helper'
2
+ require 'tailor/reporter'
3
+
4
+ describe Tailor::Reporter do
5
+ describe "#initialize" do
6
+ context "text formatter" do
7
+ let(:formats) { ['text'] }
8
+
9
+ it "creates a new Formatter object of the type passed in" do
10
+ reporter = Tailor::Reporter.new(formats)
11
+ reporter.formatters.first.should be_a Tailor::Formatter::Text
12
+ end
13
+ end
14
+ end
15
+
16
+ describe "#file_report" do
17
+ let(:file_problems) { double "file problems" }
18
+ let(:formatter) { double "Tailor::Formatter::SomeFormatter" }
19
+
20
+ subject do
21
+ t = Tailor::Reporter.new
22
+ t.instance_variable_set(:@formatters, [formatter])
23
+
24
+ t
25
+ end
26
+
27
+ it "calls #file_report on each @formatters" do
28
+ label = :some_label
29
+ formatter.should_receive(:file_report).with(file_problems, label)
30
+
31
+ subject.file_report(file_problems, label)
32
+ end
33
+ end
34
+
35
+ describe "#summary_report" do
36
+ let(:all_problems) { double "all problems" }
37
+ let(:formatter) { double "Tailor::Formatter::SomeFormatter" }
38
+
39
+ subject do
40
+ t = Tailor::Reporter.new
41
+ t.instance_variable_set(:@formatters, [formatter])
42
+
43
+ t
44
+ end
45
+
46
+ it "calls #file_report on each @formatters" do
47
+ label = :some_label
48
+ formatter.should_receive(:summary_report).with(all_problems)
49
+
50
+ subject.summary_report(all_problems)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,56 @@
1
+ require_relative '../spec_helper'
2
+ require 'tailor/ruler'
3
+
4
+ describe Tailor::Ruler do
5
+ before { subject.stub(:log) }
6
+
7
+ describe "#add_child_ruler" do
8
+ it "adds new rulers to @child_rulers" do
9
+ ruler = double "Ruler"
10
+ subject.add_child_ruler(ruler)
11
+ subject.instance_variable_get(:@child_rulers).first.should == ruler
12
+ end
13
+ end
14
+
15
+ describe "#problems" do
16
+ context "no child_rulers" do
17
+ context "@problems is empty" do
18
+ specify { subject.problems.should be_empty }
19
+ end
20
+
21
+ context "@problems.size is 1" do
22
+ before do
23
+ problem = double "Problem"
24
+ problem.should_receive(:[]).with :line
25
+ subject.instance_variable_set(:@problems, [problem])
26
+ end
27
+
28
+ specify { subject.problems.size.should == 1 }
29
+ end
30
+ end
31
+
32
+ context "child_rulers have problems" do
33
+ before do
34
+ problem = double "Problem"
35
+ problem.should_receive(:[]).with :line
36
+ child_ruler = double "Ruler"
37
+ child_ruler.stub(:problems).and_return([problem])
38
+ subject.instance_variable_set(:@child_rulers, [child_ruler])
39
+ end
40
+
41
+ context "@problems is empty" do
42
+ specify { subject.problems.size.should == 1 }
43
+ end
44
+
45
+ context "@problems.size is 1" do
46
+ before do
47
+ problem = double "Problem"
48
+ problem.should_receive(:[]).with :line
49
+ subject.instance_variable_set(:@problems, [problem])
50
+ end
51
+
52
+ specify { subject.problems.size.should == 2 }
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,454 @@
1
+ require 'ripper'
2
+ require_relative '../../../spec_helper'
3
+ require 'tailor/rulers/indentation_spaces_ruler/indentation_manager'
4
+
5
+
6
+ describe Tailor::Rulers::IndentationSpacesRuler::IndentationManager do
7
+ let!(:spaces) { 5 }
8
+ let!(:lexed_line) { double "LexedLine" }
9
+
10
+ before do
11
+ #Tailor::Logger.stub(:log)
12
+ subject.instance_variable_set(:@spaces, spaces)
13
+ end
14
+
15
+ subject do
16
+ Tailor::Rulers::IndentationSpacesRuler::IndentationManager.new spaces
17
+ end
18
+
19
+ describe "#should_be_at" do
20
+ it "returns @proper[:this_line]" do
21
+ subject.instance_variable_set(:@proper, { this_line: 321 })
22
+ subject.should_be_at.should == 321
23
+ end
24
+ end
25
+
26
+ describe "#next_should_be_at" do
27
+ it "returns @proper[:next_line]" do
28
+ subject.instance_variable_set(:@proper, { next_line: 123 })
29
+ subject.next_should_be_at.should == 123
30
+ end
31
+ end
32
+
33
+ describe "#decrease_this_line" do
34
+ let!(:spaces) { 27 }
35
+
36
+ context "#started? is true" do
37
+ before { subject.stub(:started?).and_return true }
38
+
39
+ context "@proper[:this_line] gets decremented < 0" do
40
+ it "sets @proper[:this_line] to 0" do
41
+ subject.instance_variable_set(:@proper, {
42
+ this_line: 0, next_line: 0
43
+ })
44
+
45
+ subject.decrease_this_line
46
+ proper_indentation = subject.instance_variable_get(:@proper)
47
+ proper_indentation[:this_line].should == 0
48
+ end
49
+ end
50
+
51
+ context "@proper[:this_line] NOT decremented < 0" do
52
+ it "decrements @proper[:this_line] by @spaces" do
53
+ subject.instance_variable_set(:@proper, {
54
+ this_line: 28, next_line: 28
55
+ })
56
+ subject.decrease_this_line
57
+
58
+ proper_indentation = subject.instance_variable_get(:@proper)
59
+ proper_indentation[:this_line].should == 1
60
+ end
61
+ end
62
+ end
63
+
64
+ context "#started? is false" do
65
+ before { subject.stub(:started?).and_return false }
66
+
67
+ it "does not decrement @proper[:this_line]" do
68
+ subject.instance_variable_set(:@proper, {
69
+ this_line: 28, next_line: 28
70
+ })
71
+ subject.decrease_this_line
72
+
73
+ proper_indentation = subject.instance_variable_get(:@proper)
74
+ proper_indentation[:this_line].should == 28
75
+ end
76
+ end
77
+ end
78
+
79
+ describe "#increase_next_line" do
80
+ context "#started? is true" do
81
+ before { subject.stub(:started?).and_return true }
82
+
83
+ it "increases @proper[:next_line] by @spaces" do
84
+ expect { subject.increase_next_line }.to change{subject.next_should_be_at}.
85
+ by(spaces)
86
+ end
87
+ end
88
+
89
+ context "#started? is false" do
90
+ before { subject.stub(:started?).and_return false }
91
+
92
+ it "does not increases @proper[:next_line]" do
93
+ expect { subject.increase_next_line }.to_not change{subject.next_should_be_at}.
94
+ by(spaces)
95
+ end
96
+ end
97
+ end
98
+
99
+ describe "#decrease_next_line" do
100
+ let!(:spaces) { 27 }
101
+
102
+ context "#started? is true" do
103
+ before { subject.stub(:started?).and_return true }
104
+
105
+ it "decrements @proper[:next_line] by @spaces" do
106
+ expect { subject.decrease_next_line }.to change{subject.next_should_be_at}.
107
+ by(-spaces)
108
+ end
109
+ end
110
+
111
+ context "#started? is false" do
112
+ before { subject.stub(:started?).and_return false }
113
+
114
+ it "decrements @proper[:next_line] by @spaces" do
115
+ expect { subject.decrease_next_line }.to_not change{subject.next_should_be_at}.
116
+ by(-spaces)
117
+ end
118
+ end
119
+ end
120
+
121
+ describe "#set_up_line_transition" do
122
+ context "@amount_to_change_next > 0" do
123
+ before { subject.instance_variable_set(:@amount_to_change_next, 1) }
124
+
125
+ it "should call #increase_next_line" do
126
+ subject.should_receive(:increase_next_line)
127
+ subject.set_up_line_transition
128
+ end
129
+ end
130
+
131
+ context "@amount_to_change_next < 0" do
132
+ before { subject.instance_variable_set(:@amount_to_change_next, -1) }
133
+
134
+ it "should call #increase_next_line" do
135
+ subject.should_receive(:decrease_next_line)
136
+ subject.set_up_line_transition
137
+ end
138
+ end
139
+
140
+ context "@amount_to_change_this < 0" do
141
+ before { subject.instance_variable_set(:@amount_to_change_this, -1) }
142
+
143
+ it "should call #decrease_this_line" do
144
+ subject.should_receive(:decrease_this_line)
145
+ subject.set_up_line_transition
146
+ end
147
+ end
148
+ end
149
+
150
+ describe "#transition_lines" do
151
+ context "#started? is true" do
152
+ before { subject.stub(:started?).and_return true }
153
+
154
+ it "sets @proper[:this_line] to @proper[:next_line]" do
155
+ subject.instance_variable_set(:@proper, { next_line: 33 })
156
+
157
+ expect { subject.transition_lines }.to change{subject.should_be_at}.
158
+ from(subject.should_be_at).to(subject.next_should_be_at)
159
+ end
160
+ end
161
+
162
+ context "#started? is true" do
163
+ before { subject.stub(:started?).and_return false }
164
+
165
+ it "sets @proper[:this_line] to @proper[:next_line]" do
166
+ subject.instance_variable_set(:@proper, { next_line: 33 })
167
+
168
+ expect { subject.transition_lines }.to_not change{subject.should_be_at}.
169
+ from(subject.should_be_at).to(subject.next_should_be_at)
170
+ end
171
+ end
172
+ end
173
+
174
+ describe "#start" do
175
+ it "sets @do_measurement to true" do
176
+ subject.instance_variable_set(:@do_measurement, false)
177
+ subject.start
178
+ subject.instance_variable_get(:@do_measurement).should be_true
179
+ end
180
+ end
181
+
182
+ describe "#stop" do
183
+ it "sets @do_measurement to false" do
184
+ subject.instance_variable_set(:@do_measurement, true)
185
+ subject.stop
186
+ subject.instance_variable_get(:@do_measurement).should be_false
187
+ end
188
+ end
189
+
190
+ describe "#started?" do
191
+ context "@do_measurement is true" do
192
+ before { subject.instance_variable_set(:@do_measurement, true) }
193
+ specify { subject.started?.should be_true }
194
+ end
195
+
196
+ context "@do_measurement is false" do
197
+ before { subject.instance_variable_set(:@do_measurement, false) }
198
+ specify { subject.started?.should be_false }
199
+ end
200
+ end
201
+
202
+ describe "#update_actual_indentation" do
203
+ context "lexed_line_output.end_of_multi_line_string? is true" do
204
+ before do
205
+ lexed_line.stub(:end_of_multi_line_string?).and_return true
206
+ end
207
+
208
+ it "returns without updating @actual_indentation" do
209
+ lexed_line.should_not_receive(:first_non_space_element)
210
+ subject.update_actual_indentation(lexed_line)
211
+ end
212
+ end
213
+
214
+ context "lexed_line_output.end_of_multi_line_string? is false" do
215
+ before do
216
+ lexed_line.stub(:end_of_multi_line_string?).and_return false
217
+ lexed_line.stub(:first_non_space_element).
218
+ and_return first_non_space_element
219
+ end
220
+
221
+ context "when indented" do
222
+ let(:first_non_space_element) do
223
+ [[1, 5], :on_comma, ',']
224
+ end
225
+
226
+ it "returns the column value of that element" do
227
+ subject.update_actual_indentation(lexed_line)
228
+ subject.instance_variable_get(:@actual_indentation).should == 5
229
+ end
230
+ end
231
+
232
+ context "when not indented" do
233
+ let(:first_non_space_element) do
234
+ [[1, 0], :on_kw, 'class']
235
+ end
236
+
237
+ it "returns the column value of that element" do
238
+ subject.update_actual_indentation(lexed_line)
239
+ subject.instance_variable_get(:@actual_indentation).should == 0
240
+ end
241
+ end
242
+ end
243
+ end
244
+
245
+ describe "#line_ends_with_single_token_indenter?" do
246
+ context "lexed_line doesn't end with an op, comma, or period" do
247
+ before do
248
+ lexed_line.stub(ends_with_op?: false)
249
+ lexed_line.stub(ends_with_comma?: false)
250
+ lexed_line.stub(ends_with_period?: false)
251
+ end
252
+
253
+ specify { subject.line_ends_with_single_token_indenter?(lexed_line).should be_false }
254
+ end
255
+
256
+ context "lexed_line ends with an op" do
257
+ before do
258
+ lexed_line.stub(ends_with_op?: true)
259
+ lexed_line.stub(ends_with_comma?: false)
260
+ lexed_line.stub(ends_with_period?: false)
261
+ end
262
+
263
+ specify { subject.line_ends_with_single_token_indenter?(lexed_line).should be_true }
264
+ end
265
+
266
+ context "lexed_line ends with a comma" do
267
+ before do
268
+ lexed_line.stub(ends_with_op?: false)
269
+ lexed_line.stub(ends_with_comma?: true)
270
+ lexed_line.stub(ends_with_period?: false)
271
+ end
272
+
273
+ specify { subject.line_ends_with_single_token_indenter?(lexed_line).should be_true }
274
+ end
275
+
276
+ context "lexed_line ends with a period" do
277
+ before do
278
+ lexed_line.stub(ends_with_op?: false)
279
+ lexed_line.stub(ends_with_comma?: false)
280
+ lexed_line.stub(ends_with_period?: true)
281
+ end
282
+
283
+ specify { subject.line_ends_with_single_token_indenter?(lexed_line).should be_true }
284
+ end
285
+ end
286
+
287
+ describe "#line_ends_with_same_as_last" do
288
+ context "@single_tokens is empty" do
289
+ before do
290
+ subject.instance_variable_set(:@single_tokens, [])
291
+ end
292
+
293
+ it "returns false" do
294
+ subject.line_ends_with_same_as_last([]).should be_false
295
+ end
296
+ end
297
+
298
+ context "@single_tokens.last[:token] != token_event.last" do
299
+ let(:last_single_token) { [[1, 2], :on_comma, ','] }
300
+
301
+ before do
302
+ subject.instance_variable_set(:@single_tokens, [{ event: :on_op }])
303
+ end
304
+
305
+ it "returns false" do
306
+ subject.line_ends_with_same_as_last(last_single_token).should be_false
307
+ end
308
+ end
309
+
310
+ context "@single_tokens.last[:token] == token_event.last" do
311
+ let(:last_single_token) { [[1, 2], :on_comma, ','] }
312
+
313
+ before do
314
+ subject.instance_variable_set(:@single_tokens, [{ event: :on_comma }])
315
+ end
316
+
317
+ it "returns false" do
318
+ subject.line_ends_with_same_as_last(last_single_token).should be_true
319
+ end
320
+ end
321
+ end
322
+
323
+ describe "#comma_is_part_of_enclosed_statement?" do
324
+ context "lexed_line does not end with a comma" do
325
+ before { lexed_line.stub(ends_with_comma?: false) }
326
+
327
+ it "returns false" do
328
+ subject.comma_is_part_of_enclosed_statement?(lexed_line, 1).
329
+ should be_false
330
+ end
331
+ end
332
+
333
+ context "lexed_line ends with a comma" do
334
+ before { lexed_line.stub(ends_with_comma?: true) }
335
+
336
+ context "continuing_enclosed_statement? is true" do
337
+ before { subject.stub(continuing_enclosed_statement?: true) }
338
+
339
+ it "returns true" do
340
+ subject.comma_is_part_of_enclosed_statement?(lexed_line, 1).
341
+ should be_true
342
+ end
343
+ end
344
+
345
+ context "continuing_enclosed_statement? is true" do
346
+ before { subject.stub(continuing_enclosed_statement?: false) }
347
+
348
+ it "returns false" do
349
+ subject.comma_is_part_of_enclosed_statement?(lexed_line, 1).
350
+ should be_false
351
+ end
352
+ end
353
+ end
354
+ end
355
+
356
+ describe "#keyword_and_single_token_line?" do
357
+ context "no @double_tokens on this line" do
358
+ before do
359
+ d_tokens = [{ lineno: 12345 }]
360
+ subject.instance_variable_set(:@double_tokens, d_tokens)
361
+ end
362
+
363
+ it "returns false" do
364
+ subject.keyword_and_single_token_line?(1).should be_false
365
+ end
366
+ end
367
+
368
+ context "@double_tokens exist on this line" do
369
+ context "no kw tokens on this line" do
370
+ before do
371
+ d_tokens = [{ token: '{', lineno: 1 }]
372
+ subject.instance_variable_set(:@double_tokens, d_tokens)
373
+ end
374
+
375
+ it "returns false" do
376
+ subject.keyword_and_single_token_line?(1).should be_false
377
+ end
378
+ end
379
+
380
+ context "kw tokens on this line" do
381
+ before do
382
+ d_tokens = [{ token: 'class', lineno: 1 }]
383
+ subject.instance_variable_set(:@double_tokens, d_tokens)
384
+ end
385
+
386
+ context "no @single_tokens on this line" do
387
+ it "returns false" do
388
+ subject.keyword_and_single_token_line?(1).should be_false
389
+ end
390
+ end
391
+
392
+ context "@single_tokens exist on this line" do
393
+ before do
394
+ s_tokens = [{ token: '[', lineno: 1 }]
395
+ subject.instance_variable_set(:@single_tokens, s_tokens)
396
+ end
397
+
398
+ it "returns true" do
399
+ subject.keyword_and_single_token_line?(1).should be_true
400
+ end
401
+ end
402
+ end
403
+ end
404
+ end
405
+
406
+ describe "#multi_line_braces?" do
407
+ pending
408
+ end
409
+
410
+ describe "#multi_line_brackets?" do
411
+ pending
412
+ end
413
+
414
+ describe "#multi_line_parens?" do
415
+ context "an unclosed ( exists on the previous line" do
416
+ context "an unclosed ( does not exist on the current line" do
417
+ before do
418
+ d_tokens = [{ token: '(', lineno: 1 }]
419
+ subject.instance_variable_set(:@double_tokens, d_tokens)
420
+ end
421
+
422
+ it "returns true" do
423
+ subject.multi_line_parens?(2).should be_true
424
+ end
425
+ end
426
+
427
+ context "an unclosed ( exists on the current line" do
428
+ before do
429
+ d_tokens = [{ token: '(', lineno: 1 }, { token: '(', lineno: 2 }]
430
+ subject.instance_variable_set(:@double_tokens, d_tokens)
431
+ end
432
+
433
+ it "returns true" do
434
+ subject.multi_line_parens?(2).should be_false
435
+ end
436
+ end
437
+ end
438
+
439
+ context "an unclosed ( does not exist on the previous line" do
440
+ before do
441
+ d_tokens = [{ token: '(', lineno: 1 }]
442
+ subject.instance_variable_set(:@double_tokens, d_tokens)
443
+ end
444
+
445
+ it "returns true" do
446
+ subject.multi_line_parens?(1).should be_false
447
+ end
448
+ end
449
+ end
450
+
451
+ describe "#in_tstring?" do
452
+ pending
453
+ end
454
+ end