unparser 0.0.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.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/.circle.yml +4 -0
  3. data/.gitignore +2 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +16 -0
  6. data/Changelog.md +3 -0
  7. data/Gemfile +6 -0
  8. data/Gemfile.devtools +60 -0
  9. data/Guardfile +18 -0
  10. data/README.md +41 -0
  11. data/Rakefile +24 -0
  12. data/TODO +1 -0
  13. data/config/devtools.yml +2 -0
  14. data/config/flay.yml +3 -0
  15. data/config/flog.yml +2 -0
  16. data/config/mutant.yml +3 -0
  17. data/config/reek.yml +107 -0
  18. data/config/yardstick.yml +2 -0
  19. data/lib/unparser/buffer.rb +93 -0
  20. data/lib/unparser/constants.rb +87 -0
  21. data/lib/unparser/emitter/alias.rb +27 -0
  22. data/lib/unparser/emitter/argument.rb +154 -0
  23. data/lib/unparser/emitter/assignment.rb +140 -0
  24. data/lib/unparser/emitter/begin.rb +179 -0
  25. data/lib/unparser/emitter/binary.rb +52 -0
  26. data/lib/unparser/emitter/block.rb +53 -0
  27. data/lib/unparser/emitter/break.rb +28 -0
  28. data/lib/unparser/emitter/case.rb +97 -0
  29. data/lib/unparser/emitter/cbase.rb +22 -0
  30. data/lib/unparser/emitter/class.rb +72 -0
  31. data/lib/unparser/emitter/def.rb +107 -0
  32. data/lib/unparser/emitter/defined.rb +27 -0
  33. data/lib/unparser/emitter/for.rb +50 -0
  34. data/lib/unparser/emitter/hookexe.rb +42 -0
  35. data/lib/unparser/emitter/if.rb +85 -0
  36. data/lib/unparser/emitter/literal/composed.rb +64 -0
  37. data/lib/unparser/emitter/literal/dynamic.rb +54 -0
  38. data/lib/unparser/emitter/literal/dynamic_body.rb +109 -0
  39. data/lib/unparser/emitter/literal/execute_string.rb +38 -0
  40. data/lib/unparser/emitter/literal/primitive.rb +49 -0
  41. data/lib/unparser/emitter/literal/range.rb +33 -0
  42. data/lib/unparser/emitter/literal/regexp.rb +96 -0
  43. data/lib/unparser/emitter/literal/singleton.rb +24 -0
  44. data/lib/unparser/emitter/literal.rb +7 -0
  45. data/lib/unparser/emitter/module.rb +37 -0
  46. data/lib/unparser/emitter/next.rb +22 -0
  47. data/lib/unparser/emitter/not.rb +25 -0
  48. data/lib/unparser/emitter/op_assign.rb +63 -0
  49. data/lib/unparser/emitter/redo.rb +22 -0
  50. data/lib/unparser/emitter/repetition.rb +33 -0
  51. data/lib/unparser/emitter/retry.rb +22 -0
  52. data/lib/unparser/emitter/return.rb +38 -0
  53. data/lib/unparser/emitter/root.rb +7 -0
  54. data/lib/unparser/emitter/send/binary.rb +100 -0
  55. data/lib/unparser/emitter/send/index.rb +82 -0
  56. data/lib/unparser/emitter/send/unary.rb +29 -0
  57. data/lib/unparser/emitter/send.rb +273 -0
  58. data/lib/unparser/emitter/splat.rb +24 -0
  59. data/lib/unparser/emitter/super.rb +46 -0
  60. data/lib/unparser/emitter/undef.rb +25 -0
  61. data/lib/unparser/emitter/variable.rb +83 -0
  62. data/lib/unparser/emitter/yield.rb +28 -0
  63. data/lib/unparser/emitter.rb +308 -0
  64. data/lib/unparser.rb +87 -0
  65. data/spec/integration/unparser/spike_spec.rb +914 -0
  66. data/spec/spec_helper.rb +13 -0
  67. data/spec/unit/unparser/buffer/append_spec.rb +23 -0
  68. data/spec/unit/unparser/buffer/content_spec.rb +38 -0
  69. data/spec/unit/unparser/buffer/indent_spec.rb +18 -0
  70. data/spec/unit/unparser/buffer/nl_spec.rb +16 -0
  71. data/spec/unit/unparser/buffer/unindent_spec.rb +18 -0
  72. data/spec/unit/unparser/class_methods/unparse_spec.rb +16 -0
  73. data/spec/unit/unparser/emitter/class_methods/handle_spec.rb +17 -0
  74. data/spec/unit/unparser/emitter/class_methods/visit_spec.rb +37 -0
  75. data/spec/unit/unparser/emitter/source_map/class_methods/emit_spec.rb +20 -0
  76. data/unparser.gemspec +24 -0
  77. metadata +201 -0
@@ -0,0 +1,308 @@
1
+ module Unparser
2
+
3
+ # Emitter base class
4
+ class Emitter
5
+ include Adamantium::Flat, AbstractType, Constants
6
+ include Equalizer.new(:node, :buffer, :parent)
7
+
8
+ # Registry for node emitters
9
+ REGISTRY = {}
10
+
11
+ DEFAULT_DELIMITER = ', '.freeze
12
+
13
+ CURLY_BRACKETS = IceNine.deep_freeze(%w({ }))
14
+
15
+ # Create name helpers
16
+ #
17
+ # @return [undefined]
18
+ #
19
+ # @api private
20
+ #
21
+ def self.children(*names)
22
+ names.each_with_index do |name, index|
23
+ define_method(name) do
24
+ children[index]
25
+ end
26
+ private name
27
+ end
28
+ end
29
+ private_class_method :children
30
+
31
+ # Register emitter for type
32
+ #
33
+ # @param [Symbol] type
34
+ #
35
+ # @return [undefined]
36
+ #
37
+ # @api private
38
+ #
39
+ def self.handle(*types)
40
+ types.each do |type|
41
+ REGISTRY[type] = self
42
+ end
43
+ end
44
+ private_class_method :handle
45
+
46
+ # Emit node into buffer
47
+ #
48
+ # @return [self]
49
+ #
50
+ # @api private
51
+ #
52
+ def self.emit(*arguments)
53
+ new(*arguments)
54
+ self
55
+ end
56
+
57
+ # Initialize object
58
+ #
59
+ # @param [Parser::AST::Node] node
60
+ # @param [Buffer] buffer
61
+ #
62
+ # @return [undefined]
63
+ #
64
+ # @api private
65
+ #
66
+ def initialize(node, buffer, parent)
67
+ @node, @buffer, @parent = node, buffer, parent
68
+ dispatch
69
+ end
70
+
71
+ private_class_method :new
72
+
73
+ # Visit node
74
+ #
75
+ # @param [Parser::AST::Node] node
76
+ # @param [Buffer] buffer
77
+ #
78
+ # @return [Emitter]
79
+ #
80
+ # @api private
81
+ #
82
+ def self.visit(node, buffer, parent = Root)
83
+ type = node.type
84
+ emitter = REGISTRY.fetch(type) do
85
+ raise ArgumentError, "No emitter for node: #{type.inspect}"
86
+ end
87
+ emitter.emit(node, buffer, parent)
88
+ self
89
+ end
90
+
91
+ # Test if node needs begin
92
+ #
93
+ # @return [true]
94
+ # if if node needs begin
95
+ #
96
+ # @return [false]
97
+ # otherwise
98
+ #
99
+ # @api private
100
+ #
101
+ def needs_begin?
102
+ false
103
+ end
104
+
105
+ # Return node
106
+ #
107
+ # @return [Parser::AST::Node] node
108
+ #
109
+ # @api private
110
+ #
111
+ attr_reader :node
112
+
113
+ private
114
+
115
+ # Return buffer
116
+ #
117
+ # @return [Buffer] buffer
118
+ #
119
+ # @api private
120
+ #
121
+ attr_reader :buffer
122
+ protected :buffer
123
+
124
+ # Return parent emitter
125
+ #
126
+ # @return [Parent]
127
+ #
128
+ # @api private
129
+ #
130
+ attr_reader :parent
131
+ protected :parent
132
+
133
+ # Emit contents of block within parentheses
134
+ #
135
+ # @return [undefined]
136
+ #
137
+ # @api private
138
+ #
139
+ def parentheses(open=M_PO, close=M_PC)
140
+ write(open)
141
+ yield
142
+ write(close)
143
+ end
144
+
145
+ # Emit nodes source map
146
+ #
147
+ # @return [undefined]
148
+ #
149
+ # @api private
150
+ #
151
+ def emit_source_map
152
+ SourceMap.emit(node, buffer)
153
+ end
154
+
155
+ # Dispatch helper
156
+ #
157
+ # @param [Parser::AST::Node] node
158
+ #
159
+ # @return [undefined]
160
+ #
161
+ # @api private
162
+ #
163
+ def visit(node)
164
+ self.class.visit(node, buffer, self)
165
+ end
166
+
167
+ # Emit delimited body
168
+ #
169
+ # @param [Enumerable<Parser::AST::Node>] nodes
170
+ # @param [String] delimiter
171
+ #
172
+ # @return [undefined]
173
+ #
174
+ # @api private
175
+ #
176
+ def delimited(nodes, delimiter = DEFAULT_DELIMITER)
177
+ max = nodes.length - 1
178
+ nodes.each_with_index do |node, index|
179
+ visit(node)
180
+ write(delimiter) if index < max
181
+ end
182
+ end
183
+
184
+ # Return children of node
185
+ #
186
+ # @return [Array<Parser::AST::Node>]
187
+ #
188
+ # @api private
189
+ #
190
+ def children
191
+ node.children
192
+ end
193
+
194
+ # Write newline
195
+ #
196
+ # @return [undefined]
197
+ #
198
+ # @api private
199
+ #
200
+ def nl
201
+ buffer.nl
202
+ end
203
+
204
+ # Write strings into buffer
205
+ #
206
+ # @return [undefined]
207
+ #
208
+ # @api private
209
+ #
210
+ def write(*strings)
211
+ strings.each do |string|
212
+ buffer.append(string)
213
+ end
214
+ end
215
+
216
+ # Write begin keyword
217
+ #
218
+ # @return [undefined]
219
+ #
220
+ # @api private
221
+ #
222
+ def k_begin
223
+ write(K_BEGIN)
224
+ end
225
+
226
+ # Write end keyword
227
+ #
228
+ # @return [undefined]
229
+ #
230
+ # @api private
231
+ #
232
+ def k_end
233
+ write(K_END)
234
+ end
235
+
236
+ # Return first child
237
+ #
238
+ # @return [Parser::AST::Node]
239
+ # if present
240
+ #
241
+ # @return [nil]
242
+ # otherwise
243
+ #
244
+ # @api private
245
+ #
246
+ def first_child
247
+ children.first
248
+ end
249
+
250
+ # Write whitespace
251
+ #
252
+ # @return [undefined]
253
+ #
254
+ # @api private
255
+ #
256
+ def ws
257
+ write(WS)
258
+ end
259
+
260
+ # Call emit contents of block indented
261
+ #
262
+ # @return [undefined]
263
+ #
264
+ # @api private
265
+ #
266
+ def indented
267
+ buffer = self.buffer
268
+ buffer.indent
269
+ yield
270
+ buffer.unindent
271
+ end
272
+
273
+ # Emit non nil body
274
+ #
275
+ # @param [Parser::AST::Node] node
276
+ #
277
+ # @return [undefined]
278
+ #
279
+ # @api private
280
+ #
281
+ def emit_non_nil_body(node)
282
+ if node.type == :nil
283
+ nl
284
+ return
285
+ end
286
+ indented { visit(node) }
287
+ end
288
+
289
+ # Emitter that fully relies on parser source maps
290
+ class SourceMap < self
291
+
292
+ # Perform dispatch
293
+ #
294
+ # @param [Node] node
295
+ # @param [Buffer] buffer
296
+ #
297
+ # @return [self]
298
+ #
299
+ # @api private
300
+ #
301
+ def self.emit(node, buffer)
302
+ buffer.append(node.location.expression.source)
303
+ self
304
+ end
305
+
306
+ end # SourceMap
307
+ end # Emitter
308
+ end # Unparser
data/lib/unparser.rb ADDED
@@ -0,0 +1,87 @@
1
+ require 'abstract_type'
2
+ require 'concord'
3
+ require 'parser/all'
4
+
5
+ # Library namespace
6
+ module Unparser
7
+
8
+ EMPTY_STRING = ''.freeze
9
+
10
+ # Unparse ast into string
11
+ #
12
+ # @param [Parser::Node] node
13
+ #
14
+ # @return [String]
15
+ #
16
+ # @api private
17
+ #
18
+ def self.unparse(node)
19
+ buffer = Buffer.new
20
+ Emitter.visit(node, buffer)
21
+ buffer.content
22
+ end
23
+
24
+ # Transquote string
25
+ #
26
+ # @param [String] raw_quoted
27
+ # @param [String] current_delimiter
28
+ # @param [String] target_delimiter
29
+ #
30
+ # @return [String]
31
+ #
32
+ # @api private
33
+ #
34
+ def self.transquote(raw_quoted, current_delimiter, target_delimiter)
35
+ raw = raw_quoted.gsub("\\#{current_delimiter}", current_delimiter)
36
+ raw.gsub(target_delimiter, "\\#{target_delimiter}").freeze
37
+ end
38
+
39
+ end # Unparser
40
+
41
+ require 'unparser/buffer'
42
+ require 'unparser/constants'
43
+ require 'unparser/emitter'
44
+ require 'unparser/emitter/literal'
45
+ require 'unparser/emitter/literal/primitive'
46
+ require 'unparser/emitter/literal/singleton'
47
+ require 'unparser/emitter/literal/dynamic'
48
+ require 'unparser/emitter/literal/regexp'
49
+ require 'unparser/emitter/literal/composed'
50
+ require 'unparser/emitter/literal/range'
51
+ require 'unparser/emitter/literal/dynamic_body'
52
+ require 'unparser/emitter/literal/execute_string'
53
+ require 'unparser/emitter/send'
54
+ require 'unparser/emitter/send/unary'
55
+ require 'unparser/emitter/send/binary'
56
+ require 'unparser/emitter/send/index'
57
+ require 'unparser/emitter/block'
58
+ require 'unparser/emitter/assignment'
59
+ require 'unparser/emitter/variable'
60
+ require 'unparser/emitter/splat'
61
+ require 'unparser/emitter/cbase'
62
+ require 'unparser/emitter/argument'
63
+ require 'unparser/emitter/begin'
64
+ require 'unparser/emitter/return'
65
+ require 'unparser/emitter/undef'
66
+ require 'unparser/emitter/def'
67
+ require 'unparser/emitter/class'
68
+ require 'unparser/emitter/module'
69
+ require 'unparser/emitter/op_assign'
70
+ require 'unparser/emitter/defined'
71
+ require 'unparser/emitter/hookexe'
72
+ require 'unparser/emitter/super'
73
+ require 'unparser/emitter/break'
74
+ require 'unparser/emitter/retry'
75
+ require 'unparser/emitter/redo'
76
+ require 'unparser/emitter/next'
77
+ require 'unparser/emitter/if'
78
+ require 'unparser/emitter/alias'
79
+ require 'unparser/emitter/yield'
80
+ require 'unparser/emitter/not'
81
+ require 'unparser/emitter/binary'
82
+ require 'unparser/emitter/case'
83
+ require 'unparser/emitter/for'
84
+ require 'unparser/emitter/repetition'
85
+ require 'unparser/emitter/root'
86
+
87
+ Unparser::Emitter::REGISTRY.freeze