Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'release/0.5.1'

  • Loading branch information...
commit 7f6097e5e0e64c07062a34305ecbf2526c1e6023 2 parents 798638c + bd9a767
@benlangfeld authored
View
5 CHANGELOG.md
@@ -1,5 +1,10 @@
# develop
+# 0.5.1 - 2012-01-09
+ * Feature: Chaining child injection using #<< now works
+ * Feature: Reading the repeat value for a GRXML Item now returns an Integer or a Range, rather than the plain string
+ * Feature: Most simple GRXML grammars now return PotentialMatch when the provided input is valid but incomplete. This does not work for complex grammars including repeats and deep nesting. Fixes for these coming soon.
+
# 0.5.0 - 2012-01-03
* Feature: Add a whole bunch more SSML elements:
** p & s
View
1  lib/ruby_speech.rb
@@ -2,6 +2,7 @@
active_support/dependencies/autoload
active_support/core_ext/object/blank
active_support/core_ext/numeric/time
+ active_support/core_ext/enumerable
niceogiri
}.each { |f| require f }
View
1  lib/ruby_speech/generic_element.rb
@@ -164,6 +164,7 @@ def string(other)
def <<(other)
other = encode_special_chars other if other.is_a? String
super other
+ self
end
def method_missing(method_name, *args, &block)
View
1  lib/ruby_speech/grxml.rb
@@ -15,6 +15,7 @@ module GRXML
autoload :Match
autoload :NoMatch
+ autoload :PotentialMatch
InvalidChildError = Class.new StandardError
View
17 lib/ruby_speech/grxml/element.rb
@@ -22,6 +22,23 @@ def self.module
def regexp_content # :nodoc:
children.map(&:regexp_content).join
end
+
+ def potential_match?(other)
+ false
+ end
+
+ def max_input_length
+ 0
+ end
+
+ def longest_potential_match(input)
+ input.dup.tap do |longest_input|
+ begin
+ return longest_input if potential_match? longest_input
+ longest_input.chop!
+ end until longest_input.length.zero?
+ end
+ end
end # Element
end # GRXML
end # RubySpeech
View
24 lib/ruby_speech/grxml/grammar.rb
@@ -195,15 +195,19 @@ def normalize_whitespace
# @interpretation = "1234#"
# >
# >> subject.match '111'
- # => #<RubySpeech::GRXML::NoMatch:0x00000101371660>
+ # => #<RubySpeech::GRXML::PotentialMatch:0x00000101371660>
+ #
+ # >> subject.match '11111'
+ # => #<RubySpeech::GRXML::NoMatch:0x00000101371936>
#
# ```
#
def match(other)
+ other = other.dup
regex = to_regexp
- return NoMatch.new if regex == //
+ return check_for_potential_match(other) if regex == //
match = regex.match other
- return NoMatch.new unless match
+ return check_for_potential_match(other) unless match
Match.new :mode => mode,
:confidence => dtmf? ? 1 : 0,
@@ -211,6 +215,20 @@ def match(other)
:interpretation => interpret_utterance(other)
end
+ def check_for_potential_match(other)
+ potential_match?(other) ? PotentialMatch.new : NoMatch.new
+ end
+
+ def potential_match?(other)
+ root_rule.children.each do |token|
+ return true if other.length.zero?
+ longest_potential_match = token.longest_potential_match other
+ return false if longest_potential_match.length.zero?
+ other.gsub! /^#{Regexp.escape longest_potential_match}/, ''
+ end
+ other.length.zero?
+ end
+
##
# Converts the grammar into a regular expression for matching
#
View
43 lib/ruby_speech/grxml/item.rb
@@ -26,6 +26,7 @@ module GRXML
# xml:lang declares declaration declares the language of the grammar section for the item element just as xml:lang in the <grammar> element declares for the entire document
#
class Item < Element
+ Inf = 1.0 / 0.0
register :item
@@ -61,7 +62,14 @@ def weight=(w)
# @return [String]
#
def repeat
- read_attr :repeat
+ repeat = read_attr :repeat
+ return nil unless repeat
+ if repeat.include?('-')
+ min, max = repeat.split('-').map &:to_i
+ (min || 0)..(max || Inf)
+ else
+ repeat.to_i
+ end
end
##
@@ -72,7 +80,7 @@ def repeat
# @param [String] r
#
def repeat=(r)
- r = "#{r.min}-#{r.max}" if r.is_a?(Range)
+ r = "#{r.min}-#{r.max unless r.max == Inf}" if r.is_a?(Range)
r = r.to_s
error = ArgumentError.new "A Item's repeat must be 0 or a positive integer"
@@ -122,13 +130,34 @@ def eql?(o)
end
def regexp_content # :nodoc:
- return super unless repeat
+ case repeat
+ when Range
+ "#{super}{#{repeat.min},#{repeat.max unless repeat.max == Inf}}"
+ when Integer
+ "#{super}{#{repeat}}"
+ else
+ super
+ end
+ end
- if repeat.include?('-')
- min, max = repeat.split '-'
- "#{super}{#{min},#{max}}"
+ def potential_match?(other)
+ tokens = children
+ return false if other.length > max_input_length
+ other.chars.each_with_index do |digit, index|
+ index -= tokens.size until index < tokens.size if repeat
+ return false unless tokens[index].potential_match?(digit)
+ end
+ true
+ end
+
+ def max_input_length # :nodoc:
+ case repeat
+ when Range
+ children.size * repeat.max
+ when Integer
+ children.size * repeat
else
- "#{super}{#{repeat}}"
+ children.size
end
end
end # Item
View
4 lib/ruby_speech/grxml/one_of.rb
@@ -26,6 +26,10 @@ def <<(arg)
def regexp_content # :nodoc:
"(#{children.map(&:regexp_content).join '|'})"
end
+
+ def potential_match?(input)
+ children.any? { |c| c.potential_match? input }
+ end
end # OneOf
end # GRXML
end # RubySpeech
View
10 lib/ruby_speech/grxml/potential_match.rb
@@ -0,0 +1,10 @@
+module RubySpeech
+ module GRXML
+ class PotentialMatch
+ def eql?(o)
+ o.is_a? self.class
+ end
+ alias :== :eql?
+ end
+ end
+end
View
4 lib/ruby_speech/grxml/token.rb
@@ -26,6 +26,10 @@ def normalize_whitespace
def regexp_content # :nodoc:
Regexp.escape content
end
+
+ def potential_match?(other)
+ other == content
+ end
end # Token
end # GRXML
end # RubySpeech
View
2  lib/ruby_speech/version.rb
@@ -1,3 +1,3 @@
module RubySpeech
- VERSION = "0.5.0"
+ VERSION = "0.5.1"
end
View
234 spec/ruby_speech/grxml/grammar_spec.rb
@@ -360,11 +360,13 @@ def single_rule_grammar(content = [])
end
it "should match '6'" do
+ input = '6'
expected_match = GRXML::Match.new :mode => :dtmf,
:confidence => 1,
:utterance => '6',
:interpretation => 'dtmf-6'
- subject.match('6').should == expected_match
+ subject.match(input).should == expected_match
+ input.should == '6'
end
%w{1 2 3 4 5 7 8 9 10 66 26 61}.each do |input|
@@ -391,7 +393,13 @@ def single_rule_grammar(content = [])
subject.match('56').should == expected_match
end
- %w{* *7 #6 6* 1 2 3 4 5 6 7 8 9 10 65 57 46 26 61}.each do |input|
+ it "should potentially match '5'" do
+ input = '5'
+ subject.match(input).should == GRXML::PotentialMatch.new
+ input.should == '5'
+ end
+
+ %w{* *7 #6 6* 1 2 3 4 6 7 8 9 10 65 57 46 26 61}.each do |input|
it "should not match '#{input}'" do
subject.match(input).should == GRXML::NoMatch.new
end
@@ -415,7 +423,11 @@ def single_rule_grammar(content = [])
subject.match('*6').should == expected_match
end
- %w{* *7 #6 6* 1 2 3 4 5 6 7 8 9 10 66 26 61}.each do |input|
+ it "should potentially match '*'" do
+ subject.match('*').should == GRXML::PotentialMatch.new
+ end
+
+ %w{*7 #6 6* 1 2 3 4 5 6 7 8 9 10 66 26 61}.each do |input|
it "should not match '#{input}'" do
subject.match(input).should == GRXML::NoMatch.new
end
@@ -439,6 +451,10 @@ def single_rule_grammar(content = [])
subject.match('#6').should == expected_match
end
+ it "should potentially match '#'" do
+ subject.match('#').should == GRXML::PotentialMatch.new
+ end
+
%w{* *6 #7 6* 1 2 3 4 5 6 7 8 9 10 66 26 61}.each do |input|
it "should not match '#{input}'" do
subject.match(input).should == GRXML::NoMatch.new
@@ -468,7 +484,142 @@ def single_rule_grammar(content = [])
subject.match('*6').should == expected_match
end
- %w{* *7 #6 6* 1 2 3 4 5 6 7 8 9 10 66 26 61}.each do |input|
+ it "should potentially match '*'" do
+ subject.match('*').should == GRXML::PotentialMatch.new
+ end
+
+ %w{*7 #6 6* 1 2 3 4 5 6 7 8 9 10 66 26 61}.each do |input|
+ it "should not match '#{input}'" do
+ subject.match(input).should == GRXML::NoMatch.new
+ end
+ end
+ end
+
+ context "with a grammar that takes a single digit alternative" do
+ subject do
+ GRXML.draw :mode => :dtmf, :root => 'digits' do
+ rule :id => 'digits' do
+ one_of do
+ item { '6' }
+ item { '7' }
+ end
+ end
+ end
+ end
+
+ it "should match '6'" do
+ expected_match = GRXML::Match.new :mode => :dtmf,
+ :confidence => 1,
+ :utterance => '6',
+ :interpretation => 'dtmf-6'
+ subject.match('6').should == expected_match
+ end
+
+ it "should match '7'" do
+ expected_match = GRXML::Match.new :mode => :dtmf,
+ :confidence => 1,
+ :utterance => '7',
+ :interpretation => 'dtmf-7'
+ subject.match('7').should == expected_match
+ end
+
+ %w{* # 1 2 3 4 5 8 9 10 66 26 61}.each do |input|
+ it "should not match '#{input}'" do
+ subject.match(input).should == GRXML::NoMatch.new
+ end
+ end
+ end
+
+ context "with a grammar that takes a double digit alternative" do
+ subject do
+ GRXML.draw :mode => :dtmf, :root => 'digits' do
+ rule :id => 'digits' do
+ one_of do
+ item do
+ token { '6' }
+ token { '5' }
+ end
+ item do
+ token { '7' }
+ token { '2' }
+ end
+ end
+ end
+ end
+ end
+
+ it "should match '65'" do
+ expected_match = GRXML::Match.new :mode => :dtmf,
+ :confidence => 1,
+ :utterance => '65',
+ :interpretation => 'dtmf-6 dtmf-5'
+ subject.match('65').should == expected_match
+ end
+
+ it "should match '72'" do
+ expected_match = GRXML::Match.new :mode => :dtmf,
+ :confidence => 1,
+ :utterance => '72',
+ :interpretation => 'dtmf-7 dtmf-2'
+ subject.match('72').should == expected_match
+ end
+
+ %w{6 7}.each do |input|
+ it "should potentially match '#{input}'" do
+ subject.match(input).should == GRXML::PotentialMatch.new
+ end
+ end
+
+ %w{* # 1 2 3 4 5 8 9 10 66 26 61 75}.each do |input|
+ it "should not match '#{input}'" do
+ subject.match(input).should == GRXML::NoMatch.new
+ end
+ end
+ end
+
+ context "with a grammar that takes a triple digit alternative" do
+ subject do
+ GRXML.draw :mode => :dtmf, :root => 'digits' do
+ rule :id => 'digits' do
+ one_of do
+ item do
+ token { '6' }
+ token { '5' }
+ token { '2' }
+ end
+ item do
+ token { '7' }
+ token { '2' }
+ token { '8' }
+ end
+ end
+ end
+ end
+ end
+
+ it "should match '652'" do
+ expected_match = GRXML::Match.new :mode => :dtmf,
+ :confidence => 1,
+ :utterance => '652',
+ :interpretation => 'dtmf-6 dtmf-5 dtmf-2'
+ subject.match('652').should == expected_match
+ end
+
+ it "should match '728'" do
+ expected_match = GRXML::Match.new :mode => :dtmf,
+ :confidence => 1,
+ :utterance => '728',
+ :interpretation => 'dtmf-7 dtmf-2 dtmf-8'
+ subject.match('728').should == expected_match
+ end
+
+ %w{6 65 7 72}.each do |input|
+ it "should potentially match '#{input}'" do
+ subject.match(input).should == GRXML::PotentialMatch.new
+ end
+ end
+
+ %w{* # 1 2 3 4 5 8 9 10 66 26 61 75 729 654}.each do |input|
it "should not match '#{input}'" do
subject.match(input).should == GRXML::NoMatch.new
end
@@ -504,7 +655,55 @@ def single_rule_grammar(content = [])
subject.match('*7').should == expected_match
end
- %w{* *8 #6 6* 1 2 3 4 5 6 7 8 9 10 66 26 61}.each do |input|
+ it "should potentially match '*'" do
+ subject.match('*').should == GRXML::PotentialMatch.new
+ end
+
+ %w{*8 #6 6* 1 2 3 4 5 6 7 8 9 10 66 26 61}.each do |input|
+ it "should not match '#{input}'" do
+ subject.match(input).should == GRXML::NoMatch.new
+ end
+ end
+ end
+
+ context "with a grammar that takes two specific digits with the first being an alternative" do
+ subject do
+ GRXML.draw :mode => :dtmf, :root => 'digits' do
+ rule :id => 'digits' do
+ one_of do
+ item { '6' }
+ item { '7' }
+ end
+ string '*'
+ end
+ end
+ end
+
+ it "should match '6*'" do
+ expected_match = GRXML::Match.new :mode => :dtmf,
+ :confidence => 1,
+ :utterance => '6*',
+ :interpretation => 'dtmf-6 dtmf-star'
+ subject.match('6*').should == expected_match
+ end
+
+ it "should match '7*'" do
+ expected_match = GRXML::Match.new :mode => :dtmf,
+ :confidence => 1,
+ :utterance => '7*',
+ :interpretation => 'dtmf-7 dtmf-star'
+ subject.match('7*').should == expected_match
+ end
+
+ it "should potentially match '6'" do
+ subject.match('6').should == GRXML::PotentialMatch.new
+ end
+
+ it "should potentially match '7'" do
+ subject.match('7').should == GRXML::PotentialMatch.new
+ end
+
+ %w{8* 6# *6 *7 1 2 3 4 5 8 9 10 66 26 61}.each do |input|
it "should not match '#{input}'" do
subject.match(input).should == GRXML::NoMatch.new
end
@@ -531,7 +730,13 @@ def single_rule_grammar(content = [])
subject.match('166').should == expected_match
end
- %w{1 16 1666 16666 17}.each do |input|
+ %w{1 16}.each do |input|
+ it "should potentially match '#{input}'" do
+ subject.match(input).should == GRXML::PotentialMatch.new
+ end
+ end
+
+ %w{1666 16666 17}.each do |input|
it "should not match '#{input}'" do
subject.match(input).should == GRXML::NoMatch.new
end
@@ -598,7 +803,13 @@ def single_rule_grammar(content = [])
end
end
- %w{1 16 17}.each do |input|
+ %w{1 16}.each do |input|
+ it "should potentially match '#{input}'" do
+ subject.match(input).should == GRXML::PotentialMatch.new
+ end
+ end
+
+ %w{7 17}.each do |input|
it "should not match '#{input}'" do
subject.match(input).should == GRXML::NoMatch.new
end
@@ -645,7 +856,14 @@ def single_rule_grammar(content = [])
end
end
- %w{111}.each do |input|
+ %w{* 1 12 123 1234}.each do |input|
+ it "should potentially match '#{input}'" do
+ pending
+ subject.match(input).should == GRXML::PotentialMatch.new
+ end
+ end
+
+ %w{11111 #1111 *7}.each do |input|
it "should not match '#{input}'" do
subject.match(input).should == GRXML::NoMatch.new
end
View
440 spec/ruby_speech/grxml/item_spec.rb
@@ -8,7 +8,7 @@ module GRXML
its(:name) { should == 'item' }
its(:weight) { should == 1.1 }
- its(:repeat) { should == '1' }
+ its(:repeat) { should == 1 }
it 'registers itself' do
Element.class_from_registration(:item).should == Item
@@ -22,7 +22,7 @@ module GRXML
it { should be_instance_of Item }
its(:weight) { should == 1.1 }
- its(:repeat) { should == '1' }
+ its(:repeat) { should == 1 }
its(:content) { should == 'one' }
end
@@ -69,10 +69,19 @@ module GRXML
# Validate various values for repeat -- http://www.w3.org/TR/speech-grammar/#S2.5
describe "#repeat" do
context "exact" do
- it "valid values (0 or a positive integer)" do
- lambda { subject.repeat = 0 }.should_not raise_error
- lambda { subject.repeat = 5 }.should_not raise_error
- lambda { subject.repeat = '1' }.should_not raise_error
+ context "0" do
+ before { subject.repeat = 0 }
+ its(:repeat) { should == 0 }
+ end
+
+ context "5" do
+ before { subject.repeat = 5 }
+ its(:repeat) { should == 5 }
+ end
+
+ context "'1'" do
+ before { subject.repeat = '1' }
+ its(:repeat) { should == 1 }
end
it "invalid values" do
@@ -82,10 +91,21 @@ module GRXML
end
context "ranges" do
- it "valid ranges from m to n" do
- lambda { subject.repeat = '1-5' }.should_not raise_error
- lambda { subject.repeat = '0-5' }.should_not raise_error
- lambda { subject.repeat = 0..5 }.should_not raise_error
+ context "valid ranges from m to n" do
+ context "'1-5'" do
+ before { subject.repeat = '1-5' }
+ its(:repeat) { should == (1..5) }
+ end
+
+ context "'0-5'" do
+ before { subject.repeat = '0-5' }
+ its(:repeat) { should == (0..5) }
+ end
+
+ context "0..5" do
+ before { subject.repeat = 0..5 }
+ its(:repeat) { should == (0..5) }
+ end
end
it "illegal ranges from m to n" do
@@ -97,9 +117,18 @@ module GRXML
lambda { subject.repeat = 1..-2 }.should raise_error(ArgumentError, "A Item's repeat must be 0 or a positive integer")
end
- it "valid ranges of m or more" do
- lambda { subject.repeat = '3-' }.should_not raise_error
- lambda { subject.repeat = '0-' }.should_not raise_error
+ context "valid ranges of m or more" do
+ context "'3-'" do
+ before { subject.repeat = '3-' }
+ its(:repeat) { should == (3..Item::Inf) }
+ its(:repeat) { should include 10000 }
+ end
+
+ context "'0-'" do
+ before { subject.repeat = '0-' }
+ its(:repeat) { should == (0..Item::Inf) }
+ its(:repeat) { should include 10000 }
+ end
end
it "illegal ranges for m or more" do
@@ -158,6 +187,391 @@ module GRXML
lambda { subject << Token.new }.should_not raise_error
end
end
+
+ describe "#potential_match?" do
+ subject { Item.new }
+
+ before do
+ tokens.each { |token| subject << token }
+ subject.repeat = repeat if repeat
+ end
+
+ context "with a single token of '6'" do
+ let(:tokens) { [Token.new << '6'] }
+
+ context "with no repeat" do
+ let(:repeat) { nil }
+
+ it "should be true for '6'" do
+ subject.potential_match?('6').should be true
+ end
+
+ %w{5 55 65 66}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+
+ context "with an absolute repeat of 3" do
+ let(:repeat) { 3 }
+
+ %w{6 66 666}.each do |input|
+ it "should be true for '#{input}'" do
+ subject.potential_match?(input).should be true
+ end
+ end
+
+ %w{5 55 65 6666}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+
+ context "with a range repeat of 0..2" do
+ let(:repeat) { 0..2 }
+
+ it "should be true for ''" do
+ subject.potential_match?('').should be true
+ end
+
+ %w{6 66}.each do |input|
+ it "should be true for '#{input}'" do
+ subject.potential_match?(input).should be true
+ end
+ end
+
+ %w{5 55 65 666}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+
+ context "with a minimum repeat of 2" do
+ let(:repeat) { 2..Item::Inf }
+
+ %w{6 66 666 6666 66666}.each do |input|
+ it "should be true for '#{input}'" do
+ subject.potential_match?(input).should be true
+ end
+ end
+
+ %w{5 55 65}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+ end
+
+ context "with a collection of two tokens of '6' and '7'" do
+ let(:tokens) { [Token.new << '6', Token.new << '7'] }
+
+ context "with no repeat" do
+ let(:repeat) { nil }
+
+ %w{6 67}.each do |input|
+ it "should be true for '#{input}'" do
+ subject.potential_match?(input).should be true
+ end
+ end
+
+ %w{5 55 65 66 676}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+
+ context "with an absolute repeat of 3" do
+ let(:repeat) { 3 }
+
+ %w{6 67 676 6767 67676 676767}.each do |input|
+ it "should be true for '#{input}'" do
+ subject.potential_match?(input).should be true
+ end
+ end
+
+ %w{5 57 66 677 5767 67677 676766 6767676}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+
+ context "with a range repeat of 0..2" do
+ let(:repeat) { 0..2 }
+
+ it "should be true for ''" do
+ subject.potential_match?('').should be true
+ end
+
+ %w{6 67 676 6767}.each do |input|
+ it "should be true for '#{input}'" do
+ subject.potential_match?(input).should be true
+ end
+ end
+
+ %w{5 57 66 677 5767 67676 67677 676766 6767676}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+
+ context "with a minimum repeat of 2" do
+ let(:repeat) { 2..Item::Inf }
+
+ %w{6 67 676 6767 67676 676767 67676767}.each do |input|
+ it "should be true for '#{input}'" do
+ subject.potential_match?(input).should be true
+ end
+ end
+
+ %w{5 57 66 677 5767 67677 676766}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+ end
+
+ context "with a nested item" do
+ let(:repeat) { nil }
+ let(:tokens) { [Item.new << (Token.new << '6') << (Token.new << '6')] }
+
+ before do
+ tokens.each { |token| token.repeat = nested_repeat if nested_repeat }
+ end
+
+ context "with no repeat" do
+ before { pending }
+ let(:nested_repeat) { nil }
+
+ %w{6 66}.each do |input|
+ it "should be true for '#{input}'" do
+ subject.potential_match?(input).should be true
+ end
+ end
+
+ %w{5 55 65 666}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+
+ context "with an absolute repeat of 3" do
+ before { pending }
+ let(:nested_repeat) { 3 }
+
+ %w{6 66 666}.each do |input|
+ it "should be true for '#{input}'" do
+ subject.potential_match?(input).should be true
+ end
+ end
+
+ %w{5 55 6666}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+
+ context "with a range repeat of 0..2" do
+ before { pending }
+ let(:nested_repeat) { 0..2 }
+
+ it "should be true for ''" do
+ subject.potential_match?('').should be true
+ end
+
+ %w{6 67 676 6767}.each do |input|
+ it "should be true for '#{input}'" do
+ subject.potential_match?(input).should be true
+ end
+ end
+
+ %w{5 57 66 677 5767 67676 67677 676766 6767676}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+
+ context "with a minimum repeat of 2" do
+ before { pending }
+ let(:nested_repeat) { 2..Item::Inf }
+
+ %w{6 67 676 6767 67676 676767 67676767}.each do |input|
+ it "should be true for '#{input}'" do
+ subject.potential_match?(input).should be true
+ end
+ end
+
+ %w{5 57 66 677 5767 67677 676766}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+ end
+ end
+
+ describe "#longest_potential_match" do
+ subject { Item.new }
+
+ before do
+ tokens.each { |token| subject << token }
+ subject.repeat = repeat if repeat
+ end
+
+ context "with a single token of '6'" do
+ let(:tokens) { [Token.new << '6'] }
+
+ context "with no repeat" do
+ let(:repeat) { nil }
+
+ %w{6 65 6776}.each do |input|
+ it "should be '6' for '#{input}'" do
+ subject.longest_potential_match(input).should == '6'
+ end
+ end
+
+ %w{5 7 55 56}.each do |input|
+ it "should be '' for '#{input}'" do
+ subject.longest_potential_match(input).should == ''
+ end
+ end
+ end
+
+ context "with an absolute repeat of 3" do
+ let(:repeat) { 3 }
+
+ {
+ '6' => '6',
+ '66' => '66',
+ '666' => '666',
+ '6666' => '666',
+ '66666' => '666'
+ }.each do |input, match|
+ it "should be '#{match}' for '#{input}'" do
+ subject.longest_potential_match(input).should == match
+ end
+ end
+ end
+
+ context "with a range repeat of 0..2" do
+ let(:repeat) { 0..2 }
+
+ {
+ '6' => '6',
+ '66' => '66',
+ '666' => '66',
+ '6666' => '66'
+ }.each do |input, match|
+ it "should be '#{match}' for '#{input}'" do
+ subject.longest_potential_match(input).should == match
+ end
+ end
+ end
+
+ context "with a minimum repeat of 2" do
+ let(:repeat) { 2..Item::Inf }
+
+ {
+ '6' => '6',
+ '66' => '66',
+ '666' => '666',
+ '6666' => '6666',
+ '6'*100 => '6'*100
+ }.each do |input, match|
+ it "should be '#{match}' for '#{input}'" do
+ subject.longest_potential_match(input).should == match
+ end
+ end
+ end
+ end
+
+ context "with a collection of two tokens of '6' and '7'" do
+ let(:tokens) { [Token.new << '6', Token.new << '7'] }
+
+ context "with no repeat" do
+ let(:repeat) { nil }
+
+ {
+ '6' => '6',
+ '66' => '6',
+ '67' => '67',
+ '676' => '67',
+ '6767' => '67'
+ }.each do |input, match|
+ it "should be '#{match}' for '#{input}'" do
+ subject.longest_potential_match(input).should == match
+ end
+ end
+ end
+
+ context "with an absolute repeat of 3" do
+ let(:repeat) { 3 }
+
+ {
+ '6' => '6',
+ '66' => '6',
+ '67' => '67',
+ '676' => '676',
+ '6767' => '6767',
+ '67676' => '67676',
+ '676767' => '676767',
+ '6767676' => '676767'
+ }.each do |input, match|
+ it "should be '#{match}' for '#{input}'" do
+ subject.longest_potential_match(input).should == match
+ end
+ end
+ end
+
+ context "with a range repeat of 0..2" do
+ let(:repeat) { 0..2 }
+
+ {
+ '6' => '6',
+ '66' => '6',
+ '67' => '67',
+ '676' => '676',
+ '6767' => '6767',
+ '67676' => '6767',
+ '676767' => '6767'
+ }.each do |input, match|
+ it "should be '#{match}' for '#{input}'" do
+ subject.longest_potential_match(input).should == match
+ end
+ end
+ end
+
+ context "with a minimum repeat of 2" do
+ let(:repeat) { 2..Item::Inf }
+
+ {
+ '6' => '6',
+ '66' => '6',
+ '67' => '67',
+ '676' => '676',
+ '6767' => '6767',
+ '67676' => '67676',
+ '676767' => '676767',
+ '6767676' => '6767676',
+ '67'*100 => '67'*100
+ }.each do |input, match|
+ it "should be '#{match}' for '#{input}'" do
+ subject.longest_potential_match(input).should == match
+ end
+ end
+ end
+ end
+ end
end # Item
end # GRXML
end # RubySpeech
View
237 spec/ruby_speech/grxml/one_of_spec.rb
@@ -45,6 +45,243 @@ module GRXML
end
end
+ describe "#potential_match?" do
+ before do
+ items.each { |item| subject << item }
+ end
+
+ context "with a single item of '6'" do
+ let(:items) { [Item.new << (Token.new << '6')] }
+
+ it "should be true for '6'" do
+ subject.potential_match?('6').should be true
+ end
+
+ %w{5 7}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+
+ context "with options of '6' or '7'" do
+ let(:items) { [Item.new << (Token.new << '6'), Item.new << (Token.new << '7')] }
+
+ %w{6 7}.each do |input|
+ it "should be true for '#{input}'" do
+ subject.potential_match?(input).should be true
+ end
+ end
+
+ %w{5 8 67 76}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+
+ context "with options of '67' or '25'" do
+ let(:items) { [Item.new << (Token.new << '6') << (Token.new << '7'), Item.new << (Token.new << '2') << (Token.new << '5')] }
+
+ %w{6 2}.each do |input|
+ it "should be true for '#{input}'" do
+ subject.potential_match?(input).should be true
+ end
+ end
+
+ %w{3 7 5 65 27 76 52}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+
+ context "with options of '678' or '251'" do
+ let(:items) { [Item.new << (Token.new << '6') << (Token.new << '7') << (Token.new << '8'), Item.new << (Token.new << '2') << (Token.new << '5') << (Token.new << '1')] }
+
+ %w{6 67 2 25}.each do |input|
+ it "should be true for '#{input}'" do
+ subject.potential_match?(input).should be true
+ end
+ end
+
+ %w{3 7 5 65 27 76 52}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+
+ context "with options of '6' or ('7' repeated twice)" do
+ let(:items) { [Item.new << (Token.new << '6'), Item.new << (Item.new(:repeat => 2) << (Token.new << '7'))] }
+
+ %w{6 7 77}.each do |input|
+ it "should be true for '#{input}'" do
+ pending
+ subject.potential_match?(input).should be true
+ end
+ end
+
+ %w{5 67 76 66}.each do |input|
+ it "should be false for '#{input}'" do
+ subject.potential_match?(input).should be false
+ end
+ end
+ end
+ end
+
+ describe "#longest_potential_match" do
+ before do
+ items.each { |item| subject << item }
+ end
+
+ context "with a single item of '6'" do
+ let(:items) { [Item.new << (Token.new << '6')] }
+
+ %w{6 65 6776}.each do |input|
+ it "should be '6' for '#{input}'" do
+ subject.longest_potential_match(input).should == '6'
+ end
+ end
+
+ %w{5 7 55 56}.each do |input|
+ it "should be '' for '#{input}'" do
+ subject.longest_potential_match(input).should == ''
+ end
+ end
+ end
+
+ context "with options of '6' or '7'" do
+ let(:items) { [Item.new << (Token.new << '6'), Item.new << (Token.new << '7')] }
+
+ %w{6 65 6776}.each do |input|
+ it "should be '6' for '#{input}'" do
+ subject.longest_potential_match(input).should == '6'
+ end
+ end
+
+ %w{7 74 726}.each do |input|
+ it "should be '7' for '#{input}'" do
+ subject.longest_potential_match(input).should == '7'
+ end
+ end
+
+ %w{5 55 56}.each do |input|
+ it "should be '' for '#{input}'" do
+ subject.longest_potential_match(input).should == ''
+ end
+ end
+ end
+
+ context "with options of '67' or '25'" do
+ let(:items) { [Item.new << (Token.new << '6') << (Token.new << '7'), Item.new << (Token.new << '2') << (Token.new << '5')] }
+
+ %w{6}.each do |input|
+ it "should be '6' for '#{input}'" do
+ subject.longest_potential_match(input).should == '6'
+ end
+ end
+
+ %w{67 675 6767 6756}.each do |input|
+ it "should be '67' for '#{input}'" do
+ subject.longest_potential_match(input).should == '67'
+ end
+ end
+
+ %w{2}.each do |input|
+ it "should be '2' for '#{input}'" do
+ subject.longest_potential_match(input).should == '2'
+ end
+ end
+
+ %w{25 259 2525 2567}.each do |input|
+ it "should be '25' for '#{input}'" do
+ subject.longest_potential_match(input).should == '25'
+ end
+ end
+
+ %w{5 7 72 56}.each do |input|
+ it "should be '' for '#{input}'" do
+ subject.longest_potential_match(input).should == ''
+ end
+ end
+ end
+
+ context "with options of '678' or '251'" do
+ let(:items) { [Item.new << (Token.new << '6') << (Token.new << '7') << (Token.new << '8'), Item.new << (Token.new << '2') << (Token.new << '5') << (Token.new << '1')] }
+
+ %w{6}.each do |input|
+ it "should be '6' for '#{input}'" do
+ subject.longest_potential_match(input).should == '6'
+ end
+ end
+
+ %w{67 675 6767 6756}.each do |input|
+ it "should be '67' for '#{input}'" do
+ subject.longest_potential_match(input).should == '67'
+ end
+ end
+
+ %w{678 6785 678678 67856}.each do |input|
+ it "should be '678' for '#{input}'" do
+ subject.longest_potential_match(input).should == '678'
+ end
+ end
+
+ %w{2}.each do |input|
+ it "should be '2' for '#{input}'" do
+ subject.longest_potential_match(input).should == '2'
+ end
+ end
+
+ %w{25 259 2525 2567}.each do |input|
+ it "should be '25' for '#{input}'" do
+ subject.longest_potential_match(input).should == '25'
+ end
+ end
+
+ %w{251 2519 251251 25167}.each do |input|
+ it "should be '251' for '#{input}'" do
+ subject.longest_potential_match(input).should == '251'
+ end
+ end
+
+ %w{5 7 72 56}.each do |input|
+ it "should be '' for '#{input}'" do
+ subject.longest_potential_match(input).should == ''
+ end
+ end
+ end
+
+ context "with options of '6' or '7' repeated twice" do
+ let(:items) { [Item.new << (Token.new << '6'), Item.new << (Item.new(:repeat => 2) << (Token.new << '7'))] }
+
+ %w{6 65 6776}.each do |input|
+ it "should be '6' for '#{input}'" do
+ subject.longest_potential_match(input).should == '6'
+ end
+ end
+
+ %w{7 74 726}.each do |input|
+ it "should be '7' for '#{input}'" do
+ subject.longest_potential_match(input).should == '7'
+ end
+ end
+
+ %w{7 77 774 7726}.each do |input|
+ it "should be '77' for '#{input}'" do
+ pending
+ subject.longest_potential_match(input).should == '77'
+ end
+ end
+
+ %w{5 55 56}.each do |input|
+ it "should be '' for '#{input}'" do
+ subject.longest_potential_match(input).should == ''
+ end
+ end
+ end
+ end
end # OneOf
end # GRXML
end # RubySpeech
View
17 spec/ruby_speech/grxml/potential_match_spec.rb
@@ -0,0 +1,17 @@
+require 'spec_helper'
+
+module RubySpeech
+ module GRXML
+ describe PotentialMatch do
+ describe "equality" do
+ it "should be equal to another PotentialMatch" do
+ PotentialMatch.new.should == PotentialMatch.new
+ end
+
+ it "should not equal a match" do
+ PotentialMatch.new.should_not == Match.new
+ end
+ end
+ end
+ end
+end
View
5 spec/ruby_speech/grxml/token_spec.rb
@@ -51,6 +51,11 @@ module GRXML
it "should accept String" do
lambda { subject << 'anything' }.should_not raise_error
end
+
+ it "should allow chaining" do
+ subject << 'foo' << 'bar'
+ subject.content.should == 'foobar'
+ end
end
end # Token
end # GRXML
Please sign in to comment.
Something went wrong with that request. Please try again.