unparser 0.6.15 → 0.7.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/unparser/anima.rb +11 -0
  3. data/lib/unparser/ast/local_variable_scope.rb +28 -24
  4. data/lib/unparser/ast.rb +18 -22
  5. data/lib/unparser/buffer.rb +44 -2
  6. data/lib/unparser/cli.rb +26 -5
  7. data/lib/unparser/either.rb +6 -6
  8. data/lib/unparser/emitter/array.rb +0 -4
  9. data/lib/unparser/emitter/array_pattern.rb +1 -9
  10. data/lib/unparser/emitter/assignment.rb +7 -8
  11. data/lib/unparser/emitter/begin.rb +0 -6
  12. data/lib/unparser/emitter/binary.rb +1 -1
  13. data/lib/unparser/emitter/block.rb +3 -4
  14. data/lib/unparser/emitter/def.rb +1 -1
  15. data/lib/unparser/emitter/dstr.rb +6 -5
  16. data/lib/unparser/emitter/flow_modifier.rb +0 -6
  17. data/lib/unparser/emitter/for.rb +1 -1
  18. data/lib/unparser/emitter/hash.rb +0 -8
  19. data/lib/unparser/emitter/hash_pattern.rb +1 -1
  20. data/lib/unparser/emitter/index.rb +0 -4
  21. data/lib/unparser/emitter/op_assign.rb +0 -10
  22. data/lib/unparser/emitter/primitive.rb +0 -13
  23. data/lib/unparser/emitter/regexp.rb +5 -17
  24. data/lib/unparser/emitter/rescue.rb +7 -1
  25. data/lib/unparser/emitter/root.rb +2 -9
  26. data/lib/unparser/emitter/send.rb +1 -5
  27. data/lib/unparser/emitter/string.rb +31 -0
  28. data/lib/unparser/emitter.rb +9 -10
  29. data/lib/unparser/generation.rb +8 -14
  30. data/lib/unparser/node_details.rb +1 -0
  31. data/lib/unparser/validation.rb +68 -28
  32. data/lib/unparser/writer/dynamic_string.rb +128 -135
  33. data/lib/unparser/writer/regexp.rb +98 -0
  34. data/lib/unparser/writer/resbody.rb +30 -1
  35. data/lib/unparser/writer/rescue.rb +2 -6
  36. data/lib/unparser/writer/send.rb +8 -14
  37. data/lib/unparser/writer.rb +32 -1
  38. data/lib/unparser.rb +103 -30
  39. metadata +15 -13
data/lib/unparser.rb CHANGED
@@ -44,12 +44,18 @@ module Unparser
44
44
  @node = node
45
45
  freeze
46
46
  end
47
- end
47
+ end # InvalidNodeError
48
+
49
+ # Error raised when unparser encounders AST it cannot generate source for that would parse to the same AST.
50
+ class UnsupportedNodeError < RuntimeError
51
+ end # UnsupportedNodeError
48
52
 
49
53
  # Unparse an AST (and, optionally, comments) into a string
50
54
  #
51
55
  # @param [Parser::AST::Node, nil] node
52
- # @param [Array] comment_array
56
+ # @param [Array] comments
57
+ # @param [Encoding, nil] explicit_encoding
58
+ # @param [Set<Symbol>] static_local_variables
53
59
  #
54
60
  # @return [String]
55
61
  #
@@ -57,44 +63,99 @@ module Unparser
57
63
  # if the node passed is invalid
58
64
  #
59
65
  # @api public
60
- def self.unparse(node, comment_array = [])
61
- return '' if node.nil?
66
+ #
67
+ # mutant:disable
68
+ # rubocop:disable Metrics/ParameterLists
69
+ def self.unparse(
70
+ node,
71
+ comments: EMPTY_ARRAY,
72
+ explicit_encoding: nil,
73
+ static_local_variables: Set.new
74
+ )
75
+ unparse_ast(
76
+ AST.new(
77
+ comments: comments,
78
+ explicit_encoding: explicit_encoding,
79
+ node: node,
80
+ static_local_variables: static_local_variables
81
+ )
82
+ )
83
+ end
84
+ # rubocop:enable Metrics/ParameterLists
85
+
86
+ # Unparse an AST
87
+ #
88
+ # @param [AST] ast
89
+ #
90
+ # @return [String]
91
+ #
92
+ # @raise InvalidNodeError
93
+ # if the node passed is invalid
94
+ #
95
+ # @raise UnsupportedNodeError
96
+ # if the node passed is valid but unparser cannot unparse it
97
+ #
98
+ # @api public
99
+ def self.unparse_ast(ast)
100
+ return EMPTY_STRING if ast.node.nil?
101
+
102
+ local_variable_scope = AST::LocalVariableScope.new(
103
+ node: ast.node,
104
+ static_local_variables: ast.static_local_variables
105
+ )
62
106
 
63
107
  Buffer.new.tap do |buffer|
64
108
  Emitter::Root.new(
65
- buffer,
66
- node,
67
- Comments.new(comment_array)
109
+ buffer: buffer,
110
+ comments: Comments.new(ast.comments),
111
+ explicit_encoding: ast.explicit_encoding,
112
+ local_variable_scope: local_variable_scope,
113
+ node: ast.node
68
114
  ).write_to_buffer
69
115
  end.content
70
116
  end
71
117
 
72
- # Unparse with validation
118
+ # Unparse AST either
73
119
  #
74
- # @param [Parser::AST::Node, nil] node
75
- # @param [Array] comment_array
120
+ # @param [AST] ast
76
121
  #
77
- # @return [Either<Validation,String>]
78
- def self.unparse_validate(node, comment_array = [])
79
- generated = unparse(node, comment_array)
80
- validation = Validation.from_string(generated)
122
+ # @return [Either<Exception,String>]
123
+ def self.unparse_ast_either(ast)
124
+ Either.wrap_error(Exception) { unparse_ast(ast) }
125
+ end
126
+
127
+ # Unparse AST either
128
+ #
129
+ # @param [AST] ast
130
+ #
131
+ # @return [Either<Exception,String>]
132
+ #
133
+ # mutant:disable
134
+ def self.unparse_validate_ast_either(ast:)
135
+ validation = Validation.from_ast(ast:)
81
136
 
82
137
  if validation.success?
83
- Either::Right.new(generated)
138
+ Either::Right.new(validation.generated_source.from_right)
84
139
  else
85
140
  Either::Left.new(validation)
86
141
  end
87
142
  end
88
143
 
89
- # Unparse capturing errors
90
- #
91
- # This is mostly useful for writing testing tools against unparser.
144
+ # Unparse with validation
92
145
  #
93
146
  # @param [Parser::AST::Node, nil] node
147
+ # @param [Array] comments
94
148
  #
95
- # @return [Either<Exception, String>]
96
- def self.unparse_either(node)
97
- Either.wrap_error(Exception) { unparse(node) }
149
+ # @return [Either<Validation,String>]
150
+ def self.unparse_validate(node, comments: EMPTY_ARRAY)
151
+ generated = unparse(node, comments:)
152
+ validation = Validation.from_string(generated)
153
+
154
+ if validation.success?
155
+ Either::Right.new(generated)
156
+ else
157
+ Either::Left.new(validation)
158
+ end
98
159
  end
99
160
 
100
161
  # Parse string into AST
@@ -103,27 +164,37 @@ module Unparser
103
164
  #
104
165
  # @return [Parser::AST::Node, nil]
105
166
  def self.parse(source)
106
- parser.parse(buffer(source))
167
+ parse_ast(source).node
107
168
  end
108
169
 
109
170
  # Parse string into either syntax error or AST
110
171
  #
111
172
  # @param [String] source
112
173
  #
113
- # @return [Either<Parser::SyntaxError, (Parser::ASTNode, nil)>]
114
- def self.parse_either(source)
115
- Either.wrap_error(Parser::SyntaxError) do
116
- parser.parse(buffer(source))
174
+ # @return [Either<Exception, (Parser::ASTNode, nil)>]
175
+ def self.parse_ast_either(source)
176
+ Either.wrap_error(Exception) do
177
+ parse_ast(source)
117
178
  end
118
179
  end
119
180
 
120
- # Parse string into AST, with comments
181
+ # Parse source with ast details
121
182
  #
122
183
  # @param [String] source
123
184
  #
124
- # @return [Parser::AST::Node]
125
- def self.parse_with_comments(source)
126
- parser.parse_with_comments(buffer(source))
185
+ # @return [AST]
186
+ #
187
+ # mutant:disable
188
+ def self.parse_ast(source, static_local_variables: Set.new)
189
+ explicit_encoding = Parser::Source::Buffer.recognize_encoding(source.dup.force_encoding(Encoding::BINARY))
190
+ node, comments = parser.parse_with_comments(buffer(source))
191
+
192
+ AST.new(
193
+ comments: comments,
194
+ explicit_encoding: explicit_encoding,
195
+ node: node,
196
+ static_local_variables: static_local_variables
197
+ )
127
198
  end
128
199
 
129
200
  # Parser instance that produces AST unparser understands
@@ -210,6 +281,7 @@ require 'unparser/emitter/rescue'
210
281
  require 'unparser/emitter/root'
211
282
  require 'unparser/emitter/send'
212
283
  require 'unparser/emitter/simple'
284
+ require 'unparser/emitter/string'
213
285
  require 'unparser/emitter/splat'
214
286
  require 'unparser/emitter/super'
215
287
  require 'unparser/emitter/undef'
@@ -224,6 +296,7 @@ require 'unparser/emitter/match_pattern_p'
224
296
  require 'unparser/writer'
225
297
  require 'unparser/writer/binary'
226
298
  require 'unparser/writer/dynamic_string'
299
+ require 'unparser/writer/regexp'
227
300
  require 'unparser/writer/resbody'
228
301
  require 'unparser/writer/rescue'
229
302
  require 'unparser/writer/send'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unparser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.15
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Markus Schirp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-15 00:00:00.000000000 Z
11
+ date: 2025-03-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.3'
19
+ version: '1.6'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.3'
26
+ version: '1.6'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: parser
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,56 +44,56 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.12.2
47
+ version: 0.12.4
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.12.2
54
+ version: 0.12.4
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: mutant-rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.12.2
61
+ version: 0.12.4
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.12.2
68
+ version: 0.12.4
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '3.9'
75
+ version: '3.13'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '3.9'
82
+ version: '3.13'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rspec-core
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '3.9'
89
+ version: '3.13'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '3.9'
96
+ version: '3.13'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rspec-its
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -221,6 +221,7 @@ files:
221
221
  - lib/unparser/emitter/send.rb
222
222
  - lib/unparser/emitter/simple.rb
223
223
  - lib/unparser/emitter/splat.rb
224
+ - lib/unparser/emitter/string.rb
224
225
  - lib/unparser/emitter/super.rb
225
226
  - lib/unparser/emitter/undef.rb
226
227
  - lib/unparser/emitter/variable.rb
@@ -236,6 +237,7 @@ files:
236
237
  - lib/unparser/writer.rb
237
238
  - lib/unparser/writer/binary.rb
238
239
  - lib/unparser/writer/dynamic_string.rb
240
+ - lib/unparser/writer/regexp.rb
239
241
  - lib/unparser/writer/resbody.rb
240
242
  - lib/unparser/writer/rescue.rb
241
243
  - lib/unparser/writer/send.rb
@@ -268,7 +270,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
268
270
  - !ruby/object:Gem::Version
269
271
  version: '0'
270
272
  requirements: []
271
- rubygems_version: 3.5.9
273
+ rubygems_version: 3.5.22
272
274
  signing_key:
273
275
  specification_version: 4
274
276
  summary: Generate equivalent source for parser gem AST nodes