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