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.
- data/.document +5 -0
- data/.gitignore +23 -0
- data/LICENSE +45 -0
- data/README.rdoc +17 -0
- data/Rakefile +77 -0
- data/TODO.md +17 -0
- data/VERSION +1 -0
- data/bin/wool +4 -0
- data/features/step_definitions/wool_steps.rb +39 -0
- data/features/support/env.rb +14 -0
- data/features/support/testdata/1_input +1 -0
- data/features/support/testdata/1_output +1 -0
- data/features/support/testdata/2_input +4 -0
- data/features/support/testdata/2_output +4 -0
- data/features/support/testdata/3_input +8 -0
- data/features/support/testdata/3_output +11 -0
- data/features/support/testdata/4_input +5 -0
- data/features/support/testdata/4_output +5 -0
- data/features/wool.feature +24 -0
- data/lib/wool.rb +40 -0
- data/lib/wool/advice/advice.rb +42 -0
- data/lib/wool/advice/comment_advice.rb +37 -0
- data/lib/wool/analysis/annotations.rb +34 -0
- data/lib/wool/analysis/annotations/next_annotation.rb +26 -0
- data/lib/wool/analysis/annotations/parent_annotation.rb +20 -0
- data/lib/wool/analysis/annotations/scope_annotation.rb +37 -0
- data/lib/wool/analysis/lexical_analysis.rb +165 -0
- data/lib/wool/analysis/protocol_registry.rb +32 -0
- data/lib/wool/analysis/protocols.rb +82 -0
- data/lib/wool/analysis/scope.rb +13 -0
- data/lib/wool/analysis/sexp_analysis.rb +98 -0
- data/lib/wool/analysis/signature.rb +16 -0
- data/lib/wool/analysis/symbol.rb +10 -0
- data/lib/wool/analysis/visitor.rb +36 -0
- data/lib/wool/analysis/wool_class.rb +47 -0
- data/lib/wool/rake/task.rb +42 -0
- data/lib/wool/runner.rb +156 -0
- data/lib/wool/scanner.rb +160 -0
- data/lib/wool/support/module_extensions.rb +84 -0
- data/lib/wool/third_party/trollop.rb +845 -0
- data/lib/wool/warning.rb +145 -0
- data/lib/wool/warnings/comment_spacing.rb +30 -0
- data/lib/wool/warnings/extra_blank_lines.rb +29 -0
- data/lib/wool/warnings/extra_whitespace.rb +15 -0
- data/lib/wool/warnings/line_length.rb +113 -0
- data/lib/wool/warnings/misaligned_unindentation.rb +16 -0
- data/lib/wool/warnings/operator_spacing.rb +63 -0
- data/lib/wool/warnings/rescue_exception.rb +41 -0
- data/lib/wool/warnings/semicolon.rb +24 -0
- data/lib/wool/warnings/useless_double_quotes.rb +37 -0
- data/spec/advice_specs/advice_spec.rb +69 -0
- data/spec/advice_specs/comment_advice_spec.rb +38 -0
- data/spec/advice_specs/spec_helper.rb +1 -0
- data/spec/analysis_specs/annotations_specs/next_prev_annotation_spec.rb +47 -0
- data/spec/analysis_specs/annotations_specs/parent_annotation_spec.rb +41 -0
- data/spec/analysis_specs/annotations_specs/spec_helper.rb +5 -0
- data/spec/analysis_specs/lexical_analysis_spec.rb +179 -0
- data/spec/analysis_specs/protocol_registry_spec.rb +58 -0
- data/spec/analysis_specs/protocols_spec.rb +49 -0
- data/spec/analysis_specs/scope_spec.rb +20 -0
- data/spec/analysis_specs/sexp_analysis_spec.rb +134 -0
- data/spec/analysis_specs/spec_helper.rb +2 -0
- data/spec/analysis_specs/visitor_spec.rb +53 -0
- data/spec/analysis_specs/wool_class_spec.rb +54 -0
- data/spec/rake_specs/spec_helper.rb +1 -0
- data/spec/rake_specs/task_spec.rb +67 -0
- data/spec/runner_spec.rb +171 -0
- data/spec/scanner_spec.rb +75 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +93 -0
- data/spec/support_specs/module_extensions_spec.rb +91 -0
- data/spec/support_specs/spec_helper.rb +1 -0
- data/spec/warning_spec.rb +95 -0
- data/spec/warning_specs/comment_spacing_spec.rb +57 -0
- data/spec/warning_specs/extra_blank_lines_spec.rb +70 -0
- data/spec/warning_specs/extra_whitespace_spec.rb +33 -0
- data/spec/warning_specs/line_length_spec.rb +165 -0
- data/spec/warning_specs/misaligned_unindentation_spec.rb +35 -0
- data/spec/warning_specs/operator_spacing_spec.rb +101 -0
- data/spec/warning_specs/rescue_exception_spec.rb +105 -0
- data/spec/warning_specs/semicolon_spec.rb +58 -0
- data/spec/warning_specs/spec_helper.rb +1 -0
- data/spec/warning_specs/useless_double_quotes_spec.rb +62 -0
- data/spec/wool_spec.rb +8 -0
- data/status_reports/2010/12/2010-12-14.md +163 -0
- data/test/third_party_tests/test_trollop.rb +1181 -0
- data/wool.gemspec +173 -0
- metadata +235 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
# Warning for using semicolons outside of class declarations.
|
2
|
+
class Wool::SemicolonWarning < Wool::LineWarning
|
3
|
+
type :style
|
4
|
+
short_desc 'Semicolon for multiple statements'
|
5
|
+
desc 'The line uses a semicolon to separate multiple statements outside of a class declaration.'
|
6
|
+
|
7
|
+
def initialize(*args)
|
8
|
+
super
|
9
|
+
self.severity = line =~ /['"]/ ? 2 : 4
|
10
|
+
end
|
11
|
+
|
12
|
+
def match?(line = self.body)
|
13
|
+
!!(find_token(line, :on_semicolon) && !find_keyword(line, :class))
|
14
|
+
end
|
15
|
+
|
16
|
+
def fix(line = self.body)
|
17
|
+
left, right = split_on_token(line, :on_semicolon)
|
18
|
+
return line if right.empty?
|
19
|
+
return right[1..-1] if left.empty?
|
20
|
+
|
21
|
+
right = fix(right[1..-1])
|
22
|
+
"#{indent left}\n#{indent right}"
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Warning for using semicolons outside of class declarations.
|
2
|
+
class Wool::UselessDoubleQuotesWarning < Wool::FileWarning
|
3
|
+
type :style
|
4
|
+
severity 1
|
5
|
+
short_desc 'Useless double quotes'
|
6
|
+
setting_accessor :quoted_string, :uses_q_braces
|
7
|
+
desc do
|
8
|
+
if uses_q_braces
|
9
|
+
then "The string %q{#{quoted_string}} can be written with lowercase q for efficiency."
|
10
|
+
else "The string '#{quoted_string}' can be wrapped in single quotes for efficiency."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def match?(body = self.body)
|
15
|
+
list = find_sexps(:string_content)
|
16
|
+
list.map do |sym, *parts|
|
17
|
+
next if parts.size != 1 # ignore multiparts as they're fine
|
18
|
+
inner_sym, text, pos = parts.first
|
19
|
+
# skip if the string has a backslash or an apostrophe in it.
|
20
|
+
next unless inner_sym == :@tstring_content && text !~ /(\\)|(')/
|
21
|
+
|
22
|
+
previous_char = body.lines.to_a[pos[0] - 1][pos[1]-1,1]
|
23
|
+
uses_q_braces = (previous_char == '{' && body.lines.to_a[pos[0] - 1][pos[1]-3,2] == '%Q')
|
24
|
+
if previous_char == '"' || uses_q_braces
|
25
|
+
warning = Wool::UselessDoubleQuotesWarning.new(
|
26
|
+
file, body, :quoted_string => text, :uses_q_braces => uses_q_braces)
|
27
|
+
warning.line_number = pos[0]
|
28
|
+
warning
|
29
|
+
end
|
30
|
+
end.compact
|
31
|
+
end
|
32
|
+
|
33
|
+
def fix(body = self.body)
|
34
|
+
body.gsub("\"#{quoted_string}\"", "'#{quoted_string}'").
|
35
|
+
gsub("%Q{#{quoted_string}}", "%q{#{quoted_string}}")
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Advice do
|
4
|
+
context '#before_advice' do
|
5
|
+
before do
|
6
|
+
@class = Class.new do
|
7
|
+
extend Advice
|
8
|
+
attr_accessor :closed_over
|
9
|
+
define_method :silly do
|
10
|
+
self.closed_over ||= 1
|
11
|
+
self.closed_over += 5
|
12
|
+
end
|
13
|
+
define_method :checkin do
|
14
|
+
self.closed_over ||= 1
|
15
|
+
self.closed_over *= 2
|
16
|
+
end
|
17
|
+
before_advice :silly, :checkin
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'causes the advised method to run the suggested advice before running' do
|
22
|
+
@class.new.silly.should == 7
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context '#after_advice' do
|
27
|
+
before do
|
28
|
+
@class = Class.new do
|
29
|
+
extend Advice
|
30
|
+
attr_accessor :closed_over
|
31
|
+
define_method :silly do
|
32
|
+
self.closed_over ||= 1
|
33
|
+
self.closed_over += 5
|
34
|
+
end
|
35
|
+
define_method :checkout do
|
36
|
+
self.closed_over ||= 1
|
37
|
+
self.closed_over *= 2
|
38
|
+
end
|
39
|
+
after_advice :silly, :checkout
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'causes the advised method to run the suggested advice after running' do
|
44
|
+
object = @class.new
|
45
|
+
object.silly
|
46
|
+
object.closed_over.should == 12
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context '#argument_advice' do
|
51
|
+
before do
|
52
|
+
@class = Class.new do
|
53
|
+
extend Advice
|
54
|
+
attr_accessor :closed_over
|
55
|
+
define_method :silly do |arg|
|
56
|
+
arg + 5
|
57
|
+
end
|
58
|
+
define_method :twiddle do |arg|
|
59
|
+
arg * 2
|
60
|
+
end
|
61
|
+
argument_advice :silly, :twiddle
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'causes the advised method to run, rewriting the arguments' do
|
66
|
+
@class.new.silly(1).should == 7
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Advice::CommentAdvice do
|
4
|
+
before do
|
5
|
+
@class = Class.new(Warning) do
|
6
|
+
include Advice::CommentAdvice
|
7
|
+
|
8
|
+
def match?(body = self.body, settings={})
|
9
|
+
body
|
10
|
+
end
|
11
|
+
remove_comments
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context '#remove_comments' do
|
16
|
+
it 'Returns the empty string unmodified' do
|
17
|
+
@class.new('(stdin)', '').match?('').should == ''
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'Turns a comment into the empty string' do
|
21
|
+
@class.new('(stdin)', '# hello').match?('# hello').should == ''
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'strips the comments from the end of a string of code' do
|
25
|
+
@class.new('(stdin)', 'a + b # adding').match?('a + b # adding').should == 'a + b'
|
26
|
+
end
|
27
|
+
|
28
|
+
SAMPLES = [['', ''], ['#hello', ''], [' # hello', ''],
|
29
|
+
[' a + b # hello', ' a + b'], ['(a + b) #', '(a + b)'],
|
30
|
+
['"#" + number', '"#" + number'],
|
31
|
+
['" hello \\"mam\\"" # comment', '" hello \\"mam\\""']]
|
32
|
+
SAMPLES.each do |input, output|
|
33
|
+
it "should turn #{input} into #{output}" do
|
34
|
+
@class.new('(stdin)', input).match?(input).should == output
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
require 'set'
|
3
|
+
describe NextPrevAnnotation do
|
4
|
+
it 'adds the #next and #prev methods to Sexp' do
|
5
|
+
Sexp.instance_methods.should include(:next)
|
6
|
+
Sexp.instance_methods.should include(:prev)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'adds next and prevs to each node with a toy example' do
|
10
|
+
tree = Sexp.new([:abc, Sexp.new([:def, 1, 2]),
|
11
|
+
Sexp.new([:zzz, Sexp.new([:return]), "hi", Sexp.new([:silly, 4])])])
|
12
|
+
NextPrevAnnotation::Annotator.new.annotate!(tree)
|
13
|
+
tree[1].prev.should == nil
|
14
|
+
tree[1].next.should == tree[2]
|
15
|
+
tree[2].prev.should == tree[1]
|
16
|
+
tree[2].next.should == nil
|
17
|
+
tree[2][1].prev.should == nil
|
18
|
+
tree[2][1].next.should == tree[2][2]
|
19
|
+
tree[2][3].prev.should == tree[2][2]
|
20
|
+
tree[2][3].next.should == nil
|
21
|
+
end
|
22
|
+
|
23
|
+
# This will actually verify that every node in the tree has a
|
24
|
+
# proper parent set. It's a complex, but thorough test.
|
25
|
+
it 'adds next and prevs to each node with a real-world parse result' do
|
26
|
+
tree = Sexp.new(Ripper.sexp('x = proc {|x, *rst, &blk| p x ** rst[0]; blk.call(rst[1..-1])}'))
|
27
|
+
tree.next.should == nil
|
28
|
+
tree.prev.should == nil
|
29
|
+
visited = Set.new
|
30
|
+
to_visit = tree.children
|
31
|
+
while to_visit.any?
|
32
|
+
todo = to_visit.pop
|
33
|
+
next unless is_sexp?(todo)
|
34
|
+
|
35
|
+
todo.prev.next.should == todo if is_sexp?(todo.prev)
|
36
|
+
todo.next.prev.should == todo if is_sexp?(todo.next)
|
37
|
+
|
38
|
+
visited << todo
|
39
|
+
case todo[0]
|
40
|
+
when Array
|
41
|
+
to_visit.concat todo
|
42
|
+
when Symbol
|
43
|
+
to_visit.concat todo.children
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
require 'set'
|
3
|
+
describe ParentAnnotation do
|
4
|
+
it 'adds the #parent method to Sexp' do
|
5
|
+
Sexp.instance_methods.should include(:parent)
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'adds parents to each node with a toy example' do
|
9
|
+
tree = Sexp.new([:abc, Sexp.new([:def, 1, 2]),
|
10
|
+
Sexp.new([:zzz, Sexp.new([:return]), "hi", Sexp.new([:silly, 4])])])
|
11
|
+
ParentAnnotation::Annotator.new.annotate!(tree)
|
12
|
+
tree.parent.should == nil
|
13
|
+
tree[1].parent.should == tree
|
14
|
+
tree[2].parent.should == tree
|
15
|
+
tree[2][1].parent.should == tree[2]
|
16
|
+
tree[2][3].parent.should == tree[2]
|
17
|
+
end
|
18
|
+
|
19
|
+
# This will actually verify that every node in the tree has a
|
20
|
+
# proper parent set. It's a complex, but thorough test.
|
21
|
+
it 'adds parents to each node with a real-world parse result' do
|
22
|
+
tree = Sexp.new(Ripper.sexp('x = proc {|x, *rst, &blk| p x ** rst[0]; blk.call(rst[1..-1])}'))
|
23
|
+
tree.parent.should == nil
|
24
|
+
tree.children[0].parent.should == tree
|
25
|
+
visited = Set.new
|
26
|
+
to_visit = tree.children
|
27
|
+
while to_visit.any?
|
28
|
+
todo = to_visit.pop
|
29
|
+
next unless Sexp === todo
|
30
|
+
todo.parent.children.should include(todo)
|
31
|
+
visited << todo
|
32
|
+
|
33
|
+
case todo[0]
|
34
|
+
when Array
|
35
|
+
to_visit.concat todo
|
36
|
+
when Symbol
|
37
|
+
to_visit.concat todo.children
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe LexicalAnalysis do
|
4
|
+
before do
|
5
|
+
@class = Class.new do
|
6
|
+
include LexicalAnalysis
|
7
|
+
attr_accessor :body
|
8
|
+
def initialize(body)
|
9
|
+
self.body = body
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context '#lex' do
|
15
|
+
it 'lexes its body' do
|
16
|
+
@class.new('a').lex.should == [LexicalAnalysis::Token.new([[1,0], :on_ident, 'a'])]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context '#text_between_token_positions' do
|
21
|
+
it 'finds the exclusive text between two simple tokens from a body text' do
|
22
|
+
body = "def initialize(body)\n self.body = body\nend"
|
23
|
+
left = LexicalAnalysis::Token.new([[2, 4], :on_kw, "self"])
|
24
|
+
right = LexicalAnalysis::Token.new([[2, 20], :on_nl, "\n"])
|
25
|
+
@class.new('').text_between_token_positions(body, left, right).should ==
|
26
|
+
'.body = body'
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'allows including the left token with the inclusive :left hash option' do
|
30
|
+
body = "def initialize(body)\n self.body = body\nend"
|
31
|
+
left = LexicalAnalysis::Token.new([[2, 4], :on_kw, "self"])
|
32
|
+
right = LexicalAnalysis::Token.new([[2, 20], :on_nl, "\n"])
|
33
|
+
@class.new('').text_between_token_positions(body, left, right, :left).should ==
|
34
|
+
'self.body = body'
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'allows including the right token with the inclusive :right hash option' do
|
38
|
+
body = "def initialize(body)\n self.body = body\nend"
|
39
|
+
left = LexicalAnalysis::Token.new([[2, 4], :on_kw, "self"])
|
40
|
+
right = LexicalAnalysis::Token.new([[2, 20], :on_nl, "\n"])
|
41
|
+
@class.new('').text_between_token_positions(body, left, right, :right).should ==
|
42
|
+
".body = body\n"
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'allows including both tokens with the inclusive :both hash option' do
|
46
|
+
body = "def initialize(body)\n self.body = body\nend"
|
47
|
+
left = LexicalAnalysis::Token.new([[2, 4], :on_kw, "self"])
|
48
|
+
right = LexicalAnalysis::Token.new([[2, 20], :on_nl, "\n"])
|
49
|
+
@class.new('').text_between_token_positions(body, left, right, :both).should ==
|
50
|
+
"self.body = body\n"
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'allows explicitly to exclude the tokens with the inclusive :none option' do
|
54
|
+
body = "def initialize(body)\n self.body = body\nend"
|
55
|
+
left = LexicalAnalysis::Token.new([[2, 4], :on_kw, "self"])
|
56
|
+
right = LexicalAnalysis::Token.new([[2, 20], :on_nl, "\n"])
|
57
|
+
@class.new('').text_between_token_positions(body, left, right, :none).should ==
|
58
|
+
'.body = body'
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'spanning multiple lines' do
|
62
|
+
it 'allows including the left token with the inclusive :left hash option' do
|
63
|
+
body = "def initialize(body)\n self.body = body\nend # a * b"
|
64
|
+
left = LexicalAnalysis::Token.new([[1, 14], :on_lparen, "("])
|
65
|
+
right = LexicalAnalysis::Token.new([[3, 3], :on_sp, " "])
|
66
|
+
@class.new('').text_between_token_positions(body, left, right, :left).should ==
|
67
|
+
"(body)\n self.body = body\nend"
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'allows including the right token with the inclusive :right hash option' do
|
71
|
+
body = "def initialize(body)\n self.body = body\nend # a * b"
|
72
|
+
left = LexicalAnalysis::Token.new([[1, 14], :on_lparen, "("])
|
73
|
+
right = LexicalAnalysis::Token.new([[3, 3], :on_sp, " "])
|
74
|
+
@class.new('').text_between_token_positions(body, left, right, :right).should ==
|
75
|
+
"body)\n self.body = body\nend "
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'allows including both tokens with the inclusive :both hash option' do
|
79
|
+
body = "def initialize(body)\n self.body = body\nend # a * b"
|
80
|
+
left = LexicalAnalysis::Token.new([[1, 14], :on_lparen, "("])
|
81
|
+
right = LexicalAnalysis::Token.new([[3, 3], :on_sp, " "])
|
82
|
+
@class.new('').text_between_token_positions(body, left, right, :both).should ==
|
83
|
+
"(body)\n self.body = body\nend "
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'allows explicitly to exclude the tokens with the inclusive :none option' do
|
87
|
+
body = "def initialize(body)\n self.body = body\nend # a * b"
|
88
|
+
left = LexicalAnalysis::Token.new([[1, 14], :on_lparen, "("])
|
89
|
+
right = LexicalAnalysis::Token.new([[3, 3], :on_sp, " "])
|
90
|
+
@class.new('').text_between_token_positions(body, left, right, :none).should ==
|
91
|
+
"body)\n self.body = body\nend"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context '#find_token' do
|
97
|
+
it 'lexes its body' do
|
98
|
+
@class.new('a + b').find_token(:on_op).should be_true
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'returns falsy if token not found' do
|
102
|
+
@class.new('a + b').find_token(:on_kw).should be_false
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'works with multiple token options' do
|
106
|
+
result = @class.new('a + b # hello').find_token(:on_op, :on_comment)
|
107
|
+
result.type.should == :on_op
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'is not triggered by symbols' do
|
111
|
+
@class.new(':+').find_token(:on_op).should be_false
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context '#find_keyword' do
|
116
|
+
it 'lexes its body' do
|
117
|
+
@class.new('class A < B').find_keyword(:class).should be_true
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'returns falsy if token not found' do
|
121
|
+
@class.new('class A < B').find_keyword(:end).should be_false
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'returns the actual token if it is found' do
|
125
|
+
@class.new('class A < B').find_keyword(:class).should ==
|
126
|
+
LexicalAnalysis::Token.new([[1,0], :on_kw, 'class'])
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'works with multiple keyword options' do
|
130
|
+
result = @class.new('class A < B; end').find_keyword(:class, :end)
|
131
|
+
result.body.should == 'class'
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'is not triggered by symbols' do
|
135
|
+
@class.new(':unless').find_keyword(:unless).should be_false
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context '#split_on_token' do
|
140
|
+
it 'splits the input into two parts based on the token searched' do
|
141
|
+
left, right = @class.new('a + b; c + d').split_on_token(:on_semicolon)
|
142
|
+
left.should == 'a + b'
|
143
|
+
right.should == '; c + d'
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'works with multiple searched tokens' do
|
147
|
+
left, right = @class.new('a + b; c + d').split_on_token(:on_semicolon, :on_op)
|
148
|
+
left.should == 'a '
|
149
|
+
right.should == '+ b; c + d'
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'matches its own documentation' do
|
153
|
+
left, right = @class.new('').split_on_token('x = 5 unless y == 2', :on_kw)
|
154
|
+
left.should == 'x = 5 '
|
155
|
+
right.should == 'unless y == 2'
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
context '#split_on_keyword' do
|
161
|
+
it 'splits the input into two parts based on the token searched' do
|
162
|
+
left, right = @class.new('rescue x if y').split_on_keyword(:if)
|
163
|
+
left.should == 'rescue x '
|
164
|
+
right.should == 'if y'
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'works with multiple searched tokens' do
|
168
|
+
left, right = @class.new('rescue x if y').split_on_keyword(:if, :rescue)
|
169
|
+
left.should == ''
|
170
|
+
right.should == 'rescue x if y'
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'matches its own documentation' do
|
174
|
+
left, right = @class.new('').split_on_keyword('x = 5 unless y == 2', :unless)
|
175
|
+
left.should == 'x = 5 '
|
176
|
+
right.should == 'unless y == 2'
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|