parser 2.1.9 → 2.2.0.pre.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.
@@ -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