Class: SXP::Generator

Inherits:
Object show all
Defined in:
lib/sxp/generator.rb

Overview

An S-expression generator.

Takes an object and pretty-prints it using reasonable indentation rules

Defined Under Namespace

Classes: Block

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(buffer) ⇒ Generator

Initialize output with a stack of IO buffers

Parameters:



151
152
153
# File 'lib/sxp/generator.rb', line 151

def initialize(buffer)
  @output = buffer
end

Class Method Details

Format S-expressions to STDOUT

Parameters:

Returns:



129
130
131
# File 'lib/sxp/generator.rb', line 129

def self.print(*sxps)
  write($stdout, *sxps)
end

.string(*sxps) ⇒ Object

Format S-expressions to a String

Parameters:

Returns:



117
118
119
120
121
122
# File 'lib/sxp/generator.rb', line 117

def self.string(*sxps)
  require 'stringio' unless defined?(StringIO)
  buf = StringIO.new
  write(buf, *sxps)
  buf.string
end

.write(out, *sxps) ⇒ Object

Write formatted S-expressions to an IO like object

Parameters:

Returns:



139
140
141
142
143
144
145
# File 'lib/sxp/generator.rb', line 139

def self.write(out, *sxps)
  generator = self.new(out)
  sxps.each do |sxp|
    generator.render(sxp)
  end
  generator
end

Instance Method Details

#render(sexp) ⇒ Block

Render an element. For Array, this recursively renders each constituent into blocks. If the agregate length of a block is less than MIN_BLOCK characters, combine each constituent block into a single line.

Rendering does not perform final formatting, but returns a recursive array of blocks which are each ultimattely formattted onto their own line with leading whitespace.

Parameters:

Returns:



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/sxp/generator.rb', line 167

def render(sexp)
  block = Block.new(sexp, 0)
  if block.length > 40
    buffer = block.formatted

    # Attempt to fold symbols and strings onto proceeding line
    output = ""
    prev_length = 0
    buffer.lines.each do |line|
      if (stripped = line.strip)[0,1] != '(' &&
        prev_length + stripped.length + 1 < Block::BLOCK_MIN_LENGTH

        # Append to previous line
        start, match, rem = output.rpartition(/\S/)
        output = start + match + " " + stripped + rem
        prev_length += stripped.length + 1
      else
        # Terminate line and append this line
        output += line
        prev_length = line.length - 1
      end
    end
    @output.write output.gsub(/\)\s+\)/, '))')
  else
    @output.puts(block.to_sxp)
  end
end