unparser 0.4.9 → 0.5.4

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.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -4
  3. data/bin/unparser +1 -1
  4. data/lib/unparser.rb +115 -61
  5. data/lib/unparser/ast.rb +0 -1
  6. data/lib/unparser/ast/local_variable_scope.rb +6 -76
  7. data/lib/unparser/buffer.rb +19 -16
  8. data/lib/unparser/cli.rb +26 -39
  9. data/lib/unparser/color.rb +0 -3
  10. data/lib/unparser/comments.rb +0 -26
  11. data/lib/unparser/constants.rb +4 -53
  12. data/lib/unparser/diff.rb +0 -17
  13. data/lib/unparser/dsl.rb +0 -32
  14. data/lib/unparser/emitter.rb +23 -425
  15. data/lib/unparser/emitter/alias.rb +2 -8
  16. data/lib/unparser/emitter/args.rb +45 -0
  17. data/lib/unparser/emitter/argument.rb +8 -166
  18. data/lib/unparser/emitter/array.rb +27 -0
  19. data/lib/unparser/emitter/array_pattern.rb +29 -0
  20. data/lib/unparser/emitter/assignment.rb +36 -127
  21. data/lib/unparser/emitter/begin.rb +9 -84
  22. data/lib/unparser/emitter/binary.rb +7 -20
  23. data/lib/unparser/emitter/block.rb +57 -41
  24. data/lib/unparser/emitter/case.rb +6 -48
  25. data/lib/unparser/emitter/case_guard.rb +27 -0
  26. data/lib/unparser/emitter/case_match.rb +40 -0
  27. data/lib/unparser/emitter/cbase.rb +1 -3
  28. data/lib/unparser/emitter/class.rb +6 -26
  29. data/lib/unparser/emitter/const_pattern.rb +24 -0
  30. data/lib/unparser/emitter/def.rb +7 -51
  31. data/lib/unparser/emitter/defined.rb +2 -12
  32. data/lib/unparser/emitter/dstr.rb +22 -0
  33. data/lib/unparser/emitter/dsym.rb +41 -0
  34. data/lib/unparser/emitter/flipflop.rb +11 -10
  35. data/lib/unparser/emitter/float.rb +29 -0
  36. data/lib/unparser/emitter/flow_modifier.rb +11 -55
  37. data/lib/unparser/emitter/for.rb +5 -19
  38. data/lib/unparser/emitter/hash.rb +74 -0
  39. data/lib/unparser/emitter/hash_pattern.rb +67 -0
  40. data/lib/unparser/emitter/hookexe.rb +5 -11
  41. data/lib/unparser/emitter/if.rb +15 -71
  42. data/lib/unparser/emitter/in_match.rb +21 -0
  43. data/lib/unparser/emitter/in_pattern.rb +34 -0
  44. data/lib/unparser/emitter/index.rb +21 -88
  45. data/lib/unparser/emitter/kwbegin.rb +31 -0
  46. data/lib/unparser/emitter/lambda.rb +0 -8
  47. data/lib/unparser/emitter/masgn.rb +20 -0
  48. data/lib/unparser/emitter/match.rb +3 -17
  49. data/lib/unparser/emitter/match_alt.rb +23 -0
  50. data/lib/unparser/emitter/match_as.rb +21 -0
  51. data/lib/unparser/emitter/match_rest.rb +26 -0
  52. data/lib/unparser/emitter/match_var.rb +19 -0
  53. data/lib/unparser/emitter/mlhs.rb +40 -0
  54. data/lib/unparser/emitter/module.rb +3 -9
  55. data/lib/unparser/emitter/op_assign.rb +12 -27
  56. data/lib/unparser/emitter/pin.rb +19 -0
  57. data/lib/unparser/emitter/primitive.rb +93 -0
  58. data/lib/unparser/emitter/range.rb +35 -0
  59. data/lib/unparser/emitter/regexp.rb +35 -0
  60. data/lib/unparser/emitter/repetition.rb +17 -57
  61. data/lib/unparser/emitter/rescue.rb +1 -97
  62. data/lib/unparser/emitter/root.rb +17 -1
  63. data/lib/unparser/emitter/send.rb +10 -219
  64. data/lib/unparser/emitter/simple.rb +33 -0
  65. data/lib/unparser/emitter/splat.rb +2 -18
  66. data/lib/unparser/emitter/super.rb +1 -29
  67. data/lib/unparser/emitter/undef.rb +1 -9
  68. data/lib/unparser/emitter/variable.rb +1 -31
  69. data/lib/unparser/emitter/xstr.rb +72 -0
  70. data/lib/unparser/emitter/yield.rb +1 -9
  71. data/lib/unparser/generation.rb +250 -0
  72. data/lib/unparser/node_details.rb +21 -0
  73. data/lib/unparser/node_details/send.rb +62 -0
  74. data/lib/unparser/node_helpers.rb +46 -6
  75. data/lib/unparser/validation.rb +58 -35
  76. data/lib/unparser/writer.rb +15 -0
  77. data/lib/unparser/writer/binary.rb +99 -0
  78. data/lib/unparser/writer/dynamic_string.rb +233 -0
  79. data/lib/unparser/writer/resbody.rb +40 -0
  80. data/lib/unparser/writer/rescue.rb +39 -0
  81. data/lib/unparser/writer/send.rb +124 -0
  82. data/lib/unparser/{emitter → writer}/send/attribute_assignment.rb +11 -26
  83. data/lib/unparser/writer/send/binary.rb +27 -0
  84. data/lib/unparser/writer/send/conditional.rb +25 -0
  85. data/lib/unparser/writer/send/regular.rb +33 -0
  86. data/lib/unparser/{emitter → writer}/send/unary.rb +10 -17
  87. metadata +66 -34
  88. data/lib/unparser/emitter/empty.rb +0 -23
  89. data/lib/unparser/emitter/ensure.rb +0 -37
  90. data/lib/unparser/emitter/literal.rb +0 -10
  91. data/lib/unparser/emitter/literal/array.rb +0 -29
  92. data/lib/unparser/emitter/literal/dynamic.rb +0 -53
  93. data/lib/unparser/emitter/literal/dynamic_body.rb +0 -132
  94. data/lib/unparser/emitter/literal/execute_string.rb +0 -38
  95. data/lib/unparser/emitter/literal/hash.rb +0 -156
  96. data/lib/unparser/emitter/literal/primitive.rb +0 -145
  97. data/lib/unparser/emitter/literal/range.rb +0 -36
  98. data/lib/unparser/emitter/literal/regexp.rb +0 -114
  99. data/lib/unparser/emitter/literal/singleton.rb +0 -26
  100. data/lib/unparser/emitter/meta.rb +0 -16
  101. data/lib/unparser/emitter/redo.rb +0 -25
  102. data/lib/unparser/emitter/resbody.rb +0 -76
  103. data/lib/unparser/emitter/retry.rb +0 -25
  104. data/lib/unparser/emitter/send/binary.rb +0 -57
  105. data/lib/unparser/emitter/send/conditional.rb +0 -40
  106. data/lib/unparser/emitter/send/regular.rb +0 -40
  107. data/lib/unparser/preprocessor.rb +0 -159
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10fe213bc822f4da69795458d89fc34693b5c57f1add6e910a77f8f456f5cff4
4
- data.tar.gz: a1333c5af931e182f3fe0c5586d010f306f5b51d5e8f5204beb2bd47cce8a9d2
3
+ metadata.gz: 83c5893dd093e0f106fefd55abad7931fa775001f53a7449389e40afe0640359
4
+ data.tar.gz: d4caba221ba0b3dcd5afdff73d0df537c24c56f3219e0896e5f67b92b79f6afc
5
5
  SHA512:
6
- metadata.gz: aa4d72074d1f1aeeafaf7f87cc53f5a6754dcb06ae99d1c73191b776bb10c9b58db0be2fdd8c9487e61e0cfdc1918e78aac35adccc7b706ea2b9b5b4101faaaf
7
- data.tar.gz: 336938a288a1ada6f33db990535b7d487d618a4f60725101b282c5654fd8e1c953c412c5b8dc9cad9afb936c64ddafd65b5fa0797016022c0a8ce52df35c3ec7
6
+ metadata.gz: 7c7feff0af410abca14daa35166d64b95cda39959f5f6424fb2840a8c5f63b630be4aaba9d22018d745adb2578a9ed7ffc538f4d0c3e6b5224f00e8dd6fceca0
7
+ data.tar.gz: efd0a71dc4988fcf804eab203a4fbed157629c531135d7cbaf2e4ccf5c26c9b1ea2a694c1eb1c2f451f91cfe91b6420d683ff76da6779adaef1e3d015c8ab51b
data/README.md CHANGED
@@ -4,7 +4,7 @@ unparser
4
4
  ![CI](https://github.com/mbj/unparser/workflows/CI/badge.svg)
5
5
  [![Gem Version](https://img.shields.io/gem/v/unparser.svg)](https://rubygems.org/gems/unparser)
6
6
 
7
- Generate equivalent source for ASTs from whitequarks [parser](https://github.com/whitequark/parser).
7
+ Generate equivalent source for ASTs from [parser](https://github.com/whitequark/parser).
8
8
 
9
9
  The following constraints apply:
10
10
 
@@ -12,8 +12,13 @@ The following constraints apply:
12
12
  * Only support for the [modern AST](https://github.com/whitequark/parser/#usage) format
13
13
  * Only support for Ruby >= 2.5
14
14
 
15
- It serves well for [mutant](https://github.com/mbj/mutant) mutators and the in-memory vendoring for self hosting,
16
- and other tooling.
15
+ Notable Users:
16
+
17
+ * [mutant](https://github.com/mbj/mutant) - Code review engine via mutation testing.
18
+ * [ruby-next](https://github.com/ruby-next/ruby-next) - Ruby Syntax Backports.
19
+ * May other [reverse-dependencies](https://rubygems.org/gems/unparser/reverse_dependencies).
20
+
21
+ (if you want your tool to be mentioned here please PR the addition with a TLDR of your use case).
17
22
 
18
23
  Public API:
19
24
  -----------
@@ -86,12 +91,22 @@ RUBY
86
91
 
87
92
  generated = Unparser.unparse(node) # ["foo", "bar"], NOT %w[foo bar] !
88
93
 
89
- code == generated # false, not identical code
94
+ code == generated # false, not identical code
90
95
  Unparser.parse(generated) == node # true, but identical AST
91
96
  ```
92
97
 
93
98
  Summary: unparser does not reproduce your source! It produces equivalent source.
94
99
 
100
+ Ruby Versions:
101
+ --------------
102
+
103
+ Unparsers primay reason for existance is mutant and its
104
+ supported [Ruby-Versions](https://github.com/mbj/mutant#ruby-versions).
105
+
106
+ Basically: All non EOL MRI releases.
107
+
108
+ If you need to generate Ruby Syntax outside of this band feel free to contact me (email in gemspec).
109
+
95
110
  Testing:
96
111
  --------
97
112
 
@@ -5,6 +5,6 @@ trap('INT') do |status|
5
5
  exit! 128 + status
6
6
  end
7
7
 
8
- require 'unparser/cli'
8
+ require 'unparser'
9
9
 
10
10
  exit Unparser::CLI.run(ARGV)
@@ -6,6 +6,7 @@ require 'concord'
6
6
  require 'diff/lcs'
7
7
  require 'diff/lcs/hunk'
8
8
  require 'mprelude'
9
+ require 'optparse'
9
10
  require 'parser/current'
10
11
  require 'procto'
11
12
  require 'set'
@@ -15,6 +16,12 @@ module Unparser
15
16
  # Unparser specific AST builder defaulting to modern AST format
16
17
  class Builder < Parser::Builders::Default
17
18
  modernize
19
+
20
+ def initialize
21
+ super
22
+
23
+ self.emit_file_line_as_literals = false
24
+ end
18
25
  end
19
26
 
20
27
  EMPTY_STRING = ''.freeze
@@ -32,12 +39,44 @@ module Unparser
32
39
  # @api private
33
40
  #
34
41
  def self.unparse(node, comment_array = [])
35
- node = Preprocessor.run(node)
36
- buffer = Buffer.new
37
- comments = Comments.new(comment_array)
38
- root = Emitter::Root.new(Parser::AST::Node.new(:root, [node]), buffer, comments)
39
- Emitter.emitter(node, root).write_to_buffer
40
- buffer.content
42
+ return '' if node.nil?
43
+
44
+ Buffer.new.tap do |buffer|
45
+ Emitter::Root.new(
46
+ buffer,
47
+ node,
48
+ Comments.new(comment_array)
49
+ ).write_to_buffer
50
+ end.content
51
+ end
52
+
53
+ # Unparse with validation
54
+ #
55
+ # @param [Parser::AST::Node, nil] node
56
+ # @param [Array] comment_array
57
+ #
58
+ # @return [Either<Validation,String>]
59
+ def self.unparse_validate(node, comment_array = [])
60
+ generated = unparse(node, comment_array)
61
+ validation = Validation.from_string(generated)
62
+
63
+ if validation.success?
64
+ MPrelude::Either::Right.new(generated)
65
+ else
66
+ MPrelude::Either::Left.new(validation)
67
+ end
68
+ end
69
+
70
+ # Unparse capturing errors
71
+ #
72
+ # This is mostly useful for writing testing tools against unparser.
73
+ #
74
+ # @param [Parser::AST::Node, nil] node
75
+ #
76
+ # @return [Either<Exception, String>]
77
+ def self.unparse_either(node)
78
+ MPrelude::Either
79
+ .wrap_error(Exception) { unparse(node) }
41
80
  end
42
81
 
43
82
  # Parse string into AST
@@ -74,8 +113,6 @@ module Unparser
74
113
  # @return [Parser::Base]
75
114
  #
76
115
  # @api private
77
- #
78
- # ignore :reek:NestedIterators
79
116
  def self.parser
80
117
  Parser::CurrentRuby.new(Builder.new).tap do |parser|
81
118
  parser.diagnostics.tap do |diagnostics|
@@ -100,75 +137,92 @@ module Unparser
100
137
  # @param [String] source
101
138
  #
102
139
  # @return [Parser::Source::Buffer]
103
- def self.buffer(source)
104
- Parser::Source::Buffer.new('(string)').tap do |buffer|
105
- buffer.source = source
106
- end
140
+ def self.buffer(source, identification = '(string)')
141
+ Parser::Source::Buffer.new(identification, source: source)
107
142
  end
108
143
  end # Unparser
109
144
 
110
- require 'unparser/buffer'
111
145
  require 'unparser/node_helpers'
112
- require 'unparser/preprocessor'
113
- require 'unparser/comments'
114
- require 'unparser/constants'
115
- require 'unparser/dsl'
116
146
  require 'unparser/ast'
117
147
  require 'unparser/ast/local_variable_scope'
118
- require 'unparser/diff'
148
+ require 'unparser/buffer'
149
+ require 'unparser/generation'
119
150
  require 'unparser/color'
151
+ require 'unparser/comments'
152
+ require 'unparser/constants'
153
+ require 'unparser/diff'
154
+ require 'unparser/dsl'
120
155
  require 'unparser/emitter'
121
- require 'unparser/emitter/literal'
122
- require 'unparser/emitter/literal/primitive'
123
- require 'unparser/emitter/literal/singleton'
124
- require 'unparser/emitter/literal/dynamic'
125
- require 'unparser/emitter/literal/regexp'
126
- require 'unparser/emitter/literal/array'
127
- require 'unparser/emitter/literal/hash'
128
- require 'unparser/emitter/literal/range'
129
- require 'unparser/emitter/literal/dynamic_body'
130
- require 'unparser/emitter/literal/execute_string'
131
- require 'unparser/emitter/meta'
132
- require 'unparser/emitter/send'
133
- require 'unparser/emitter/send/unary'
134
- require 'unparser/emitter/send/binary'
135
- require 'unparser/emitter/send/regular'
136
- require 'unparser/emitter/send/conditional'
137
- require 'unparser/emitter/send/attribute_assignment'
138
- require 'unparser/emitter/block'
139
- require 'unparser/emitter/assignment'
140
- require 'unparser/emitter/variable'
141
- require 'unparser/emitter/splat'
142
- require 'unparser/emitter/cbase'
156
+ require 'unparser/emitter/alias'
157
+ require 'unparser/emitter/args'
143
158
  require 'unparser/emitter/argument'
159
+ require 'unparser/emitter/array'
160
+ require 'unparser/emitter/array_pattern'
161
+ require 'unparser/emitter/assignment'
144
162
  require 'unparser/emitter/begin'
145
- require 'unparser/emitter/flow_modifier'
146
- require 'unparser/emitter/undef'
147
- require 'unparser/emitter/def'
163
+ require 'unparser/emitter/binary'
164
+ require 'unparser/emitter/block'
165
+ require 'unparser/emitter/case'
166
+ require 'unparser/emitter/case_guard'
167
+ require 'unparser/emitter/case_match'
168
+ require 'unparser/emitter/cbase'
148
169
  require 'unparser/emitter/class'
149
- require 'unparser/emitter/module'
150
- require 'unparser/emitter/op_assign'
170
+ require 'unparser/emitter/const_pattern'
171
+ require 'unparser/emitter/def'
151
172
  require 'unparser/emitter/defined'
173
+ require 'unparser/emitter/dstr'
174
+ require 'unparser/emitter/dsym'
175
+ require 'unparser/emitter/flipflop'
176
+ require 'unparser/emitter/float'
177
+ require 'unparser/emitter/flow_modifier'
178
+ require 'unparser/emitter/for'
179
+ require 'unparser/emitter/hash'
180
+ require 'unparser/emitter/hash_pattern'
152
181
  require 'unparser/emitter/hookexe'
153
- require 'unparser/emitter/super'
154
- require 'unparser/emitter/retry'
155
- require 'unparser/emitter/redo'
156
182
  require 'unparser/emitter/if'
157
- require 'unparser/emitter/alias'
158
- require 'unparser/emitter/yield'
159
- require 'unparser/emitter/binary'
160
- require 'unparser/emitter/case'
161
- require 'unparser/emitter/for'
162
- require 'unparser/emitter/repetition'
163
- require 'unparser/emitter/root'
164
- require 'unparser/emitter/match'
165
- require 'unparser/emitter/empty'
166
- require 'unparser/emitter/flipflop'
167
- require 'unparser/emitter/rescue'
168
- require 'unparser/emitter/resbody'
169
- require 'unparser/emitter/ensure'
183
+ require 'unparser/emitter/in_match'
184
+ require 'unparser/emitter/in_pattern'
170
185
  require 'unparser/emitter/index'
186
+ require 'unparser/emitter/kwbegin'
171
187
  require 'unparser/emitter/lambda'
188
+ require 'unparser/emitter/masgn'
189
+ require 'unparser/emitter/match'
190
+ require 'unparser/emitter/match_alt'
191
+ require 'unparser/emitter/match_as'
192
+ require 'unparser/emitter/match_rest'
193
+ require 'unparser/emitter/match_var'
194
+ require 'unparser/emitter/mlhs'
195
+ require 'unparser/emitter/module'
196
+ require 'unparser/emitter/op_assign'
197
+ require 'unparser/emitter/pin'
198
+ require 'unparser/emitter/primitive'
199
+ require 'unparser/emitter/range'
200
+ require 'unparser/emitter/regexp'
201
+ require 'unparser/emitter/repetition'
202
+ require 'unparser/emitter/rescue'
203
+ require 'unparser/emitter/root'
204
+ require 'unparser/emitter/send'
205
+ require 'unparser/emitter/simple'
206
+ require 'unparser/emitter/splat'
207
+ require 'unparser/emitter/super'
208
+ require 'unparser/emitter/undef'
209
+ require 'unparser/emitter/variable'
210
+ require 'unparser/emitter/xstr'
211
+ require 'unparser/emitter/yield'
212
+ require 'unparser/writer'
213
+ require 'unparser/writer/binary'
214
+ require 'unparser/writer/dynamic_string'
215
+ require 'unparser/writer/resbody'
216
+ require 'unparser/writer/rescue'
217
+ require 'unparser/writer/send'
218
+ require 'unparser/writer/send/attribute_assignment'
219
+ require 'unparser/writer/send/binary'
220
+ require 'unparser/writer/send/regular'
221
+ require 'unparser/writer/send/unary'
222
+ require 'unparser/node_details'
223
+ require 'unparser/node_details/send'
224
+ require 'unparser/cli'
225
+
172
226
  require 'unparser/validation'
173
227
  # make it easy for zombie
174
228
  require 'unparser/finalize'
@@ -2,7 +2,6 @@
2
2
 
3
3
  module Unparser
4
4
  # Namespace for AST processing tools
5
- # :reek:TooManyConstants
6
5
  module AST
7
6
 
8
7
  FIRST_CHILD = ->(node) { node.children.first }.freeze
@@ -61,35 +61,22 @@ module Unparser
61
61
  #
62
62
  # @api private
63
63
  #
64
- def first_assignment_in_body_and_used_in_condition?(body, condition)
65
- condition_reads = AST.local_variable_reads(condition)
64
+ def first_assignment_in?(left, right)
65
+ condition_reads = AST.local_variable_reads(right)
66
66
 
67
- candidates = AST.local_variable_assignments(body).select do |node|
68
- name = node.children.first
69
- condition_reads.include?(name)
67
+ candidates = AST.local_variable_assignments(left).select do |node|
68
+ condition_reads.include?(node.children.first)
70
69
  end
71
70
 
72
- candidates.any? do |node|
73
- first_assignment?(node)
74
- end
71
+ candidates.any?(&public_method(:first_assignment?))
75
72
  end
76
73
 
77
74
  private
78
75
 
79
- # Match node
80
- #
81
- # @param [Parser::AST::Node] needle
82
- # if block given
83
- #
84
- # @return [Boolean]
85
- #
86
- # @api private
87
- #
88
76
  def match(needle)
89
77
  @items.each do |node, current, before|
90
78
  return yield(current, before) if node.equal?(needle)
91
79
  end
92
- false
93
80
  end
94
81
 
95
82
  end # LocalVariableScope
@@ -137,25 +124,10 @@ module Unparser
137
124
 
138
125
  private
139
126
 
140
- # Return current set of local variables
141
- #
142
- # @return [Set<Symbol>]
143
- #
144
- # @api private
145
- #
146
127
  def current
147
128
  @stack.last
148
129
  end
149
130
 
150
- # Visit node and record local variable state
151
- #
152
- # @param [Parser::AST::Node] node
153
- #
154
- # @return [undefined]
155
- #
156
- # @api private
157
- #
158
- # ignore :reek:LongYieldList
159
131
  def visit(node, &block)
160
132
  before = current.dup
161
133
  enter(node)
@@ -166,75 +138,33 @@ module Unparser
166
138
  leave(node)
167
139
  end
168
140
 
169
- # Record local variable state
170
- #
171
- # @param [Parser::AST::Node] node
172
- #
173
- # @return [undefined]
174
- #
175
- # @api private
176
- #
177
141
  def enter(node)
178
142
  case node.type
179
143
  when *RESET_NODES
180
144
  push_reset
181
- when *ASSIGN_NODES
145
+ when ASSIGN_NODES
182
146
  define(node.children.first)
183
147
  when *INHERIT_NODES
184
148
  push_inherit
185
149
  end
186
150
  end
187
151
 
188
- # Pop from local variable state
189
- #
190
- # @param [Parser::AST::Node] node
191
- #
192
- # @return [undefined]
193
- #
194
- # @api private
195
- #
196
152
  def leave(node)
197
153
  pop if CLOSE_NODES.include?(node.type)
198
154
  end
199
155
 
200
- # Define a local variable on current stack
201
- #
202
- # @param [Symbol] name
203
- #
204
- # @return [undefined]
205
- #
206
- # @api private
207
- #
208
156
  def define(name)
209
157
  current << name
210
158
  end
211
159
 
212
- # Push reset scope on stack
213
- #
214
- # @return [undefined]
215
- #
216
- # @api private
217
- #
218
160
  def push_reset
219
161
  @stack << Set.new
220
162
  end
221
163
 
222
- # Push inherited lvar scope on stack
223
- #
224
- # @return [undefined]
225
- #
226
- # @api private
227
- #
228
164
  def push_inherit
229
165
  @stack << current.dup
230
166
  end
231
167
 
232
- # Pop lvar scope from stack
233
- #
234
- # @return [undefined]
235
- #
236
- # @api private
237
- #
238
168
  def pop
239
169
  @stack.pop
240
170
  end
@@ -3,8 +3,6 @@
3
3
  module Unparser
4
4
 
5
5
  # Buffer used to emit into
6
- #
7
- # ignore :reek:TooManyMethods
8
6
  class Buffer
9
7
 
10
8
  NL = "\n".freeze
@@ -82,6 +80,13 @@ module Unparser
82
80
  self
83
81
  end
84
82
 
83
+ def root_indent
84
+ before = @indent
85
+ @indent = 0
86
+ yield
87
+ @indent = before
88
+ end
89
+
85
90
  # Test for a fresh line
86
91
  #
87
92
  # @return [Boolean]
@@ -114,26 +119,24 @@ module Unparser
114
119
  @content[size_before..-1]
115
120
  end
116
121
 
117
- private
118
-
119
- INDENT_SPACE = ' '.freeze
120
-
121
- # Write prefix
122
- #
123
- # @return [String]
122
+ # Write raw fragment to buffer
124
123
  #
125
- # @api private
126
- #
127
- def prefix
128
- write(INDENT_SPACE * @indent)
129
- end
130
-
131
- # Write to content buffer
124
+ # Does not do indentation logic.
132
125
  #
133
126
  # @param [String] fragment
134
127
  #
128
+ # @return [self]
135
129
  def write(fragment)
136
130
  @content << fragment
131
+ self
132
+ end
133
+
134
+ private
135
+
136
+ INDENT_SPACE = ' '.freeze
137
+
138
+ def prefix
139
+ write(INDENT_SPACE * @indent)
137
140
  end
138
141
 
139
142
  end # Buffer