ripper_ruby_parser 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -5,13 +5,13 @@ namespace :test do
5
5
  Rake::TestTask.new(:unit) do |t|
6
6
  t.libs = ['lib']
7
7
  t.test_files = FileList['test/unit/*_test.rb']
8
- t.ruby_opts += ["-w"]
8
+ t.warning = true
9
9
  end
10
10
 
11
11
  Rake::TestTask.new(:end_to_end) do |t|
12
12
  t.libs = ['lib']
13
13
  t.test_files = FileList['test/end_to_end/*_test.rb']
14
- t.ruby_opts += ["-w"]
14
+ t.warning = true
15
15
  end
16
16
 
17
17
  task :run => [:unit, :end_to_end]
@@ -7,6 +7,7 @@ module RipperRubyParser
7
7
  super
8
8
  @comment = nil
9
9
  @comment_stack = []
10
+ @in_symbol = false
10
11
  end
11
12
 
12
13
  def on_comment tok
@@ -18,22 +19,42 @@ module RipperRubyParser
18
19
  def on_kw tok
19
20
  case tok
20
21
  when "class", "def", "module"
21
- @comment_stack.push @comment
22
- @comment = nil
22
+ unless @in_symbol
23
+ @comment_stack.push [tok.to_sym, @comment]
24
+ @comment = nil
25
+ end
23
26
  end
24
27
  super
25
28
  end
26
29
 
30
+ def on_module *args
31
+ commentize(:module, super)
32
+ end
33
+
27
34
  def on_class *args
28
- commentize(super)
35
+ commentize(:class, super)
36
+ end
37
+
38
+ def on_sclass *args
39
+ commentize(:class, super)
29
40
  end
30
41
 
31
42
  def on_def *args
32
- commentize(super)
43
+ commentize(:def, super)
33
44
  end
34
45
 
35
- def on_module *args
36
- commentize(super)
46
+ def on_defs *args
47
+ commentize(:def, super)
48
+ end
49
+
50
+ def on_symbeg *args
51
+ @in_symbol = true
52
+ super
53
+ end
54
+
55
+ def on_symbol *args
56
+ @in_symbol = false
57
+ super
37
58
  end
38
59
 
39
60
  def on_parse_error *args
@@ -58,8 +79,13 @@ module RipperRubyParser
58
79
 
59
80
  private
60
81
 
61
- def commentize exp
62
- comment = @comment_stack.pop
82
+ def commentize name, exp
83
+ tok, comment = @comment_stack.pop
84
+ unless tok == name
85
+ p @comment_stack
86
+ p [tok, comment]
87
+ raise "Expected on_#{tok} event, got on_#{name}"
88
+ end
63
89
  if comment.nil?
64
90
  [:comment, "", exp]
65
91
  else
@@ -13,14 +13,28 @@ module RipperRubyParser
13
13
  end
14
14
 
15
15
  def parse source, filename='(string)', lineno=1
16
+ # FIXME: Allow parser class to be passed to #initialize also.
16
17
  parser = CommentingSexpBuilder.new(source, filename, lineno)
17
- result = parser.parse
18
+
19
+ result = suppress_warnings { parser.parse }
18
20
  raise "Ripper parse failed." if result.nil?
21
+
19
22
  exp = Sexp.from_array(result)
23
+
20
24
  @processor.filename = filename
21
25
  @processor.extra_compatible = extra_compatible
22
26
  @processor.process exp
23
27
  end
28
+
29
+ private
30
+
31
+ def suppress_warnings
32
+ old_verbose = $VERBOSE
33
+ $VERBOSE = nil
34
+ result = yield
35
+ $VERBOSE = old_verbose
36
+ result
37
+ end
24
38
  end
25
39
  end
26
40
 
@@ -22,6 +22,11 @@ module RipperRubyParser
22
22
  end
23
23
  process(args)
24
24
  end
25
+
26
+ def process_rest_param exp
27
+ _, ident = exp.shift 2
28
+ s(:splat, process(ident))
29
+ end
25
30
  end
26
31
  end
27
32
  end
@@ -3,15 +3,7 @@ module RipperRubyParser
3
3
  module Arrays
4
4
  def process_array exp
5
5
  _, elems = exp.shift 2
6
- elems = handle_potentially_typeless_sexp(elems)
7
- elems.map! do |elem|
8
- if elem.first.is_a? Symbol
9
- elem
10
- else
11
- elem.first
12
- end
13
- end
14
- s(:array, *elems)
6
+ s(:array, *handle_array_elements(elems))
15
7
  end
16
8
 
17
9
  def process_aref exp
@@ -21,11 +21,11 @@ module RipperRubyParser
21
21
  left.shift
22
22
  end
23
23
 
24
- left = create_multiple_assignement_sub_types left
24
+ left = create_multiple_assignment_sub_types left
25
25
 
26
26
  right = process(right)
27
27
 
28
- unless right.sexp_type == :array
28
+ unless [:array, :splat].include? right.sexp_type
29
29
  right = s(:to_ary, right)
30
30
  end
31
31
 
@@ -35,21 +35,30 @@ module RipperRubyParser
35
35
  def process_mrhs_new_from_args exp
36
36
  _, inner, last = exp.shift 3
37
37
  inner.map! {|item| process(item)}
38
- inner.push process(last)
38
+ inner.push process(last) unless last.nil?
39
39
  s(:array, *inner)
40
40
  end
41
41
 
42
+ def process_mrhs_add_star exp
43
+ exp = generic_add_star exp
44
+ unless exp.first.is_a? Symbol
45
+ exp = exp.first
46
+ end
47
+ exp
48
+ end
49
+
42
50
  def process_mlhs_add_star exp
43
51
  generic_add_star exp
44
52
  end
45
53
 
46
54
  def process_mlhs_paren exp
47
55
  _, contents = exp.shift 2
56
+
48
57
  items = handle_potentially_typeless_sexp(contents)
49
58
 
50
- items = create_multiple_assignement_sub_types items
59
+ return items if items.first.is_a? Symbol
51
60
 
52
- s(:masgn, s(:array, *items))
61
+ s(:masgn, s(:array, *create_multiple_assignment_sub_types(items)))
53
62
  end
54
63
 
55
64
  def process_opassign exp
@@ -64,10 +73,14 @@ module RipperRubyParser
64
73
 
65
74
  private
66
75
 
67
- def create_multiple_assignement_sub_types sexp_list
76
+ def create_multiple_assignment_sub_types sexp_list
68
77
  sexp_list.map! do |item|
69
78
  if item.sexp_type == :splat
70
- s(:splat, create_valueless_assignment_sub_type(item[1]))
79
+ if item[1].nil?
80
+ s(:splat)
81
+ else
82
+ s(:splat, create_valueless_assignment_sub_type(item[1]))
83
+ end
71
84
  else
72
85
  create_valueless_assignment_sub_type item
73
86
  end
@@ -88,9 +101,11 @@ module RipperRubyParser
88
101
  def create_operator_assignment_sub_type lvalue, value, operator
89
102
  case lvalue.sexp_type
90
103
  when :aref_field
91
- s(:op_asgn1, lvalue[1], s(:arglist, lvalue[2][1]), operator, value)
104
+ _, arr, arglist = lvalue
105
+ s(:op_asgn1, arr, arglist, operator, value)
92
106
  when :field
93
- s(:op_asgn2, lvalue[1], :"#{lvalue[3][1]}=", operator, value)
107
+ _, obj, _, (_, field) = lvalue
108
+ s(:op_asgn2, obj, :"#{field}=", operator, value)
94
109
  else
95
110
  if operator == :"||"
96
111
  s(:op_asgn_or, lvalue, create_assignment_sub_type(lvalue, value))
@@ -104,9 +119,12 @@ module RipperRubyParser
104
119
  def create_regular_assignment_sub_type lvalue, value
105
120
  case lvalue.sexp_type
106
121
  when :aref_field
107
- s(:attrasgn, lvalue[1], :[]=, s(:arglist, lvalue[2][1], value))
122
+ _, arr, arglist = lvalue
123
+ arglist << value
124
+ s(:attrasgn, arr, :[]=, arglist)
108
125
  when :field
109
- s(:attrasgn, lvalue[1], :"#{lvalue[3][1]}=", s(:arglist, value))
126
+ _, obj, _, (_, field) = lvalue
127
+ s(:attrasgn, obj, :"#{field}=", s(:arglist, value))
110
128
  else
111
129
  create_assignment_sub_type lvalue, value
112
130
  end
@@ -4,7 +4,7 @@ module RipperRubyParser
4
4
  def process_method_add_block exp
5
5
  _, call, block = exp.shift 3
6
6
  block = process(block)
7
- args = convert_block_args(block[1])
7
+ args = block[1]
8
8
  stmt = block[2].first
9
9
  if stmt.nil?
10
10
  s(:iter, process(call), args)
@@ -25,27 +25,36 @@ module RipperRubyParser
25
25
  _, normal, defaults, rest, _, block = exp.shift 6
26
26
 
27
27
  args = [*normal].map do |id|
28
- extract_node_symbol id
28
+ process(id)
29
29
  end
30
30
 
31
31
  assigns = [*defaults].map do |pair|
32
- sym = extract_node_symbol pair[0]
32
+ sym = process(pair[0])
33
33
  args << sym
34
- val = process pair[1]
35
- s(:lasgn, sym, val)
34
+ val = process(pair[1])
35
+ s(:lasgn, sym[1], val)
36
36
  end
37
37
 
38
- # FIXME: Delay conflating all arguments until later, so that
39
- # #convert_block_args doesn't need to tease this apart again.
40
- add_arg_unless_nil(rest, args) {|name| :"*#{name}" }
38
+ args << process(rest) unless rest.nil?
39
+ args << process(block) unless block.nil?
40
+ args << s(:block, *assigns) if assigns.length > 0
41
41
 
42
- add_arg_unless_nil(block, args) {|name| :"&#{name}" }
42
+ s(:args, *args)
43
+ end
43
44
 
44
- if assigns.length > 0
45
- args << s(:block, *assigns)
46
- end
45
+ def process_block_var exp
46
+ _, args, _ = exp.shift 3
47
47
 
48
- s(:args, *args)
48
+ names = process(args)
49
+ names.shift
50
+
51
+ if names.length == 1 and names.first.sexp_type == :lvar
52
+ s(:lasgn, names.first[1])
53
+ elsif names.length == 1 and names.first.sexp_type == :masgn
54
+ names.first
55
+ else
56
+ s(:masgn, s(:array, *names.map { |name| arg_name_to_lasgn(name) }))
57
+ end
49
58
  end
50
59
 
51
60
  def process_begin exp
@@ -57,7 +66,7 @@ module RipperRubyParser
57
66
  end
58
67
 
59
68
  def process_rescue exp
60
- _, eclass, evar, block, _ = exp.shift 5
69
+ _, eclass, evar, block, after = exp.shift 5
61
70
  rescue_block = map_body(block)
62
71
 
63
72
  arr = []
@@ -76,34 +85,46 @@ module RipperRubyParser
76
85
  arr << easgn
77
86
  end
78
87
 
79
- s(:resbody, s(:array, *arr),
80
- wrap_in_block(rescue_block))
88
+ s(
89
+ s(:resbody, s(:array, *arr), wrap_in_block(rescue_block)),
90
+ *process(after))
81
91
  end
82
92
 
83
93
  def process_bodystmt exp
84
- _, body, rescue_block, _, ensure_block = exp.shift 5
94
+ _, body, rescue_block, else_block, ensure_block = exp.shift 5
85
95
 
86
96
  body = map_body body
87
97
 
88
- unless rescue_block or ensure_block
89
- return s(:scope, s(:block, *body))
90
- end
98
+ #unless rescue_block or ensure_block
99
+ # return s(:scope, s(:block, *body))
100
+ #end
91
101
 
92
102
  body = wrap_in_block(body)
93
103
 
104
+ body = if body.nil?
105
+ s()
106
+ else
107
+ s(body)
108
+ end
109
+
94
110
  if rescue_block
95
- if body.nil?
96
- body = s(:rescue, process(rescue_block))
97
- else
98
- body = s(:rescue, body, process(rescue_block))
99
- end
111
+ body.push(*process(rescue_block))
112
+ body << process(else_block) if else_block
113
+ body = s(s(:rescue, *body))
114
+ elsif else_block
115
+ body << process(else_block)
100
116
  end
101
117
 
102
118
  if ensure_block
103
- body = s(:ensure, body, process(ensure_block))
119
+ body << process(ensure_block)
120
+ body = s(s(:ensure, *body))
104
121
  end
105
122
 
106
- s(:scope, s(:block, body))
123
+ if body.length == 1 and body.first.sexp_type == :block
124
+ s(:scope, *body)
125
+ else
126
+ s(:scope, s(:block, *body))
127
+ end
107
128
  end
108
129
 
109
130
  def process_rescue_mod exp
@@ -154,12 +175,21 @@ module RipperRubyParser
154
175
  end
155
176
  end
156
177
 
157
- def add_arg_unless_nil(item, args)
158
- unless item.nil?
159
- name = extract_node_symbol item[1]
160
- args << yield(name)
178
+ def arg_name_to_lasgn(name)
179
+ case name.sexp_type
180
+ when :lvar
181
+ s(:lasgn, name[1])
182
+ when :splat
183
+ if name[1].nil?
184
+ s(:splat)
185
+ else
186
+ s(:splat, s(:lasgn, name[1][1]))
187
+ end
188
+ else
189
+ name
161
190
  end
162
191
  end
192
+
163
193
  end
164
194
  end
165
195
  end
@@ -26,7 +26,7 @@ module RipperRubyParser
26
26
 
27
27
  def process_if_mod exp
28
28
  _, cond, truepart = exp.shift 3
29
- s(:if, process(cond), process(truepart), nil)
29
+ process_if s(:if, cond, s(truepart), nil)
30
30
  end
31
31
 
32
32
  def process_unless_mod exp
@@ -59,8 +59,16 @@ module RipperRubyParser
59
59
  end
60
60
  end
61
61
 
62
- s(s(:when,
63
- process(s(:array, values)),
62
+ values = handle_array_elements values
63
+ values = values.map do |val|
64
+ if val.sexp_type == :splat
65
+ s(:when, val[1], nil)
66
+ else
67
+ val
68
+ end
69
+ end
70
+
71
+ s(s(:when, s(:array, *values),
64
72
  handle_statement_list(truepart)),
65
73
  *falsepart)
66
74
  end
@@ -23,25 +23,6 @@ module RipperRubyParser
23
23
  end
24
24
  end
25
25
 
26
- def convert_block_args(args)
27
- if args
28
- names = args[1][1..-1]
29
- if names.length > 1 or names.first =~ /^\*/
30
- s(:masgn, s(:array, *names.map { |name| arg_name_to_lasgn(name) }))
31
- else
32
- s(:lasgn, names.first)
33
- end
34
- end
35
- end
36
-
37
- def arg_name_to_lasgn(name)
38
- if name =~ /^\*(.*)/
39
- s(:splat, s(:lasgn, $1.to_sym))
40
- else
41
- s(:lasgn, name)
42
- end
43
- end
44
-
45
26
  def handle_statement_list exp
46
27
  statements = map_body exp
47
28
 
@@ -60,8 +41,9 @@ module RipperRubyParser
60
41
  ident.to_sym
61
42
  end
62
43
 
63
- def with_position pos, exp
44
+ def with_position pos, exp=nil
64
45
  (line, _) = pos
46
+ exp = yield if exp.nil?
65
47
  with_line_number line, exp
66
48
  end
67
49
 
@@ -77,9 +59,9 @@ module RipperRubyParser
77
59
 
78
60
  def generic_add_star exp
79
61
  _, args, splatarg = exp.shift 3
80
- items = args.map { |sub| process(sub) }
62
+ items = handle_potentially_typeless_sexp args
81
63
  items << s(:splat, process(splatarg))
82
- s(*items)
64
+ items
83
65
  end
84
66
 
85
67
  def is_literal? exp
@@ -118,6 +100,17 @@ module RipperRubyParser
118
100
  s(:array, *args)
119
101
  end
120
102
  end
103
+
104
+ def handle_array_elements elems
105
+ elems = handle_potentially_typeless_sexp(elems)
106
+ elems.map do |elem|
107
+ if elem.first.is_a? Symbol
108
+ elem
109
+ else
110
+ elem.first
111
+ end
112
+ end
113
+ end
121
114
  end
122
115
  end
123
116
  end
@@ -41,6 +41,13 @@ module RipperRubyParser
41
41
  with_position_from_node_symbol(ident) {|method|
42
42
  s(:call, nil, method, s(:arglist)) }
43
43
  end
44
+
45
+ def process_super exp
46
+ _, args = exp.shift 2
47
+ args = process(args)
48
+ args.shift
49
+ s(:super, *args)
50
+ end
44
51
  end
45
52
  end
46
53
  end
@@ -4,15 +4,17 @@ module RipperRubyParser
4
4
  def process_def exp
5
5
  _, ident, params, body = exp.shift 4
6
6
  ident, pos = extract_node_symbol_with_position ident
7
+ params = convert_special_args(process(params))
7
8
  with_position(pos,
8
- s(:defn, ident, process(params), method_body(body)))
9
+ s(:defn, ident, params, method_body(body)))
9
10
  end
10
11
 
11
12
  def process_defs exp
12
- _, receiver, _, method, args, body = exp.shift 6
13
+ _, receiver, _, method, params, body = exp.shift 6
14
+ params = convert_special_args(process(params))
13
15
  s(:defs, process(receiver),
14
16
  extract_node_symbol(method),
15
- process(args), in_method { process(body) })
17
+ params, in_method { process(body) })
16
18
  end
17
19
 
18
20
  def process_return exp
@@ -81,6 +83,28 @@ module RipperRubyParser
81
83
  end
82
84
  scope
83
85
  end
86
+
87
+ SPECIAL_ARG_MARKER = {
88
+ :splat => "*",
89
+ :blockarg => "&"
90
+ }
91
+
92
+ def convert_special_args args
93
+ args.map! do |item|
94
+ if item.is_a? Symbol
95
+ item
96
+ else
97
+ if (marker = SPECIAL_ARG_MARKER[item.sexp_type])
98
+ name = extract_node_symbol item[1]
99
+ :"#{marker}#{name}"
100
+ elsif item.sexp_type == :lvar
101
+ item[1]
102
+ else
103
+ item
104
+ end
105
+ end
106
+ end
107
+ end
84
108
  end
85
109
  end
86
110
  end
@@ -1,7 +1,7 @@
1
1
  module RipperRubyParser
2
2
  module SexpHandlers
3
3
  module Operators
4
- BINARY_OPERTOR_MAP = {
4
+ BINARY_OPERATOR_MAP = {
5
5
  "&&".to_sym => :and,
6
6
  "||".to_sym => :or,
7
7
  :and => :and,
@@ -13,6 +13,11 @@ module RipperRubyParser
13
13
  :not => :not
14
14
  }
15
15
 
16
+ NEGATED_BINARY_OPERATOR_MAP = {
17
+ :"!~" => :=~,
18
+ :"!=" => :==
19
+ }
20
+
16
21
  def process_binary exp
17
22
  _, left, op, right = exp.shift 4
18
23
  if op == :=~
@@ -23,21 +28,18 @@ module RipperRubyParser
23
28
  else
24
29
  s(:call, process(left), op, s(:arglist, process(right)))
25
30
  end
26
- elsif op == :"!="
27
- s(:not, s(:call, process(left), :==, s(:arglist, process(right))))
28
- else
29
- mapped = BINARY_OPERTOR_MAP[op]
30
- if mapped
31
- left = process(left)
32
- right = process(right)
33
- if mapped == left.sexp_type
34
- s(left.sexp_type, left[1], s(mapped, left[2], right))
35
- else
36
- s(mapped, left, right)
37
- end
31
+ elsif (mapped = NEGATED_BINARY_OPERATOR_MAP[op])
32
+ s(:not, process(s(:binary, left, mapped, right)))
33
+ elsif (mapped = BINARY_OPERATOR_MAP[op])
34
+ left = process(left)
35
+ right = process(right)
36
+ if mapped == left.sexp_type
37
+ s(left.sexp_type, left[1], s(mapped, left[2], right))
38
38
  else
39
- s(:call, process(left), op, s(:arglist, process(right)))
39
+ s(mapped, left, right)
40
40
  end
41
+ else
42
+ s(:call, process(left), op, s(:arglist, process(right)))
41
43
  end
42
44
  end
43
45
 
@@ -71,6 +71,11 @@ module RipperRubyParser
71
71
  s(:class, const, parent, class_or_module_body(body)))
72
72
  end
73
73
 
74
+ def process_sclass exp
75
+ _, klass, block = exp.shift 3
76
+ s(:sclass, process(klass), class_or_module_body(block))
77
+ end
78
+
74
79
  def process_var_ref exp
75
80
  _, contents = exp.shift 2
76
81
  process(contents)
@@ -178,7 +183,14 @@ module RipperRubyParser
178
183
 
179
184
  def process_at_backref exp
180
185
  _, str, pos = exp.shift 3
181
- with_position(pos, s(:nth_ref, str[1..-1].to_i))
186
+ name = str[1..-1]
187
+ with_position pos do
188
+ if name =~ /[0-9]/
189
+ s(:nth_ref, name.to_i)
190
+ else
191
+ s(:back_ref, name.to_sym)
192
+ end
193
+ end
182
194
  end
183
195
 
184
196
  private
@@ -1,3 +1,3 @@
1
1
  module RipperRubyParser
2
- VERSION = '0.0.4'
2
+ VERSION = '0.0.5'
3
3
  end
@@ -2,22 +2,6 @@ require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
2
2
  require 'ruby_parser'
3
3
 
4
4
  describe "Using RipperRubyParser and RubyParser" do
5
- def to_comments exp
6
- inner = exp.map do |sub_exp|
7
- if sub_exp.is_a? Sexp
8
- to_comments sub_exp
9
- else
10
- sub_exp
11
- end
12
- end
13
-
14
- if exp.comments.nil?
15
- s(*inner)
16
- else
17
- s(:comment, exp.comments, s(*inner))
18
- end
19
- end
20
-
21
5
  let :newparser do
22
6
  RipperRubyParser::Parser.new
23
7
  end
@@ -16,13 +16,23 @@ describe "Using RipperRubyParser and RubyParser" do
16
16
  File.read file
17
17
  end
18
18
 
19
- it "gives the same result" do
19
+ let :original do
20
+ oldparser.parse program
21
+ end
22
+
23
+ let :imitation do
20
24
  newparser.extra_compatible = true
21
- original = oldparser.parse program
22
- imitation = newparser.parse program
25
+ newparser.parse program
26
+ end
23
27
 
28
+ it "gives the same result" do
24
29
  formatted(imitation).must_equal formatted(original)
25
30
  end
31
+
32
+ it "gives the same result with comments" do
33
+ formatted(to_comments(imitation)).
34
+ must_equal formatted(to_comments(original))
35
+ end
26
36
  end
27
37
  end
28
38
  end
data/test/test_helper.rb CHANGED
@@ -9,16 +9,36 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
9
9
 
10
10
  require 'ripper_ruby_parser'
11
11
 
12
- class MiniTest::Unit::TestCase
12
+ class MiniTest::Spec
13
13
  def formatted exp
14
14
  exp.to_s.gsub(/\), /, "),\n")
15
15
  end
16
16
 
17
- def suppress_warnings
18
- old_verbose = $VERBOSE
19
- $VERBOSE = nil
20
- result = yield
21
- $VERBOSE = old_verbose
22
- result
17
+ def to_comments exp
18
+ inner = exp.map do |sub_exp|
19
+ if sub_exp.is_a? Sexp
20
+ to_comments sub_exp
21
+ else
22
+ sub_exp
23
+ end
24
+ end
25
+
26
+ comments = exp.comments.to_s.gsub(/\n\s*\n/, "\n")
27
+ if comments.empty?
28
+ s(*inner)
29
+ else
30
+ s(:comment, comments, s(*inner))
31
+ end
32
+ end
33
+
34
+ def assert_parsed_as sexp, code
35
+ parser = RipperRubyParser::Parser.new
36
+ result = parser.parse code
37
+ assert_equal sexp, result
23
38
  end
24
39
  end
40
+
41
+ module MiniTest::Expectations
42
+ infect_an_assertion :assert_parsed_as, :must_be_parsed_as
43
+ end
44
+
@@ -0,0 +1,70 @@
1
+ require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
2
+
3
+ describe RipperRubyParser::Parser do
4
+ describe "#parse" do
5
+ describe "for multiple assignment" do
6
+ specify do
7
+ "foo, * = bar".
8
+ must_be_parsed_as s(:masgn,
9
+ s(:array, s(:lasgn, :foo), s(:splat)),
10
+ s(:to_ary, s(:call, nil, :bar, s(:arglist))))
11
+ end
12
+
13
+ specify do
14
+ "(foo, *bar) = baz".
15
+ must_be_parsed_as s(:masgn,
16
+ s(:array,
17
+ s(:lasgn, :foo),
18
+ s(:splat, s(:lasgn, :bar))),
19
+ s(:to_ary, s(:call, nil, :baz, s(:arglist))))
20
+ end
21
+ end
22
+
23
+ describe "for assignment to a collection element" do
24
+ it "handles multiple indices" do
25
+ "foo[bar, baz] = qux".
26
+ must_be_parsed_as s(:attrasgn,
27
+ s(:call, nil, :foo, s(:arglist)),
28
+ :[]=,
29
+ s(:arglist,
30
+ s(:call, nil, :bar, s(:arglist)),
31
+ s(:call, nil, :baz, s(:arglist)),
32
+ s(:call, nil, :qux, s(:arglist))))
33
+ end
34
+ end
35
+
36
+ describe "for operator assignment" do
37
+ describe "assigning to a collection element" do
38
+ it "handles multiple indices" do
39
+ "foo[bar, baz] += qux".
40
+ must_be_parsed_as s(:op_asgn1,
41
+ s(:call, nil, :foo, s(:arglist)),
42
+ s(:arglist,
43
+ s(:call, nil, :bar, s(:arglist)),
44
+ s(:call, nil, :baz, s(:arglist))),
45
+ :+,
46
+ s(:call, nil, :qux, s(:arglist)))
47
+ end
48
+ end
49
+ end
50
+
51
+ describe "for multiple assignment" do
52
+ describe "with a right-hand splat" do
53
+ specify do
54
+ "foo, bar = *baz".
55
+ must_be_parsed_as s(:masgn,
56
+ s(:array, s(:lasgn, :foo), s(:lasgn, :bar)),
57
+ s(:splat, s(:call, nil, :baz, s(:arglist))))
58
+ end
59
+ specify do
60
+ "foo, bar = baz, *qux".
61
+ must_be_parsed_as s(:masgn,
62
+ s(:array, s(:lasgn, :foo), s(:lasgn, :bar)),
63
+ s(:array,
64
+ s(:call, nil, :baz, s(:arglist)),
65
+ s(:splat, s(:call, nil, :qux, s(:arglist)))))
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,72 @@
1
+ require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
2
+
3
+ describe RipperRubyParser::Parser do
4
+ describe "#parse" do
5
+ describe "for block parameters" do
6
+ specify do
7
+ "foo do |(bar, baz)| end".
8
+ must_be_parsed_as s(:iter,
9
+ s(:call, nil, :foo, s(:arglist)),
10
+ s(:masgn,
11
+ s(:array,
12
+ s(:lasgn, :bar),
13
+ s(:lasgn, :baz))))
14
+ end
15
+
16
+ specify do
17
+ "foo do |(bar, *baz)| end".
18
+ must_be_parsed_as s(:iter,
19
+ s(:call, nil, :foo, s(:arglist)),
20
+ s(:masgn,
21
+ s(:array,
22
+ s(:lasgn, :bar),
23
+ s(:splat, s(:lasgn, :baz)))))
24
+ end
25
+
26
+ specify do
27
+ "foo do |bar,*| end".
28
+ must_be_parsed_as s(:iter,
29
+ s(:call, nil, :foo, s(:arglist)),
30
+ s(:masgn, s(:array, s(:lasgn, :bar), s(:splat))))
31
+ end
32
+
33
+ it "behaves differently from RubyParser with a trailing comma in the block parameters" do
34
+ "foo do |bar, | end".
35
+ must_be_parsed_as s(:iter,
36
+ s(:call, nil, :foo, s(:arglist)),
37
+ s(:lasgn, :bar))
38
+ end
39
+ end
40
+
41
+ describe "for rescue/else/ensure" do
42
+ it "works for a block with multiple rescue statements" do
43
+ "begin foo; rescue; bar; rescue; baz; end".
44
+ must_be_parsed_as s(:rescue,
45
+ s(:call, nil, :foo, s(:arglist)),
46
+ s(:resbody,
47
+ s(:array),
48
+ s(:call, nil, :bar, s(:arglist))),
49
+ s(:resbody,
50
+ s(:array),
51
+ s(:call, nil, :baz, s(:arglist))))
52
+ end
53
+
54
+ it "works for a block with rescue and else" do
55
+ "begin; foo; rescue; bar; else; baz; end".
56
+ must_be_parsed_as s(:rescue,
57
+ s(:call, nil, :foo, s(:arglist)),
58
+ s(:resbody,
59
+ s(:array),
60
+ s(:call, nil, :bar, s(:arglist))),
61
+ s(:call, nil, :baz, s(:arglist)))
62
+ end
63
+
64
+ it "works for a block with only else" do
65
+ "begin; foo; else; bar; end".
66
+ must_be_parsed_as s(:block,
67
+ s(:call, nil, :foo, s(:arglist)),
68
+ s(:call, nil, :bar, s(:arglist)))
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,29 @@
1
+ require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
2
+
3
+ describe RipperRubyParser::Parser do
4
+ describe "#parse" do
5
+ describe "for postfix if" do
6
+ it "normalizes negative conditions" do
7
+ "foo if not bar".
8
+ must_be_parsed_as s(:if,
9
+ s(:call, nil, :bar, s(:arglist)),
10
+ nil,
11
+ s(:call, nil, :foo, s(:arglist)))
12
+ end
13
+ end
14
+
15
+ describe "for case" do
16
+ it "emulates RubyParser's strange handling of splat" do
17
+ "case foo; when *bar; baz; end".
18
+ must_be_parsed_as s(:case, s(:call, nil, :foo, s(:arglist)),
19
+ s(:when,
20
+ s(:array,
21
+ s(:when, s(:call, nil, :bar, s(:arglist)),
22
+ nil)),
23
+ s(:call, nil, :baz, s(:arglist))),
24
+ nil)
25
+
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,27 @@
1
+ require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
2
+
3
+ describe RipperRubyParser::Parser do
4
+ describe "#parse" do
5
+ describe "for calls to super" do
6
+ specify { "super".must_be_parsed_as s(:zsuper) }
7
+ specify { "super foo".must_be_parsed_as s(:super,
8
+ s(:call, nil, :foo, s(:arglist))) }
9
+ specify {
10
+ "super foo, bar".must_be_parsed_as s(:super,
11
+ s(:call, nil, :foo, s(:arglist)),
12
+ s(:call, nil, :bar, s(:arglist))) }
13
+ specify {
14
+ "super foo, *bar".must_be_parsed_as s(:super,
15
+ s(:call, nil, :foo, s(:arglist)),
16
+ s(:splat,
17
+ s(:call, nil, :bar, s(:arglist)))) }
18
+ specify {
19
+ "super foo, *bar, &baz".
20
+ must_be_parsed_as s(:super,
21
+ s(:call, nil, :foo, s(:arglist)),
22
+ s(:splat, s(:call, nil, :bar, s(:arglist))),
23
+ s(:block_pass, s(:call, nil, :baz, s(:arglist)))) }
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,16 @@
1
+ require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
2
+
3
+ describe RipperRubyParser::Parser do
4
+ describe "#parse" do
5
+ describe "for negated operators" do
6
+ specify do
7
+ "foo !~ bar".must_be_parsed_as s(:not,
8
+ s(:call,
9
+ s(:call, nil, :foo, s(:arglist)),
10
+ :=~,
11
+ s(:arglist,
12
+ s(:call, nil, :bar, s(:arglist)))))
13
+ end
14
+ end
15
+ end
16
+ end
@@ -29,6 +29,10 @@ describe RipperRubyParser::Parser do
29
29
  nil,
30
30
  s(:scope))
31
31
  end
32
+
33
+ it "works for singleton classes" do
34
+ "class << self; end".must_be_parsed_as s(:sclass, s(:self), s(:scope))
35
+ end
32
36
  end
33
37
 
34
38
  describe "for a module declaration" do
@@ -254,8 +258,7 @@ describe RipperRubyParser::Parser do
254
258
 
255
259
  describe "for the for statement" do
256
260
  it "works with do" do
257
- result = suppress_warnings {
258
- parser.parse "for foo in bar do; baz; end" }
261
+ result = parser.parse "for foo in bar do; baz; end"
259
262
  result.must_equal s(:for,
260
263
  s(:call, nil, :bar, s(:arglist)),
261
264
  s(:lasgn, :foo),
@@ -263,8 +266,7 @@ describe RipperRubyParser::Parser do
263
266
  end
264
267
 
265
268
  it "works without do" do
266
- result = suppress_warnings {
267
- parser.parse "for foo in bar; baz; end" }
269
+ result = parser.parse "for foo in bar; baz; end"
268
270
  result.must_equal s(:for,
269
271
  s(:call, nil, :bar, s(:arglist)),
270
272
  s(:lasgn, :foo),
@@ -321,8 +323,7 @@ describe RipperRubyParser::Parser do
321
323
  end
322
324
 
323
325
  it "works with assignment to an error variable" do
324
- result = suppress_warnings {
325
- parser.parse "begin; foo; rescue => e; bar; end" }
326
+ result = parser.parse "begin; foo; rescue => e; bar; end"
326
327
  result.must_equal s(:rescue,
327
328
  s(:call, nil, :foo, s(:arglist)),
328
329
  s(:resbody,
@@ -340,8 +341,7 @@ describe RipperRubyParser::Parser do
340
341
  end
341
342
 
342
343
  it "works with filtering of the exception type and assignment to an error variable" do
343
- result = suppress_warnings {
344
- parser.parse "begin; foo; rescue Bar => e; baz; end" }
344
+ result = parser.parse "begin; foo; rescue Bar => e; baz; end"
345
345
  result.must_equal s(:rescue,
346
346
  s(:call, nil, :foo, s(:arglist)),
347
347
  s(:resbody,
@@ -1188,6 +1188,9 @@ describe RipperRubyParser::Parser do
1188
1188
  result.must_equal s(:nth_ref, 1)
1189
1189
  end
1190
1190
 
1191
+ specify { "$'".must_be_parsed_as s(:back_ref, :"'") }
1192
+ specify { "$&".must_be_parsed_as s(:back_ref, :"&") }
1193
+
1191
1194
  it "works for class variables" do
1192
1195
  result = parser.parse "@@foo"
1193
1196
  result.must_equal s(:cvar, :@@foo)
@@ -1263,7 +1266,7 @@ describe RipperRubyParser::Parser do
1263
1266
 
1264
1267
  describe "for operator assignment" do
1265
1268
  it "works with +=" do
1266
- result = suppress_warnings { parser.parse "foo += bar" }
1269
+ result = parser.parse "foo += bar"
1267
1270
  result.must_equal s(:lasgn,
1268
1271
  :foo,
1269
1272
  s(:call,
@@ -1273,7 +1276,7 @@ describe RipperRubyParser::Parser do
1273
1276
  end
1274
1277
 
1275
1278
  it "works with -=" do
1276
- result = suppress_warnings { parser.parse "foo -= bar" }
1279
+ result = parser.parse "foo -= bar"
1277
1280
  result.must_equal s(:lasgn,
1278
1281
  :foo,
1279
1282
  s(:call,
@@ -1283,7 +1286,7 @@ describe RipperRubyParser::Parser do
1283
1286
  end
1284
1287
 
1285
1288
  it "works with ||=" do
1286
- result = suppress_warnings { parser.parse "foo ||= bar" }
1289
+ result = parser.parse "foo ||= bar"
1287
1290
  result.must_equal s(:op_asgn_or,
1288
1291
  s(:lvar, :foo),
1289
1292
  s(:lasgn, :foo,
@@ -1339,7 +1342,7 @@ describe RipperRubyParser::Parser do
1339
1342
 
1340
1343
  describe "for multiple assignment" do
1341
1344
  it "works the same number of items on each side" do
1342
- result = suppress_warnings { parser.parse "foo, bar = baz, qux" }
1345
+ result = parser.parse "foo, bar = baz, qux"
1343
1346
  result.must_equal s(:masgn,
1344
1347
  s(:array, s(:lasgn, :foo), s(:lasgn, :bar)),
1345
1348
  s(:array,
@@ -1348,7 +1351,7 @@ describe RipperRubyParser::Parser do
1348
1351
  end
1349
1352
 
1350
1353
  it "works with a single item on the right-hand side" do
1351
- result = suppress_warnings { parser.parse "foo, bar = baz" }
1354
+ result = parser.parse "foo, bar = baz"
1352
1355
  result.must_equal s(:masgn,
1353
1356
  s(:array, s(:lasgn, :foo), s(:lasgn, :bar)),
1354
1357
  s(:to_ary,
@@ -1356,7 +1359,7 @@ describe RipperRubyParser::Parser do
1356
1359
  end
1357
1360
 
1358
1361
  it "works with left-hand splat" do
1359
- result = suppress_warnings { parser.parse "foo, *bar = baz, qux" }
1362
+ result = parser.parse "foo, *bar = baz, qux"
1360
1363
  result.must_equal s(:masgn,
1361
1364
  s(:array, s(:lasgn, :foo), s(:splat, s(:lasgn, :bar))),
1362
1365
  s(:array,
@@ -1365,7 +1368,7 @@ describe RipperRubyParser::Parser do
1365
1368
  end
1366
1369
 
1367
1370
  it "works with brackets around the left-hand side" do
1368
- result = suppress_warnings { parser.parse "(foo, bar) = baz" }
1371
+ result = parser.parse "(foo, bar) = baz"
1369
1372
  result.must_equal s(:masgn,
1370
1373
  s(:array, s(:lasgn, :foo), s(:lasgn, :bar)),
1371
1374
  s(:to_ary,
@@ -1373,7 +1376,7 @@ describe RipperRubyParser::Parser do
1373
1376
  end
1374
1377
 
1375
1378
  it "works with complex destructuring" do
1376
- result = suppress_warnings { parser.parse "foo, (bar, baz) = qux" }
1379
+ result = parser.parse "foo, (bar, baz) = qux"
1377
1380
  result.must_equal s(:masgn,
1378
1381
  s(:array,
1379
1382
  s(:lasgn, :foo),
@@ -1620,7 +1623,7 @@ describe RipperRubyParser::Parser do
1620
1623
 
1621
1624
  describe "for expressions" do
1622
1625
  it "handles assignment inside binary operator expressions" do
1623
- result = suppress_warnings { parser.parse "foo + (bar = baz)" }
1626
+ result = parser.parse "foo + (bar = baz)"
1624
1627
  result.must_equal s(:call,
1625
1628
  s(:call, nil, :foo, s(:arglist)),
1626
1629
  :+,
@@ -1631,7 +1634,7 @@ describe RipperRubyParser::Parser do
1631
1634
  end
1632
1635
 
1633
1636
  it "handles assignment inside unary operator expressions" do
1634
- result = suppress_warnings { parser.parse "+(foo = bar)" }
1637
+ result = parser.parse "+(foo = bar)"
1635
1638
  result.must_equal s(:call,
1636
1639
  s(:lasgn, :foo, s(:call, nil, :bar, s(:arglist))),
1637
1640
  :+@,
@@ -1650,6 +1653,15 @@ describe RipperRubyParser::Parser do
1650
1653
  result.comments.must_equal "# Foo\n"
1651
1654
  end
1652
1655
 
1656
+ it "handles comments for methods with explicit receiver" do
1657
+ result = parser.parse "# Foo\ndef foo.bar; end"
1658
+ result.must_equal s(:defs,
1659
+ s(:call, nil, :foo, s(:arglist)),
1660
+ :bar,
1661
+ s(:args), s(:scope, s(:block)))
1662
+ result.comments.must_equal "# Foo\n"
1663
+ end
1664
+
1653
1665
  it "matches comments to the correct entity" do
1654
1666
  result = parser.parse "# Foo\nclass Foo\n# Bar\ndef bar\nend\nend"
1655
1667
  result.must_equal s(:class, :Foo, nil,
@@ -1669,6 +1681,27 @@ describe RipperRubyParser::Parser do
1669
1681
  s(:args), s(:scope, s(:block, s(:nil))))
1670
1682
  result.comments.must_equal "# Foo\n# Bar\n"
1671
1683
  end
1684
+
1685
+ it "handles the use of symbols that are keywords" do
1686
+ result = parser.parse "# Foo\ndef bar\n:class\nend"
1687
+ result.must_equal s(:defn,
1688
+ :bar,
1689
+ s(:args),
1690
+ s(:scope, s(:block, s(:lit, :class))))
1691
+ result.comments.must_equal "# Foo\n"
1692
+ end
1693
+
1694
+ it "handles use of singleton class inside methods" do
1695
+ result = parser.parse "# Foo\ndef bar\nclass << self\nbaz\nend\nend"
1696
+ result.must_equal s(:defn,
1697
+ :bar,
1698
+ s(:args),
1699
+ s(:scope,
1700
+ s(:block,
1701
+ s(:sclass, s(:self),
1702
+ s(:scope, s(:call, nil, :baz, s(:arglist)))))))
1703
+ result.comments.must_equal "# Foo\n"
1704
+ end
1672
1705
  end
1673
1706
 
1674
1707
  # Note: differences in the handling of line numbers are not caught by
@@ -1786,12 +1819,12 @@ describe RipperRubyParser::Parser do
1786
1819
  end
1787
1820
 
1788
1821
  it "works for assignment of the empty hash" do
1789
- result = suppress_warnings { parser.parse "foo = {}" }
1822
+ result = parser.parse "foo = {}"
1790
1823
  result.line.must_equal 1
1791
1824
  end
1792
1825
 
1793
1826
  it "works for multiple assignment of empty hashes" do
1794
- result = suppress_warnings { parser.parse "foo, bar = {}, {}" }
1827
+ result = parser.parse "foo, bar = {}, {}"
1795
1828
  result.line.must_equal 1
1796
1829
  end
1797
1830
 
@@ -185,11 +185,11 @@ describe RipperRubyParser::SexpProcessor do
185
185
  end
186
186
 
187
187
  describe "for a :params sexp" do
188
- describe "with a normal argument" do
189
- it "uses the bare argument names" do
188
+ describe "with a normal arguments" do
189
+ it "creates :lvar sexps" do
190
190
  sexp = s(:params, s(s(:@ident, "bar", s(1, 8))), nil, nil, nil, nil)
191
191
  result = processor.process sexp
192
- result.must_equal s(:args, :bar)
192
+ result.must_equal s(:args, s(:lvar, :bar))
193
193
  end
194
194
  end
195
195
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ripper_ruby_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-31 00:00:00.000000000 Z
12
+ date: 2012-04-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sexp_processor
16
- requirement: &22929360 !ruby/object:Gem::Requirement
16
+ requirement: &18762580 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '3.0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *22929360
24
+ version_requirements: *18762580
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: minitest
27
- requirement: &22928840 !ruby/object:Gem::Requirement
27
+ requirement: &18762060 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 2.11.2
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *22928840
35
+ version_requirements: *18762060
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rake
38
- requirement: &22928360 !ruby/object:Gem::Requirement
38
+ requirement: &18761580 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 0.9.2
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *22928360
46
+ version_requirements: *18761580
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: ruby_parser
49
- requirement: &22927880 !ruby/object:Gem::Requirement
49
+ requirement: &18761100 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 2.3.1
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *22927880
57
+ version_requirements: *18761100
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: simplecov
60
- requirement: &22927500 !ruby/object:Gem::Requirement
60
+ requirement: &18760720 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,7 +65,7 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *22927500
68
+ version_requirements: *18760720
69
69
  description:
70
70
  email:
71
71
  - matijs@matijs.net
@@ -103,8 +103,13 @@ files:
103
103
  - test/end_to_end/line_numbering_test.rb
104
104
  - test/end_to_end/error_conditions_test.rb
105
105
  - test/unit/parser_test.rb
106
+ - test/unit/parser_blocks_test.rb
106
107
  - test/unit/sexp_processor_test.rb
108
+ - test/unit/parser_operators_test.rb
109
+ - test/unit/parser_conditionals_test.rb
107
110
  - test/unit/version_test.rb
111
+ - test/unit/parser_assignment_test.rb
112
+ - test/unit/parser_method_calls_test.rb
108
113
  - test/unit/commenting_sexp_builder_test.rb
109
114
  - README.rdoc
110
115
  - Rakefile
@@ -144,6 +149,11 @@ test_files:
144
149
  - test/end_to_end/test_comparison_test.rb
145
150
  - test/test_helper.rb
146
151
  - test/unit/commenting_sexp_builder_test.rb
152
+ - test/unit/parser_assignment_test.rb
153
+ - test/unit/parser_blocks_test.rb
154
+ - test/unit/parser_conditionals_test.rb
155
+ - test/unit/parser_method_calls_test.rb
156
+ - test/unit/parser_operators_test.rb
147
157
  - test/unit/parser_test.rb
148
158
  - test/unit/sexp_processor_test.rb
149
159
  - test/unit/version_test.rb