class Soroban::Sheet

A container for cells.

Attributes

bindings[R]

Public Class Methods

new() click to toggle source

Creates a new sheet.

# File lib/soroban/sheet.rb, line 13
def initialize
  @cells = {}
  @bindings = {}
end

Public Instance Methods

bind(name, label) click to toggle source

Bind one or more named variables to a cell.

# File lib/soroban/sheet.rb, line 55
def bind(name, label)
  unless @cells.keys.include?(label.to_sym)
    raise Soroban::UndefinedError, "Cannot bind '#{name}' to non-existent cell '#{label}'"
  end
  _bind(name, label)
end
cells() click to toggle source

Return a hash of `label => contents` for each cell in the sheet.

# File lib/soroban/sheet.rb, line 68
def cells
  Hash[@cells.keys.map { |label| label.to_s }.zip( @cells.keys.map { |label| eval("@#{label}.excel") } )]
end
get(label_or_name) click to toggle source

Retrieve the contents of a cell.

# File lib/soroban/sheet.rb, line 50
def get(label_or_name)
  _get(label_or_name, eval("@#{label_or_name}", binding))
end
method_missing(method, *args, &block) click to toggle source

Used for calling dynamically defined functions, and for creating new cells (via `label=`).

Calls superclass method
# File lib/soroban/sheet.rb, line 20
def method_missing(method, *args, &block)
  if match = /^func_(.*)$/i.match(method.to_s)
    return Soroban::call(self, match[1], *args)
  elsif match = /^([a-z][\w]*)=$/i.match(method.to_s)
    return _add(match[1], args[0])
  end
  super
end
missing() click to toggle source

Return a list of referenced but undefined cells.

# File lib/soroban/sheet.rb, line 73
def missing
  @cells.values.map.flatten.uniq - @cells.keys
end
set(label_or_range, contents) click to toggle source

Set the contents of one or more cells or ranges.

# File lib/soroban/sheet.rb, line 30
def set(label_or_range, contents)
  unless range = Soroban::getRange(label_or_range)
    return _add(label_or_range, contents)
  end
  fc, fr, tc, tr = range
  if fc == tc || fr == tr
    raise ArgumentError, "Expecting an array when setting #{label_or_range}" unless contents.kind_of? Array
    cc, cr = fc, fr
    contents.each do |item|
      set("#{cc}#{cr}", item)
      cc.next! if fr == tr
      cr.next! if fc == tc
    end
    raise Soroban::RangeError, "Supplied array doesn't match range length" if cc != tc && cr != tr
  else
    raise ArgumentError, "Can only set cells or 1-dimensional ranges of cells"
  end
end
walk(range) click to toggle source

Visit each cell in the supplied range, yielding its value.

# File lib/soroban/sheet.rb, line 63
def walk(range)
  Walker.new(range, binding)
end

Private Instance Methods

_add(label, contents) click to toggle source
# File lib/soroban/sheet.rb, line 79
def _add(label, contents)
  internal = "@#{label}"
  _expose(internal, label)
  cell = Cell.new(binding)
  _set(label, cell, contents)
  instance_variable_set(internal, cell)
end
_bind(name, label) click to toggle source
# File lib/soroban/sheet.rb, line 100
def _bind(name, label)
  @bindings[name.to_sym] = label.to_sym
  internal = "@#{label}"
  _expose(internal, name)
end
_expose(internal, name) click to toggle source
# File lib/soroban/sheet.rb, line 106
    def _expose(internal, name)
      instance_eval <<-EOV, __FILE__, __LINE__ + 1
        def #{name}
          _get("#{name}", #{internal})
        end
        def #{name}=(contents)
          _set("#{name}", #{internal}, contents)
        end
      EOV
    end
_get(label_or_name, cell) click to toggle source
# File lib/soroban/sheet.rb, line 92
def _get(label_or_name, cell)
  label = label_or_name.to_sym
  name = @cells[label] ? label : @bindings[label]
  badref = @cells[name] & missing
  raise Soroban::UndefinedError, "Unmet dependencies #{badref.join(', ')} for #{label}" if badref.length > 0
  cell.get
end
_set(label, cell, contents) click to toggle source
# File lib/soroban/sheet.rb, line 87
def _set(label, cell, contents)
  cell.set(contents)
  @cells[label.to_sym] = cell.dependencies
end