module Tracery

Constants

VERSION

Public Class Methods

random() click to toggle source
# File lib/tracery.rb, line 21
def self.random
    return @@rnd_proc.call 
end
resetRnd() click to toggle source
# File lib/tracery.rb, line 17
def self.resetRnd
    setRnd(lambda { @@internal_rnd.rand })
end
setRnd(lambdaproc) click to toggle source
# File lib/tracery.rb, line 13
def self.setRnd(lambdaproc) 
    @@rnd_proc = lambdaproc
end

Public Instance Methods

createGrammar(raw) click to toggle source

Parses a plaintext rule in the tracery syntax

# File lib/tracery.rb, line 6
def createGrammar(raw)
    return Grammar.new(raw)
end
createSection(start, finish, type, results, lastEscapedChar, escapedSubstring, rule, errors) click to toggle source

TODO_: needs heavy refactoring – no nesting in ruby (ie. move entire parser to another class w/ shared state)

# File lib/tracery.rb, line 60
def createSection(start, finish, type, results, lastEscapedChar, escapedSubstring, rule, errors)
    if(finish - start < 1) then
        if(type == 1) then
            errors << "#{start}: empty tag"
        else
            if(type == 2) then
                errors << "#{start}: empty action"
            end
        end
    end
    rawSubstring = ""
    if(!lastEscapedChar.nil?) then
        rawSubstring = escapedSubstring + "\\" + rule[(lastEscapedChar+1)...finish]
    else
        rawSubstring = rule[start...finish]
    end
    
    results[:sections] << {
            type: type,
            raw: rawSubstring
        }
end
parse(rule) click to toggle source
# File lib/tracery.rb, line 83
def parse(rule)
    depth = 0
    inTag = false
    results = {errors: [], sections: []}
    escaped = false
    
    errors = []
    start = 0
    
    escapedSubstring = ""
    lastEscapedChar = nil

    if(rule.nil?) then
        sections = {errors: errors, sections: []}
        return sections
    end
    
    rule.each_char.with_index do |c, i|
        if(!escaped) then
            case(c)
                when '[' then
                    # Enter a deeper bracketed section
                    if(depth == 0 && !inTag) then
                        if(start < i) then
                            createSection(start, i, 0, results, lastEscapedChar, escapedSubstring, rule, errors)
                            lastEscapedChar = nil
                            escapedSubstring = ""
                        end
                        start = i + 1
                    end
                    depth += 1
                when ']' then
                    depth -= 1
                    # End a bracketed section
                    if(depth == 0 && !inTag) then
                        createSection(start, i, 2, results, lastEscapedChar, escapedSubstring, rule, errors)
                        lastEscapedChar = nil
                        escapedSubstring = ""
                        start = i + 1
                    end
                when '#' then
                    # Hashtag
                    #   ignore if not at depth 0, that means we are in a bracket
                    if(depth == 0) then
                        if(inTag) then
                            createSection(start, i, 1, results, lastEscapedChar, escapedSubstring, rule, errors)
                            lastEscapedChar = nil
                            escapedSubstring = ""
                            start = i + 1
                        else
                            if(start < i) then
                                createSection(start, i, 0, results, lastEscapedChar, escapedSubstring, rule, errors)
                                lastEscapedChar = nil
                                escapedSubstring = ""
                            end
                            start = i + 1
                        end
                        inTag = !inTag
                    end
                when '\\' then
                    escaped = true;
                    escapedSubstring = escapedSubstring + rule[start...i];
                    start = i + 1;
                    lastEscapedChar = i;
            end
        else
            escaped = false
        end
    end #each character in rule
    
    if(start < rule.length) then
        createSection(start, rule.length, 0, results, lastEscapedChar, escapedSubstring, rule, errors)
        lastEscapedChar = nil
        escapedSubstring = ""
    end
    
    errors << ("Unclosed tag") if inTag
    errors << ("Too many [") if depth > 0
    errors << ("Too many ]") if depth < 0

    # Strip out empty plaintext sections
    results[:sections].select! {|section| 
        if(section[:type] == 0 && section[:raw].empty?) then
            false
        else
            true
        end
    }
    results[:errors] = errors;
    return results
end
parseTag(tagContents) click to toggle source
# File lib/tracery.rb, line 25
def parseTag(tagContents)
    parsed = {
            symbol: nil,
            preactions: [],
            postactions: [],
            modifiers: []
        }
    
    sections = parse(tagContents)[:sections]
    symbolSection = nil;
    sections.each do |section|
        if(section[:type] == 0) then
            if(symbolSection.nil?) then
                symbolSection = section[:raw]
            else
                raise "multiple main sections in #{tagContents}"
            end
        else
            parsed[:preactions].push(section)
        end
    end
    
    if(symbolSection.nil?) then
        # raise "no main section in #{tagContents}"
    else
        
        components = symbolSection.split(".");
        parsed[:symbol] = components.first
        parsed[:modifiers] = components.drop(1)
    end

    return parsed
end