Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
initial grxml skeleton for ruby_speech
- Loading branch information
1 parent
0a24104
commit 6f18bae
Showing
6 changed files
with
222 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,4 @@ pkg/* | |
spec/reports | ||
.yardoc | ||
doc | ||
.*.swp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,5 +11,6 @@ module RubySpeech | |
autoload :Version | ||
|
||
autoload :SSML | ||
autoload :GRXML | ||
autoload :XML | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
module RubySpeech | ||
module GRXML | ||
extend ActiveSupport::Autoload | ||
|
||
autoload :Element | ||
autoload :Grammar | ||
#autoload :Dtfm | ||
|
||
InvalidChildError = Class.new StandardError | ||
|
||
GRXML_NAMESPACE = 'http://www.w3.org/2001/06/grammar' | ||
|
||
def self.draw(&block) | ||
Grammar.new.tap do |grammar| | ||
block_return = grammar.instance_eval(&block) if block_given? | ||
grammar << block_return if block_return.is_a?(String) | ||
end | ||
end | ||
end # GRXML | ||
end # RubySpeech |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
require 'active_support/core_ext/class/inheritable_attributes' | ||
|
||
module RubySpeech | ||
module GRXML | ||
class Element < Niceogiri::XML::Node | ||
@@registrations = {} | ||
|
||
class_inheritable_accessor :registered_ns, :registered_name | ||
|
||
# Register a new stanza class to a name and/or namespace | ||
# | ||
# This registers a namespace that is used when looking | ||
# up the class name of the object to instantiate when a new | ||
# stanza is received | ||
# | ||
# @param [#to_s] name the name of the node | ||
# | ||
def self.register(name) | ||
self.registered_name = name.to_s | ||
self.registered_ns = GRXML_NAMESPACE | ||
@@registrations[[self.registered_name, self.registered_ns]] = self | ||
end | ||
|
||
# Find the class to use given the name and namespace of a stanza | ||
# | ||
# @param [#to_s] name the name to lookup | ||
# | ||
# @return [Class, nil] the class appropriate for the name | ||
def self.class_from_registration(name) | ||
@@registrations[[name.to_s, GRXML_NAMESPACE]] | ||
end | ||
|
||
# Import an XML::Node to the appropriate class | ||
# | ||
# Looks up the class the node should be then creates it based on the | ||
# elements of the XML::Node | ||
# @param [XML::Node] node the node to import | ||
# @return the appropriate object based on the node name and namespace | ||
def self.import(node) | ||
return node.content if node.is_a?(Nokogiri::XML::Text) | ||
klass = class_from_registration(node.element_name) | ||
if klass && klass != self | ||
klass.import node | ||
else | ||
new.inherit node | ||
end | ||
end | ||
|
||
# Inherit the attributes and children of an XML::Node | ||
# | ||
# @param [XML::Node] node the node to inherit | ||
# @return [self] | ||
def inherit(node) | ||
inherit_attrs node.attributes | ||
node.children.each do |c| | ||
self << c.dup | ||
end | ||
self | ||
end | ||
|
||
def self.new(element_name, atts = {}, &block) | ||
super(element_name) do |new_node| | ||
atts.each_pair { |k, v| new_node.send :"#{k}=", v } | ||
block_return = new_node.instance_eval &block if block_given? | ||
new_node << new_node.encode_special_chars(block_return) if block_return.is_a?(String) | ||
end | ||
end | ||
|
||
def children | ||
super.map { |c| Element.import c } | ||
end | ||
|
||
def method_missing(method_name, *args, &block) | ||
const_name = method_name.to_s.sub('ssml', '').titleize.gsub(' ', '') | ||
const = GRXML.const_get const_name | ||
if const && self.class::VALID_CHILD_TYPES.include?(const) | ||
if const == String | ||
self << encode_special_chars(args.first) | ||
else | ||
self << const.new(*args, &block) | ||
end | ||
else | ||
super | ||
end | ||
end | ||
|
||
def eql?(o, *args) | ||
super o, :content, :children, *args | ||
end | ||
end # Element | ||
end # GRXML | ||
end # RubySpeech |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
module RubySpeech | ||
module GRXML | ||
## | ||
# The Speech Recognition Grammar Language is an XML application. The root element is grammar. | ||
# | ||
# http://www.w3.org/TR/speech-grammar/#S4.3 | ||
# | ||
class Grammar < Element | ||
include XML::Language | ||
|
||
register :grammar | ||
|
||
#VALID_CHILD_TYPES = [Nokogiri::XML::Element, Nokogiri::XML::Text, DTMF].freeze | ||
VALID_CHILD_TYPES = [Nokogiri::XML::Element, Nokogiri::XML::Text].freeze | ||
|
||
## | ||
# Create a new GRXML grammar root element | ||
# | ||
# @param [Hash] atts Key-value pairs of options mapping to setter methods | ||
# | ||
# @return [Grammar] an element for use in an GRXML document | ||
# | ||
def self.new(atts = {}, &block) | ||
new_node = super('grammar', atts) | ||
new_node[:version] = '1.0' | ||
new_node.namespace = GRXML_NAMESPACE | ||
new_node.language ||= "en-US" | ||
new_node.instance_eval &block if block_given? | ||
new_node | ||
end | ||
|
||
## | ||
# @return [String] the base URI to which relative URLs are resolved | ||
# | ||
def base_uri | ||
read_attr :base | ||
end | ||
|
||
## | ||
# @param [String] uri the base URI to which relative URLs are resolved | ||
# | ||
def base_uri=(uri) | ||
write_attr 'xml:base', uri | ||
end | ||
|
||
def <<(arg) | ||
#raise InvalidChildError, "A Grammar can only accept String, Audio, Break, Emphasis, Mark, P, Phoneme, Prosody, SayAs, Sub, S, Voice as children" unless VALID_CHILD_TYPES.include? arg.class | ||
raise InvalidChildError, "A Grammar can only accept DTMF as children" unless VALID_CHILD_TYPES.include? arg.class | ||
super | ||
end | ||
|
||
def to_doc | ||
Nokogiri::XML::Document.new.tap do |doc| | ||
doc << self | ||
end | ||
end | ||
|
||
def +(other) | ||
self.class.new(:base_uri => base_uri).tap do |new_grammar| | ||
(self.children + other.children).each do |child| | ||
new_grammar << child | ||
end | ||
end | ||
end | ||
|
||
def eql?(o) | ||
super o, :language, :base_uri | ||
end | ||
end # Grammar | ||
end # GRXML | ||
end # RubySpeech |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
require 'spec_helper' | ||
|
||
module RubySpeech | ||
describe GRXML do | ||
describe "#draw" do | ||
it "should create an GRXML document" do | ||
expected_doc = GRXML::Grammar.new | ||
GRXML.draw.should == expected_doc | ||
end | ||
end | ||
end | ||
end | ||
|
||
__END__ | ||
doc = RubySpeech::GRXML.draw do | ||
rule :id => :digit do | ||
one_of do | ||
10.times do |i| | ||
item i | ||
end | ||
end | ||
end | ||
end | ||
<rule id="digit"> | ||
<one-of> | ||
<item> 0 </item> | ||
<item> 1 </item> | ||
<item> 2 </item> | ||
<item> 3 </item> | ||
<item> 4 </item> | ||
<item> 5 </item> | ||
<item> 6 </item> | ||
<item> 7 </item> | ||
<item> 8 </item> | ||
<item> 9 </item> | ||
</one-of> | ||
</rule> |