unparser 0.1.7 → 0.1.8
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/.rubocop.yml +7 -0
- data/.travis.yml +3 -0
- data/Changelog.md +4 -0
- data/README.md +4 -2
- data/config/flay.yml +1 -1
- data/config/flog.yml +1 -1
- data/config/reek.yml +24 -19
- data/config/rubocop.yml +2 -3
- data/lib/unparser.rb +8 -22
- data/lib/unparser/ast.rb +232 -0
- data/lib/unparser/ast/local_variable_scope.rb +198 -0
- data/lib/unparser/cli.rb +41 -24
- data/lib/unparser/cli/differ.rb +38 -16
- data/lib/unparser/cli/source.rb +46 -17
- data/lib/unparser/constants.rb +23 -6
- data/lib/unparser/emitter.rb +32 -0
- data/lib/unparser/emitter/argument.rb +30 -4
- data/lib/unparser/emitter/assignment.rb +12 -1
- data/lib/unparser/emitter/begin.rb +23 -2
- data/lib/unparser/emitter/case.rb +1 -1
- data/lib/unparser/emitter/class.rb +1 -0
- data/lib/unparser/emitter/def.rb +28 -1
- data/lib/unparser/emitter/defined.rb +3 -1
- data/lib/unparser/emitter/flow_modifier.rb +63 -0
- data/lib/unparser/emitter/if.rb +44 -0
- data/lib/unparser/emitter/literal/dynamic.rb +25 -1
- data/lib/unparser/emitter/literal/hash.rb +3 -3
- data/lib/unparser/emitter/literal/primitive.rb +9 -47
- data/lib/unparser/emitter/literal/regexp.rb +5 -16
- data/lib/unparser/emitter/module.rb +1 -0
- data/lib/unparser/emitter/repetition.rb +52 -0
- data/lib/unparser/emitter/resbody.rb +4 -2
- data/lib/unparser/emitter/rescue.rb +12 -2
- data/lib/unparser/emitter/root.rb +2 -11
- data/lib/unparser/emitter/send.rb +19 -2
- data/lib/unparser/emitter/send/index.rb +42 -4
- data/lib/unparser/emitter/send/unary.rb +4 -0
- data/lib/unparser/emitter/undef.rb +1 -3
- data/lib/unparser/node_helpers.rb +13 -1
- data/lib/unparser/preprocessor.rb +226 -0
- data/lib/unparser/strip_helper.rb +23 -0
- data/rubyspec.sh +20 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/unit/unparser_spec.rb +390 -151
- data/unparser.gemspec +1 -1
- metadata +27 -24
- data/lib/unparser/cli/preprocessor.rb +0 -197
- data/lib/unparser/emitter/break.rb +0 -27
- data/lib/unparser/emitter/next.rb +0 -28
- data/lib/unparser/emitter/return.rb +0 -41
@@ -20,7 +20,7 @@ module Unparser
|
|
20
20
|
if interpolation?
|
21
21
|
visit_parentheses(dynamic_body, util::OPEN, util::CLOSE)
|
22
22
|
else
|
23
|
-
|
23
|
+
emit_non_interpolated
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -54,6 +54,18 @@ module Unparser
|
|
54
54
|
OPEN = CLOSE = '"'.freeze
|
55
55
|
handle :dstr
|
56
56
|
|
57
|
+
private
|
58
|
+
|
59
|
+
# Emit non interpolated form
|
60
|
+
#
|
61
|
+
# @return [undefined]
|
62
|
+
#
|
63
|
+
# @api private
|
64
|
+
#
|
65
|
+
def emit_non_interpolated
|
66
|
+
delimited(children, WS)
|
67
|
+
end
|
68
|
+
|
57
69
|
end # String
|
58
70
|
|
59
71
|
# Dynamic symbol literal emitter
|
@@ -64,6 +76,18 @@ module Unparser
|
|
64
76
|
|
65
77
|
handle :dsym
|
66
78
|
|
79
|
+
private
|
80
|
+
|
81
|
+
# Emit non interpolated form
|
82
|
+
#
|
83
|
+
# @return [undefined]
|
84
|
+
#
|
85
|
+
# @api private
|
86
|
+
#
|
87
|
+
def emit_non_interpolated
|
88
|
+
visit_parentheses(dynamic_body, OPEN, CLOSE)
|
89
|
+
end
|
90
|
+
|
67
91
|
end # Symbol
|
68
92
|
|
69
93
|
end
|
@@ -45,7 +45,7 @@ module Unparser
|
|
45
45
|
#
|
46
46
|
def dispatch
|
47
47
|
write(key.children.first.to_s, COLON)
|
48
|
-
|
48
|
+
visit_terminated(value)
|
49
49
|
end
|
50
50
|
|
51
51
|
end # Colon
|
@@ -82,9 +82,9 @@ module Unparser
|
|
82
82
|
children.map do |pair|
|
83
83
|
key, _value = *pair
|
84
84
|
if key.type == :sym && key.children.first.to_s =~ BAREWORD
|
85
|
-
|
85
|
+
n(:pair_colon, pair.children)
|
86
86
|
else
|
87
|
-
|
87
|
+
n(:pair_rocket, pair.children)
|
88
88
|
end
|
89
89
|
end
|
90
90
|
end
|
@@ -14,7 +14,7 @@ module Unparser
|
|
14
14
|
# Emitter for primitives based on Object#inspect
|
15
15
|
class Inspect < self
|
16
16
|
|
17
|
-
handle :
|
17
|
+
handle :sym, :str
|
18
18
|
|
19
19
|
private
|
20
20
|
|
@@ -30,64 +30,26 @@ module Unparser
|
|
30
30
|
|
31
31
|
end # Inspect
|
32
32
|
|
33
|
-
#
|
34
|
-
class
|
33
|
+
# Emiter for numeric literals
|
34
|
+
class Numeric < self
|
35
|
+
|
36
|
+
handle :int, :float
|
35
37
|
|
36
38
|
private
|
37
39
|
|
38
|
-
#
|
40
|
+
# Dispatch value
|
39
41
|
#
|
40
42
|
# @return [undefined]
|
41
43
|
#
|
42
44
|
# @api private
|
43
45
|
#
|
44
46
|
def dispatch
|
45
|
-
|
46
|
-
write(
|
47
|
-
return
|
47
|
+
conditional_parentheses(parent.kind_of?(Emitter::Send) && value < 0) do
|
48
|
+
write(value.inspect)
|
48
49
|
end
|
49
|
-
write(value.inspect)
|
50
|
-
end
|
51
|
-
|
52
|
-
# Return source, if present
|
53
|
-
#
|
54
|
-
# @return [String]
|
55
|
-
# if present
|
56
|
-
#
|
57
|
-
# @return [nil]
|
58
|
-
# otherwise
|
59
|
-
#
|
60
|
-
# @api private
|
61
|
-
#
|
62
|
-
def source
|
63
|
-
location = node.location || return
|
64
|
-
expression = location.expression || return
|
65
|
-
expression.source
|
66
50
|
end
|
67
51
|
|
68
|
-
|
69
|
-
#
|
70
|
-
# @return [String]
|
71
|
-
#
|
72
|
-
# @api private
|
73
|
-
#
|
74
|
-
def macro
|
75
|
-
self.class::MACRO
|
76
|
-
end
|
77
|
-
|
78
|
-
# String macro safe emitter
|
79
|
-
class String < self
|
80
|
-
MACRO = '__FILE__'.freeze
|
81
|
-
handle :str
|
82
|
-
end # String
|
83
|
-
|
84
|
-
# Integer macro safe emitter
|
85
|
-
class Integer < self
|
86
|
-
MACRO = '__LINE__'.freeze
|
87
|
-
handle :int
|
88
|
-
end # Integer
|
89
|
-
|
90
|
-
end # MacroSave
|
52
|
+
end # Numeric
|
91
53
|
end # Primitive
|
92
54
|
end # Literal
|
93
55
|
end # Emitter
|
@@ -7,6 +7,7 @@ module Unparser
|
|
7
7
|
# Emitter for regexp literals
|
8
8
|
class Regexp < self
|
9
9
|
DELIMITER = '/'.freeze
|
10
|
+
ESCAPED_DELIMITER = '\/'.freeze
|
10
11
|
|
11
12
|
handle :regexp
|
12
13
|
|
@@ -50,7 +51,7 @@ module Unparser
|
|
50
51
|
when :str
|
51
52
|
buffer.append_without_prefix(escape(node).children.first)
|
52
53
|
else
|
53
|
-
visit(s(:interpolated,
|
54
|
+
visit(s(:interpolated, node))
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
@@ -78,28 +79,16 @@ module Unparser
|
|
78
79
|
|
79
80
|
# Return escaped child
|
80
81
|
#
|
82
|
+
# @param [Parser::AST::Node] child
|
83
|
+
#
|
81
84
|
# @return [Parser::AST::Node]
|
82
85
|
#
|
83
86
|
# @api private
|
84
87
|
#
|
85
88
|
def escape(child)
|
86
|
-
return child unless child.type == :str
|
87
89
|
source = child.children.first
|
88
|
-
|
89
|
-
end
|
90
|
-
|
91
|
-
# Return closing delimiter
|
92
|
-
#
|
93
|
-
# @return [String]
|
94
|
-
#
|
95
|
-
# @api private
|
96
|
-
#
|
97
|
-
def delimiter
|
98
|
-
location = node.location
|
99
|
-
return DELIMITER unless location
|
100
|
-
location.end.source[-1]
|
90
|
+
s(:str, source.gsub(DELIMITER, ESCAPED_DELIMITER))
|
101
91
|
end
|
102
|
-
memoize :delimiter
|
103
92
|
|
104
93
|
end # Regexp
|
105
94
|
|
@@ -51,12 +51,64 @@ module Unparser
|
|
51
51
|
# @api private
|
52
52
|
#
|
53
53
|
def dispatch
|
54
|
+
if postcontrol?
|
55
|
+
emit_postcontrol
|
56
|
+
else
|
57
|
+
emit_normal
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Test for postcontrol
|
62
|
+
#
|
63
|
+
# @return [true]
|
64
|
+
# if repetition must be emitted as post control
|
65
|
+
#
|
66
|
+
# @return [false]
|
67
|
+
# otherwise
|
68
|
+
#
|
69
|
+
# @api private
|
70
|
+
#
|
71
|
+
def postcontrol?
|
72
|
+
return false unless body
|
73
|
+
AST.first_assignment_in_body_and_used_in_condition?(local_variable_root, body, condition)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Emit keyword
|
77
|
+
#
|
78
|
+
# @return [undefined]
|
79
|
+
#
|
80
|
+
# @api private
|
81
|
+
#
|
82
|
+
def emit_keyword
|
54
83
|
write(MAP.fetch(node.type), WS)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Emit embedded
|
87
|
+
#
|
88
|
+
# @return [undefned]
|
89
|
+
#
|
90
|
+
# @api private
|
91
|
+
#
|
92
|
+
def emit_normal
|
93
|
+
emit_keyword
|
55
94
|
visit(condition)
|
56
95
|
emit_body
|
57
96
|
k_end
|
58
97
|
end
|
59
98
|
|
99
|
+
# Emit postcontrol
|
100
|
+
#
|
101
|
+
# @return [undefined]
|
102
|
+
#
|
103
|
+
# @api private
|
104
|
+
#
|
105
|
+
def emit_postcontrol
|
106
|
+
visit(body)
|
107
|
+
ws
|
108
|
+
emit_keyword
|
109
|
+
visit(condition)
|
110
|
+
end
|
111
|
+
|
60
112
|
end # Repetition
|
61
113
|
end # Emitter
|
62
114
|
end # Unparser
|
@@ -7,10 +7,9 @@ module Unparser
|
|
7
7
|
|
8
8
|
children :exception, :assignment, :body
|
9
9
|
|
10
|
+
# Emitter for resbody in standalone form
|
10
11
|
class Standalone < self
|
11
12
|
|
12
|
-
handle :resbody
|
13
|
-
|
14
13
|
private
|
15
14
|
|
16
15
|
# Perform dispatch
|
@@ -49,8 +48,11 @@ module Unparser
|
|
49
48
|
end
|
50
49
|
end
|
51
50
|
|
51
|
+
# Emitter for resbody in keyworkd-embedded form
|
52
52
|
class Embedded < self
|
53
53
|
|
54
|
+
handle :resbody
|
55
|
+
|
54
56
|
private
|
55
57
|
|
56
58
|
# Perform dispatch
|
@@ -13,6 +13,8 @@ module Unparser
|
|
13
13
|
|
14
14
|
EMBEDDED_TYPES = [:def, :defs, :kwbegin, :ensure].to_set.freeze
|
15
15
|
|
16
|
+
NOINDENT_STANDALONE_RESCUE = [:root, :begin, :pair_rocket, :pair_colon, :lvasgn, :ivasgn].to_set.freeze
|
17
|
+
|
16
18
|
private
|
17
19
|
|
18
20
|
# Perform dispatch
|
@@ -23,7 +25,11 @@ module Unparser
|
|
23
25
|
#
|
24
26
|
def dispatch
|
25
27
|
if standalone?
|
26
|
-
|
28
|
+
if NOINDENT_STANDALONE_RESCUE.include?(parent_type)
|
29
|
+
emit_standalone
|
30
|
+
else
|
31
|
+
indented { emit_standalone }
|
32
|
+
end
|
27
33
|
else
|
28
34
|
emit_embedded
|
29
35
|
end
|
@@ -40,7 +46,11 @@ module Unparser
|
|
40
46
|
# @api private
|
41
47
|
#
|
42
48
|
def standalone?
|
43
|
-
|
49
|
+
if parent_type == :ensure
|
50
|
+
!parent.node.children.first.equal?(node)
|
51
|
+
else
|
52
|
+
!EMBEDDED_TYPES.include?(parent_type) && body
|
53
|
+
end
|
44
54
|
end
|
45
55
|
|
46
56
|
# Emit standalone form
|
@@ -4,17 +4,8 @@ module Unparser
|
|
4
4
|
class Emitter
|
5
5
|
# Root emitter a special case
|
6
6
|
class Root < self
|
7
|
-
include Concord::Public.new(:buffer, :comments)
|
8
|
-
|
9
|
-
# Return root node type
|
10
|
-
#
|
11
|
-
# @return [nil]
|
12
|
-
#
|
13
|
-
# @api private
|
14
|
-
#
|
15
|
-
def node_type
|
16
|
-
nil
|
17
|
-
end
|
7
|
+
include Concord::Public.new(:node, :buffer, :comments)
|
8
|
+
include LocalVariableRoot
|
18
9
|
|
19
10
|
end # Root
|
20
11
|
end # Emitter
|
@@ -30,7 +30,6 @@ module Unparser
|
|
30
30
|
#
|
31
31
|
def terminated?
|
32
32
|
[
|
33
|
-
Unary,
|
34
33
|
Index::Reference,
|
35
34
|
Regular
|
36
35
|
].include?(effective_emitter)
|
@@ -212,7 +211,25 @@ module Unparser
|
|
212
211
|
# @api private
|
213
212
|
#
|
214
213
|
def emit_arguments
|
215
|
-
|
214
|
+
if arguments.empty? && receiver.nil? && local_variable_clash?
|
215
|
+
write('()')
|
216
|
+
else
|
217
|
+
run(Arguments, n(:arguments, arguments))
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Test for local variable clash
|
222
|
+
#
|
223
|
+
# @return [true]
|
224
|
+
# if selector clashes with a local variable
|
225
|
+
#
|
226
|
+
# @return [false]
|
227
|
+
# otherwise
|
228
|
+
#
|
229
|
+
# @api private
|
230
|
+
#
|
231
|
+
def local_variable_clash?
|
232
|
+
AST.local_variable_defined_for_node?(local_variable_root, node, selector)
|
216
233
|
end
|
217
234
|
|
218
235
|
end # Send
|
@@ -57,13 +57,51 @@ module Unparser
|
|
57
57
|
# @api private
|
58
58
|
#
|
59
59
|
def emit_arguments
|
60
|
-
|
60
|
+
case arguments.length
|
61
|
+
when 0
|
62
|
+
emit_regular_with_empty_args
|
63
|
+
when 1
|
64
|
+
emit_mlhs_arguments
|
65
|
+
else
|
66
|
+
emit_normal_arguments
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Emit mlhs arguments
|
71
|
+
#
|
72
|
+
# @return [undefined]
|
73
|
+
#
|
74
|
+
# @api private
|
75
|
+
#
|
76
|
+
def emit_mlhs_arguments
|
61
77
|
parentheses(*INDEX_PARENS) do
|
62
|
-
delimited(
|
78
|
+
delimited(arguments)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Emit normal arguments
|
83
|
+
#
|
84
|
+
# @return [undefined]
|
85
|
+
#
|
86
|
+
# @api private
|
87
|
+
#
|
88
|
+
def emit_normal_arguments
|
89
|
+
*indices, value = arguments
|
90
|
+
parentheses(*INDEX_PARENS) do
|
91
|
+
delimited(indices)
|
63
92
|
end
|
64
|
-
return if assignment.empty? # mlhs
|
65
93
|
write(WS, T_ASN, WS)
|
66
|
-
|
94
|
+
visit(value)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Emit regular with empty ars
|
98
|
+
#
|
99
|
+
# @return [undefined]
|
100
|
+
#
|
101
|
+
# @api private
|
102
|
+
#
|
103
|
+
def emit_regular_with_empty_args
|
104
|
+
write(T_DOT, '[]=()')
|
67
105
|
end
|
68
106
|
|
69
107
|
end # Assign
|