Skip to content

Commit

Permalink
Introduce value object which encapsulates a generated result
Browse files Browse the repository at this point in the history
As described in #23, this introduces a result object which wraps the
expression tree returned from evaluating a grammar and provides access
to the result as a raw tree, flattened string or symbol.

The generated result object is returned from a new
`Calyx::Grammar#generate_result` method. `Calyx::Grammar#generate` still
returns a string and `Calyx::Grammar#evaluate` now fires a deprecation
warning and will be removed soon.
  • Loading branch information
maetl committed Sep 21, 2017
1 parent 0bec38a commit 5943806
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 9 deletions.
2 changes: 2 additions & 0 deletions lib/calyx.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
require 'rubygems/deprecate'
require 'calyx/version'
require 'calyx/options'
require 'calyx/rule'
require 'calyx/result'
require 'calyx/grammar'
require 'calyx/errors'
require 'calyx/format'
Expand Down
28 changes: 20 additions & 8 deletions lib/calyx/grammar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -138,23 +138,35 @@ def initialize(opts={}, &block)
# @param [Hash] rules_map
# @return [String]
def generate(*args)
start_symbol, rules_map = map_default_args(*args)

@registry.evaluate(start_symbol, rules_map).flatten.reject do |obj|
obj.is_a?(Symbol)
end.join
result = generate_result(*args)
result.text
end

# Produces a syntax tree of nested list nodes as an output of the grammar.
#
# @deprecated Please use {#generate_result} instead.
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

# Produces a generated result from evaluating the grammar.
#
# @see Calyx::Result
# @overload
# @param [Symbol] start_symbol
# @param [Hash] rules_map
# @return [Array]
def evaluate(*args)
# @return [Calyx::Result]
def generate_result(*args)
start_symbol, rules_map = map_default_args(*args)

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

private
Expand Down
38 changes: 38 additions & 0 deletions lib/calyx/result.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module Calyx
# Value object representing a generated grammar result.
class Result
def initialize(expression)
@expression = expression.freeze
end

# The syntax tree of nested nodes representing the production rules which
# generated this result.
#
# @return [Array]
def tree
@expression
end

alias_method :to_exp, :tree

# The generated text string produced by the grammar.
#
# @return [String]
def text
@expression.flatten.reject do |obj|
obj.is_a?(Symbol)
end.join
end

alias_method :to_s, :text

# A symbol produced by converting the generated text string where possible.
#
# @return [Symbol]
def symbol
text.to_sym
end

alias_method :to_sym, :symbol
end
end
2 changes: 1 addition & 1 deletion spec/grammar/context_hash_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class StockReport < Calyx::Grammar
priority '(A)'
end

expect { grammar.evaluate(priority: '(B)') }.to raise_error(Calyx::Errors::DuplicateRule)
expect { grammar.generate(priority: '(B)') }.to raise_error(Calyx::Errors::DuplicateRule)
end
end
end
50 changes: 50 additions & 0 deletions spec/result_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
require 'spec_helper'

describe Calyx::Result do
describe '#tree' do
specify 'wraps expression tree' do
tree = Calyx::Result.new([:root, [:leaf, 'atom']]).tree
expect(tree).to eq([:root, [:leaf, 'atom']])
end

specify 'expression tree is immutable' do
tree = Calyx::Result.new([:root, [:leaf, 'atom']]).tree
expect { tree << [:leaf, 'atom'] }.to raise_error(RuntimeError)
end

specify '#to_exp aliases #tree' do
result = Calyx::Result.new([:root, [:leaf, 'atom']])
expect(result.to_exp).to eq(result.tree)
end
end

describe '#text' do
specify 'flattens expression tree to string' do
expr = [:root, [:branch, [:leaf, 'one'], [:leaf, ' '], [:leaf, 'two']]]
text = Calyx::Result.new(expr).text
expect(text).to eq('one two')
end

specify '#to_s aliases #text' do
result = Calyx::Result.new([:root, [:leaf, 'atom']])
expect(result.to_s).to eq(result.text)
end

specify '#to_s interpolates automatically' do
result = Calyx::Result.new([:root, [:leaf, 'atom']])
expect("#{result}").to eq(result.text)
end
end

describe '#symbol' do
specify 'flattens expression tree to symbol' do
symbol = Calyx::Result.new([:root, [:leaf, 'atom']]).symbol
expect(symbol).to eq(:atom)
end

specify '#to_sym aliases #symbol' do
result = Calyx::Result.new([:root, [:leaf, 'atom']])
expect(result.to_sym).to eq(result.symbol)
end
end
end

0 comments on commit 5943806

Please sign in to comment.