unparser 0.1.2 → 0.1.3
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.
- checksums.yaml +4 -4
- data/README.md +12 -2
- data/lib/unparser.rb +7 -3
- data/lib/unparser/buffer.rb +39 -2
- data/lib/unparser/comments.rb +112 -0
- data/lib/unparser/emitter.rb +94 -4
- data/lib/unparser/emitter/block.rb +1 -0
- data/lib/unparser/emitter/class.rb +1 -2
- data/lib/unparser/emitter/def.rb +1 -0
- data/lib/unparser/emitter/module.rb +1 -2
- data/lib/unparser/emitter/root.rb +1 -1
- data/lib/unparser/emitter/send.rb +1 -1
- data/lib/unparser/emitter/send/index.rb +2 -12
- data/spec/unit/unparser/buffer/append_spec.rb +1 -0
- data/spec/unit/unparser/buffer/append_without_prefix_spec.rb +23 -0
- data/spec/unit/unparser/buffer/capture_content_spec.rb +17 -0
- data/spec/unit/unparser/buffer/fresh_line_spec.rb +20 -0
- data/spec/unit/unparser/buffer/indent_spec.rb +2 -0
- data/spec/unit/unparser/buffer/unindent_spec.rb +2 -0
- data/spec/unit/unparser/comments/consume_spec.rb +23 -0
- data/spec/unit/unparser/comments/skip_eol_comment_spec.rb +29 -0
- data/spec/unit/unparser/comments/take_all_spec.rb +20 -0
- data/spec/unit/unparser/comments/take_before_spec.rb +25 -0
- data/spec/unit/unparser/comments/take_eol_comments_spec.rb +33 -0
- data/spec/unit/unparser_spec.rb +89 -15
- data/unparser.gemspec +2 -2
- metadata +21 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46f62b35c534e13da34486c1650bb14e406fe48b
|
4
|
+
data.tar.gz: 3bdedfa5f88178cd4ebeafedb72e2ce47a5552a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cdfc4fb2f77e221b2af12dc14cb7504e3220e6e08c4da8919617f9b3cd9f9082d6b69129bf46aa7caba119681aed1255240eaf97b888a3b274c2432def82155e
|
7
|
+
data.tar.gz: efd08e3645878e75d316e07b2fb58de2c254c6588183e725c48af4739079856d41d547354114e33acd2c29c010fffea17cb211065c8823fde55692adc475e30a
|
data/README.md
CHANGED
@@ -21,6 +21,15 @@ require 'unparser'
|
|
21
21
|
Unparser.unparse(your_ast) # => "the code"
|
22
22
|
```
|
23
23
|
|
24
|
+
To preserve the comments from the source:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
require 'parser/current'
|
28
|
+
require 'unparser'
|
29
|
+
ast, comments = Parser::CurrentRuby.parse_with_comments(your_source)
|
30
|
+
Unparser.unparse(ast, comments) # => "the code # with comments"
|
31
|
+
```
|
32
|
+
|
24
33
|
Equivalent vs identical:
|
25
34
|
|
26
35
|
```ruby
|
@@ -45,10 +54,11 @@ Installation
|
|
45
54
|
|
46
55
|
Install the gem `unparser` via your prefered method.
|
47
56
|
|
48
|
-
|
49
|
-
|
57
|
+
People
|
58
|
+
------
|
50
59
|
|
51
60
|
* [Markus Schirp (mbj)](https://github.com/mbj) Author
|
61
|
+
* [Trent Ogren](https://github.com/misfo) Adding comment reproduction
|
52
62
|
|
53
63
|
Contributing
|
54
64
|
-------------
|
data/lib/unparser.rb
CHANGED
@@ -7,20 +7,23 @@ module Unparser
|
|
7
7
|
|
8
8
|
EMPTY_STRING = ''.freeze
|
9
9
|
|
10
|
-
# Unparse
|
10
|
+
# Unparse an AST (and, optionally, comments) into a string
|
11
11
|
#
|
12
12
|
# @param [Parser::Node, nil] node
|
13
|
+
# @param [Array] comment_array
|
13
14
|
#
|
14
15
|
# @return [String]
|
15
16
|
#
|
16
17
|
# @api private
|
17
18
|
#
|
18
|
-
def self.unparse(node)
|
19
|
+
def self.unparse(node, comment_array = [])
|
19
20
|
if node.nil?
|
20
21
|
node = Parser::AST::Node.new(:empty)
|
21
22
|
end
|
22
23
|
buffer = Buffer.new
|
23
|
-
|
24
|
+
comments = Comments.new(comment_array)
|
25
|
+
root = Emitter::Root.new(buffer, comments)
|
26
|
+
Emitter.emitter(node, root).write_to_buffer
|
24
27
|
buffer.content
|
25
28
|
end
|
26
29
|
|
@@ -42,6 +45,7 @@ module Unparser
|
|
42
45
|
end # Unparser
|
43
46
|
|
44
47
|
require 'unparser/buffer'
|
48
|
+
require 'unparser/comments'
|
45
49
|
require 'unparser/constants'
|
46
50
|
require 'unparser/emitter'
|
47
51
|
require 'unparser/emitter/literal'
|
data/lib/unparser/buffer.rb
CHANGED
@@ -32,6 +32,19 @@ module Unparser
|
|
32
32
|
self
|
33
33
|
end
|
34
34
|
|
35
|
+
# Append a string without an indentation prefix
|
36
|
+
#
|
37
|
+
# @param [String] string
|
38
|
+
#
|
39
|
+
# @return [self]
|
40
|
+
#
|
41
|
+
# @api private
|
42
|
+
#
|
43
|
+
def append_without_prefix(string)
|
44
|
+
@content << string
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
35
48
|
# Increase indent
|
36
49
|
#
|
37
50
|
# @return [self]
|
@@ -39,7 +52,6 @@ module Unparser
|
|
39
52
|
# @api private
|
40
53
|
#
|
41
54
|
def indent
|
42
|
-
nl
|
43
55
|
@indent+=1
|
44
56
|
self
|
45
57
|
end
|
@@ -51,7 +63,6 @@ module Unparser
|
|
51
63
|
# @api private
|
52
64
|
#
|
53
65
|
def unindent
|
54
|
-
nl
|
55
66
|
@indent-=1
|
56
67
|
self
|
57
68
|
end
|
@@ -67,6 +78,20 @@ module Unparser
|
|
67
78
|
self
|
68
79
|
end
|
69
80
|
|
81
|
+
# Test for a fresh line
|
82
|
+
#
|
83
|
+
# @return [true]
|
84
|
+
# if the buffer content ends with a fresh line
|
85
|
+
#
|
86
|
+
# @return [false]
|
87
|
+
# otherwise
|
88
|
+
#
|
89
|
+
# @api private
|
90
|
+
#
|
91
|
+
def fresh_line?
|
92
|
+
@content.empty? || @content[-1] == NL
|
93
|
+
end
|
94
|
+
|
70
95
|
# Return content of buffer
|
71
96
|
#
|
72
97
|
# @return [String]
|
@@ -77,6 +102,18 @@ module Unparser
|
|
77
102
|
@content.dup.freeze
|
78
103
|
end
|
79
104
|
|
105
|
+
# Capture the content written to the buffer within the block
|
106
|
+
#
|
107
|
+
# @return [String]
|
108
|
+
#
|
109
|
+
# @api private
|
110
|
+
#
|
111
|
+
def capture_content
|
112
|
+
size_before = @content.size
|
113
|
+
yield
|
114
|
+
@content[size_before..-1]
|
115
|
+
end
|
116
|
+
|
80
117
|
private
|
81
118
|
|
82
119
|
# Write prefix
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Unparser
|
2
|
+
|
3
|
+
# Holds the comments that remain to be emitted
|
4
|
+
#
|
5
|
+
# @api private
|
6
|
+
#
|
7
|
+
class Comments
|
8
|
+
|
9
|
+
# Initialize object
|
10
|
+
#
|
11
|
+
# @param [Array] comments
|
12
|
+
#
|
13
|
+
# @return [undefined]
|
14
|
+
#
|
15
|
+
def initialize(comments)
|
16
|
+
@comments = comments.dup
|
17
|
+
@eol_text_to_skip = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
# Consume part or all of the node
|
21
|
+
#
|
22
|
+
# @param [Parser::AST::Node] node
|
23
|
+
# @param [Symbol] source_part
|
24
|
+
#
|
25
|
+
# @return [undefined]
|
26
|
+
#
|
27
|
+
def consume(node, source_part = :expression)
|
28
|
+
return unless node.location
|
29
|
+
@last_range_consumed = node.location.public_send(source_part)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Skip any EOL comment with the specified text next time they're taken
|
33
|
+
#
|
34
|
+
# @param [String] comment_text
|
35
|
+
#
|
36
|
+
# @return [undefined]
|
37
|
+
#
|
38
|
+
def skip_eol_comment(comment_text)
|
39
|
+
@eol_text_to_skip = comment_text
|
40
|
+
end
|
41
|
+
|
42
|
+
# Take end-of-line comments
|
43
|
+
#
|
44
|
+
# @return [Array]
|
45
|
+
#
|
46
|
+
def take_eol_comments
|
47
|
+
text_to_skip = @eol_text_to_skip
|
48
|
+
@eol_text_to_skip = nil
|
49
|
+
return [] if @last_range_consumed.nil?
|
50
|
+
comments = take_up_to_line(@last_range_consumed.end.line)
|
51
|
+
eol_comments = unshift_documents(comments)
|
52
|
+
eol_comments.reject {|comment| comment.text == text_to_skip }
|
53
|
+
end
|
54
|
+
|
55
|
+
# Take all remaining comments
|
56
|
+
#
|
57
|
+
# @return [Array]
|
58
|
+
#
|
59
|
+
def take_all
|
60
|
+
take_while { true }
|
61
|
+
end
|
62
|
+
|
63
|
+
# Take comments appear in the source before the specified part of the node
|
64
|
+
#
|
65
|
+
# @param [Parser::AST::Node] node
|
66
|
+
# @param [Symbol] source_part
|
67
|
+
#
|
68
|
+
# @return [Array]
|
69
|
+
#
|
70
|
+
def take_before(node, source_part)
|
71
|
+
loc = node.location
|
72
|
+
range = loc.public_send(source_part) if loc.respond_to?(source_part)
|
73
|
+
return [] if range.nil?
|
74
|
+
take_while { |comment| comment.location.expression.end_pos <= range.begin_pos }
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
# Take comments while the provided block returns true
|
80
|
+
#
|
81
|
+
# @yield [comment]
|
82
|
+
#
|
83
|
+
# @return [Array]
|
84
|
+
#
|
85
|
+
def take_while
|
86
|
+
number_to_take = @comments.index {|comment| !yield(comment) } || @comments.size
|
87
|
+
@comments.shift(number_to_take)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Take comments up to the line number
|
91
|
+
#
|
92
|
+
# @param [Fixnum] line
|
93
|
+
#
|
94
|
+
# @return [Array]
|
95
|
+
#
|
96
|
+
def take_up_to_line(line)
|
97
|
+
take_while { |comment| comment.location.expression.line <= line }
|
98
|
+
end
|
99
|
+
|
100
|
+
# Unshift document comments and return the rest
|
101
|
+
#
|
102
|
+
# @param [Array] comments
|
103
|
+
#
|
104
|
+
# @return [Array]
|
105
|
+
#
|
106
|
+
def unshift_documents(comments)
|
107
|
+
doc_comments, other_comments = comments.partition(&:document?)
|
108
|
+
doc_comments.reverse_each {|comment| @comments.unshift(comment) }
|
109
|
+
other_comments
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/lib/unparser/emitter.rb
CHANGED
@@ -84,7 +84,10 @@ module Unparser
|
|
84
84
|
# @api private
|
85
85
|
#
|
86
86
|
def write_to_buffer
|
87
|
+
emit_comments_before if buffer.fresh_line?
|
87
88
|
dispatch
|
89
|
+
comments.consume(node)
|
90
|
+
emit_eof_comments if parent.is_a?(Root)
|
88
91
|
self
|
89
92
|
end
|
90
93
|
memoize :write_to_buffer
|
@@ -147,6 +150,17 @@ module Unparser
|
|
147
150
|
end
|
148
151
|
memoize :buffer, :freezer => :noop
|
149
152
|
|
153
|
+
# Return comments
|
154
|
+
#
|
155
|
+
# @return [Comments] comments
|
156
|
+
#
|
157
|
+
# @api private
|
158
|
+
#
|
159
|
+
def comments
|
160
|
+
parent.comments
|
161
|
+
end
|
162
|
+
memoize :comments, :freezer => :noop
|
163
|
+
|
150
164
|
private
|
151
165
|
|
152
166
|
# Emit contents of block within parentheses
|
@@ -276,9 +290,73 @@ module Unparser
|
|
276
290
|
# @api private
|
277
291
|
#
|
278
292
|
def nl
|
293
|
+
emit_eol_comments
|
279
294
|
buffer.nl
|
280
295
|
end
|
281
296
|
|
297
|
+
# Write comments that appeared before source_part in the source
|
298
|
+
#
|
299
|
+
# @param [Symbol] source_part
|
300
|
+
#
|
301
|
+
# @return [undefined]
|
302
|
+
#
|
303
|
+
# @api private
|
304
|
+
#
|
305
|
+
def emit_comments_before(source_part = :expression)
|
306
|
+
comments_before = comments.take_before(node, source_part)
|
307
|
+
unless comments_before.empty?
|
308
|
+
emit_comments(comments_before)
|
309
|
+
buffer.nl
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# Write end-of-line comments
|
314
|
+
#
|
315
|
+
# @return [undefined]
|
316
|
+
#
|
317
|
+
# @api private
|
318
|
+
#
|
319
|
+
def emit_eol_comments
|
320
|
+
comments.take_eol_comments.each do |comment|
|
321
|
+
write(WS, comment.text)
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
# Write end-of-file comments
|
326
|
+
#
|
327
|
+
# @return [undefined]
|
328
|
+
#
|
329
|
+
# @api private
|
330
|
+
#
|
331
|
+
def emit_eof_comments
|
332
|
+
emit_eol_comments
|
333
|
+
comments_left = comments.take_all
|
334
|
+
unless comments_left.empty?
|
335
|
+
buffer.nl
|
336
|
+
emit_comments(comments_left)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
# Write each comment to a separate line
|
341
|
+
#
|
342
|
+
# @param [Array] comment_array
|
343
|
+
#
|
344
|
+
# @return [undefined]
|
345
|
+
#
|
346
|
+
# @api private
|
347
|
+
#
|
348
|
+
def emit_comments(comment_array)
|
349
|
+
max = comment_array.size - 1
|
350
|
+
comment_array.each_with_index do |comment, index|
|
351
|
+
if comment.type == :document
|
352
|
+
buffer.append_without_prefix(comment.text.chomp)
|
353
|
+
else
|
354
|
+
write(comment.text)
|
355
|
+
end
|
356
|
+
buffer.nl if index < max
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
282
360
|
# Write strings into buffer
|
283
361
|
#
|
284
362
|
# @return [undefined]
|
@@ -298,6 +376,9 @@ module Unparser
|
|
298
376
|
# @api private
|
299
377
|
#
|
300
378
|
def k_end
|
379
|
+
buffer.indent
|
380
|
+
emit_comments_before(:end)
|
381
|
+
buffer.unindent
|
301
382
|
write(K_END)
|
302
383
|
end
|
303
384
|
|
@@ -334,7 +415,9 @@ module Unparser
|
|
334
415
|
def indented
|
335
416
|
buffer = self.buffer
|
336
417
|
buffer.indent
|
418
|
+
nl
|
337
419
|
yield
|
420
|
+
nl
|
338
421
|
buffer.unindent
|
339
422
|
end
|
340
423
|
|
@@ -348,7 +431,9 @@ module Unparser
|
|
348
431
|
#
|
349
432
|
def emit_body(body = self.body)
|
350
433
|
unless body
|
434
|
+
buffer.indent
|
351
435
|
nl
|
436
|
+
buffer.unindent
|
352
437
|
return
|
353
438
|
end
|
354
439
|
visit_indented(body)
|
@@ -376,7 +461,7 @@ module Unparser
|
|
376
461
|
# if parent is present
|
377
462
|
#
|
378
463
|
# @return [nil]
|
379
|
-
#
|
464
|
+
# otherwise
|
380
465
|
#
|
381
466
|
# @api private
|
382
467
|
#
|
@@ -396,14 +481,19 @@ module Unparser
|
|
396
481
|
Parser::AST::Node.new(type, *children)
|
397
482
|
end
|
398
483
|
|
399
|
-
# Helper to introduce comment
|
484
|
+
# Helper to introduce an end-of-line comment
|
400
485
|
#
|
401
486
|
# @return [undefined]
|
402
487
|
#
|
403
488
|
# @api private
|
404
489
|
#
|
405
|
-
def
|
406
|
-
|
490
|
+
def eol_comment
|
491
|
+
write(WS)
|
492
|
+
comment = buffer.capture_content do
|
493
|
+
write(COMMENT, WS)
|
494
|
+
yield
|
495
|
+
end
|
496
|
+
comments.skip_eol_comment(comment)
|
407
497
|
end
|
408
498
|
|
409
499
|
# Emitter that fully relies on parser source maps
|
data/lib/unparser/emitter/def.rb
CHANGED
@@ -17,16 +17,6 @@ module Unparser
|
|
17
17
|
emit_arguments
|
18
18
|
end
|
19
19
|
|
20
|
-
# Emit block within parentheses
|
21
|
-
#
|
22
|
-
# @return [undefined]
|
23
|
-
#
|
24
|
-
# @api private
|
25
|
-
#
|
26
|
-
def parentheses(&block)
|
27
|
-
super(*INDEX_PARENS, &block)
|
28
|
-
end
|
29
|
-
|
30
20
|
# Emit receiver
|
31
21
|
#
|
32
22
|
# @return [undefined]
|
@@ -49,7 +39,7 @@ module Unparser
|
|
49
39
|
# @api private
|
50
40
|
#
|
51
41
|
def emit_arguments
|
52
|
-
parentheses do
|
42
|
+
parentheses(*INDEX_PARENS) do
|
53
43
|
delimited(arguments)
|
54
44
|
end
|
55
45
|
end
|
@@ -66,7 +56,7 @@ module Unparser
|
|
66
56
|
#
|
67
57
|
def emit_arguments
|
68
58
|
index, *assignment = arguments
|
69
|
-
parentheses do
|
59
|
+
parentheses(*INDEX_PARENS) do
|
70
60
|
delimited([index])
|
71
61
|
end
|
72
62
|
return if assignment.empty? # mlhs
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Unparser::Buffer, '#append_without_prefix' do
|
4
|
+
subject { object.append_without_prefix(string) }
|
5
|
+
|
6
|
+
let(:object) { described_class.new }
|
7
|
+
let(:string) { 'foo' }
|
8
|
+
|
9
|
+
specify do
|
10
|
+
expect { subject }.to change { object.content }.from('').to('foo')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should not prefix with indentation' do
|
14
|
+
object.append_without_prefix('foo')
|
15
|
+
object.nl
|
16
|
+
object.indent
|
17
|
+
object.append_without_prefix('bar')
|
18
|
+
object.append_without_prefix('baz')
|
19
|
+
expect(object.content).to eql("foo\nbarbaz")
|
20
|
+
end
|
21
|
+
|
22
|
+
it_should_behave_like 'a command method'
|
23
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Unparser::Buffer, '#capture_content' do
|
4
|
+
|
5
|
+
let(:object) { described_class.new }
|
6
|
+
|
7
|
+
it 'should capture only the content appended within the block' do
|
8
|
+
object.append('foo')
|
9
|
+
object.nl
|
10
|
+
object.indent
|
11
|
+
captured = object.capture_content do
|
12
|
+
object.append('bar')
|
13
|
+
object.nl
|
14
|
+
end
|
15
|
+
expect(captured).to eql(" bar\n")
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Unparser::Buffer, '#fresh_line?' do
|
4
|
+
let(:object) { described_class.new }
|
5
|
+
|
6
|
+
it 'should return true while buffer is empty' do
|
7
|
+
expect(object.fresh_line?).to eql(true)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should return false after content has been appended' do
|
11
|
+
object.append('foo')
|
12
|
+
expect(object.fresh_line?).to eql(false)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should return true after a nl has been appended' do
|
16
|
+
object.append('foo')
|
17
|
+
object.nl
|
18
|
+
expect(object.fresh_line?).to eql(true)
|
19
|
+
end
|
20
|
+
end
|
@@ -7,8 +7,10 @@ describe Unparser::Buffer, '#indent' do
|
|
7
7
|
|
8
8
|
it 'should indent with two chars' do
|
9
9
|
object.append('foo')
|
10
|
+
object.nl
|
10
11
|
object.indent
|
11
12
|
object.append('bar')
|
13
|
+
object.nl
|
12
14
|
object.indent
|
13
15
|
object.append('baz')
|
14
16
|
expect(object.content).to eql("foo\n bar\n baz")
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'parser/current'
|
3
|
+
|
4
|
+
describe Unparser::Comments, '#consume' do
|
5
|
+
|
6
|
+
let(:ast_and_comments) do
|
7
|
+
Parser::CurrentRuby.parse_with_comments(<<-RUBY)
|
8
|
+
def hi # EOL 1
|
9
|
+
end # EOL 2
|
10
|
+
RUBY
|
11
|
+
end
|
12
|
+
let(:ast) { ast_and_comments[0] }
|
13
|
+
let(:comments) { ast_and_comments[1] }
|
14
|
+
let(:object) { described_class.new(comments) }
|
15
|
+
|
16
|
+
it 'should cause further EOL comments to be returned' do
|
17
|
+
expect(object.take_eol_comments).to eql([])
|
18
|
+
object.consume(ast, :name)
|
19
|
+
expect(object.take_eol_comments).to eql([comments[0]])
|
20
|
+
object.consume(ast, :end)
|
21
|
+
expect(object.take_eol_comments).to eql([comments[1]])
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'parser/current'
|
3
|
+
|
4
|
+
describe Unparser::Comments, '#skip_eol_comment' do
|
5
|
+
|
6
|
+
let(:ast_and_comments) do
|
7
|
+
Parser::CurrentRuby.parse_with_comments(<<-RUBY)
|
8
|
+
def hi # comment
|
9
|
+
end # comment
|
10
|
+
RUBY
|
11
|
+
end
|
12
|
+
let(:ast) { ast_and_comments[0] }
|
13
|
+
let(:comments) { ast_and_comments[1] }
|
14
|
+
let(:object) { described_class.new(comments) }
|
15
|
+
|
16
|
+
it 'should skip the specified comment only for one subsequent take' do
|
17
|
+
object.consume(ast, :name)
|
18
|
+
object.skip_eol_comment("# comment")
|
19
|
+
expect(object.take_eol_comments).to eql([])
|
20
|
+
object.consume(ast, :end)
|
21
|
+
expect(object.take_eol_comments).to eql([comments[1]])
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should not skip comments with different text' do
|
25
|
+
object.skip_eol_comment("# not the comment")
|
26
|
+
object.consume(ast, :end)
|
27
|
+
expect(object.take_eol_comments).to eql(comments)
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'parser/current'
|
3
|
+
|
4
|
+
describe Unparser::Comments, '#take_all' do
|
5
|
+
|
6
|
+
let(:ast_and_comments) do
|
7
|
+
Parser::CurrentRuby.parse_with_comments(<<-RUBY)
|
8
|
+
def hi # EOL 1
|
9
|
+
end # EOL 2
|
10
|
+
RUBY
|
11
|
+
end
|
12
|
+
let(:ast) { ast_and_comments[0] }
|
13
|
+
let(:comments) { ast_and_comments[1] }
|
14
|
+
let(:object) { described_class.new(comments) }
|
15
|
+
|
16
|
+
it 'should take all comments' do
|
17
|
+
expect(object.take_all).to eql(comments)
|
18
|
+
expect(object.take_all).to eql([])
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'parser/current'
|
3
|
+
|
4
|
+
describe Unparser::Comments, '#take_before' do
|
5
|
+
|
6
|
+
let(:ast_and_comments) do
|
7
|
+
Parser::CurrentRuby.parse_with_comments(<<-RUBY)
|
8
|
+
def hi # EOL 1
|
9
|
+
# comment
|
10
|
+
end # EOL 2
|
11
|
+
RUBY
|
12
|
+
end
|
13
|
+
let(:ast) { ast_and_comments[0] }
|
14
|
+
let(:comments) { ast_and_comments[1] }
|
15
|
+
let(:object) { described_class.new(comments) }
|
16
|
+
|
17
|
+
it 'should return no comments none are before the node' do
|
18
|
+
expect(object.take_before(ast, :expression)).to eql([])
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should only the comments that are before the specified part of the node' do
|
22
|
+
expect(object.take_before(ast, :end)).to eql(comments.first(2))
|
23
|
+
expect(object.take_all).to eql([comments[2]])
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'parser/current'
|
3
|
+
|
4
|
+
describe Unparser::Comments, '#take_eol_comments' do
|
5
|
+
|
6
|
+
let(:ast_and_comments) do
|
7
|
+
Parser::CurrentRuby.parse_with_comments(<<-RUBY)
|
8
|
+
def hi # EOL 1
|
9
|
+
=begin
|
10
|
+
doc comment
|
11
|
+
=end
|
12
|
+
end # EOL 2
|
13
|
+
RUBY
|
14
|
+
end
|
15
|
+
let(:ast) { ast_and_comments[0] }
|
16
|
+
let(:comments) { ast_and_comments[1] }
|
17
|
+
let(:object) { described_class.new(comments) }
|
18
|
+
|
19
|
+
it 'should return no comments if nothing has been consumed' do
|
20
|
+
expect(object.take_eol_comments).to eql([])
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should return comments once their line has been consumed' do
|
24
|
+
object.consume(ast, :name)
|
25
|
+
expect(object.take_eol_comments).to eql([comments[0]])
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should leave doc comments to be taken later' do
|
29
|
+
object.consume(ast)
|
30
|
+
expect(object.take_eol_comments).to eql([comments[0], comments[2]])
|
31
|
+
expect(object.take_all).to eql([comments[1]])
|
32
|
+
end
|
33
|
+
end
|
data/spec/unit/unparser_spec.rb
CHANGED
@@ -25,6 +25,7 @@ describe Unparser do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def self.strip(ruby)
|
28
|
+
return ruby if ruby.empty?
|
28
29
|
lines = ruby.lines
|
29
30
|
line = lines.first
|
30
31
|
match = /\A[ ]*/.match(line)
|
@@ -35,34 +36,39 @@ describe Unparser do
|
|
35
36
|
source.chomp
|
36
37
|
end
|
37
38
|
|
38
|
-
def assert_round_trip(input,
|
39
|
-
ast =
|
40
|
-
generated = Unparser.unparse(ast)
|
39
|
+
def assert_round_trip(input, parser_class)
|
40
|
+
ast, comments = parser_class.parse_with_comments(input)
|
41
|
+
generated = Unparser.unparse(ast, comments)
|
41
42
|
generated.should eql(input)
|
42
43
|
end
|
43
44
|
|
44
45
|
def self.assert_generates_one_way(ast, expected, versions = RUBIES)
|
45
|
-
with_versions(versions) do |version,
|
46
|
+
with_versions(versions) do |version, parser_class|
|
46
47
|
it "should generate #{ast.inspect} as #{expected} under #{version}" do
|
48
|
+
comments = []
|
47
49
|
if ast.kind_of?(String)
|
48
|
-
ast =
|
50
|
+
ast, comments = parser_class.parse_with_comments(input)
|
49
51
|
end
|
50
|
-
generated = Unparser.unparse(ast)
|
52
|
+
generated = Unparser.unparse(ast, comments)
|
51
53
|
generated.should eql(expected)
|
52
54
|
end
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
56
|
-
def self.assert_generates(
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
58
|
+
def self.assert_generates(ast_or_string, expected, versions = RUBIES)
|
59
|
+
ast_or_string = strip(ast_or_string) if ast_or_string.is_a?(String)
|
60
|
+
expected = strip(expected)
|
61
|
+
with_versions(versions) do |version, parser_class|
|
62
|
+
it "should generate #{ast_or_string.inspect} as #{expected} under #{version}" do
|
63
|
+
ast, comments = if ast_or_string.kind_of?(String)
|
64
|
+
parser_class.parse_with_comments(ast_or_string)
|
65
|
+
else
|
66
|
+
[ast_or_string, []]
|
67
|
+
end
|
68
|
+
generated = Unparser.unparse(ast, comments)
|
63
69
|
generated.should eql(expected)
|
64
|
-
ast =
|
65
|
-
Unparser.unparse(ast).should eql(expected)
|
70
|
+
ast, comments = parser_class.parse_with_comments(generated)
|
71
|
+
Unparser.unparse(ast, comments).should eql(expected)
|
66
72
|
end
|
67
73
|
end
|
68
74
|
end
|
@@ -1034,6 +1040,7 @@ describe Unparser do
|
|
1034
1040
|
assert_source 'a &&= b'
|
1035
1041
|
assert_source 'a ||= 2'
|
1036
1042
|
assert_source '(a ||= 2).bar'
|
1043
|
+
assert_source '(h ||= {})[k] = v'
|
1037
1044
|
end
|
1038
1045
|
|
1039
1046
|
context 'flip flops' do
|
@@ -1190,5 +1197,72 @@ describe Unparser do
|
|
1190
1197
|
end
|
1191
1198
|
RUBY
|
1192
1199
|
end
|
1200
|
+
|
1201
|
+
context 'comments' do
|
1202
|
+
assert_source <<-RUBY
|
1203
|
+
# comment before
|
1204
|
+
a_line_of_code
|
1205
|
+
RUBY
|
1206
|
+
|
1207
|
+
assert_source <<-RUBY
|
1208
|
+
a_line_of_code # comment after
|
1209
|
+
RUBY
|
1210
|
+
|
1211
|
+
assert_source <<-RUBY
|
1212
|
+
nested do # first
|
1213
|
+
# second
|
1214
|
+
something # comment
|
1215
|
+
# another
|
1216
|
+
end
|
1217
|
+
# last
|
1218
|
+
RUBY
|
1219
|
+
|
1220
|
+
assert_source <<-RUBY
|
1221
|
+
def noop
|
1222
|
+
# do nothing
|
1223
|
+
end
|
1224
|
+
RUBY
|
1225
|
+
|
1226
|
+
assert_source <<-RUBY
|
1227
|
+
=begin
|
1228
|
+
block comment
|
1229
|
+
=end
|
1230
|
+
nested do
|
1231
|
+
=begin
|
1232
|
+
another block comment
|
1233
|
+
=end
|
1234
|
+
something
|
1235
|
+
=begin
|
1236
|
+
last block comment
|
1237
|
+
=end
|
1238
|
+
end
|
1239
|
+
RUBY
|
1240
|
+
|
1241
|
+
assert_generates(<<-RUBY, <<-RUBY)
|
1242
|
+
1 + # first
|
1243
|
+
2 # second
|
1244
|
+
RUBY
|
1245
|
+
1 + 2 # first # second
|
1246
|
+
RUBY
|
1247
|
+
assert_generates(<<-RUBY, <<-RUBY)
|
1248
|
+
1 +
|
1249
|
+
# first
|
1250
|
+
2 # second
|
1251
|
+
RUBY
|
1252
|
+
1 + 2 # first # second
|
1253
|
+
RUBY
|
1254
|
+
assert_generates(<<-RUBY, <<-RUBY)
|
1255
|
+
1 +
|
1256
|
+
=begin
|
1257
|
+
block comment
|
1258
|
+
=end
|
1259
|
+
2
|
1260
|
+
RUBY
|
1261
|
+
1 + 2
|
1262
|
+
=begin
|
1263
|
+
block comment
|
1264
|
+
=end
|
1265
|
+
RUBY
|
1266
|
+
end
|
1193
1267
|
end
|
1194
1268
|
end
|
data/unparser.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'unparser'
|
5
|
-
s.version = '0.1.
|
5
|
+
s.version = '0.1.3'
|
6
6
|
|
7
7
|
s.authors = ['Markus Schirp']
|
8
8
|
s.email = 'mbj@schir-dso.com'
|
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.extra_rdoc_files = %w(README.md)
|
18
18
|
s.executables = [ 'test-unparser' ]
|
19
19
|
|
20
|
-
s.add_dependency('parser', '~> 2.0.0.
|
20
|
+
s.add_dependency('parser', '~> 2.0.0.pre7')
|
21
21
|
s.add_dependency('concord', '~> 0.1.1' )
|
22
22
|
s.add_dependency('adamantium', '~> 0.1.0' )
|
23
23
|
s.add_dependency('equalizer', '~> 0.0.7' )
|
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.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Markus Schirp
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-09-
|
11
|
+
date: 2013-09-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.0.0.
|
19
|
+
version: 2.0.0.pre7
|
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: 2.0.0.
|
26
|
+
version: 2.0.0.pre7
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: concord
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,6 +109,7 @@ files:
|
|
109
109
|
- config/yardstick.yml
|
110
110
|
- lib/unparser.rb
|
111
111
|
- lib/unparser/buffer.rb
|
112
|
+
- lib/unparser/comments.rb
|
112
113
|
- lib/unparser/constants.rb
|
113
114
|
- lib/unparser/emitter.rb
|
114
115
|
- lib/unparser/emitter/alias.rb
|
@@ -162,10 +163,18 @@ files:
|
|
162
163
|
- lib/unparser/finalize.rb
|
163
164
|
- spec/spec_helper.rb
|
164
165
|
- spec/unit/unparser/buffer/append_spec.rb
|
166
|
+
- spec/unit/unparser/buffer/append_without_prefix_spec.rb
|
167
|
+
- spec/unit/unparser/buffer/capture_content_spec.rb
|
165
168
|
- spec/unit/unparser/buffer/content_spec.rb
|
169
|
+
- spec/unit/unparser/buffer/fresh_line_spec.rb
|
166
170
|
- spec/unit/unparser/buffer/indent_spec.rb
|
167
171
|
- spec/unit/unparser/buffer/nl_spec.rb
|
168
172
|
- spec/unit/unparser/buffer/unindent_spec.rb
|
173
|
+
- spec/unit/unparser/comments/consume_spec.rb
|
174
|
+
- spec/unit/unparser/comments/skip_eol_comment_spec.rb
|
175
|
+
- spec/unit/unparser/comments/take_all_spec.rb
|
176
|
+
- spec/unit/unparser/comments/take_before_spec.rb
|
177
|
+
- spec/unit/unparser/comments/take_eol_comments_spec.rb
|
169
178
|
- spec/unit/unparser/emitter/class_methods/handle_spec.rb
|
170
179
|
- spec/unit/unparser/emitter/source_map/class_methods/emit_spec.rb
|
171
180
|
- spec/unit/unparser_spec.rb
|
@@ -197,10 +206,18 @@ summary: Generate equivalent source for parser gem AST nodes
|
|
197
206
|
test_files:
|
198
207
|
- spec/spec_helper.rb
|
199
208
|
- spec/unit/unparser/buffer/append_spec.rb
|
209
|
+
- spec/unit/unparser/buffer/append_without_prefix_spec.rb
|
210
|
+
- spec/unit/unparser/buffer/capture_content_spec.rb
|
200
211
|
- spec/unit/unparser/buffer/content_spec.rb
|
212
|
+
- spec/unit/unparser/buffer/fresh_line_spec.rb
|
201
213
|
- spec/unit/unparser/buffer/indent_spec.rb
|
202
214
|
- spec/unit/unparser/buffer/nl_spec.rb
|
203
215
|
- spec/unit/unparser/buffer/unindent_spec.rb
|
216
|
+
- spec/unit/unparser/comments/consume_spec.rb
|
217
|
+
- spec/unit/unparser/comments/skip_eol_comment_spec.rb
|
218
|
+
- spec/unit/unparser/comments/take_all_spec.rb
|
219
|
+
- spec/unit/unparser/comments/take_before_spec.rb
|
220
|
+
- spec/unit/unparser/comments/take_eol_comments_spec.rb
|
204
221
|
- spec/unit/unparser/emitter/class_methods/handle_spec.rb
|
205
222
|
- spec/unit/unparser/emitter/source_map/class_methods/emit_spec.rb
|
206
223
|
- spec/unit/unparser_spec.rb
|