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


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

def initialize(buffer)
  @output = buffer
end

Class Method Details

Format S-expressions to STDOUT


106
107
108
# File 'lib/sxp/generator.rb', line 106

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

.string(*sxps) ⇒ Object

Format S-expressions to a String


94
95
96
97
98
99
# File 'lib/sxp/generator.rb', line 94

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


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

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.


144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/sxp/generator.rb', line 144

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