parser 2.1.9 → 2.2.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -67,16 +67,21 @@ module Parser
67
67
  @parser_class = Parser::Ruby19
68
68
  end
69
69
 
70
- @slop.on '20', 'Parse as Ruby 2.0.0 would' do
70
+ @slop.on '20', 'Parse as Ruby 2.0 would' do
71
71
  require 'parser/ruby20'
72
72
  @parser_class = Parser::Ruby20
73
73
  end
74
74
 
75
- @slop.on '21', 'Parse as Ruby 2.1.0 would' do
75
+ @slop.on '21', 'Parse as Ruby 2.1 would' do
76
76
  require 'parser/ruby21'
77
77
  @parser_class = Parser::Ruby21
78
78
  end
79
79
 
80
+ @slop.on '22', 'Parse as Ruby 2.2 would' do
81
+ require 'parser/ruby22'
82
+ @parser_class = Parser::Ruby22
83
+ end
84
+
80
85
  @slop.on 'w', 'warnings', 'Enable warnings'
81
86
 
82
87
  @slop.on 'B', 'benchmark', 'Benchmark the processor'
@@ -140,7 +145,9 @@ module Parser
140
145
 
141
146
  def process_fragments
142
147
  @fragments.each_with_index do |fragment, index|
143
- fragment = fragment.dup.force_encoding(@parser.default_encoding)
148
+ if fragment.respond_to? :force_encoding
149
+ fragment = fragment.dup.force_encoding(@parser.default_encoding)
150
+ end
144
151
 
145
152
  buffer = Source::Buffer.new("(fragment:#{index})")
146
153
  buffer.source = fragment
@@ -152,7 +159,9 @@ module Parser
152
159
  def process_files
153
160
  @files.each do |filename|
154
161
  source = File.read(filename)
155
- source.force_encoding(@parser.default_encoding)
162
+ if source.respond_to? :force_encoding
163
+ source.force_encoding(@parser.default_encoding)
164
+ end
156
165
 
157
166
  buffer = Parser::Source::Buffer.new(filename)
158
167
 
@@ -44,7 +44,7 @@ module Parser
44
44
  #
45
45
  # @param [Range] range
46
46
  # @return [Rewriter] self
47
- # @raise [RuntimeError] when clobbering is detected
47
+ # @raise [ClobberingError] when clobbering is detected
48
48
  #
49
49
  def remove(range)
50
50
  append Rewriter::Action.new(range, '')
@@ -56,7 +56,7 @@ module Parser
56
56
  # @param [Range] range
57
57
  # @param [String] content
58
58
  # @return [Rewriter] self
59
- # @raise [RuntimeError] when clobbering is detected
59
+ # @raise [ClobberingError] when clobbering is detected
60
60
  #
61
61
  def insert_before(range, content)
62
62
  append Rewriter::Action.new(range.begin, content)
@@ -68,7 +68,7 @@ module Parser
68
68
  # @param [Range] range
69
69
  # @param [String] content
70
70
  # @return [Rewriter] self
71
- # @raise [RuntimeError] when clobbering is detected
71
+ # @raise [ClobberingError] when clobbering is detected
72
72
  #
73
73
  def insert_after(range, content)
74
74
  append Rewriter::Action.new(range.end, content)
@@ -80,7 +80,7 @@ module Parser
80
80
  # @param [Range] range
81
81
  # @param [String] content
82
82
  # @return [Rewriter] self
83
- # @raise [RuntimeError] when clobbering is detected
83
+ # @raise [ClobberingError] when clobbering is detected
84
84
  #
85
85
  def replace(range, content)
86
86
  append Rewriter::Action.new(range, content)
@@ -93,6 +93,10 @@ module Parser
93
93
  # @return [String]
94
94
  #
95
95
  def process
96
+ if in_transaction?
97
+ raise "Do not call #{self.class}##{__method__} inside a transaction"
98
+ end
99
+
96
100
  adjustment = 0
97
101
  source = @source_buffer.source.dup
98
102
 
@@ -112,6 +116,46 @@ module Parser
112
116
  source
113
117
  end
114
118
 
119
+ ##
120
+ # Provides a protected block where a sequence of multiple rewrite actions
121
+ # are handled atomic. If any of the action failed by clobbering,
122
+ # all the actions are rolled back.
123
+ #
124
+ # @example
125
+ # begin
126
+ # rewriter.transaction do
127
+ # rewriter.insert_before(range_of_something, '(')
128
+ # rewriter.insert_after(range_of_something, ')')
129
+ # end
130
+ # rescue Parser::ClobberingError
131
+ # end
132
+ #
133
+ # @raise [RuntimeError] when no block is passed
134
+ # @raise [RuntimeError] when already in a transaction
135
+ #
136
+ def transaction
137
+ unless block_given?
138
+ raise "#{self.class}##{__method__} requires block"
139
+ end
140
+
141
+ if in_transaction?
142
+ raise 'Nested transaction is not supported'
143
+ end
144
+
145
+ @pending_queue = @queue.dup
146
+ @pending_clobber = @clobber
147
+
148
+ yield
149
+
150
+ @queue = @pending_queue
151
+ @clobber = @pending_clobber
152
+
153
+ self
154
+ ensure
155
+ @pending_queue = nil
156
+ @pending_clobber = nil
157
+ end
158
+
115
159
  private
116
160
 
117
161
  def append(action)
@@ -130,27 +174,47 @@ module Parser
130
174
  clobber_action.range)
131
175
  @diagnostics.process(diagnostic)
132
176
 
133
- raise RuntimeError, "Parser::Source::Rewriter detected clobbering"
177
+ raise ClobberingError, "Parser::Source::Rewriter detected clobbering"
134
178
  else
135
179
  clobber(action.range)
136
180
 
137
- @queue << action
181
+ active_queue << action
138
182
  end
139
183
 
140
184
  self
141
185
  end
142
186
 
143
187
  def clobber(range)
144
- @clobber |= (2 ** range.size - 1) << range.begin_pos
188
+ self.active_clobber = active_clobber | (2 ** range.size - 1) << range.begin_pos
145
189
  end
146
190
 
147
191
  def clobbered?(range)
148
- if @clobber & ((2 ** range.size - 1) << range.begin_pos) != 0
149
- @queue.find do |action|
192
+ if active_clobber & ((2 ** range.size - 1) << range.begin_pos) != 0
193
+ active_queue.find do |action|
150
194
  action.range.to_a & range.to_a
151
195
  end
152
196
  end
153
197
  end
198
+
199
+ def in_transaction?
200
+ !@pending_queue.nil?
201
+ end
202
+
203
+ def active_queue
204
+ @pending_queue || @queue
205
+ end
206
+
207
+ def active_clobber
208
+ @pending_clobber || @clobber
209
+ end
210
+
211
+ def active_clobber=(value)
212
+ if @pending_clobber
213
+ @pending_clobber = value
214
+ else
215
+ @clobber = value
216
+ end
217
+ end
154
218
  end
155
219
 
156
220
  end
@@ -1,3 +1,3 @@
1
1
  module Parser
2
- VERSION = '2.1.9'
2
+ VERSION = '2.2.0.pre.1'
3
3
  end
@@ -21,14 +21,14 @@ Gem::Specification.new do |spec|
21
21
  lib/parser/ruby21.rb
22
22
  )
23
23
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
24
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
24
+ spec.test_files = spec.files.grep(%r{^test/})
25
25
  spec.require_paths = ['lib']
26
26
 
27
27
  spec.add_dependency 'ast', ['>= 1.1', '< 3.0']
28
28
  spec.add_dependency 'slop', ['~> 3.4', '>= 3.4.5']
29
29
 
30
30
  spec.add_development_dependency 'bundler', '~> 1.2'
31
- spec.add_development_dependency 'rake', '~> 0.9'
31
+ spec.add_development_dependency 'rake', ['>= 0.9', '< 11.0']
32
32
  spec.add_development_dependency 'racc', '= 1.4.9' # update to 1.4.11 when it's done
33
33
  spec.add_development_dependency 'cliver', '~> 0.3.0'
34
34
 
@@ -7,9 +7,9 @@ module ParseHelper
7
7
  ALL_VERSIONS = %w(1.8)
8
8
  else
9
9
  require 'parser/all'
10
- require 'parser/ruby21'
10
+ require 'parser/ruby22'
11
11
 
12
- ALL_VERSIONS = %w(1.8 1.9 2.0 2.1)
12
+ ALL_VERSIONS = %w(1.8 1.9 2.0 2.1 2.2)
13
13
  end
14
14
 
15
15
  def setup
@@ -24,6 +24,7 @@ module ParseHelper
24
24
  when '1.9' then parser = Parser::Ruby19.new
25
25
  when '2.0' then parser = Parser::Ruby20.new
26
26
  when '2.1' then parser = Parser::Ruby21.new
27
+ when '2.2' then parser = Parser::Ruby22.new
27
28
  else raise "Unrecognized Ruby version #{version}"
28
29
  end
29
30
 
@@ -10,8 +10,10 @@ class TestCurrent < Minitest::Test
10
10
  assert_equal Parser::Ruby19, Parser::CurrentRuby
11
11
  when '2.0.0'
12
12
  assert_equal Parser::Ruby20, Parser::CurrentRuby
13
- when '2.1.0', '2.1.1'
13
+ when '2.1.0', '2.1.1', '2.1.2'
14
14
  assert_equal Parser::Ruby21, Parser::CurrentRuby
15
+ when '2.2.0'
16
+ assert_equal Parser::Ruby22, Parser::CurrentRuby
15
17
  else
16
18
  flunk "Update test_parser_current for #{RUBY_VERSION}"
17
19
  end
@@ -1769,6 +1769,25 @@ class TestParser < Minitest::Test
1769
1769
  | ~~~~~~ expression (args.blockarg)})
1770
1770
  end
1771
1771
 
1772
+ def test_arg_scope
1773
+ # [ruby-core:61299] [Bug #9593]
1774
+ assert_parses(
1775
+ s(:def, :f,
1776
+ s(:args, s(:optarg, :var, s(:defined?, s(:lvar, :var)))),
1777
+ s(:lvar, :var)),
1778
+ %q{def f(var = defined?(var)) var end},
1779
+ %q{},
1780
+ ALL_VERSIONS - %w(1.8 1.9 2.0))
1781
+
1782
+ assert_parses(
1783
+ s(:def, :f,
1784
+ s(:args, s(:kwoptarg, :var, s(:defined?, s(:lvar, :var)))),
1785
+ s(:lvar, :var)),
1786
+ %q{def f(var: defined?(var)) var end},
1787
+ %q{},
1788
+ ALL_VERSIONS - %w(1.8 1.9 2.0))
1789
+ end
1790
+
1772
1791
  def assert_parses_args(ast, code, versions=ALL_VERSIONS)
1773
1792
  assert_parses(
1774
1793
  s(:def, :f, ast, nil),
@@ -4765,6 +4784,34 @@ class TestParser < Minitest::Test
4765
4784
  %q{desc "foo" do end})
4766
4785
  end
4767
4786
 
4787
+ def test_bug_do_block_in_call_args
4788
+ # [ruby-core:59342] [Bug #9308]
4789
+ assert_parses(
4790
+ s(:send, nil, :bar,
4791
+ s(:def, :foo,
4792
+ s(:args),
4793
+ s(:block,
4794
+ s(:send, s(:self), :each),
4795
+ s(:args),
4796
+ nil))),
4797
+ %q{bar def foo; self.each do end end},
4798
+ %q{},
4799
+ ALL_VERSIONS - %w(1.8 1.9 2.0 2.1))
4800
+ end
4801
+
4802
+ def test_bug_do_block_in_cmdarg
4803
+ # [ruby-core:61950] [Bug #9726]
4804
+ assert_parses(
4805
+ s(:send, nil, :tap,
4806
+ s(:begin,
4807
+ s(:block,
4808
+ s(:send, nil, :proc),
4809
+ s(:args), nil))),
4810
+ %q{tap (proc do end)},
4811
+ %q{},
4812
+ ALL_VERSIONS - %w(1.8 1.9 2.0 2.1))
4813
+ end
4814
+
4768
4815
  def test_bug_interp_single
4769
4816
  assert_parses(
4770
4817
  s(:dstr, s(:begin, s(:int, 1))),
@@ -74,7 +74,7 @@ class TestSourceRewriter < Minitest::Test
74
74
  diagnostics << diag
75
75
  end
76
76
 
77
- assert_raises RuntimeError, /clobber/ do
77
+ assert_raises Parser::ClobberingError do
78
78
  @rewriter.
79
79
  replace(range(3, 1), '---').
80
80
  remove(range(3, 1))
@@ -92,4 +92,88 @@ class TestSourceRewriter < Minitest::Test
92
92
  diagnostics.last.message
93
93
  assert_equal range(3, 1), diagnostics.last.location
94
94
  end
95
+
96
+ def test_clobbering_error_backward_compatibility
97
+ silence_diagnostics
98
+
99
+ rescued = false
100
+
101
+ # We use begin..rescue..end here rather than #assert_raises
102
+ # since #assert_raises expects exact error class.
103
+ begin
104
+ @rewriter.
105
+ replace(range(3, 1), '---').
106
+ remove(range(3, 1))
107
+ rescue RuntimeError => error
108
+ rescued = true if error.message.include?('clobber')
109
+ end
110
+
111
+ assert rescued
112
+ end
113
+
114
+ def test_transaction_returns_self
115
+ assert_equal @rewriter, @rewriter.transaction {}
116
+ end
117
+
118
+ def test_transaction_commit
119
+ silence_diagnostics
120
+
121
+ # Original: 'foo bar baz'
122
+
123
+ # Rewrite as 'foo BAR baz'
124
+ @rewriter.replace(range(4, 3), 'BAR')
125
+
126
+ # Rewrite as '( bar )'
127
+ @rewriter.transaction do
128
+ @rewriter.replace(range(0, 3), '(')
129
+ @rewriter.replace(range(8, 3), ')')
130
+ end
131
+
132
+ @rewriter.replace(range(3, 1), '_')
133
+ @rewriter.replace(range(7, 1), '_')
134
+
135
+ assert_equal '(_BAR_)', @rewriter.process
136
+ end
137
+
138
+ def test_transaction_rollback
139
+ silence_diagnostics
140
+
141
+ # Original: 'foo bar baz'
142
+
143
+ # Rewrite as 'foo bar BAZ'
144
+ @rewriter.replace(range(8, 3), 'BAZ')
145
+
146
+ assert_raises Parser::ClobberingError do
147
+ # Trying to rewrite as '( bar )', but it fails
148
+ @rewriter.transaction do
149
+ @rewriter.replace(range(0, 3), '(')
150
+ @rewriter.replace(range(8, 3), ')')
151
+ end
152
+ end
153
+
154
+ @rewriter.replace(range(0, 3), 'FOO')
155
+
156
+ assert_equal 'FOO bar BAZ', @rewriter.process
157
+ end
158
+
159
+ def test_nested_transaction_raises_error
160
+ assert_raises RuntimeError, /nested/ do
161
+ @rewriter.transaction do
162
+ @rewriter.transaction do
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ def test_process_in_transaction_raises_error
169
+ assert_raises RuntimeError, /transaction/ do
170
+ @rewriter.transaction do
171
+ @rewriter.process
172
+ end
173
+ end
174
+ end
175
+
176
+ def silence_diagnostics
177
+ @rewriter.diagnostics.consumer = proc {}
178
+ end
95
179
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.9
4
+ version: 2.2.0.pre.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Zotov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-21 00:00:00.000000000 Z
11
+ date: 2014-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ast
@@ -68,16 +68,22 @@ dependencies:
68
68
  name: rake
69
69
  requirement: !ruby/object:Gem::Requirement
70
70
  requirements:
71
- - - "~>"
71
+ - - ">="
72
72
  - !ruby/object:Gem::Version
73
73
  version: '0.9'
74
+ - - "<"
75
+ - !ruby/object:Gem::Version
76
+ version: '11.0'
74
77
  type: :development
75
78
  prerelease: false
76
79
  version_requirements: !ruby/object:Gem::Requirement
77
80
  requirements:
78
- - - "~>"
81
+ - - ">="
79
82
  - !ruby/object:Gem::Version
80
83
  version: '0.9'
84
+ - - "<"
85
+ - !ruby/object:Gem::Version
86
+ version: '11.0'
81
87
  - !ruby/object:Gem::Dependency
82
88
  name: racc
83
89
  requirement: !ruby/object:Gem::Requirement
@@ -242,7 +248,6 @@ extensions: []
242
248
  extra_rdoc_files: []
243
249
  files:
244
250
  - ".gitignore"
245
- - ".rubocop.yml"
246
251
  - ".travis.yml"
247
252
  - ".yardopts"
248
253
  - CHANGELOG.md
@@ -265,6 +270,7 @@ files:
265
270
  - lib/parser/ast/processor.rb
266
271
  - lib/parser/base.rb
267
272
  - lib/parser/builders/default.rb
273
+ - lib/parser/clobbering_error.rb
268
274
  - lib/parser/compatibility/ruby1_8.rb
269
275
  - lib/parser/compatibility/ruby1_9.rb
270
276
  - lib/parser/current.rb
@@ -286,6 +292,7 @@ files:
286
292
  - lib/parser/ruby20.y
287
293
  - lib/parser/ruby21.rb
288
294
  - lib/parser/ruby21.y
295
+ - lib/parser/ruby22.y
289
296
  - lib/parser/runner.rb
290
297
  - lib/parser/runner/ruby_parse.rb
291
298
  - lib/parser/runner/ruby_rewrite.rb
@@ -346,9 +353,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
346
353
  version: '0'
347
354
  required_rubygems_version: !ruby/object:Gem::Requirement
348
355
  requirements:
349
- - - ">="
356
+ - - ">"
350
357
  - !ruby/object:Gem::Version
351
- version: '0'
358
+ version: 1.3.1
352
359
  requirements: []
353
360
  rubyforge_project:
354
361
  rubygems_version: 2.2.2