class Calyx::Grammar

The main public interface to Calyx. Grammars represent the concept of a template grammar defined by a set of production rules that can be chained and nested from a given starting rule.

Calyx works like a traditional phrase-structured grammar in reverse. Instead of recognising strings based on a union of possible matches, it generates strings by representing the union as a choice and randomly picking one of the options each time the grammar runs.

Public Class Methods

filter(name, &block) click to toggle source

DSL helper method for registering the given block as a string filter.

@param [Symbol] name @yieldparam [String] the input string to be processed by the filter @yieldreturn [String] the processed output string

# File lib/calyx/grammar.rb, line 60
def filter(name, &block)
  warn [
    "NOTE: The fixed `filter` class method is deprecated.",
    "This will be removed in 0.22. Use the API for modifers instead."
  ].join
  registry.filter(name, &block)
end
inherit_registry(child_registry) click to toggle source

Hook for combining the registry of a parent grammar into the child that inherits from it.

@param [Calyx::Registry] child_registry

# File lib/calyx/grammar.rb, line 94
def inherit_registry(child_registry)
  registry.combine(child_registry) unless child_registry.nil?
end
inherited(subclass) click to toggle source

Hook for combining the rules from a parent grammar into the child that inherits from it.

This is automatically called by the Ruby engine.

@param [Class] subclass

# File lib/calyx/grammar.rb, line 104
def inherited(subclass)
  subclass.inherit_registry(registry)
end
load(filename) click to toggle source

Load a grammar instance from the given file.

Accepts a JSON or YAML file path, identified by its extension (`.json` or `.yml`).

@param [String] filename @return [Calyx::Grammar]

# File lib/calyx/grammar.rb, line 28
def load(filename)
  Format.load(filename)
end
mapping(name, pairs) click to toggle source

DSL helper method for registering a paired mapping regex.

@param [Symbol] name @param [Hash<Regex,String>] pairs

# File lib/calyx/grammar.rb, line 47
def mapping(name, pairs)
  warn [
    "NOTE: The fixed `mapping` class method is deprecated.",
    "This still works but will be replaced with a new mapping format."
  ].join
  registry.mapping(name, pairs)
end
method_missing(name, *productions) click to toggle source

Augument the grammar with a method missing hook that treats class method calls as declarations of a new rule.

This must be bypassed by calling `#rule` directly if the name of the desired rule clashes with an existing helper method.

@param [Symbol] name @param [Array] productions

# File lib/calyx/grammar.rb, line 86
def method_missing(name, *productions)
  registry.define_rule(name, caller_locations.first, productions)
end
modifier(module_name) click to toggle source

DSL helper method for registering a modifier module with the grammar.

@param [Module] module_name

# File lib/calyx/grammar.rb, line 35
def modifier(module_name)
  warn [
    "NOTE: Loading modifiers via grammar class methods is deprecated.",
    "Alternative API TBD. For now this method still works."
  ].join
  registry.modifier(module_name)
end
new(options={}, &block) click to toggle source

Create a new grammar instance, passing in a random seed if needed.

Grammar rules can be constructed on the fly when the passed-in block is evaluated.

@param [Numeric, Random, Hash] options

# File lib/calyx/grammar.rb, line 115
def initialize(options={}, &block)
  unless options.is_a?(Hash)
    config_opts = {}
    if options.is_a?(Numeric)
      warn [
        "NOTE: Passing a numeric seed arg directly is deprecated. ",
        "Use the options hash instead: `Calyx::Grammar.new(seed: 1234)`"
      ].join
      config_opts[:seed] = options
    elsif options.is_a?(Random)
      warn [
        "NOTE: Passing a Random object directly is deprecated. ",
        "Use the options hash instead: `Calyx::Grammar.new(rng: Random.new)`"
      ].join
      config_opts[:rng] = options
    end
  else
    config_opts = options
  end

  @options = Options.new(config_opts)

  if block_given?
    @registry = Registry.new
    @registry.instance_eval(&block)
  else
    @registry = self.class.registry
  end

  @registry.options(@options)
end
registry() click to toggle source

Access the registry belonging to this grammar class.

Constructs a new registry if it isn't already available.

@return [Calyx::Registry]

# File lib/calyx/grammar.rb, line 17
def registry
  @registry ||= Registry.new
end
rule(name, *productions) click to toggle source

DSL helper method for registering a new grammar rule.

Not usually used directly, as the method missing API is less verbose.

@param [Symbol] name @param [Array] productions

# File lib/calyx/grammar.rb, line 74
def rule(name, *productions)
  registry.define_rule(name, caller_locations.first, productions)
end

Public Instance Methods

evaluate(*args) click to toggle source

Produces a syntax tree of nested list nodes as an output of the grammar.

@deprecated Please use {#generate_result} instead.

# File lib/calyx/grammar.rb, line 165
    def evaluate(*args)
      warn <<~DEPRECATION
        [DEPRECATION] `evaluate` is deprecated and will be removed in 1.0.
        Please use #generate_result instead.
        See https://github.com/maetl/calyx/issues/23 for more details.
      DEPRECATION

      result = generate_result(*args)
      result.tree
    end
generate(*args) click to toggle source

Produces a string as an output of the grammar.

@overload generate(start_symbol)

@param [Symbol] start_symbol

@overload generate(rules_map)

@param [Hash] rules_map

@overload generate(start_symbol, rules_map)

@param [Symbol] start_symbol
@param [Hash] rules_map

@return [String]

# File lib/calyx/grammar.rb, line 157
def generate(*args)
  result = generate_result(*args)
  result.text
end
generate_result(*args) click to toggle source

Produces a generated result from evaluating the grammar.

@see Calyx::Result @overload generate_result(start_symbol)

@param [Symbol] start_symbol

@overload generate_result(rules_map)

@param [Hash] rules_map

@overload generate_result(start_symbol, rules_map)

@param [Symbol] start_symbol
@param [Hash] rules_map

@return [Calyx::Result]

# File lib/calyx/grammar.rb, line 187
def generate_result(*args)
  start_symbol, rules_map = map_default_args(*args)

  Result.new(@registry.evaluate(start_symbol, rules_map))
end

Private Instance Methods

map_default_args(*args) click to toggle source
# File lib/calyx/grammar.rb, line 195
def map_default_args(*args)
  start_symbol = :start
  rules_map = {}

  args.each do |arg|
    start_symbol = arg if arg.class == Symbol
    rules_map = arg if arg.class == Hash
  end

  [start_symbol, rules_map]
end