Permalink
Browse files

Merge branch 'release/0.5.1'

  • Loading branch information...
2 parents 798638c + bd9a767 commit 7f6097e5e0e64c07062a34305ecbf2526c1e6023 @benlangfeld benlangfeld committed Jan 9, 2012
View
@@ -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
@@ -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 }
@@ -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
@@ -15,6 +15,7 @@ module GRXML
autoload :Match
autoload :NoMatch
+ autoload :PotentialMatch
InvalidChildError = Class.new StandardError
@@ -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
@@ -195,22 +195,40 @@ 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,
:utterance => 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
#
@@ -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
@@ -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
@@ -0,0 +1,10 @@
+module RubySpeech
+ module GRXML
+ class PotentialMatch
+ def eql?(o)
+ o.is_a? self.class
+ end
+ alias :== :eql?
+ end
+ end
+end
@@ -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
@@ -1,3 +1,3 @@
module RubySpeech
- VERSION = "0.5.0"
+ VERSION = "0.5.1"
end
Oops, something went wrong.

0 comments on commit 7f6097e

Please sign in to comment.