parser 2.7.1.0 → 2.7.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 46184af7a1e0d843e62e720cd7795bb196972603e588eed69f47791b3c799288
4
- data.tar.gz: 1a9d809fc7443fb09deb3a36ea19ad418ff56119040b14a292c9ed8d112d1f29
3
+ metadata.gz: fb7c9797808fcd8920ef34ccce6dae7f416d0fe3084a863fa3fec7fa30b086fc
4
+ data.tar.gz: 828a937688a35e277c7d435197ca2d023458de366a8e94fbaa67bdd6d3a04145
5
5
  SHA512:
6
- metadata.gz: 9a91995ac131a4048976358a7bce1bd09b09893bb0b13fa39f2128c47fb0b1179f830a4adbb766df768bfbd2f89a1c5a5ee437dc1433ccaf5ad2307ff7c09d77
7
- data.tar.gz: 4fe835bc9fe1ff030d57e9a4d9a4657a0d244db23bac3c117e8f78bfc51d9dc330f51257e04c8ba5ef737d3feab11152db2e1ecde1e8b136d4fcc4f253ed549d
6
+ metadata.gz: 679bc103f3d8b2663a1ec2de6c3acac41c90c1d738b40bf4b5ed945b8e3f51e22359caa0789e55009f3bd2c45ac832d00182db9ba9be1f43b18e6fe0e0508278
7
+ data.tar.gz: b4f4d29766e23ca406644fb578e2134f28a9983d765d4aa45117dcb5a9ee012f27c2b8b65eccf11b7e3818b1543a62cc0483aa510a51352bc2260ad0fd650acd
@@ -2,8 +2,8 @@ dist: trusty
2
2
  language: ruby
3
3
  matrix:
4
4
  include:
5
- - name: 2.4.9 / Parser tests
6
- rvm: 2.4.9
5
+ - name: 2.4.10 / Parser tests
6
+ rvm: 2.4.10
7
7
  script: bundle exec rake test_cov
8
8
  - name: 2.5.8 / Parser tests
9
9
  rvm: 2.5.8
@@ -1,9 +1,16 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
- Not released (2020-04-03)
4
+ Not released (2020-04-15)
5
5
  -------------------------
6
6
 
7
+ Features implemented:
8
+ * Add Source::Range#eql? and hash (#675) (Marc-André Lafortune)
9
+ * Source::TreeRewriter: Add #merge, #merge! and #empty? (#674) (Marc-André Lafortune)
10
+
11
+ v2.7.1.0 (2020-04-03)
12
+ ---------------------
13
+
7
14
  API modifications:
8
15
  * Bump ruby versions to 2.4.10, 2.5.8, 2.6.6, 2.7.1. (#665) (Ilya Bylich)
9
16
 
@@ -298,6 +298,15 @@ module Parser
298
298
  (@end_pos <=> other.end_pos)
299
299
  end
300
300
 
301
+ alias_method :eql?, :==
302
+
303
+ ##
304
+ # Support for Ranges be used in as Hash indices and in Sets.
305
+ #
306
+ def hash
307
+ [@source_buffer, @begin_pos, @end_pos].hash
308
+ end
309
+
301
310
  ##
302
311
  # @return [String] a human-readable representation of this range.
303
312
  #
@@ -117,6 +117,43 @@ module Parser
117
117
  @action_root = TreeRewriter::Action.new(all_encompassing_range, @enforcer)
118
118
  end
119
119
 
120
+ ##
121
+ # Returns true iff no (non trivial) update has been recorded
122
+ #
123
+ # @return [Boolean]
124
+ #
125
+ def empty?
126
+ @action_root.empty?
127
+ end
128
+
129
+ ##
130
+ # Merges the updates of argument with the receiver.
131
+ # Policies of the receiver are used.
132
+ #
133
+ # @param [Rewriter] with
134
+ # @return [Rewriter] self
135
+ # @raise [ClobberingError] when clobbering is detected
136
+ #
137
+ def merge!(with)
138
+ raise 'TreeRewriter are not for the same source_buffer' unless
139
+ source_buffer == with.source_buffer
140
+
141
+ @action_root = @action_root.combine(with.action_root)
142
+ self
143
+ end
144
+
145
+ ##
146
+ # Returns a new rewriter that consists of the updates of the received
147
+ # and the given argument. Policies of the receiver are used.
148
+ #
149
+ # @param [Rewriter] with
150
+ # @return [Rewriter] merge of receiver and argument
151
+ # @raise [ClobberingError] when clobbering is detected
152
+ #
153
+ def merge(with)
154
+ dup.merge!(with)
155
+ end
156
+
120
157
  ##
121
158
  # Replaces the code of the source range `range` with `content`.
122
159
  #
@@ -203,10 +240,9 @@ module Parser
203
240
  ##
204
241
  # Provides a protected block where a sequence of multiple rewrite actions
205
242
  # are handled atomically. If any of the actions failed by clobbering,
206
- # all the actions are rolled back.
243
+ # all the actions are rolled back. Transactions can be nested.
207
244
  #
208
245
  # @raise [RuntimeError] when no block is passed
209
- # @raise [RuntimeError] when already in a transaction
210
246
  #
211
247
  def transaction
212
248
  unless block_given?
@@ -256,6 +292,10 @@ module Parser
256
292
 
257
293
  extend Deprecation
258
294
 
295
+ protected
296
+
297
+ attr_reader :action_root
298
+
259
299
  private
260
300
 
261
301
  ACTIONS = %i[accept warn raise].freeze
@@ -25,12 +25,18 @@ module Parser
25
25
  freeze
26
26
  end
27
27
 
28
- # Assumes action.children.empty?
29
28
  def combine(action)
30
- return self unless action.insertion? || action.replacement # Ignore empty action
29
+ return self if action.empty? # Ignore empty action
31
30
  do_combine(action)
32
31
  end
33
32
 
33
+ def empty?
34
+ @insert_before.empty? &&
35
+ @insert_after.empty? &&
36
+ @children.empty? &&
37
+ (@replacement == nil || (@replacement.empty? && @range.empty?))
38
+ end
39
+
34
40
  def ordered_replacements
35
41
  reps = []
36
42
  reps << [@range.begin, @insert_before] unless @insert_before.empty?
@@ -46,9 +52,11 @@ module Parser
46
52
 
47
53
  protected
48
54
 
49
- def with(range: @range, children: @children, insert_before: @insert_before, replacement: @replacement, insert_after: @insert_after)
55
+ attr_reader :children
56
+
57
+ def with(range: @range, enforcer: @enforcer, children: @children, insert_before: @insert_before, replacement: @replacement, insert_after: @insert_after)
50
58
  children = swallow(children) if replacement
51
- self.class.new(range, @enforcer, children: children, insert_before: insert_before, replacement: replacement, insert_after: insert_after)
59
+ self.class.new(range, enforcer, children: children, insert_before: insert_before, replacement: replacement, insert_after: insert_after)
52
60
  end
53
61
 
54
62
  # Assumes range.contains?(action.range) && action.children.empty?
@@ -69,7 +77,8 @@ module Parser
69
77
  extra_sibbling = if family[:parent] # action should be a descendant of one of the children
70
78
  family[:parent][0].do_combine(action)
71
79
  elsif family[:child] # or it should become the parent of some of the children,
72
- action.with(children: family[:child])
80
+ action.with(children: family[:child], enforcer: @enforcer)
81
+ .combine_children(action.children)
73
82
  else # or else it should become an additional child
74
83
  action
75
84
  end
@@ -77,6 +86,13 @@ module Parser
77
86
  end
78
87
  end
79
88
 
89
+ # Assumes more_children all contained within @range
90
+ def combine_children(more_children)
91
+ more_children.inject(self) do |parent, new_child|
92
+ parent.place_in_hierarchy(new_child)
93
+ end
94
+ end
95
+
80
96
  def fuse_deletions(action, fusible, other_sibblings)
81
97
  without_fusible = with(children: other_sibblings)
82
98
  fused_range = [action, *fusible].map(&:range).inject(:join)
@@ -109,7 +125,7 @@ module Parser
109
125
  insert_before: "#{action.insert_before}#{insert_before}",
110
126
  replacement: action.replacement || @replacement,
111
127
  insert_after: "#{insert_after}#{action.insert_after}",
112
- )
128
+ ).combine_children(action.children)
113
129
  end
114
130
 
115
131
  def call_enforcer_for_merge(action)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Parser
4
- VERSION = '2.7.1.0'
4
+ VERSION = '2.7.1.1'
5
5
  end
@@ -169,4 +169,19 @@ class TestSourceRange < Minitest::Test
169
169
  assert_equal 1, sr3.begin_pos
170
170
  assert_equal 4, sr3.end_pos
171
171
  end
172
+
173
+ def test_eql_and_hash
174
+ assert_equal false, @sr1_3.eql?(@sr3_3)
175
+ assert @sr1_3.hash != @sr3_3.hash
176
+
177
+ also_1_3 = @sr3_3.with(begin_pos: 1)
178
+ assert_equal true, @sr1_3.eql?(also_1_3)
179
+ assert_equal @sr1_3.hash, also_1_3.hash
180
+
181
+ buf2 = Parser::Source::Buffer.new('(string)')
182
+ buf2.source = "foobar\nbaz"
183
+ from_other_buf = Parser::Source::Range.new(buf2, 1, 3)
184
+ assert_equal false, @sr1_3.eql?(from_other_buf)
185
+ assert @sr1_3.hash != from_other_buf.hash
186
+ end
172
187
  end
@@ -8,8 +8,10 @@ class TestSourceTreeRewriter < Minitest::Test
8
8
  @buf.source = 'puts(:hello, :world)'
9
9
 
10
10
  @hello = range(5, 6)
11
+ @ll = range(7, 2)
11
12
  @comma_space = range(11,2)
12
13
  @world = range(13,6)
14
+ @whole = range(0, @buf.source.length)
13
15
  end
14
16
 
15
17
  def range(from, len)
@@ -17,11 +19,11 @@ class TestSourceTreeRewriter < Minitest::Test
17
19
  end
18
20
 
19
21
  # Returns either:
20
- # - String (Normal operation)
22
+ # - yield rewriter
21
23
  # - [diagnostic, ...] (Diagnostics)
22
24
  # - Parser::ClobberingError
23
25
  #
24
- def apply(actions, **policy)
26
+ def build(actions, **policy)
25
27
  diagnostics = []
26
28
  diags = -> { diagnostics.flatten.map(&:strip).join("\n") }
27
29
  rewriter = Parser::Source::TreeRewriter.new(@buf, **policy)
@@ -30,7 +32,7 @@ class TestSourceTreeRewriter < Minitest::Test
30
32
  rewriter.public_send(action, range, *args)
31
33
  end
32
34
  if diagnostics.empty?
33
- rewriter.process
35
+ yield rewriter
34
36
  else
35
37
  diags.call
36
38
  end
@@ -38,6 +40,15 @@ class TestSourceTreeRewriter < Minitest::Test
38
40
  [::Parser::ClobberingError, diags.call]
39
41
  end
40
42
 
43
+ # Returns either:
44
+ # - String (Normal operation)
45
+ # - [diagnostic, ...] (Diagnostics)
46
+ # - Parser::ClobberingError
47
+ #
48
+ def apply(actions, **policy)
49
+ build(actions, **policy) { |rewriter| rewriter.process }
50
+ end
51
+
41
52
  # Expects ordered actions to be grouped together
42
53
  def check_actions(expected, grouped_actions, **policy)
43
54
  grouped_actions.permutation do |sequence|
@@ -170,4 +181,73 @@ DIAGNOSTIC
170
181
  rewriter = Parser::Source::TreeRewriter.new(@buf)
171
182
  assert_raises(IndexError) { rewriter.insert_before(range(0, 100), 'hola') }
172
183
  end
184
+
185
+ def test_empty
186
+ rewriter = Parser::Source::TreeRewriter.new(@buf)
187
+ assert_equal true, rewriter.empty?
188
+
189
+ # This is a trivial wrap
190
+ rewriter.wrap(range(2,3), '', '')
191
+ assert_equal true, rewriter.empty?
192
+
193
+ # This is a trivial deletion
194
+ rewriter.remove(range(2,0))
195
+ assert_equal true, rewriter.empty?
196
+
197
+ rewriter.remove(range(2,3))
198
+ assert_equal false, rewriter.empty?
199
+ end
200
+
201
+ # splits array into two groups, yield all such possible pairs of groups
202
+ # each_split([1, 2, 3, 4]) yields [1, 2], [3, 4];
203
+ # then [1, 3], [2, 4]
204
+ # ...
205
+ # and finally [3, 4], [1, 2]
206
+ def each_split(array)
207
+ n = array.size
208
+ first_split_size = n.div(2)
209
+ splitting = (0...n).to_set
210
+ splitting.to_a.combination(first_split_size) do |indices|
211
+ yield array.values_at(*indices),
212
+ array.values_at(*(splitting - indices))
213
+ end
214
+ end
215
+
216
+ # Checks that `actions+extra` give the same result when
217
+ # made in order or from subgroups that are later merged.
218
+ # The `extra` actions are always added at the end of the second group.
219
+ #
220
+ def check_all_merge_possibilities(actions, extra, **policy)
221
+ expected = apply(actions + extra, **policy)
222
+
223
+ each_split(actions) do |actions_1, actions_2|
224
+ build(actions_1, **policy) do |rewriter_1|
225
+ build(actions_2 + extra, **policy) do |rewriter_2|
226
+ result = rewriter_1.merge(rewriter_2).process
227
+ assert_equal(expected, result,
228
+ "Group 1: #{actions_1.inspect}\n\n" +
229
+ "Group 2: #{(actions_2 + extra).inspect}"
230
+ )
231
+ end
232
+ end
233
+ end
234
+ end
235
+
236
+ def test_merge
237
+ check_all_merge_possibilities([
238
+ [:wrap, @whole, '<', '>'],
239
+ [:replace, @comma_space, ' => '],
240
+ [:wrap, @hello, '!', '!'],
241
+ # Following two wraps must have same value as they
242
+ # will be applied in different orders...
243
+ [:wrap, @hello.join(@world), '{', '}'],
244
+ [:wrap, @hello.join(@world), '{', '}'],
245
+ [:remove, @ll],
246
+ [:replace, @world, ':everybody'],
247
+ [:wrap, @world, '[', ']']
248
+ ],
249
+ [ # ... but this one is always going to be applied last (extra)
250
+ [:wrap, @hello.join(@world), '@', '@'],
251
+ ])
252
+ end
173
253
  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.7.1.0
4
+ version: 2.7.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - whitequark
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-03 00:00:00.000000000 Z
11
+ date: 2020-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ast
@@ -297,9 +297,9 @@ licenses:
297
297
  - MIT
298
298
  metadata:
299
299
  bug_tracker_uri: https://github.com/whitequark/parser/issues
300
- changelog_uri: https://github.com/whitequark/parser/blob/v2.7.1.0/CHANGELOG.md
301
- documentation_uri: https://www.rubydoc.info/gems/parser/2.7.1.0
302
- source_code_uri: https://github.com/whitequark/parser/tree/v2.7.1.0
300
+ changelog_uri: https://github.com/whitequark/parser/blob/v2.7.1.1/CHANGELOG.md
301
+ documentation_uri: https://www.rubydoc.info/gems/parser/2.7.1.1
302
+ source_code_uri: https://github.com/whitequark/parser/tree/v2.7.1.1
303
303
  post_install_message:
304
304
  rdoc_options: []
305
305
  require_paths: