ripper_ruby_parser 0.0.8 → 1.0.0

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 (31) hide show
  1. checksums.yaml +7 -0
  2. data/{README.rdoc → README.md} +17 -17
  3. data/Rakefile +3 -1
  4. data/lib/ripper_ruby_parser/{commenting_sexp_builder.rb → commenting_ripper_parser.rb} +22 -6
  5. data/lib/ripper_ruby_parser/parser.rb +3 -18
  6. data/lib/ripper_ruby_parser/sexp_handlers/arrays.rb +2 -1
  7. data/lib/ripper_ruby_parser/sexp_handlers/assignment.rb +6 -10
  8. data/lib/ripper_ruby_parser/sexp_handlers/blocks.rb +37 -60
  9. data/lib/ripper_ruby_parser/sexp_handlers/conditionals.rb +31 -25
  10. data/lib/ripper_ruby_parser/sexp_handlers/helper_methods.rb +18 -8
  11. data/lib/ripper_ruby_parser/sexp_handlers/literals.rb +22 -18
  12. data/lib/ripper_ruby_parser/sexp_handlers/loops.rb +12 -23
  13. data/lib/ripper_ruby_parser/sexp_handlers/method_calls.rb +16 -8
  14. data/lib/ripper_ruby_parser/sexp_handlers/methods.rb +41 -15
  15. data/lib/ripper_ruby_parser/sexp_handlers/operators.rb +40 -23
  16. data/lib/ripper_ruby_parser/sexp_processor.rb +38 -19
  17. data/lib/ripper_ruby_parser/version.rb +1 -1
  18. data/test/pt_testcase/pt_test.rb +15 -1
  19. data/test/test_helper.rb +6 -3
  20. data/test/unit/commenting_ripper_parser_test.rb +121 -0
  21. data/test/unit/parser_assignment_test.rb +23 -24
  22. data/test/unit/parser_blocks_test.rb +207 -35
  23. data/test/unit/parser_conditionals_test.rb +251 -9
  24. data/test/unit/parser_literals_test.rb +348 -8
  25. data/test/unit/parser_loops_test.rb +20 -21
  26. data/test/unit/parser_method_calls_test.rb +132 -8
  27. data/test/unit/parser_operators_test.rb +97 -7
  28. data/test/unit/parser_test.rb +631 -1231
  29. data/test/unit/sexp_processor_test.rb +26 -28
  30. metadata +28 -38
  31. data/test/unit/commenting_sexp_builder_test.rb +0 -113
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 12102f722ef4074c0f6d46d207dba7dac580d0af
4
+ data.tar.gz: edf3dc287249ae2f0ccedb39e2f3cfdae622daff
5
+ SHA512:
6
+ metadata.gz: 9450f761539fbf3b3d662447497ef1fa7a220a02e9656139bb35d305863cde02a1364b9c9802dcd20883a0c6be16f7d8e80aa4529409445bf280d07e5d4a29fb
7
+ data.tar.gz: 231ced88a63860467aa18a66c37513b49e232dc9aff74c03d6ba6b7b1ac5d30bf284616ec50d05e38385b66237c3086cb78fe526aeae648b6dd1f4a8dda8a85b
@@ -1,38 +1,38 @@
1
- = RipperRubyParser
1
+ # RipperRubyParser
2
2
 
3
3
  by Matijs van Zuijlen
4
4
 
5
5
  http://www.github.com/mvz/ripper_ruby_parser
6
6
 
7
- == Description
7
+ ## Description
8
8
 
9
9
  Parse with Ripper, produce sexps that are compatible with RubyParser.
10
10
 
11
- == Features/Notes
11
+ ## Features/Notes
12
12
 
13
13
  * Drop-in replacement for RubyParser.
14
- * Should handle 1.9 syntax gracefully.
15
- * Needs MRI 1.9.3.
14
+ * Should handle 1.9 and later syntax gracefully.
15
+ * Needs MRI 1.9.3 or higher
16
16
 
17
- == Install
17
+ ## Install
18
18
 
19
19
  * gem install ripper_ruby_parser
20
20
 
21
- == Synopsis
21
+ ## Synopsis
22
22
 
23
- require 'ripper_ruby_parser'
23
+ require 'ripper_ruby_parser'
24
24
 
25
- parser = RipperRubyParser::Parser.new
26
- result = parser.parse "puts 'Hello World'"
27
- p result
28
- # => s(:call, nil, :puts, s(:arglist, s(:str, "Hello World!")))
25
+ parser = RipperRubyParser::Parser.new
26
+ result = parser.parse "puts 'Hello World'"
27
+ p result
28
+ # => s(:call, nil, :puts, s(:arglist, s(:str, "Hello World!")))
29
29
 
30
- == Requirements
30
+ ## Requirements
31
31
 
32
- * Ruby 1.9.3.
32
+ * Ruby 1.9.3 or higher
33
33
  * sexp_processor
34
34
 
35
- == Hacking and contributing
35
+ ## Hacking and contributing
36
36
 
37
37
  If you want to send pull requests or patches, please:
38
38
 
@@ -45,11 +45,11 @@ If you want to send pull requests or patches, please:
45
45
  * Try not to include changes that are irrelevant to your feature in the
46
46
  same commit.
47
47
 
48
- == License
48
+ ## License
49
49
 
50
50
  (The MIT License)
51
51
 
52
- Copyright (c) 2012 Matijs van Zuijlen
52
+ Copyright (c) 2012, 2014 Matijs van Zuijlen
53
53
 
54
54
  Permission is hereby granted, free of charge, to any person obtaining
55
55
  a copy of this software and associated documentation files (the
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ require 'rake/clean'
2
+ require "bundler/gem_tasks"
1
3
  require 'rake/testtask'
2
4
 
3
5
  namespace :test do
@@ -20,7 +22,7 @@ namespace :test do
20
22
  t.warning = true
21
23
  end
22
24
 
23
- task :run => [:unit, :end_to_end]
25
+ task :run => [:unit, :end_to_end, :pt_testcase]
24
26
  end
25
27
 
26
28
  desc 'Alias to test:run'
@@ -2,7 +2,9 @@ require 'ripper'
2
2
  require 'ripper_ruby_parser/syntax_error'
3
3
 
4
4
  module RipperRubyParser
5
- class CommentingSexpBuilder < Ripper::SexpBuilderPP
5
+ # Variant of Ripper's SexpBuilderPP parser class that inserts comments as
6
+ # Sexps into the built parse tree.
7
+ class CommentingRipperParser < Ripper::SexpBuilderPP
6
8
  def initialize *args
7
9
  super
8
10
  @comment = nil
@@ -10,6 +12,13 @@ module RipperRubyParser
10
12
  @in_symbol = false
11
13
  end
12
14
 
15
+ def parse
16
+ result = suppress_warnings { super }
17
+ raise "Ripper parse failed." unless result
18
+
19
+ Sexp.from_array(result)
20
+ end
21
+
13
22
  def on_comment tok
14
23
  @comment ||= ""
15
24
  @comment += tok
@@ -92,14 +101,21 @@ module RipperRubyParser
92
101
  def commentize name, exp
93
102
  raise "Comment stack empty in #{name} event" if @comment_stack.empty?
94
103
  tok, comment = @comment_stack.pop
104
+ @comment = nil
95
105
  unless tok == name
96
106
  raise "Expected on_#{tok} event, got on_#{name}"
97
107
  end
98
- if comment.nil?
99
- [:comment, "", exp]
100
- else
101
- [:comment, comment, exp]
102
- end
108
+ [:comment, comment || "", exp]
109
+ end
110
+
111
+ private
112
+
113
+ def suppress_warnings
114
+ old_verbose = $VERBOSE
115
+ $VERBOSE = nil
116
+ result = yield
117
+ $VERBOSE = old_verbose
118
+ result
103
119
  end
104
120
  end
105
121
  end
@@ -1,4 +1,4 @@
1
- require 'ripper_ruby_parser/commenting_sexp_builder'
1
+ require 'ripper_ruby_parser/commenting_ripper_parser'
2
2
  require 'ripper_ruby_parser/sexp_processor'
3
3
 
4
4
  module RipperRubyParser
@@ -13,13 +13,8 @@ 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.
17
- parser = CommentingSexpBuilder.new(source, filename, lineno)
18
-
19
- result = suppress_warnings { parser.parse }
20
- raise "Ripper parse failed." if result.nil?
21
-
22
- exp = Sexp.from_array(result)
16
+ parser = CommentingRipperParser.new(source, filename, lineno)
17
+ exp = parser.parse
23
18
 
24
19
  @processor.filename = filename
25
20
  @processor.extra_compatible = extra_compatible
@@ -31,16 +26,6 @@ module RipperRubyParser
31
26
  result
32
27
  end
33
28
  end
34
-
35
- private
36
-
37
- def suppress_warnings
38
- old_verbose = $VERBOSE
39
- $VERBOSE = nil
40
- result = yield
41
- $VERBOSE = old_verbose
42
- result
43
- end
44
29
  end
45
30
  end
46
31
 
@@ -13,7 +13,8 @@ module RipperRubyParser
13
13
  coll = nil if coll == s(:self)
14
14
 
15
15
  idx = process(idx) || s(:arglist)
16
- s(:call, coll, :[], idx)
16
+ idx.shift
17
+ s(:call, coll, :[], *idx)
17
18
  end
18
19
  end
19
20
  end
@@ -3,7 +3,6 @@ module RipperRubyParser
3
3
  module Assignment
4
4
  def process_assign exp
5
5
  _, lvalue, value = exp.shift 3
6
-
7
6
  lvalue = process(lvalue)
8
7
  value = process(value)
9
8
 
@@ -35,7 +34,7 @@ module RipperRubyParser
35
34
  case right.sexp_type
36
35
  when :fake_array
37
36
  right[0] = :array
38
- when :array, :splat
37
+ when :splat
39
38
  # Do nothing
40
39
  else
41
40
  right = s(:to_ary, right)
@@ -104,11 +103,7 @@ module RipperRubyParser
104
103
  def create_valueless_assignment_sub_type(item)
105
104
  item = with_line_number(item.line,
106
105
  create_regular_assignment_sub_type(item, nil))
107
- if item.sexp_type == :attrasgn
108
- item.last.pop
109
- else
110
- item.pop
111
- end
106
+ item.pop
112
107
  return item
113
108
  end
114
109
 
@@ -129,7 +124,7 @@ module RipperRubyParser
129
124
  if (mapped = OPERATOR_ASSIGNMENT_MAP[operator])
130
125
  s(mapped, lvalue, create_assignment_sub_type(lvalue, value))
131
126
  else
132
- operator_call = s(:call, lvalue, operator, s(:arglist, value))
127
+ operator_call = s(:call, lvalue, operator, value)
133
128
  create_assignment_sub_type lvalue, operator_call
134
129
  end
135
130
  end
@@ -140,10 +135,11 @@ module RipperRubyParser
140
135
  when :aref_field
141
136
  _, arr, arglist = lvalue
142
137
  arglist << value
143
- s(:attrasgn, arr, :[]=, arglist)
138
+ arglist.shift
139
+ s(:attrasgn, arr, :[]=, *arglist)
144
140
  when :field
145
141
  _, obj, _, (_, field) = lvalue
146
- s(:attrasgn, obj, :"#{field}=", s(:arglist, value))
142
+ s(:attrasgn, obj, :"#{field}=", value)
147
143
  else
148
144
  create_assignment_sub_type lvalue, value
149
145
  end
@@ -19,22 +19,25 @@ module RipperRubyParser
19
19
  end
20
20
 
21
21
  def process_params exp
22
- _, normal, defaults, rest, _, block = exp.shift 6
22
+ if exp.size == 6
23
+ _, normal, defaults, splat, rest, block = exp.shift 6
24
+ else
25
+ _, normal, defaults, splat, rest, _, _, block = exp.shift 8
26
+ end
23
27
 
24
28
  args = [*normal].map do |id|
25
29
  process(id)
26
30
  end
27
31
 
28
- assigns = [*defaults].map do |pair|
32
+ [*defaults].each do |pair|
29
33
  sym = process(pair[0])
30
- args << sym
31
34
  val = process(pair[1])
32
- s(:lasgn, sym[1], val)
35
+ args << s(:lasgn, sym[1], val)
33
36
  end
34
37
 
35
- args << process(rest) unless rest.nil?
38
+ args << process(splat) unless splat.nil? || splat == 0
39
+ [*rest].each {|arg| args << process(arg)}
36
40
  args << process(block) unless block.nil?
37
- args << s(:block, *assigns) if assigns.length > 0
38
41
 
39
42
  s(:args, *args)
40
43
  end
@@ -44,20 +47,20 @@ module RipperRubyParser
44
47
 
45
48
  names = process(args)
46
49
 
47
- args_to_assignment names
50
+ convert_special_args names
48
51
  end
49
52
 
50
53
  def process_begin exp
51
54
  _, body = exp.shift 2
52
55
 
53
- block = process(body)[1]
54
-
55
- strip_wrapping_block(block.compact)
56
+ body = process(body)
57
+ strip_typeless_sexp(body)
56
58
  end
57
59
 
58
60
  def process_rescue exp
59
61
  _, eclass, evar, block, after = exp.shift 5
60
62
  rescue_block = map_body(block)
63
+ rescue_block << nil if rescue_block.empty?
61
64
 
62
65
  arr = []
63
66
  if eclass
@@ -70,13 +73,11 @@ module RipperRubyParser
70
73
  end
71
74
 
72
75
  if evar
73
- evar = process(evar)[1]
74
- easgn = s(:lasgn, evar, s(:gvar, :$!))
75
- arr << easgn
76
+ arr << create_assignment_sub_type(process(evar), s(:gvar, :$!))
76
77
  end
77
78
 
78
79
  s(
79
- s(:resbody, s(:array, *arr), wrap_in_block(rescue_block)),
80
+ s(:resbody, s(:array, *arr), *rescue_block),
80
81
  *process(after))
81
82
  end
82
83
 
@@ -85,10 +86,6 @@ module RipperRubyParser
85
86
 
86
87
  body = map_body body
87
88
 
88
- #unless rescue_block or ensure_block
89
- # return s(:scope, s(:block, *body))
90
- #end
91
-
92
89
  body = wrap_in_block(body)
93
90
 
94
91
  body = if body.nil?
@@ -110,11 +107,15 @@ module RipperRubyParser
110
107
  body = s(s(:ensure, *body))
111
108
  end
112
109
 
113
- if body.length == 1 and body.first.sexp_type == :block
114
- s(:scope, *body)
115
- else
116
- s(:scope, s(:block, *body))
117
- end
110
+ body = wrap_in_block(body)
111
+
112
+ body = if body.nil?
113
+ s()
114
+ else
115
+ s(body)
116
+ end
117
+
118
+ body
118
119
  end
119
120
 
120
121
  def process_rescue_mod exp
@@ -124,7 +125,7 @@ module RipperRubyParser
124
125
 
125
126
  def process_ensure exp
126
127
  _, block = exp.shift 2
127
- wrap_in_block s(*map_body(block))
128
+ strip_typeless_sexp safe_wrap_in_block s(*map_body(block))
128
129
  end
129
130
 
130
131
  def process_next exp
@@ -147,8 +148,10 @@ module RipperRubyParser
147
148
 
148
149
  def process_lambda exp
149
150
  _, args, statements = exp.shift 3
150
- make_iter(s(:call, nil, :lambda, s(:arglist)),
151
- args_to_assignment(process(args)),
151
+ args = convert_special_args(process(args))
152
+ args = 0 if args == s(:args)
153
+ make_iter(s(:call, nil, :lambda),
154
+ args,
152
155
  *handle_potentially_typeless_sexp(statements))
153
156
  end
154
157
 
@@ -156,57 +159,31 @@ module RipperRubyParser
156
159
 
157
160
  def handle_generic_block exp
158
161
  _, args, stmts = exp.shift 3
162
+ args = process(args)
163
+ args = 0 if args == s(:args)
159
164
  # FIXME: Symbol :block is irrelevant.
160
- s(:block, process(args), s(handle_statement_list(stmts)))
165
+ s(:block, args, s(wrap_in_block(map_body(stmts))))
161
166
  end
162
167
 
163
- def strip_wrapping_block(block)
164
- return block unless block.sexp_type == :block
168
+ def strip_typeless_sexp(block)
165
169
  case block.length
166
- when 1
170
+ when 0
167
171
  s(:nil)
168
- when 2
169
- block[1]
172
+ when 1
173
+ block[0]
170
174
  else
171
175
  block
172
176
  end
173
177
  end
174
178
 
175
- def arg_name_to_lasgn(name)
176
- case name.sexp_type
177
- when :lvar
178
- s(:lasgn, name[1])
179
- when :blockarg
180
- s(:lasgn, :"&#{name[1][1]}")
181
- when :splat
182
- if name[1].nil?
183
- s(:splat)
184
- else
185
- s(:splat, s(:lasgn, name[1][1]))
186
- end
187
- else
188
- name
189
- end
190
- end
191
-
192
179
  def make_iter call, args, stmt
180
+ args = s(:args) unless args
193
181
  if stmt.nil?
194
182
  s(:iter, call, args)
195
183
  else
196
184
  s(:iter, call, args, stmt)
197
185
  end
198
186
  end
199
-
200
- def args_to_assignment names
201
- names.shift
202
- if names.length == 1 and names.first.sexp_type == :lvar
203
- s(:lasgn, names.first[1])
204
- elsif names.length == 1 and names.first.sexp_type == :masgn
205
- names.first
206
- else
207
- s(:masgn, s(:array, *names.map { |name| arg_name_to_lasgn(name) }))
208
- end
209
- end
210
187
  end
211
188
  end
212
189
  end
@@ -4,42 +4,35 @@ module RipperRubyParser
4
4
  def process_if exp
5
5
  _, cond, truepart, falsepart = exp.shift 4
6
6
 
7
- cond = process(cond)
8
- truepart = handle_statement_list(truepart)
9
- falsepart = process(falsepart)
10
-
11
- if cond.sexp_type == :not
12
- cond = cond[1]
13
- truepart, falsepart = falsepart, truepart
14
- end
15
-
16
- s(:if, cond, truepart, falsepart)
7
+ s(:if, handle_condition(cond),
8
+ wrap_in_block(map_body(truepart)),
9
+ process(falsepart))
17
10
  end
18
11
 
19
12
  def process_elsif exp
20
13
  _, cond, truepart, falsepart = exp.shift 4
21
14
 
22
15
  s(:if, process(cond),
23
- handle_statement_list(truepart),
16
+ wrap_in_block(map_body(truepart)),
24
17
  process(falsepart))
25
18
  end
26
19
 
27
20
  def process_if_mod exp
28
21
  _, cond, truepart = exp.shift 3
29
- process_if s(:if, cond, s(truepart), nil)
22
+ s(:if, handle_condition(cond), process(truepart), nil)
30
23
  end
31
24
 
32
25
  def process_unless_mod exp
33
26
  _, cond, truepart = exp.shift 3
34
- s(:if, process(cond), nil, process(truepart))
27
+ s(:if, handle_condition(cond), nil, process(truepart))
35
28
  end
36
29
 
37
30
  def process_unless exp
38
31
  _, cond, truepart, falsepart = exp.shift 4
39
32
  s(:if,
40
- process(cond),
33
+ handle_condition(cond),
41
34
  process(falsepart),
42
- handle_statement_list(truepart))
35
+ wrap_in_block(map_body(truepart)))
43
36
  end
44
37
 
45
38
  def process_case exp
@@ -58,25 +51,38 @@ module RipperRubyParser
58
51
  falsepart = s(falsepart)
59
52
  end
60
53
  end
54
+ falsepart = [nil] if falsepart.empty?
61
55
 
62
56
  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
57
 
71
- s(s(:when, s(:array, *values),
72
- handle_statement_list(truepart)),
58
+ truepart = map_body(truepart)
59
+ truepart = [nil] if truepart.empty?
60
+
61
+ s(s(:when,
62
+ s(:array, *values),
63
+ *truepart),
73
64
  *falsepart)
74
65
  end
75
66
 
76
67
  def process_else exp
77
68
  _, body = exp.shift 2
78
- handle_statement_list body
69
+ safe_wrap_in_block(map_body(body))
79
70
  end
71
+
72
+ private
73
+
74
+ def handle_condition(cond)
75
+ cond = process(cond)
76
+ if (cond.sexp_type == :lit) && cond[1].is_a?(Regexp)
77
+ cond = s(:match, cond)
78
+ elsif cond.sexp_type == :dot2
79
+ cond = s(:flip2, *cond[1..-1])
80
+ elsif cond.sexp_type == :dot3
81
+ cond = s(:flip3, *cond[1..-1])
82
+ end
83
+ return cond
84
+ end
85
+
80
86
  end
81
87
  end
82
88
  end