unparser 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|