Skip to content

Instantly share code, notes, and snippets.

@collin
Created January 3, 2009 21:03
Show Gist options
  • Select an option

  • Save collin/42929 to your computer and use it in GitHub Desktop.

Select an option

Save collin/42929 to your computer and use it in GitHub Desktop.
# Working through some ideas from the subtext language project
# http://www.subtextual.org/
# http://alarmingdevelopment.org/?p=160 <= Subtext Source
require 'rubygems'
require 'extlib'
class Node
attr_accessor :input, :parent, :children, :assertion, :root, :table
def initialize input, assertion
raise "Assertion can only be true/false!" unless [true, false].include? assertion
@input = input
@assertion = assertion
@children = []
end
def unflattened_all_nodes
children + map{|child| child.all_nodes}
end
def all_nodes
unflattened_all_nodes.flatten
end
def all_ids
all_nodes.map{|node| node.id }
end
def id
"#{parent_id}#{self_id}"
end
def self_id
return "/" if root?
"#{input.name}/#{assertion}"
end
def root?
root.object_id == self.object_id
end
def table
return @table if root?
root.table
end
def parent_id
return "" if parent.nil?
"#{parent.id}"
end
def == other
self.id == other.id
end
def empty?
children.empty?
end
def gaps
(instance_gaps + children.map{|child| child.gaps }).flatten.uniq
end
def instance_gaps
NodeSet.new(table.inputs.map { |input|
[Node.new(input.last, true), Node.new(input.last, false)]
}.flatten) - (parent_ids << id)
# []
end
def parent_ids
ids = [parent_id]
ids += parent.parent_ids unless parent.nil?
ids
end
def overlaps
[]
end
def inspect
"#<Node #{id}>"
end
alias to_s inspect
def map &block
children.map &block
end
def append input, assertion
node = Node.new input, assertion
node.parent = self
node.root = self if self.root?
children << node
node
end
end
class Input
attr_accessor :name
def initialize name
@name = name
end
end
class Inputs
def initialize
@inputs = {}
end
def [] name
@inputs[name]
end
def names
@inputs.keys
end
def map &block
@inputs.map &block
end
def << name
raise "Cannot have two inputs with the same name, fool!" if names.include? name
input = Input.new(name)
@inputs[name] = input
input
end
end
class Table
@@input_names = []
attr_accessor :inputs, :root
def initialize
@inputs = Inputs.new
@root = Node.new Input.new(:root), true
@root.root = @root
@root.table = self
end
def inspect
"#<Table #{root.all_ids}>"
end
def append *args
root.append *args
end
def gaps
set = if root.empty?
[]
else
root.gaps
end
GapSet.new set
end
def overlaps
set = if root.empty?
[]
else
root.overlaps
end
OverlapSet.new set
end
def [] *args
inputs.[] *args
end
alias to_s inspect
end
class NodeSet
def initialize nodes
@nodes = nodes
end
def inspect
"#<#{self.class.name} [#{@nodes.map{|node| node.inspect }.join(', ')}]>"
end
def + nodeset
@nodes += nodeset.instance_variable_get :@nodes
end
def - nodes
@nodes = @nodes.reject do |node|
nodes.include? node.id
end
end
alias to_s inspect
end
class GapSet < NodeSet
end
class OverlapSet < NodeSet
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment