unparser 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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,107 @@
1
+ module Unparser
2
+ class Emitter
3
+ # Emitter for def node
4
+ class Def < self
5
+
6
+ private
7
+
8
+ # Emit name
9
+ #
10
+ # @return [undefined]
11
+ #
12
+ # @api private
13
+ #
14
+ abstract_method :emit_name
15
+ private :emit_name
16
+
17
+ # Return body node
18
+ #
19
+ # @return [Parser::AST::Node]
20
+ #
21
+ # @api private
22
+ #
23
+ abstract_method :body
24
+ private :body
25
+
26
+ # Perform dispatch
27
+ #
28
+ # @return [undefined]
29
+ #
30
+ # @api private
31
+ #
32
+ def dispatch
33
+ write(K_DEF, WS)
34
+ emit_name
35
+ emit_arguments
36
+ emit_body
37
+ k_end
38
+ end
39
+
40
+ # Emit body
41
+ #
42
+ # @return [undefined]
43
+ #
44
+ # @api private
45
+ #
46
+ def emit_body
47
+ indented { visit(body) }
48
+ end
49
+
50
+ # Emit arguments
51
+ #
52
+ # @return [undefined]
53
+ #
54
+ # @api private
55
+ #
56
+ def emit_arguments
57
+ return if arguments.children.empty?
58
+ parentheses do
59
+ visit(arguments)
60
+ end
61
+ end
62
+
63
+ # Instance def emitter
64
+ class Instance < self
65
+
66
+ handle :def
67
+
68
+ children :name, :arguments, :body
69
+
70
+ private
71
+
72
+ # Emit name
73
+ #
74
+ # @return [undefined]
75
+ #
76
+ # @api private
77
+ #
78
+ def emit_name
79
+ write(name.to_s)
80
+ end
81
+
82
+ end # Instance
83
+
84
+ # Emitter for defines on singleton
85
+ class Singleton < self
86
+
87
+ handle :defs
88
+
89
+ children :subject, :name, :arguments, :body
90
+
91
+ private
92
+
93
+ # Return mame
94
+ #
95
+ # @return [String]
96
+ #
97
+ # @api private
98
+ #
99
+ def emit_name
100
+ visit(subject)
101
+ write(O_DOT, name.to_s)
102
+ end
103
+
104
+ end # Singleton
105
+ end # Def
106
+ end # Emitter
107
+ end # Unparser
@@ -0,0 +1,27 @@
1
+ module Unparser
2
+ class Emitter
3
+ # Emitter for defined? nodes
4
+ class Defined < self
5
+
6
+ handle :defined?
7
+
8
+ children :subject
9
+
10
+ private
11
+
12
+ # Perform dispatch
13
+ #
14
+ # @return [undefined]
15
+ #
16
+ # @api private
17
+ #
18
+ def dispatch
19
+ write(K_DEFINED)
20
+ parentheses do
21
+ visit(subject)
22
+ end
23
+ end
24
+
25
+ end # Defined
26
+ end # Emitter
27
+ end # Unparser
@@ -0,0 +1,50 @@
1
+ module Unparser
2
+ class Emitter
3
+ # Emitter for for nodes
4
+ class For < self
5
+
6
+ handle :for
7
+
8
+ children :condition, :assignment, :body
9
+
10
+ private
11
+
12
+ # Perform dispatch
13
+ #
14
+ # @return [undefined]
15
+ #
16
+ # @api private
17
+ #
18
+ def dispatch
19
+ write(K_FOR, WS)
20
+ emit_condition
21
+ emit_body
22
+ k_end
23
+ end
24
+
25
+ # Emit assignment
26
+ #
27
+ # @return [undefined]
28
+ #
29
+ # @api private
30
+ #
31
+ def emit_condition
32
+ visit(condition)
33
+ write(WS, K_IN, WS)
34
+ visit(assignment)
35
+ write(WS, K_DO)
36
+ end
37
+
38
+ # Emit body
39
+ #
40
+ # @return [undefined]
41
+ #
42
+ # @api private
43
+ #
44
+ def emit_body
45
+ indented { visit(body) }
46
+ end
47
+
48
+ end # For
49
+ end # Emitter
50
+ end # Unparser
@@ -0,0 +1,42 @@
1
+ module Unparser
2
+ class Emitter
3
+ # Base class for pre and postexe emitters
4
+ class Hookexe < self
5
+
6
+ MAP = {
7
+ :preexe => K_PREEXE,
8
+ :postexe => K_POSTEXE
9
+ }.freeze
10
+
11
+ handle *MAP.keys
12
+
13
+ children :body
14
+
15
+ private
16
+
17
+ # Perfrom dispatch
18
+ #
19
+ # @return [undefined]
20
+ #
21
+ # @api private
22
+ #
23
+ def dispatch
24
+ write(MAP.fetch(node.type), WS)
25
+ parentheses(*CURLY_BRACKETS) do
26
+ emit_body
27
+ end
28
+ end
29
+
30
+ # Emit body
31
+ #
32
+ # @return [undefined]
33
+ #
34
+ # @api private
35
+ #
36
+ def emit_body
37
+ indented { visit(body) }
38
+ end
39
+
40
+ end # Hookexe
41
+ end # Emitter
42
+ end # Unparser
@@ -0,0 +1,85 @@
1
+ module Unparser
2
+ class Emitter
3
+ # Emitter if nodes
4
+ class If < self
5
+
6
+ handle :if
7
+
8
+ children :condition, :if_branch, :else_branch
9
+
10
+ private
11
+
12
+ # Perform dispatch
13
+ #
14
+ # @return [undefined]
15
+ #
16
+ # @api private
17
+ #
18
+ def dispatch
19
+ write(keyword, WS)
20
+ emit_condition
21
+ emit_if_branch
22
+ emit_else_branch
23
+ k_end
24
+ end
25
+
26
+ # Test for unless
27
+ #
28
+ # @return [true]
29
+ # if to emit as unless
30
+ #
31
+ # @return [false]
32
+ # otherwise
33
+ #
34
+ # @api private
35
+ #
36
+ def unless?
37
+ !if_branch
38
+ end
39
+
40
+ # Return keyword
41
+ #
42
+ # @return [String]
43
+ #
44
+ # @api private
45
+ #
46
+ def keyword
47
+ unless? ? K_UNLESS : K_IF
48
+ end
49
+
50
+ # Emit condition
51
+ #
52
+ # @return [undefined]
53
+ #
54
+ # @api private
55
+ #
56
+ def emit_condition
57
+ visit(condition)
58
+ end
59
+
60
+ # Emit if branch
61
+ #
62
+ # @return [undefined]
63
+ #
64
+ # @api private
65
+ #
66
+ def emit_if_branch
67
+ return unless if_branch
68
+ indented { visit(if_branch) }
69
+ end
70
+
71
+ # Emit else branch
72
+ #
73
+ # @return [undefined]
74
+ #
75
+ # @api private
76
+ #
77
+ def emit_else_branch
78
+ return unless else_branch
79
+ write(K_ELSE) unless unless?
80
+ indented { visit(else_branch) }
81
+ end
82
+
83
+ end # If
84
+ end # Emitter
85
+ end # Unparser
@@ -0,0 +1,64 @@
1
+ module Unparser
2
+ class Emitter
3
+ class Literal
4
+
5
+ # Emitter for hash keyvalue pair
6
+ class HashPair < self
7
+ HASHROCKET = ' => '.freeze
8
+
9
+ handle :pair
10
+
11
+ private
12
+
13
+ # Perform dispatch
14
+ #
15
+ # @return [undefined]
16
+ #
17
+ # @api private
18
+ #
19
+ def dispatch
20
+ delimited(children, HASHROCKET)
21
+ end
22
+
23
+ end # HashPair
24
+
25
+ # Base class for compound literal emitters
26
+ class Compound < self
27
+
28
+ private
29
+
30
+ # Perform dispatch
31
+ #
32
+ # @return [undefined]
33
+ #
34
+ # @api private
35
+ #
36
+ def dispatch
37
+ util = self.class
38
+ parentheses(util::OPEN, util::CLOSE) do
39
+ delimited(children, util::DELIMITER)
40
+ end
41
+ end
42
+
43
+ # Hash literal emitter
44
+ class Hash < self
45
+ OPEN = '{'.freeze
46
+ CLOSE = '}'.freeze
47
+ DELIMITER = ', '.freeze
48
+
49
+ handle :hash
50
+ end # Hash
51
+
52
+ # Array literal emitter
53
+ class Array < self
54
+ OPEN = '['.freeze
55
+ CLOSE = ']'.freeze
56
+ DELIMITER = ', '.freeze
57
+
58
+ handle :array
59
+ end # Array
60
+
61
+ end # Compound
62
+ end # Literal
63
+ end # Emitter
64
+ end # Unparser
@@ -0,0 +1,54 @@
1
+ module Unparser
2
+ class Emitter
3
+ class Literal
4
+
5
+ # Base class for dynamic literal emitters
6
+ class Dynamic < self
7
+
8
+ private
9
+
10
+ # Perform dispatch
11
+ #
12
+ # @return [undefined]
13
+ #
14
+ # @api private
15
+ #
16
+ def dispatch
17
+ util = self.class
18
+ parentheses(util::OPEN, util::CLOSE) do
19
+ visit(dynamic_body)
20
+ end
21
+ end
22
+
23
+ # Return dynamic body
24
+ #
25
+ # @return [Parser::AST::Node]
26
+ #
27
+ # @api private
28
+ #
29
+ def dynamic_body
30
+ Parser::AST::Node.new(:dyn_str_body, children)
31
+ end
32
+
33
+ # Dynamic string literal emitter
34
+ class String < self
35
+
36
+ OPEN = CLOSE = '"'.freeze
37
+ handle :dstr
38
+
39
+ end # String
40
+
41
+ # Dynamic symbol literal emitter
42
+ class Symbol < self
43
+
44
+ OPEN = ':"'.freeze
45
+ CLOSE = '"'.freeze
46
+
47
+ handle :dsym
48
+
49
+ end # Symbol
50
+
51
+ end
52
+ end # Literal
53
+ end # Emitter
54
+ end # Unparser
@@ -0,0 +1,109 @@
1
+ module Unparser
2
+ class Emitter
3
+ class Literal
4
+
5
+ # Emitter for dynamic bodies
6
+ class DynamicBody < self
7
+
8
+ OPEN = '#{'.freeze
9
+ CLOSE = '}'.freeze
10
+
11
+ private
12
+
13
+ # Perform dispatch
14
+ #
15
+ # @return [undefined]
16
+ #
17
+ # @api private
18
+ #
19
+ def dispatch
20
+ children.each do |node|
21
+ emit_segment(node)
22
+ end
23
+ end
24
+
25
+ # Emit segment
26
+ #
27
+ # @param [Parser::Node] node
28
+ #
29
+ # @return [undefined]
30
+ #
31
+ # @api private
32
+ #
33
+ def emit_segment(node)
34
+ if node.type == :str
35
+ emit_str_segment(node)
36
+ return
37
+ end
38
+ emit_interpolated_segment(node)
39
+ end
40
+
41
+ ESCAPES = IceNine.deep_freeze(
42
+ "\n" => '\n'
43
+ )
44
+
45
+ REPLACEMENTS = ::Regexp.union(ESCAPES.keys)
46
+
47
+ # Emit str segment
48
+ #
49
+ # @param [Parser::Node] node
50
+ #
51
+ # @return [undefined]
52
+ #
53
+ # @api private
54
+ #
55
+ def emit_str_segment(node)
56
+ util = self.class
57
+ str = node.children.first
58
+ str = str.
59
+ gsub(util::DELIMITER, util::REPLACEMENT).
60
+ gsub(REPLACEMENTS, ESCAPES)
61
+ write(str)
62
+ end
63
+
64
+ # Emit interpolated segment
65
+ #
66
+ # @param [Parser::Node] node
67
+ #
68
+ # @return [undefined]
69
+ #
70
+ # @api private
71
+ #
72
+ def emit_interpolated_segment(node)
73
+ parentheses(OPEN, CLOSE) { visit(node) }
74
+ end
75
+
76
+ # Dynamic string body
77
+ class String < self
78
+
79
+ handle :dyn_str_body
80
+
81
+ DELIMITER = '"'.freeze
82
+ REPLACEMENT = '\"'.freeze
83
+
84
+ end # String
85
+
86
+ # Dynamic regexp body
87
+ class Regexp < self
88
+
89
+ handle :dyn_regexp_body
90
+
91
+ DELIMITER = '/'.freeze
92
+ REPLACEMENT = '/'.freeze
93
+
94
+ end # Regexp
95
+
96
+ # Dynamic regexp body
97
+ class ExecuteString < self
98
+
99
+ handle :dyn_xstr_body
100
+
101
+ DELIMITER = '`'.freeze
102
+ REPLACEMENT = '\`'.freeze
103
+
104
+ end # ExecuteString
105
+
106
+ end # DynamicBody
107
+ end # Literal
108
+ end # Emitter
109
+ end # Unparser
@@ -0,0 +1,38 @@
1
+ module Unparser
2
+ class Emitter
3
+ class Literal
4
+ # Emitter for execute strings (xstr) nodes
5
+ class ExecuteString < self
6
+
7
+ OPEN = CLOSE = '`'.freeze
8
+
9
+ handle :xstr
10
+
11
+ private
12
+
13
+ # Perform dispatch
14
+ #
15
+ # @return [undefined]
16
+ #
17
+ # @api private
18
+ #
19
+ def dispatch
20
+ parentheses(OPEN, CLOSE) do
21
+ visit(dynamic_body)
22
+ end
23
+ end
24
+
25
+ # Return dynamic body
26
+ #
27
+ # @return [Parser::AST::Node]
28
+ #
29
+ # @api private
30
+ #
31
+ def dynamic_body
32
+ Parser::AST::Node.new(:dyn_xstr_body, children)
33
+ end
34
+
35
+ end # ExecuteString
36
+ end # Literal
37
+ end # Emitter
38
+ end # Unparser
@@ -0,0 +1,49 @@
1
+ module Unparser
2
+ class Emitter
3
+ class Literal
4
+
5
+ # Base class for primitive emitters
6
+ class Primitive < self
7
+
8
+ children :value
9
+
10
+ private
11
+
12
+ # Dispatch node
13
+ #
14
+ # @return [undefined]
15
+ #
16
+ # @api private
17
+ #
18
+ def dispatch
19
+ if node.location
20
+ emit_source_map
21
+ else
22
+ dispatch_value
23
+ end
24
+ end
25
+
26
+ abstract_method :disaptch_value
27
+
28
+ # Emitter for primitives based on Object#inspect
29
+ class Inspect < self
30
+
31
+ handle :int, :str, :float, :sym
32
+
33
+ private
34
+
35
+ # Dispatch value
36
+ #
37
+ # @return [undefined]
38
+ #
39
+ # @api private
40
+ #
41
+ def dispatch_value
42
+ buffer.append(value.inspect)
43
+ end
44
+
45
+ end # Inspect
46
+ end # Primitive
47
+ end # Literal
48
+ end # Emitter
49
+ end # Unparser
@@ -0,0 +1,33 @@
1
+ module Unparser
2
+ class Emitter
3
+ class Literal
4
+ # Abstract base class for literal range emitter
5
+ class Range < self
6
+
7
+ TOKENS = IceNine.deep_freeze(
8
+ :irange => '..',
9
+ :erange => '...'
10
+ )
11
+
12
+ handle *TOKENS.keys
13
+
14
+ children :begin_node, :end_node
15
+
16
+ private
17
+
18
+ # Perform dispatch
19
+ #
20
+ # @return [undefined]
21
+ #
22
+ # @api private
23
+ #
24
+ def dispatch
25
+ visit(begin_node)
26
+ write(TOKENS.fetch(node.type))
27
+ visit(end_node)
28
+ end
29
+
30
+ end # Range
31
+ end # Literal
32
+ end # Emitter
33
+ end # Unparser