wool 0.5.1

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 (88) hide show
  1. data/.document +5 -0
  2. data/.gitignore +23 -0
  3. data/LICENSE +45 -0
  4. data/README.rdoc +17 -0
  5. data/Rakefile +77 -0
  6. data/TODO.md +17 -0
  7. data/VERSION +1 -0
  8. data/bin/wool +4 -0
  9. data/features/step_definitions/wool_steps.rb +39 -0
  10. data/features/support/env.rb +14 -0
  11. data/features/support/testdata/1_input +1 -0
  12. data/features/support/testdata/1_output +1 -0
  13. data/features/support/testdata/2_input +4 -0
  14. data/features/support/testdata/2_output +4 -0
  15. data/features/support/testdata/3_input +8 -0
  16. data/features/support/testdata/3_output +11 -0
  17. data/features/support/testdata/4_input +5 -0
  18. data/features/support/testdata/4_output +5 -0
  19. data/features/wool.feature +24 -0
  20. data/lib/wool.rb +40 -0
  21. data/lib/wool/advice/advice.rb +42 -0
  22. data/lib/wool/advice/comment_advice.rb +37 -0
  23. data/lib/wool/analysis/annotations.rb +34 -0
  24. data/lib/wool/analysis/annotations/next_annotation.rb +26 -0
  25. data/lib/wool/analysis/annotations/parent_annotation.rb +20 -0
  26. data/lib/wool/analysis/annotations/scope_annotation.rb +37 -0
  27. data/lib/wool/analysis/lexical_analysis.rb +165 -0
  28. data/lib/wool/analysis/protocol_registry.rb +32 -0
  29. data/lib/wool/analysis/protocols.rb +82 -0
  30. data/lib/wool/analysis/scope.rb +13 -0
  31. data/lib/wool/analysis/sexp_analysis.rb +98 -0
  32. data/lib/wool/analysis/signature.rb +16 -0
  33. data/lib/wool/analysis/symbol.rb +10 -0
  34. data/lib/wool/analysis/visitor.rb +36 -0
  35. data/lib/wool/analysis/wool_class.rb +47 -0
  36. data/lib/wool/rake/task.rb +42 -0
  37. data/lib/wool/runner.rb +156 -0
  38. data/lib/wool/scanner.rb +160 -0
  39. data/lib/wool/support/module_extensions.rb +84 -0
  40. data/lib/wool/third_party/trollop.rb +845 -0
  41. data/lib/wool/warning.rb +145 -0
  42. data/lib/wool/warnings/comment_spacing.rb +30 -0
  43. data/lib/wool/warnings/extra_blank_lines.rb +29 -0
  44. data/lib/wool/warnings/extra_whitespace.rb +15 -0
  45. data/lib/wool/warnings/line_length.rb +113 -0
  46. data/lib/wool/warnings/misaligned_unindentation.rb +16 -0
  47. data/lib/wool/warnings/operator_spacing.rb +63 -0
  48. data/lib/wool/warnings/rescue_exception.rb +41 -0
  49. data/lib/wool/warnings/semicolon.rb +24 -0
  50. data/lib/wool/warnings/useless_double_quotes.rb +37 -0
  51. data/spec/advice_specs/advice_spec.rb +69 -0
  52. data/spec/advice_specs/comment_advice_spec.rb +38 -0
  53. data/spec/advice_specs/spec_helper.rb +1 -0
  54. data/spec/analysis_specs/annotations_specs/next_prev_annotation_spec.rb +47 -0
  55. data/spec/analysis_specs/annotations_specs/parent_annotation_spec.rb +41 -0
  56. data/spec/analysis_specs/annotations_specs/spec_helper.rb +5 -0
  57. data/spec/analysis_specs/lexical_analysis_spec.rb +179 -0
  58. data/spec/analysis_specs/protocol_registry_spec.rb +58 -0
  59. data/spec/analysis_specs/protocols_spec.rb +49 -0
  60. data/spec/analysis_specs/scope_spec.rb +20 -0
  61. data/spec/analysis_specs/sexp_analysis_spec.rb +134 -0
  62. data/spec/analysis_specs/spec_helper.rb +2 -0
  63. data/spec/analysis_specs/visitor_spec.rb +53 -0
  64. data/spec/analysis_specs/wool_class_spec.rb +54 -0
  65. data/spec/rake_specs/spec_helper.rb +1 -0
  66. data/spec/rake_specs/task_spec.rb +67 -0
  67. data/spec/runner_spec.rb +171 -0
  68. data/spec/scanner_spec.rb +75 -0
  69. data/spec/spec.opts +1 -0
  70. data/spec/spec_helper.rb +93 -0
  71. data/spec/support_specs/module_extensions_spec.rb +91 -0
  72. data/spec/support_specs/spec_helper.rb +1 -0
  73. data/spec/warning_spec.rb +95 -0
  74. data/spec/warning_specs/comment_spacing_spec.rb +57 -0
  75. data/spec/warning_specs/extra_blank_lines_spec.rb +70 -0
  76. data/spec/warning_specs/extra_whitespace_spec.rb +33 -0
  77. data/spec/warning_specs/line_length_spec.rb +165 -0
  78. data/spec/warning_specs/misaligned_unindentation_spec.rb +35 -0
  79. data/spec/warning_specs/operator_spacing_spec.rb +101 -0
  80. data/spec/warning_specs/rescue_exception_spec.rb +105 -0
  81. data/spec/warning_specs/semicolon_spec.rb +58 -0
  82. data/spec/warning_specs/spec_helper.rb +1 -0
  83. data/spec/warning_specs/useless_double_quotes_spec.rb +62 -0
  84. data/spec/wool_spec.rb +8 -0
  85. data/status_reports/2010/12/2010-12-14.md +163 -0
  86. data/test/third_party_tests/test_trollop.rb +1181 -0
  87. data/wool.gemspec +173 -0
  88. metadata +235 -0
@@ -0,0 +1,57 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe InlineCommentSpaceWarning do
4
+ SETTINGS = {InlineCommentSpaceWarning::OPTION_KEY => 2, :indent_size => 2}
5
+ it 'is a line-based warning' do
6
+ InlineCommentSpaceWarning.new('(stdin)', 'hello').should be_a(LineWarning)
7
+ end
8
+
9
+ it 'matches when there are less than 2 spaces between code and comment' do
10
+ InlineCommentSpaceWarning.should warn('a + b#comment', SETTINGS)
11
+ InlineCommentSpaceWarning.should warn('a + b # comment', SETTINGS)
12
+ InlineCommentSpaceWarning.should_not warn('a + b # comment', SETTINGS)
13
+ InlineCommentSpaceWarning.should_not warn('a +b # wool: ignore OperatorSpacing', SETTINGS)
14
+ end
15
+
16
+ it 'has an option to specify the necessary spacing' do
17
+ InlineCommentSpaceWarning.options.size.should be > 0
18
+ InlineCommentSpaceWarning.options[0].first.should ==
19
+ InlineCommentSpaceWarning::OPTION_KEY
20
+ end
21
+
22
+ it 'respects the option for specifying the necessary spacing' do
23
+ settings = {InlineCommentSpaceWarning::OPTION_KEY => 0}
24
+ InlineCommentSpaceWarning.should warn('a + b # comment', settings)
25
+ InlineCommentSpaceWarning.should_not warn('a + b# comment', settings)
26
+ end
27
+
28
+ it 'has a remotely useful description' do
29
+ InlineCommentSpaceWarning.new('(stdin)', 'hello #').desc.should =~ /inline.*comment/i
30
+ end
31
+
32
+ context 'when fixing' do
33
+ before do
34
+ @settings = {InlineCommentSpaceWarning::OPTION_KEY => 2}
35
+ end
36
+
37
+ after do
38
+ InlineCommentSpaceWarning.should correct_to(@input, @output, @settings)
39
+ end
40
+
41
+ it 'adds spaces when necessary' do
42
+ @input = 'a + b#comment'
43
+ @output = 'a + b #comment'
44
+ end
45
+
46
+ it 'removes spaces when necessary' do
47
+ @input = 'a + b #comment'
48
+ @output = 'a + b #comment'
49
+ end
50
+
51
+ it 'respects the option for spacing' do
52
+ @settings = {InlineCommentSpaceWarning::OPTION_KEY => 0}
53
+ @input = 'a + b #comment'
54
+ @output = 'a + b#comment'
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,70 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe ExtraBlankLinesWarning do
4
+ it 'is a file-based warning' do
5
+ ExtraBlankLinesWarning.new('(stdin)', 'hello').should be_a(FileWarning)
6
+ FileWarning.all_warnings.should include(ExtraBlankLinesWarning)
7
+ end
8
+
9
+ it 'matches when there is a single empty blank line' do
10
+ ExtraBlankLinesWarning.should warn("a + b\n")
11
+ end
12
+
13
+ it 'matches when there is a single blank line with spaces' do
14
+ ExtraBlankLinesWarning.should warn("a + b\n ")
15
+ end
16
+
17
+ it 'matches when there is are multiple blank lines' do
18
+ ExtraBlankLinesWarning.should warn("a + b\n \n\t\n")
19
+ end
20
+
21
+ it 'counts the number of blank lines' do
22
+ ExtraBlankLinesWarning.new('(stdin)', "a + b\n").count_extra_lines.should == 1
23
+ ExtraBlankLinesWarning.new('(stdin)', "a + b\n\t\n").count_extra_lines.should == 2
24
+ ExtraBlankLinesWarning.new('(stdin)', "a + b\n\n").count_extra_lines.should == 2
25
+ ExtraBlankLinesWarning.new('(stdin)', "a + b\n \n\n").count_extra_lines.should == 3
26
+ ExtraBlankLinesWarning.new('(stdin)', "a + b\n \n\t\n").count_extra_lines.should == 3
27
+ ExtraBlankLinesWarning.new('(stdin)', "a + b\n\n\n\n\n").count_extra_lines.should == 5
28
+ end
29
+
30
+ it 'has a remotely useful description' do
31
+ ExtraBlankLinesWarning.new('(stdin)', 'hello ').desc.should =~ /blank line/
32
+ end
33
+
34
+ INPUTS = ["a + b\n\n\t \t\n\t ", "a + b\n \n\t\n", "a + b\n \n\n",
35
+ "a + b\n\n\n\n\n", "a + b\n", "a + b\n " ]
36
+
37
+ INPUTS.each do |input|
38
+ context "When fixing #{input.inspect}" do
39
+ it 'fixes by removing all extra whitespace' do
40
+ ExtraBlankLinesWarning.should correct_to(input, 'a + b')
41
+ end
42
+ end
43
+ end
44
+
45
+ context 'when fixing a realistic multiline block' do
46
+ before do
47
+ @original = <<-EOF
48
+ # Warning for using semicolons outside of class declarations.
49
+ class SemicolonWarning < LineWarning
50
+
51
+ def initialize(file, line)
52
+ severity = line =~ /['"]/ ? 2 : 4
53
+ super('Semicolon for multiple statements', file, line, 0, severity)
54
+ end
55
+
56
+ def desc
57
+ 'The line uses a semicolon to separate multiple statements outside of a class declaration.'
58
+ end
59
+
60
+ end
61
+ EOF
62
+ @original.strip!
63
+ @invalid = @original + "\n \t\t\n \n\n"
64
+ end
65
+
66
+ it 'only removes the trailing whitespace' do
67
+ ExtraBlankLinesWarning.should correct_to(@invalid, @original)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,33 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe ExtraWhitespaceWarning do
4
+ it 'is a line-based warning' do
5
+ ExtraWhitespaceWarning.new('(stdin)', 'hello').should be_a(LineWarning)
6
+ end
7
+
8
+ it 'matches when there are spaces at the end of a line' do
9
+ ExtraWhitespaceWarning.should warn('a + b ')
10
+ ExtraWhitespaceWarning.should warn('a + b ')
11
+ ExtraWhitespaceWarning.should_not warn('a + b')
12
+ end
13
+
14
+ it 'matches when there are tabs at the end of a line' do
15
+ ExtraWhitespaceWarning.should warn("a + b\t\t")
16
+ ExtraWhitespaceWarning.should warn("a + b\t")
17
+ ExtraWhitespaceWarning.should_not warn('a + b')
18
+ end
19
+
20
+ it 'has a remotely useful description' do
21
+ ExtraWhitespaceWarning.new('(stdin)', 'hello ').desc.should =~ /whitespace/
22
+ end
23
+
24
+ context 'when fixing' do
25
+ it 'fixes by removing extra spaces' do
26
+ ExtraWhitespaceWarning.should correct_to('a + b ', 'a + b')
27
+ end
28
+
29
+ it 'fixes by removing extra tabs' do
30
+ ExtraWhitespaceWarning.should correct_to("a + b\t\t", 'a + b')
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,165 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe GenericLineLengthWarning do
4
+ before do
5
+ @eighty_cap = LineLengthCustomSeverity(80, 2)
6
+ @eighty_cap.line_length_limit = 80
7
+ end
8
+
9
+ it 'is a line-based warning' do
10
+ GenericLineLengthWarning.new('(stdin)', 'hello').should be_a(LineWarning)
11
+ end
12
+
13
+ it 'initializes to a file and line' do
14
+ warning = @eighty_cap.new('(stdin)', 'x' * 81)
15
+ warning.severity.should == @eighty_cap.severity
16
+ end
17
+
18
+ it 'has a remotely useful description' do
19
+ @eighty_cap.new('(stdin)', 'x' * 80).desc.should =~ /line length/i
20
+ end
21
+
22
+ it 'matches lines longer than the specified number of characters' do
23
+ @eighty_cap.should warn('x' * 82)
24
+ end
25
+
26
+ it 'does not match lines shorter than the specified number of characters' do
27
+ @eighty_cap.should_not warn('x' * 78)
28
+ end
29
+
30
+ it 'does not match lines equal to the specified number of characters' do
31
+ @eighty_cap.should_not warn('x' * 80)
32
+ end
33
+
34
+ context 'when fixing' do
35
+ before do
36
+ @twenty_cap = Class.new(GenericLineLengthWarning)
37
+ @twenty_cap.line_length_limit = 20
38
+ @settings = {}
39
+ end
40
+
41
+ after do
42
+ @twenty_cap.should correct_to(@input, @output, @settings)
43
+ end
44
+
45
+ it 'takes a line with just a comment on it and breaks it into many lines' do
46
+ @input = '# my comment is this and that and another thing'
47
+ @output = "# my comment is this\n# and that and\n# another thing"
48
+ end
49
+
50
+ it 'creates new lines with the same indentation as the input' do
51
+ @input = ' # my comment is this and that and another thing'
52
+ @output = " # my comment is\n # this and that\n # and another\n # thing"
53
+ end
54
+
55
+ it 'uses the same number of hashes to denote the comment' do
56
+ @input = ' ## my comment is this and that and another thing'
57
+ @output = " ## my comment is\n ## this and that\n ## and another\n ## thing"
58
+ end
59
+
60
+ it 'splits up code with an overly long comment at the end' do
61
+ @input = ' a + b # this is a stupidly long comment lol'
62
+ @output = " # this is a\n # stupidly long\n # comment lol\n a + b"
63
+ end
64
+
65
+ it 'uses the same indentation and hashes for the new comment' do
66
+ @input = ' a + b ### this is a stupidly long comment lol'
67
+ @output = " ### this is a\n ### stupidly long\n ### comment lol\n a + b"
68
+ end
69
+
70
+ it 'fails to fix when if/unless are in a symbol' do
71
+ # This came from an actual bug from running wool on wool's source.
72
+ @input = " left, right = @class.new('').split_on_keyword('x = 5 unless y == 2', :unless)"
73
+ @output = @input
74
+ end
75
+
76
+ context 'with an indent size of 2' do
77
+ before { @settings = {:indent_size => 2} }
78
+ it "doesn't try to convert the 'end if foobar' technique" do
79
+ @input = ' end if should_run_block?'
80
+ @output = ' end if should_run_block?'
81
+ end
82
+
83
+ it "doesn't try to convert the 'end unless foobar' technique" do
84
+ @input = ' end unless should_run_block?'
85
+ @output = ' end unless should_run_block?'
86
+ end
87
+
88
+ it 'converts lines with guarded ifs into 3 liners' do
89
+ @input = 'puts x if x > y && y.call'
90
+ @output = "if x > y && y.call\n puts x\nend"
91
+ end
92
+
93
+ it 'converts lines with guarded unlesses into 3 liners' do
94
+ @input = 'puts x unless x > number'
95
+ @output = "unless x > number\n puts x\nend"
96
+ end
97
+
98
+ it 'converts lines with guarded ifs while maintaining indentation' do
99
+ @input = ' puts x unless x > number'
100
+ @output = " unless x > number\n puts x\n end"
101
+ end
102
+
103
+ it 'only converts when it finds a guard on the top level expression' do
104
+ @input = %Q[syms.each { |sym| raise ArgumentError, "unknown option '\#{sym}'" unless @specs[sym] }]
105
+ @output = %Q[syms.each { |sym| raise ArgumentError, "unknown option '\#{sym}'" unless @specs[sym] }]
106
+ end
107
+
108
+ it 'only converts when it finds a guard on the real-world top level expression' do
109
+ @input = 'x.select { |x| x if 5 }'
110
+ @output = 'x.select { |x| x if 5 }'
111
+ end
112
+
113
+ it 'converts nested if/unless as guards' do
114
+ @input = 'puts x if foo.bar unless baz.boo'
115
+ @output = "unless baz.boo\n if foo.bar\n puts x\n end\nend"
116
+ end
117
+
118
+ it 'converts nested three if/unless as guards' do
119
+ @input = 'puts x if foo.bar unless baz.boo if alpha.beta'
120
+ @output = "if alpha.beta\n unless baz.boo\n if foo.bar\n puts x\n end\n end\nend"
121
+ end
122
+
123
+ it 'converts nested three if/unless as guards maintaining indentation' do
124
+ @input = ' puts x if foo.bar unless baz.boo if alpha.beta'
125
+ @output = " if alpha.beta\n unless baz.boo\n if foo.bar\n puts x\n end\n end\n end"
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ describe 'LineLengthMaximum' do
132
+ before do
133
+ @hundred_cap = LineLengthMaximum(100)
134
+ end
135
+
136
+ it 'matches lines longer than the specified maximum' do
137
+ @hundred_cap.should warn('x' * 101)
138
+ end
139
+
140
+ it 'has a high severity' do
141
+ @hundred_cap.severity.should >= 7.5
142
+ end
143
+
144
+ it 'does not match lines smaller than the specified maximum' do
145
+ @hundred_cap.should_not warn('x' * 100)
146
+ end
147
+ end
148
+
149
+ describe 'LineLengthWarning' do
150
+ before do
151
+ @hundred_cap = LineLengthWarning(80)
152
+ end
153
+
154
+ it 'matches lines longer than the specified maximum' do
155
+ @hundred_cap.should warn('x' * 81)
156
+ end
157
+
158
+ it 'has a lower severity' do
159
+ @hundred_cap.severity.should <= 4
160
+ end
161
+
162
+ it 'does not match lines smaller than the specified maximum' do
163
+ @hundred_cap.should_not warn('x' * 80)
164
+ end
165
+ end
@@ -0,0 +1,35 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe MisalignedUnindentationWarning do
4
+ context 'when fixing' do
5
+ it 'is a line-based warning' do
6
+ MisalignedUnindentationWarning.new('(stdin)', 'hello', 80).should be_a(LineWarning)
7
+ end
8
+
9
+ it 'matches nothing' do
10
+ MisalignedUnindentationWarning.should_not warn(' a + b', 2)
11
+ end
12
+
13
+ it 'fixes by removing more spaces than expected' do
14
+ MisalignedUnindentationWarning.should correct_to(' a + b', ' a + b', 2)
15
+ end
16
+
17
+ it 'fixes by adding a second space' do
18
+ MisalignedUnindentationWarning.should correct_to(' a + b', ' a + b', 2)
19
+ end
20
+
21
+ it 'fixes by adding indentation' do
22
+ MisalignedUnindentationWarning.should correct_to('a + b', ' a + b', 4)
23
+ end
24
+
25
+ it 'describes the incorrect indentation values' do
26
+ warning = MisalignedUnindentationWarning.new('(stdin)', ' a + b', 2)
27
+ other_warning = MisalignedUnindentationWarning.new('(stdin)', ' a + b', 2)
28
+ warning_3 = MisalignedUnindentationWarning.new('(stdin)', 'a + b', 4)
29
+ warning.desc.should =~ /Expected 2/
30
+ warning.desc.should =~ /found 3/
31
+ other_warning.desc.should =~ /Expected 2/
32
+ other_warning.desc.should =~ /found 1/
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,101 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe OperatorSpacing do
4
+ it 'is a line-based warning' do
5
+ OperatorSpacing.new('(stdin)', 'hello').should be_a(LineWarning)
6
+ end
7
+
8
+ it "doesn't match block declarations" do
9
+ OperatorSpacing.should_not warn('[1, 2].each { |x| p x }')
10
+ OperatorSpacing.should_not warn('[1, 2].each {| y | p x }')
11
+ OperatorSpacing.should_not warn("[1, 2].each do |x|\n p x\nend")
12
+ OperatorSpacing.should_not warn("[1, 2].each do|x|\n p x\nend")
13
+ end
14
+
15
+ it "doesn't match in a comment" do
16
+ OperatorSpacing.should_not warn('hello # a+b')
17
+ end
18
+
19
+ it "doesn't match a <<- heredoc" do
20
+ OperatorSpacing.should_not warn('@original = <<-EOF')
21
+ end
22
+
23
+ it "doesn't match a << heredoc" do
24
+ OperatorSpacing.should_not warn('@original = <<EOF')
25
+ end
26
+
27
+ it "doesn't match adjacent negative numbers" do
28
+ OperatorSpacing.should_not warn(' exit(-1)')
29
+ end
30
+
31
+ it "doesn't match *args in block parameters" do
32
+ OperatorSpacing.should_not warn('list.each do |*args|')
33
+ OperatorSpacing.should_not warn('list.each { |*args| }')
34
+ end
35
+
36
+ it "doesn't match splat arguments" do
37
+ OperatorSpacing.should_not warn('x.call(*args)')
38
+ OperatorSpacing.should_not warn('x.call(a, *args)')
39
+ OperatorSpacing.should_not warn('x.call(*args, b)')
40
+ OperatorSpacing.should_not warn('x.call(a, *args, b)')
41
+ end
42
+
43
+ it "does match multiplication in an argument list" do
44
+ OperatorSpacing.should warn('x.call(a *b)')
45
+ OperatorSpacing.should warn('x.call(x, a *b)')
46
+ OperatorSpacing.should warn('x.call(a *b, z)')
47
+ end
48
+
49
+ it "doesn't match block arguments" do
50
+ OperatorSpacing.should_not warn('x.call(&b)')
51
+ OperatorSpacing.should_not warn('x.call(a, &b)')
52
+ OperatorSpacing.should_not warn('x.call(&b, b)')
53
+ OperatorSpacing.should_not warn('x.call(a, &b, b)')
54
+ end
55
+
56
+ it "doesn't match the [*item] idiom" do
57
+ OperatorSpacing.should_not warn('[*args]')
58
+ end
59
+
60
+ it 'has a reasonable description' do
61
+ OperatorSpacing.new('(stdin)', 'a+ b').desc.should =~ /spacing/
62
+ end
63
+
64
+ OperatorSpacing::OPERATORS.each do |operator|
65
+ context "with #{operator}" do
66
+ it "matches when there is no space on the left side" do
67
+ OperatorSpacing.should warn("a#{operator} b")
68
+ end
69
+
70
+ it "matches when there is no space on the right side" do
71
+ OperatorSpacing.should warn("a #{operator}b")
72
+ end unless operator == '/' # This confuses the shit out of the lexer
73
+
74
+ it "matches when there is no space on both sides" do
75
+ OperatorSpacing.should warn("a#{operator}b")
76
+ end
77
+
78
+ it "doesn't match when there is exactly one space on both sides" do
79
+ OperatorSpacing.should_not warn("a #{operator} b")
80
+ end
81
+
82
+ context 'when fixing' do
83
+ it 'changes nothing when there is one space on both sides' do
84
+ OperatorSpacing.should correct_to("a #{operator} b", "a #{operator} b")
85
+ end
86
+
87
+ it 'fixes by inserting an extra space on the left' do
88
+ OperatorSpacing.should correct_to("a#{operator} b", "a #{operator} b")
89
+ end
90
+
91
+ it 'fixes by inserting an extra space on the right' do
92
+ OperatorSpacing.should correct_to("a #{operator}b", "a #{operator} b")
93
+ end unless operator == '/' # This confuses the shit out of the lexer
94
+
95
+ it 'fixes by inserting an extra space on both sides' do
96
+ OperatorSpacing.should correct_to("a#{operator}b", "a #{operator} b")
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end