ruby_speech 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +15 -0
 - data/README.md +108 -14
 - data/lib/ruby_speech/generic_element.rb +71 -10
 - data/lib/ruby_speech/grxml.rb +4 -1
 - data/lib/ruby_speech/grxml/element.rb +4 -0
 - data/lib/ruby_speech/grxml/grammar.rb +177 -46
 - data/lib/ruby_speech/grxml/item.rb +12 -11
 - data/lib/ruby_speech/grxml/match.rb +16 -0
 - data/lib/ruby_speech/grxml/no_match.rb +10 -0
 - data/lib/ruby_speech/grxml/one_of.rb +4 -11
 - data/lib/ruby_speech/grxml/rule.rb +0 -11
 - data/lib/ruby_speech/grxml/ruleref.rb +0 -11
 - data/lib/ruby_speech/grxml/tag.rb +0 -11
 - data/lib/ruby_speech/grxml/token.rb +8 -11
 - data/lib/ruby_speech/ssml.rb +6 -0
 - data/lib/ruby_speech/ssml/audio.rb +1 -12
 - data/lib/ruby_speech/ssml/break.rb +0 -11
 - data/lib/ruby_speech/ssml/desc.rb +24 -0
 - data/lib/ruby_speech/ssml/emphasis.rb +1 -12
 - data/lib/ruby_speech/ssml/mark.rb +43 -0
 - data/lib/ruby_speech/ssml/p.rb +25 -0
 - data/lib/ruby_speech/ssml/phoneme.rb +72 -0
 - data/lib/ruby_speech/ssml/prosody.rb +1 -12
 - data/lib/ruby_speech/ssml/s.rb +25 -0
 - data/lib/ruby_speech/ssml/say_as.rb +0 -11
 - data/lib/ruby_speech/ssml/speak.rb +2 -44
 - data/lib/ruby_speech/ssml/sub.rb +42 -0
 - data/lib/ruby_speech/ssml/voice.rb +1 -12
 - data/lib/ruby_speech/version.rb +1 -1
 - data/spec/ruby_speech/grxml/grammar_spec.rb +478 -35
 - data/spec/ruby_speech/grxml/item_spec.rb +5 -2
 - data/spec/ruby_speech/grxml/match_spec.rb +49 -0
 - data/spec/ruby_speech/grxml/no_match_spec.rb +17 -0
 - data/spec/ruby_speech/grxml/one_of_spec.rb +1 -1
 - data/spec/ruby_speech/grxml/rule_spec.rb +1 -1
 - data/spec/ruby_speech/grxml/ruleref_spec.rb +1 -1
 - data/spec/ruby_speech/grxml/tag_spec.rb +1 -1
 - data/spec/ruby_speech/grxml/token_spec.rb +11 -1
 - data/spec/ruby_speech/grxml_spec.rb +64 -5
 - data/spec/ruby_speech/ssml/audio_spec.rb +5 -6
 - data/spec/ruby_speech/ssml/break_spec.rb +1 -1
 - data/spec/ruby_speech/ssml/desc_spec.rb +57 -0
 - data/spec/ruby_speech/ssml/emphasis_spec.rb +1 -4
 - data/spec/ruby_speech/ssml/mark_spec.rb +53 -0
 - data/spec/ruby_speech/ssml/p_spec.rb +96 -0
 - data/spec/ruby_speech/ssml/phoneme_spec.rb +65 -0
 - data/spec/ruby_speech/ssml/prosody_spec.rb +9 -4
 - data/spec/ruby_speech/ssml/s_spec.rb +92 -0
 - data/spec/ruby_speech/ssml/say_as_spec.rb +1 -1
 - data/spec/ruby_speech/ssml/speak_spec.rb +1 -6
 - data/spec/ruby_speech/ssml/sub_spec.rb +57 -0
 - data/spec/ruby_speech/ssml/voice_spec.rb +1 -6
 - data/spec/spec_helper.rb +0 -4
 - data/spec/support/matchers.rb +13 -53
 - metadata +200 -113
 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -1,5 +1,20 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # develop
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            # 0.5.0 - 2012-01-03
         
     | 
| 
      
 4 
     | 
    
         
            +
              * Feature: Add a whole bunch more SSML elements:
         
     | 
| 
      
 5 
     | 
    
         
            +
              ** p & s
         
     | 
| 
      
 6 
     | 
    
         
            +
              ** mark
         
     | 
| 
      
 7 
     | 
    
         
            +
              ** desc
         
     | 
| 
      
 8 
     | 
    
         
            +
              ** sub
         
     | 
| 
      
 9 
     | 
    
         
            +
              ** phoneme
         
     | 
| 
      
 10 
     | 
    
         
            +
              * Feature: Added the ability to inline grammar rule references in both destructive and non-destructive modes
         
     | 
| 
      
 11 
     | 
    
         
            +
              * Feature: Added the ability to tokenize a grammar, turning all tokens into unambiguous `<token/>` elements
         
     | 
| 
      
 12 
     | 
    
         
            +
              * Feature: Added the ability to whitespace normalize a grammar
         
     | 
| 
      
 13 
     | 
    
         
            +
              * Feature: Added the ability to match an input string against a Grammar
         
     | 
| 
      
 14 
     | 
    
         
            +
              * Feature: Constructing a GRXML grammar with a root rule specified but not provided will raise an exception
         
     | 
| 
      
 15 
     | 
    
         
            +
              * Feature: Embedding a GRXML grammar of a mode different from the host will raise an exception
         
     | 
| 
      
 16 
     | 
    
         
            +
              * Bugfix: Fix upward traversal through a document via #parent
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
       3 
18 
     | 
    
         
             
            # 0.4.0 - 2011-12-30
         
     | 
| 
       4 
19 
     | 
    
         
             
              * Feature: Add the ability to look up child elements by name/attributes easily
         
     | 
| 
       5 
20 
     | 
    
         
             
              * Feature: Allow easy access to a GRXML grammar's root rule element
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -46,15 +46,15 @@ Once your `Speak` is fully prepared and you're ready to send it off for processi 
     | 
|
| 
       46 
46 
     | 
    
         
             
            You may also then need to call `to_s`.
         
     | 
| 
       47 
47 
     | 
    
         | 
| 
       48 
48 
     | 
    
         | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
      
 49 
     | 
    
         
            +
            Construct a GRXML (SRGS) document like this:
         
     | 
| 
       50 
50 
     | 
    
         | 
| 
       51 
51 
     | 
    
         
             
            ```ruby
         
     | 
| 
       52 
52 
     | 
    
         
             
            require 'ruby_speech'
         
     | 
| 
       53 
53 
     | 
    
         | 
| 
       54 
     | 
    
         
            -
            grammy = RubySpeech::GRXML.draw : 
     | 
| 
       55 
     | 
    
         
            -
              rule id: ' 
     | 
| 
      
 54 
     | 
    
         
            +
            grammy = RubySpeech::GRXML.draw mode: :dtmf, root: 'pin' do
         
     | 
| 
      
 55 
     | 
    
         
            +
              rule id: 'digit' do
         
     | 
| 
       56 
56 
     | 
    
         
             
                one_of do
         
     | 
| 
       57 
     | 
    
         
            -
                  0 
     | 
| 
      
 57 
     | 
    
         
            +
                  ('0'..'9').map { |d| item { d } }
         
     | 
| 
       58 
58 
     | 
    
         
             
                end
         
     | 
| 
       59 
59 
     | 
    
         
             
              end
         
     | 
| 
       60 
60 
     | 
    
         | 
| 
         @@ -79,8 +79,8 @@ grammy.to_s 
     | 
|
| 
       79 
79 
     | 
    
         
             
            which becomes
         
     | 
| 
       80 
80 
     | 
    
         | 
| 
       81 
81 
     | 
    
         
             
            ```xml
         
     | 
| 
       82 
     | 
    
         
            -
            <grammar xmlns="http://www.w3.org/2001/06/grammar" version="1.0" xml:lang="en-US" mode="dtmf" root=" 
     | 
| 
       83 
     | 
    
         
            -
              <rule id=" 
     | 
| 
      
 82 
     | 
    
         
            +
            <grammar xmlns="http://www.w3.org/2001/06/grammar" version="1.0" xml:lang="en-US" mode="dtmf" root="pin">
         
     | 
| 
      
 83 
     | 
    
         
            +
              <rule id="digit">
         
     | 
| 
       84 
84 
     | 
    
         
             
                <one-of>
         
     | 
| 
       85 
85 
     | 
    
         
             
                  <item>0</item>
         
     | 
| 
       86 
86 
     | 
    
         
             
                  <item>1</item>
         
     | 
| 
         @@ -103,6 +103,101 @@ which becomes 
     | 
|
| 
       103 
103 
     | 
    
         
             
            </grammar>
         
     | 
| 
       104 
104 
     | 
    
         
             
            ```
         
     | 
| 
       105 
105 
     | 
    
         | 
| 
      
 106 
     | 
    
         
            +
            ### Grammar matching
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
            It is possible to match some arbitrary input against a GRXML grammar. In order to do so, certain normalization routines should first be run on the grammar in order to prepare it for matching. These are reference inlining, tokenization and whitespace normalization, and are described [in the SRGS spec](http://www.w3.org/TR/speech-grammar/#S2.1). This process will transform the above grammar like so:
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 111 
     | 
    
         
            +
            grammy.inline!
         
     | 
| 
      
 112 
     | 
    
         
            +
            grammy.tokenize!
         
     | 
| 
      
 113 
     | 
    
         
            +
            grammy.normalize_whitespace
         
     | 
| 
      
 114 
     | 
    
         
            +
            ```
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
            ```xml
         
     | 
| 
      
 117 
     | 
    
         
            +
            <grammar xmlns="http://www.w3.org/2001/06/grammar" version="1.0" xml:lang="en-US" mode="dtmf" root="pin">
         
     | 
| 
      
 118 
     | 
    
         
            +
              <rule id="pin" scope="public">
         
     | 
| 
      
 119 
     | 
    
         
            +
                <one-of>
         
     | 
| 
      
 120 
     | 
    
         
            +
                  <item>
         
     | 
| 
      
 121 
     | 
    
         
            +
                    <item repeat="4">
         
     | 
| 
      
 122 
     | 
    
         
            +
                      <one-of>
         
     | 
| 
      
 123 
     | 
    
         
            +
                        <item>
         
     | 
| 
      
 124 
     | 
    
         
            +
                          <token>0</token>
         
     | 
| 
      
 125 
     | 
    
         
            +
                        </item>
         
     | 
| 
      
 126 
     | 
    
         
            +
                        <item>
         
     | 
| 
      
 127 
     | 
    
         
            +
                          <token>1</token>
         
     | 
| 
      
 128 
     | 
    
         
            +
                        </item>
         
     | 
| 
      
 129 
     | 
    
         
            +
                        <item>
         
     | 
| 
      
 130 
     | 
    
         
            +
                          <token>2</token>
         
     | 
| 
      
 131 
     | 
    
         
            +
                        </item>
         
     | 
| 
      
 132 
     | 
    
         
            +
                        <item>
         
     | 
| 
      
 133 
     | 
    
         
            +
                          <token>3</token>
         
     | 
| 
      
 134 
     | 
    
         
            +
                        </item>
         
     | 
| 
      
 135 
     | 
    
         
            +
                        <item>
         
     | 
| 
      
 136 
     | 
    
         
            +
                          <token>4</token>
         
     | 
| 
      
 137 
     | 
    
         
            +
                        </item>
         
     | 
| 
      
 138 
     | 
    
         
            +
                        <item>
         
     | 
| 
      
 139 
     | 
    
         
            +
                          <token>5</token>
         
     | 
| 
      
 140 
     | 
    
         
            +
                        </item>
         
     | 
| 
      
 141 
     | 
    
         
            +
                        <item>
         
     | 
| 
      
 142 
     | 
    
         
            +
                          <token>6</token>
         
     | 
| 
      
 143 
     | 
    
         
            +
                        </item>
         
     | 
| 
      
 144 
     | 
    
         
            +
                        <item>
         
     | 
| 
      
 145 
     | 
    
         
            +
                          <token>7</token>
         
     | 
| 
      
 146 
     | 
    
         
            +
                        </item>
         
     | 
| 
      
 147 
     | 
    
         
            +
                        <item>
         
     | 
| 
      
 148 
     | 
    
         
            +
                          <token>8</token>
         
     | 
| 
      
 149 
     | 
    
         
            +
                        </item>
         
     | 
| 
      
 150 
     | 
    
         
            +
                        <item>
         
     | 
| 
      
 151 
     | 
    
         
            +
                          <token>9</token>
         
     | 
| 
      
 152 
     | 
    
         
            +
                        </item>
         
     | 
| 
      
 153 
     | 
    
         
            +
                      </one-of>
         
     | 
| 
      
 154 
     | 
    
         
            +
                    </item>
         
     | 
| 
      
 155 
     | 
    
         
            +
                    <token>#</token>
         
     | 
| 
      
 156 
     | 
    
         
            +
                  </item>
         
     | 
| 
      
 157 
     | 
    
         
            +
                  <item>
         
     | 
| 
      
 158 
     | 
    
         
            +
                    <token>*</token>
         
     | 
| 
      
 159 
     | 
    
         
            +
                    <token>9</token>
         
     | 
| 
      
 160 
     | 
    
         
            +
                  </item>
         
     | 
| 
      
 161 
     | 
    
         
            +
                </one-of>
         
     | 
| 
      
 162 
     | 
    
         
            +
              </rule>
         
     | 
| 
      
 163 
     | 
    
         
            +
            </grammar>
         
     | 
| 
      
 164 
     | 
    
         
            +
            ```
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
            Matching against some sample input strings then returns the following results:
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 169 
     | 
    
         
            +
            >> subject.match '*9'
         
     | 
| 
      
 170 
     | 
    
         
            +
            => #<RubySpeech::GRXML::Match:0x00000100ae5d98
         
     | 
| 
      
 171 
     | 
    
         
            +
                  @mode = :dtmf,
         
     | 
| 
      
 172 
     | 
    
         
            +
                  @confidence = 1,
         
     | 
| 
      
 173 
     | 
    
         
            +
                  @utterance = "*9",
         
     | 
| 
      
 174 
     | 
    
         
            +
                  @interpretation = "*9"
         
     | 
| 
      
 175 
     | 
    
         
            +
                >
         
     | 
| 
      
 176 
     | 
    
         
            +
            >> subject.match '1234#'
         
     | 
| 
      
 177 
     | 
    
         
            +
            => #<RubySpeech::GRXML::Match:0x00000100b7e020
         
     | 
| 
      
 178 
     | 
    
         
            +
                  @mode = :dtmf,
         
     | 
| 
      
 179 
     | 
    
         
            +
                  @confidence = 1,
         
     | 
| 
      
 180 
     | 
    
         
            +
                  @utterance = "1234#",
         
     | 
| 
      
 181 
     | 
    
         
            +
                  @interpretation = "1234#"
         
     | 
| 
      
 182 
     | 
    
         
            +
                >
         
     | 
| 
      
 183 
     | 
    
         
            +
            >> subject.match '5678#'
         
     | 
| 
      
 184 
     | 
    
         
            +
            => #<RubySpeech::GRXML::Match:0x00000101218688
         
     | 
| 
      
 185 
     | 
    
         
            +
                  @mode = :dtmf,
         
     | 
| 
      
 186 
     | 
    
         
            +
                  @confidence = 1,
         
     | 
| 
      
 187 
     | 
    
         
            +
                  @utterance = "5678#",
         
     | 
| 
      
 188 
     | 
    
         
            +
                  @interpretation = "5678#"
         
     | 
| 
      
 189 
     | 
    
         
            +
                >
         
     | 
| 
      
 190 
     | 
    
         
            +
            >> subject.match '1111#'
         
     | 
| 
      
 191 
     | 
    
         
            +
            => #<RubySpeech::GRXML::Match:0x000001012f69d8
         
     | 
| 
      
 192 
     | 
    
         
            +
                  @mode = :dtmf,
         
     | 
| 
      
 193 
     | 
    
         
            +
                  @confidence = 1,
         
     | 
| 
      
 194 
     | 
    
         
            +
                  @utterance = "1111#",
         
     | 
| 
      
 195 
     | 
    
         
            +
                  @interpretation = "1111#"
         
     | 
| 
      
 196 
     | 
    
         
            +
                >
         
     | 
| 
      
 197 
     | 
    
         
            +
            >> subject.match '111'
         
     | 
| 
      
 198 
     | 
    
         
            +
            => #<RubySpeech::GRXML::NoMatch:0x00000101371660>
         
     | 
| 
      
 199 
     | 
    
         
            +
            ```
         
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
       106 
201 
     | 
    
         
             
            Check out the [YARD documentation](http://rdoc.info/github/benlangfeld/ruby_speech/master/frames) for more
         
     | 
| 
       107 
202 
     | 
    
         | 
| 
       108 
203 
     | 
    
         
             
            ## Features:
         
     | 
| 
         @@ -114,6 +209,13 @@ Check out the [YARD documentation](http://rdoc.info/github/benlangfeld/ruby_spee 
     | 
|
| 
       114 
209 
     | 
    
         
             
            * `<say-as/>`
         
     | 
| 
       115 
210 
     | 
    
         
             
            * `<break/>`
         
     | 
| 
       116 
211 
     | 
    
         
             
            * `<audio/>`
         
     | 
| 
      
 212 
     | 
    
         
            +
            * `<p/>` and `<s/>`
         
     | 
| 
      
 213 
     | 
    
         
            +
            * `<phoneme/>`
         
     | 
| 
      
 214 
     | 
    
         
            +
            * `<sub/>`
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
            #### Misc
         
     | 
| 
      
 217 
     | 
    
         
            +
            * `<mark/>`
         
     | 
| 
      
 218 
     | 
    
         
            +
            * `<desc/>`
         
     | 
| 
       117 
219 
     | 
    
         | 
| 
       118 
220 
     | 
    
         
             
            ### GRXML
         
     | 
| 
       119 
221 
     | 
    
         
             
            * Document construction
         
     | 
| 
         @@ -126,17 +228,9 @@ Check out the [YARD documentation](http://rdoc.info/github/benlangfeld/ruby_spee 
     | 
|
| 
       126 
228 
     | 
    
         | 
| 
       127 
229 
     | 
    
         
             
            ## TODO:
         
     | 
| 
       128 
230 
     | 
    
         
             
            ### SSML
         
     | 
| 
       129 
     | 
    
         
            -
            #### Document Structure
         
     | 
| 
       130 
     | 
    
         
            -
            * `<p/>` and `<s/>`
         
     | 
| 
       131 
     | 
    
         
            -
            * `<phoneme/>`
         
     | 
| 
       132 
     | 
    
         
            -
            * `<sub/>`
         
     | 
| 
       133 
231 
     | 
    
         
             
            * `<lexicon/>`
         
     | 
| 
       134 
232 
     | 
    
         
             
            * `<meta/>` and `<metadata/>`
         
     | 
| 
       135 
233 
     | 
    
         | 
| 
       136 
     | 
    
         
            -
            #### Misc
         
     | 
| 
       137 
     | 
    
         
            -
            * `<mark/>`
         
     | 
| 
       138 
     | 
    
         
            -
            * `<desc/>`
         
     | 
| 
       139 
     | 
    
         
            -
             
     | 
| 
       140 
234 
     | 
    
         
             
            ### GRXML
         
     | 
| 
       141 
235 
     | 
    
         
             
            * `<meta/>` and `<metadata/>`
         
     | 
| 
       142 
236 
     | 
    
         
             
            * `<example/>`
         
     | 
| 
         @@ -4,7 +4,7 @@ module RubySpeech 
     | 
|
| 
       4 
4 
     | 
    
         
             
              module GenericElement
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
                def self.included(klass)
         
     | 
| 
       7 
     | 
    
         
            -
                  klass.class_attribute :registered_ns, :registered_name
         
     | 
| 
      
 7 
     | 
    
         
            +
                  klass.class_attribute :registered_ns, :registered_name, :defaults
         
     | 
| 
       8 
8 
     | 
    
         
             
                  klass.extend ClassMethods
         
     | 
| 
       9 
9 
     | 
    
         
             
                end
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
         @@ -43,7 +43,7 @@ module RubySpeech 
     | 
|
| 
       43 
43 
     | 
    
         
             
                  def import(node)
         
     | 
| 
       44 
44 
     | 
    
         
             
                    node = Nokogiri::XML.parse(node, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root unless node.is_a?(Nokogiri::XML::Node)
         
     | 
| 
       45 
45 
     | 
    
         
             
                    return node.content if node.is_a?(Nokogiri::XML::Text)
         
     | 
| 
       46 
     | 
    
         
            -
                    klass = class_from_registration 
     | 
| 
      
 46 
     | 
    
         
            +
                    klass = class_from_registration node.element_name
         
     | 
| 
       47 
47 
     | 
    
         
             
                    if klass && klass != self
         
     | 
| 
       48 
48 
     | 
    
         
             
                      klass.import node
         
     | 
| 
       49 
49 
     | 
    
         
             
                    else
         
     | 
| 
         @@ -51,26 +51,73 @@ module RubySpeech 
     | 
|
| 
       51 
51 
     | 
    
         
             
                    end
         
     | 
| 
       52 
52 
     | 
    
         
             
                  end
         
     | 
| 
       53 
53 
     | 
    
         | 
| 
       54 
     | 
    
         
            -
                  def new( 
     | 
| 
      
 54 
     | 
    
         
            +
                  def new(atts = {}, &block)
         
     | 
| 
       55 
55 
     | 
    
         
             
                    blk_proc = lambda do |new_node|
         
     | 
| 
       56 
     | 
    
         
            -
                      atts.each_pair { |k, v| new_node.send :"#{k}=", v }
         
     | 
| 
      
 56 
     | 
    
         
            +
                      (self.defaults || {}).merge(atts).each_pair { |k, v| new_node.send :"#{k}=", v }
         
     | 
| 
       57 
57 
     | 
    
         
             
                      block_return = new_node.eval_dsl_block &block
         
     | 
| 
       58 
     | 
    
         
            -
                      new_node <<  
     | 
| 
      
 58 
     | 
    
         
            +
                      new_node << block_return if block_return.is_a?(String)
         
     | 
| 
       59 
59 
     | 
    
         
             
                    end
         
     | 
| 
       60 
60 
     | 
    
         | 
| 
       61 
61 
     | 
    
         
             
                    case RUBY_VERSION.split('.')[0,2].join.to_i
         
     | 
| 
       62 
62 
     | 
    
         
             
                    when 18
         
     | 
| 
       63 
     | 
    
         
            -
                      super( 
     | 
| 
      
 63 
     | 
    
         
            +
                      super(self.registered_name, nil, self.namespace).tap do |n|
         
     | 
| 
       64 
64 
     | 
    
         
             
                        blk_proc[n]
         
     | 
| 
       65 
65 
     | 
    
         
             
                      end
         
     | 
| 
       66 
66 
     | 
    
         
             
                    else
         
     | 
| 
       67 
     | 
    
         
            -
                      super( 
     | 
| 
      
 67 
     | 
    
         
            +
                      super(self.registered_name, nil, self.namespace) do |n|
         
     | 
| 
       68 
68 
     | 
    
         
             
                        blk_proc[n]
         
     | 
| 
       69 
69 
     | 
    
         
             
                      end
         
     | 
| 
       70 
70 
     | 
    
         
             
                    end
         
     | 
| 
       71 
71 
     | 
    
         
             
                  end
         
     | 
| 
       72 
72 
     | 
    
         
             
                end
         
     | 
| 
       73 
73 
     | 
    
         | 
| 
      
 74 
     | 
    
         
            +
                attr_writer :parent
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                def parent
         
     | 
| 
      
 77 
     | 
    
         
            +
                  @parent || super
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                def inherit(node)
         
     | 
| 
      
 81 
     | 
    
         
            +
                  self.parent = node.parent
         
     | 
| 
      
 82 
     | 
    
         
            +
                  super
         
     | 
| 
      
 83 
     | 
    
         
            +
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                def version
         
     | 
| 
      
 86 
     | 
    
         
            +
                  read_attr :version
         
     | 
| 
      
 87 
     | 
    
         
            +
                end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                def version=(other)
         
     | 
| 
      
 90 
     | 
    
         
            +
                  write_attr :version, other
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                ##
         
     | 
| 
      
 94 
     | 
    
         
            +
                # @return [String] the base URI to which relative URLs are resolved
         
     | 
| 
      
 95 
     | 
    
         
            +
                #
         
     | 
| 
      
 96 
     | 
    
         
            +
                def base_uri
         
     | 
| 
      
 97 
     | 
    
         
            +
                  read_attr :base
         
     | 
| 
      
 98 
     | 
    
         
            +
                end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                ##
         
     | 
| 
      
 101 
     | 
    
         
            +
                # @param [String] uri the base URI to which relative URLs are resolved
         
     | 
| 
      
 102 
     | 
    
         
            +
                #
         
     | 
| 
      
 103 
     | 
    
         
            +
                def base_uri=(uri)
         
     | 
| 
      
 104 
     | 
    
         
            +
                  write_attr 'xml:base', uri
         
     | 
| 
      
 105 
     | 
    
         
            +
                end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                def to_doc
         
     | 
| 
      
 108 
     | 
    
         
            +
                  Nokogiri::XML::Document.new.tap do |doc|
         
     | 
| 
      
 109 
     | 
    
         
            +
                    doc << self
         
     | 
| 
      
 110 
     | 
    
         
            +
                  end
         
     | 
| 
      
 111 
     | 
    
         
            +
                end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                def +(other)
         
     | 
| 
      
 114 
     | 
    
         
            +
                  self.class.new(:base_uri => base_uri).tap do |new_element|
         
     | 
| 
      
 115 
     | 
    
         
            +
                    (self.children + other.children).each do |child|
         
     | 
| 
      
 116 
     | 
    
         
            +
                      new_element << child
         
     | 
| 
      
 117 
     | 
    
         
            +
                    end
         
     | 
| 
      
 118 
     | 
    
         
            +
                  end
         
     | 
| 
      
 119 
     | 
    
         
            +
                end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
       74 
121 
     | 
    
         
             
                def eval_dsl_block(&block)
         
     | 
| 
       75 
122 
     | 
    
         
             
                  return unless block_given?
         
     | 
| 
       76 
123 
     | 
    
         
             
                  @block_binding = eval "self", block.binding
         
     | 
| 
         @@ -106,19 +153,24 @@ module RubySpeech 
     | 
|
| 
       106 
153 
     | 
    
         
             
                  when self.class.module::Element
         
     | 
| 
       107 
154 
     | 
    
         
             
                    self << other
         
     | 
| 
       108 
155 
     | 
    
         
             
                  else
         
     | 
| 
       109 
     | 
    
         
            -
                    raise ArgumentError, "Can only embed a String or  
     | 
| 
      
 156 
     | 
    
         
            +
                    raise ArgumentError, "Can only embed a String or a #{self.class.module} element, not a #{other}"
         
     | 
| 
       110 
157 
     | 
    
         
             
                  end
         
     | 
| 
       111 
158 
     | 
    
         
             
                end
         
     | 
| 
       112 
159 
     | 
    
         | 
| 
       113 
160 
     | 
    
         
             
                def string(other)
         
     | 
| 
       114 
     | 
    
         
            -
                  self <<  
     | 
| 
      
 161 
     | 
    
         
            +
                  self << other
         
     | 
| 
      
 162 
     | 
    
         
            +
                end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                def <<(other)
         
     | 
| 
      
 165 
     | 
    
         
            +
                  other = encode_special_chars other if other.is_a? String
         
     | 
| 
      
 166 
     | 
    
         
            +
                  super other
         
     | 
| 
       115 
167 
     | 
    
         
             
                end
         
     | 
| 
       116 
168 
     | 
    
         | 
| 
       117 
169 
     | 
    
         
             
                def method_missing(method_name, *args, &block)
         
     | 
| 
       118 
170 
     | 
    
         
             
                  const_name = method_name.to_s.sub('ssml', '').titleize.gsub(' ', '')
         
     | 
| 
       119 
171 
     | 
    
         
             
                  if self.class.module.const_defined?(const_name)
         
     | 
| 
       120 
172 
     | 
    
         
             
                    const = self.class.module.const_get const_name
         
     | 
| 
       121 
     | 
    
         
            -
                     
     | 
| 
      
 173 
     | 
    
         
            +
                    embed const.new(*args, &block)
         
     | 
| 
       122 
174 
     | 
    
         
             
                  elsif @block_binding && @block_binding.respond_to?(method_name)
         
     | 
| 
       123 
175 
     | 
    
         
             
                    @block_binding.send method_name, *args, &block
         
     | 
| 
       124 
176 
     | 
    
         
             
                  else
         
     | 
| 
         @@ -126,6 +178,15 @@ module RubySpeech 
     | 
|
| 
       126 
178 
     | 
    
         
             
                  end
         
     | 
| 
       127 
179 
     | 
    
         
             
                end
         
     | 
| 
       128 
180 
     | 
    
         | 
| 
      
 181 
     | 
    
         
            +
                def clone
         
     | 
| 
      
 182 
     | 
    
         
            +
                  GRXML.import to_xml
         
     | 
| 
      
 183 
     | 
    
         
            +
                end
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
                def traverse(&block)
         
     | 
| 
      
 186 
     | 
    
         
            +
                  nokogiri_children.each { |j| j.traverse &block }
         
     | 
| 
      
 187 
     | 
    
         
            +
                  block.call self
         
     | 
| 
      
 188 
     | 
    
         
            +
                end
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
       129 
190 
     | 
    
         
             
                def eql?(o, *args)
         
     | 
| 
       130 
191 
     | 
    
         
             
                  super o, :content, :children, *args
         
     | 
| 
       131 
192 
     | 
    
         
             
                end
         
     | 
    
        data/lib/ruby_speech/grxml.rb
    CHANGED
    
    | 
         @@ -13,6 +13,9 @@ module RubySpeech 
     | 
|
| 
       13 
13 
     | 
    
         
             
                  autoload :Token
         
     | 
| 
       14 
14 
     | 
    
         
             
                end
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
      
 16 
     | 
    
         
            +
                autoload :Match
         
     | 
| 
      
 17 
     | 
    
         
            +
                autoload :NoMatch
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
       16 
19 
     | 
    
         
             
                InvalidChildError = Class.new StandardError
         
     | 
| 
       17 
20 
     | 
    
         | 
| 
       18 
21 
     | 
    
         
             
                GRXML_NAMESPACE = 'http://www.w3.org/2001/06/grammar'
         
     | 
| 
         @@ -21,7 +24,7 @@ module RubySpeech 
     | 
|
| 
       21 
24 
     | 
    
         
             
                  Grammar.new(attributes).tap do |grammar|
         
     | 
| 
       22 
25 
     | 
    
         
             
                    block_return = grammar.eval_dsl_block &block
         
     | 
| 
       23 
26 
     | 
    
         
             
                    grammar << block_return if block_return.is_a?(String)
         
     | 
| 
       24 
     | 
    
         
            -
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end.assert_has_matching_root_rule
         
     | 
| 
       25 
28 
     | 
    
         
             
                end
         
     | 
| 
       26 
29 
     | 
    
         | 
| 
       27 
30 
     | 
    
         
             
                def self.import(other)
         
     | 
| 
         @@ -18,37 +18,9 @@ module RubySpeech 
     | 
|
| 
       18 
18 
     | 
    
         | 
| 
       19 
19 
     | 
    
         
             
                  register :grammar
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
                   
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
                  ##
         
     | 
| 
       24 
     | 
    
         
            -
                  # Create a new GRXML grammar root element
         
     | 
| 
       25 
     | 
    
         
            -
                  #
         
     | 
| 
       26 
     | 
    
         
            -
                  # @param [Hash] atts Key-value pairs of options mapping to setter methods
         
     | 
| 
       27 
     | 
    
         
            -
                  #
         
     | 
| 
       28 
     | 
    
         
            -
                  # @return [Grammar] an element for use in an GRXML document
         
     | 
| 
       29 
     | 
    
         
            -
                  #
         
     | 
| 
       30 
     | 
    
         
            -
                  def self.new(atts = {}, &block)
         
     | 
| 
       31 
     | 
    
         
            -
                    new_node = super('grammar', atts)
         
     | 
| 
       32 
     | 
    
         
            -
                    new_node[:version] = '1.0'
         
     | 
| 
       33 
     | 
    
         
            -
                    new_node.namespace = GRXML_NAMESPACE
         
     | 
| 
       34 
     | 
    
         
            -
                    new_node.language ||= "en-US"
         
     | 
| 
       35 
     | 
    
         
            -
                    new_node.eval_dsl_block &block
         
     | 
| 
       36 
     | 
    
         
            -
                    new_node
         
     | 
| 
       37 
     | 
    
         
            -
                  end
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                  ##
         
     | 
| 
       40 
     | 
    
         
            -
                  # @return [String] the base URI to which relative URLs are resolved
         
     | 
| 
       41 
     | 
    
         
            -
                  #
         
     | 
| 
       42 
     | 
    
         
            -
                  def base_uri
         
     | 
| 
       43 
     | 
    
         
            -
                    read_attr :base
         
     | 
| 
       44 
     | 
    
         
            -
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                  self.defaults = { :version => '1.0', :language => "en-US" }
         
     | 
| 
       45 
22 
     | 
    
         | 
| 
       46 
     | 
    
         
            -
                   
     | 
| 
       47 
     | 
    
         
            -
                  # @param [String] uri the base URI to which relative URLs are resolved
         
     | 
| 
       48 
     | 
    
         
            -
                  #
         
     | 
| 
       49 
     | 
    
         
            -
                  def base_uri=(uri)
         
     | 
| 
       50 
     | 
    
         
            -
                    write_attr 'xml:base', uri
         
     | 
| 
       51 
     | 
    
         
            -
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
                  VALID_CHILD_TYPES = [Nokogiri::XML::Element, Nokogiri::XML::Text, Rule, Tag].freeze
         
     | 
| 
       52 
24 
     | 
    
         | 
| 
       53 
25 
     | 
    
         
             
                  ##
         
     | 
| 
       54 
26 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -57,7 +29,7 @@ module RubySpeech 
     | 
|
| 
       57 
29 
     | 
    
         
             
                  # @return [String]
         
     | 
| 
       58 
30 
     | 
    
         
             
                  #
         
     | 
| 
       59 
31 
     | 
    
         
             
                  def mode
         
     | 
| 
       60 
     | 
    
         
            -
                    read_attr :mode
         
     | 
| 
      
 32 
     | 
    
         
            +
                    read_attr :mode, :to_sym
         
     | 
| 
       61 
33 
     | 
    
         
             
                  end
         
     | 
| 
       62 
34 
     | 
    
         | 
| 
       63 
35 
     | 
    
         
             
                  ##
         
     | 
| 
         @@ -84,17 +56,6 @@ module RubySpeech 
     | 
|
| 
       84 
56 
     | 
    
         
             
                    write_attr :root, ia
         
     | 
| 
       85 
57 
     | 
    
         
             
                  end
         
     | 
| 
       86 
58 
     | 
    
         | 
| 
       87 
     | 
    
         
            -
                  def <<(arg)
         
     | 
| 
       88 
     | 
    
         
            -
                    raise InvalidChildError, "A Grammar can only accept Rule and Tag as children" unless VALID_CHILD_TYPES.include? arg.class
         
     | 
| 
       89 
     | 
    
         
            -
                    super
         
     | 
| 
       90 
     | 
    
         
            -
                  end
         
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
       92 
     | 
    
         
            -
                  def to_doc
         
     | 
| 
       93 
     | 
    
         
            -
                    Nokogiri::XML::Document.new.tap do |doc|
         
     | 
| 
       94 
     | 
    
         
            -
                      doc << self
         
     | 
| 
       95 
     | 
    
         
            -
                    end
         
     | 
| 
       96 
     | 
    
         
            -
                  end
         
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
59 
     | 
    
         
             
                  ##
         
     | 
| 
       99 
60 
     | 
    
         
             
                  #
         
     | 
| 
       100 
61 
     | 
    
         
             
                  # @return [String]
         
     | 
| 
         @@ -110,11 +71,39 @@ module RubySpeech 
     | 
|
| 
       110 
71 
     | 
    
         
             
                    write_attr :'tag-format', s
         
     | 
| 
       111 
72 
     | 
    
         
             
                  end
         
     | 
| 
       112 
73 
     | 
    
         | 
| 
      
 74 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 75 
     | 
    
         
            +
                  # @return [Rule] The root rule node for the document
         
     | 
| 
      
 76 
     | 
    
         
            +
                  #
         
     | 
| 
       113 
77 
     | 
    
         
             
                  def root_rule
         
     | 
| 
       114 
78 
     | 
    
         
             
                    children(:rule, :id => root).first
         
     | 
| 
       115 
79 
     | 
    
         
             
                  end
         
     | 
| 
       116 
80 
     | 
    
         | 
| 
      
 81 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 82 
     | 
    
         
            +
                  # Checks for a root rule matching the value of the root tag
         
     | 
| 
      
 83 
     | 
    
         
            +
                  #
         
     | 
| 
      
 84 
     | 
    
         
            +
                  # @raises [InvalidChildError] if there is not a rule present in the document with the correct ID
         
     | 
| 
      
 85 
     | 
    
         
            +
                  #
         
     | 
| 
      
 86 
     | 
    
         
            +
                  # @return [Grammar] self
         
     | 
| 
      
 87 
     | 
    
         
            +
                  #
         
     | 
| 
      
 88 
     | 
    
         
            +
                  def assert_has_matching_root_rule
         
     | 
| 
      
 89 
     | 
    
         
            +
                    raise InvalidChildError, "A GRXML document must have a rule matching the root rule name" unless has_matching_root_rule?
         
     | 
| 
      
 90 
     | 
    
         
            +
                    self
         
     | 
| 
      
 91 
     | 
    
         
            +
                  end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 94 
     | 
    
         
            +
                  # @return [Grammar] an inlined copy of self
         
     | 
| 
      
 95 
     | 
    
         
            +
                  #
         
     | 
| 
       117 
96 
     | 
    
         
             
                  def inline
         
     | 
| 
      
 97 
     | 
    
         
            +
                    clone.inline!
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 101 
     | 
    
         
            +
                  # Replaces rulerefs in the document with a copy of the original rule.
         
     | 
| 
      
 102 
     | 
    
         
            +
                  # Removes all top level rules except the root rule
         
     | 
| 
      
 103 
     | 
    
         
            +
                  #
         
     | 
| 
      
 104 
     | 
    
         
            +
                  # @return self
         
     | 
| 
      
 105 
     | 
    
         
            +
                  #
         
     | 
| 
      
 106 
     | 
    
         
            +
                  def inline!
         
     | 
| 
       118 
107 
     | 
    
         
             
                    find("//ns:ruleref", :ns => namespace_href).each do |ref|
         
     | 
| 
       119 
108 
     | 
    
         
             
                      rule = children(:rule, :id => ref[:uri].sub(/^#/, '')).first
         
     | 
| 
       120 
109 
     | 
    
         
             
                      ref.swap rule.nokogiri_children
         
     | 
| 
         @@ -126,17 +115,159 @@ module RubySpeech 
     | 
|
| 
       126 
115 
     | 
    
         
             
                    self
         
     | 
| 
       127 
116 
     | 
    
         
             
                  end
         
     | 
| 
       128 
117 
     | 
    
         | 
| 
       129 
     | 
    
         
            -
                   
     | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
       132 
     | 
    
         
            -
             
     | 
| 
      
 118 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 119 
     | 
    
         
            +
                  # Replaces textual content of the document with token elements containing such content.
         
     | 
| 
      
 120 
     | 
    
         
            +
                  # This homogenises all tokens in the document to a consistent format for processing.
         
     | 
| 
      
 121 
     | 
    
         
            +
                  #
         
     | 
| 
      
 122 
     | 
    
         
            +
                  def tokenize!
         
     | 
| 
      
 123 
     | 
    
         
            +
                    traverse do |element|
         
     | 
| 
      
 124 
     | 
    
         
            +
                      next unless element.is_a? Nokogiri::XML::Text
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                      next if self.class.import(element.parent).is_a? Token
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                      tokens = split_tokens(element).map do |string|
         
     | 
| 
      
 129 
     | 
    
         
            +
                        Token.new.tap { |token| token << string }
         
     | 
| 
       133 
130 
     | 
    
         
             
                      end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                      element.swap Nokogiri::XML::NodeSet.new(Nokogiri::XML::Document.new, tokens)
         
     | 
| 
       134 
133 
     | 
    
         
             
                    end
         
     | 
| 
       135 
134 
     | 
    
         
             
                  end
         
     | 
| 
       136 
135 
     | 
    
         | 
| 
      
 136 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 137 
     | 
    
         
            +
                  # Normalizes whitespace within tokens in the document according to the rules in the SRGS spec (http://www.w3.org/TR/speech-grammar/#S2.1)
         
     | 
| 
      
 138 
     | 
    
         
            +
                  # Leading and trailing whitespace is removed, and multiple spaces within the string are collapsed down to single spaces.
         
     | 
| 
      
 139 
     | 
    
         
            +
                  #
         
     | 
| 
      
 140 
     | 
    
         
            +
                  def normalize_whitespace
         
     | 
| 
      
 141 
     | 
    
         
            +
                    traverse do |element|
         
     | 
| 
      
 142 
     | 
    
         
            +
                      next if element === self
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                      imported_element = self.class.import element
         
     | 
| 
      
 145 
     | 
    
         
            +
                      next unless imported_element.respond_to? :normalize_whitespace
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                      imported_element.normalize_whitespace
         
     | 
| 
      
 148 
     | 
    
         
            +
                      element.swap imported_element
         
     | 
| 
      
 149 
     | 
    
         
            +
                    end
         
     | 
| 
      
 150 
     | 
    
         
            +
                  end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 153 
     | 
    
         
            +
                  # Checks the grammar for a match against an input string
         
     | 
| 
      
 154 
     | 
    
         
            +
                  #
         
     | 
| 
      
 155 
     | 
    
         
            +
                  # @param [String] other the input string to check for a match with the grammar
         
     | 
| 
      
 156 
     | 
    
         
            +
                  #
         
     | 
| 
      
 157 
     | 
    
         
            +
                  # @return [NoMatch, Match] depending on the result of a match attempt. If a match can be found, it will be returned with appropriate mode/confidence/utterance and interpretation attributes
         
     | 
| 
      
 158 
     | 
    
         
            +
                  #
         
     | 
| 
      
 159 
     | 
    
         
            +
                  # @example A grammar that takes a 4 digit pin terminated by hash, or the *9 escape sequence
         
     | 
| 
      
 160 
     | 
    
         
            +
                  #     ```ruby
         
     | 
| 
      
 161 
     | 
    
         
            +
                  #       grammar = RubySpeech::GRXML.draw :mode => :dtmf, :root => 'pin' do
         
     | 
| 
      
 162 
     | 
    
         
            +
                  #         rule :id => 'digit' do
         
     | 
| 
      
 163 
     | 
    
         
            +
                  #           one_of do
         
     | 
| 
      
 164 
     | 
    
         
            +
                  #             ('0'..'9').map { |d| item { d } }
         
     | 
| 
      
 165 
     | 
    
         
            +
                  #           end
         
     | 
| 
      
 166 
     | 
    
         
            +
                  #         end
         
     | 
| 
      
 167 
     | 
    
         
            +
                  #
         
     | 
| 
      
 168 
     | 
    
         
            +
                  #         rule :id => 'pin', :scope => 'public' do
         
     | 
| 
      
 169 
     | 
    
         
            +
                  #           one_of do
         
     | 
| 
      
 170 
     | 
    
         
            +
                  #             item do
         
     | 
| 
      
 171 
     | 
    
         
            +
                  #               item :repeat => '4' do
         
     | 
| 
      
 172 
     | 
    
         
            +
                  #                 ruleref :uri => '#digit'
         
     | 
| 
      
 173 
     | 
    
         
            +
                  #               end
         
     | 
| 
      
 174 
     | 
    
         
            +
                  #               "#"
         
     | 
| 
      
 175 
     | 
    
         
            +
                  #             end
         
     | 
| 
      
 176 
     | 
    
         
            +
                  #             item do
         
     | 
| 
      
 177 
     | 
    
         
            +
                  #               "\* 9"
         
     | 
| 
      
 178 
     | 
    
         
            +
                  #             end
         
     | 
| 
      
 179 
     | 
    
         
            +
                  #           end
         
     | 
| 
      
 180 
     | 
    
         
            +
                  #         end
         
     | 
| 
      
 181 
     | 
    
         
            +
                  #       end
         
     | 
| 
      
 182 
     | 
    
         
            +
                  #
         
     | 
| 
      
 183 
     | 
    
         
            +
                  #       >> subject.match '*9'
         
     | 
| 
      
 184 
     | 
    
         
            +
                  #       => #<RubySpeech::GRXML::Match:0x00000100ae5d98
         
     | 
| 
      
 185 
     | 
    
         
            +
                  #             @mode = :dtmf,
         
     | 
| 
      
 186 
     | 
    
         
            +
                  #             @confidence = 1,
         
     | 
| 
      
 187 
     | 
    
         
            +
                  #             @utterance = "*9",
         
     | 
| 
      
 188 
     | 
    
         
            +
                  #             @interpretation = "*9"
         
     | 
| 
      
 189 
     | 
    
         
            +
                  #           >
         
     | 
| 
      
 190 
     | 
    
         
            +
                  #       >> subject.match '1234#'
         
     | 
| 
      
 191 
     | 
    
         
            +
                  #       => #<RubySpeech::GRXML::Match:0x00000100b7e020
         
     | 
| 
      
 192 
     | 
    
         
            +
                  #             @mode = :dtmf,
         
     | 
| 
      
 193 
     | 
    
         
            +
                  #             @confidence = 1,
         
     | 
| 
      
 194 
     | 
    
         
            +
                  #             @utterance = "1234#",
         
     | 
| 
      
 195 
     | 
    
         
            +
                  #             @interpretation = "1234#"
         
     | 
| 
      
 196 
     | 
    
         
            +
                  #           >
         
     | 
| 
      
 197 
     | 
    
         
            +
                  #       >> subject.match '111'
         
     | 
| 
      
 198 
     | 
    
         
            +
                  #       => #<RubySpeech::GRXML::NoMatch:0x00000101371660>
         
     | 
| 
      
 199 
     | 
    
         
            +
                  #
         
     | 
| 
      
 200 
     | 
    
         
            +
                  #     ```
         
     | 
| 
      
 201 
     | 
    
         
            +
                  #
         
     | 
| 
      
 202 
     | 
    
         
            +
                  def match(other)
         
     | 
| 
      
 203 
     | 
    
         
            +
                    regex = to_regexp
         
     | 
| 
      
 204 
     | 
    
         
            +
                    return NoMatch.new if regex == //
         
     | 
| 
      
 205 
     | 
    
         
            +
                    match = regex.match other
         
     | 
| 
      
 206 
     | 
    
         
            +
                    return NoMatch.new unless match
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
                    Match.new :mode           => mode,
         
     | 
| 
      
 209 
     | 
    
         
            +
                              :confidence     => dtmf? ? 1 : 0,
         
     | 
| 
      
 210 
     | 
    
         
            +
                              :utterance      => other,
         
     | 
| 
      
 211 
     | 
    
         
            +
                              :interpretation => interpret_utterance(other)
         
     | 
| 
      
 212 
     | 
    
         
            +
                  end
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 215 
     | 
    
         
            +
                  # Converts the grammar into a regular expression for matching
         
     | 
| 
      
 216 
     | 
    
         
            +
                  #
         
     | 
| 
      
 217 
     | 
    
         
            +
                  # @return [Regexp] a regular expression which is equivalent to the grammar
         
     | 
| 
      
 218 
     | 
    
         
            +
                  #
         
     | 
| 
      
 219 
     | 
    
         
            +
                  def to_regexp
         
     | 
| 
      
 220 
     | 
    
         
            +
                    /^#{regexp_content.join}$/
         
     | 
| 
      
 221 
     | 
    
         
            +
                  end
         
     | 
| 
      
 222 
     | 
    
         
            +
             
     | 
| 
      
 223 
     | 
    
         
            +
                  def regexp_content
         
     | 
| 
      
 224 
     | 
    
         
            +
                    root_rule.children.map &:regexp_content
         
     | 
| 
      
 225 
     | 
    
         
            +
                  end
         
     | 
| 
      
 226 
     | 
    
         
            +
             
     | 
| 
      
 227 
     | 
    
         
            +
                  def dtmf?
         
     | 
| 
      
 228 
     | 
    
         
            +
                    mode == :dtmf
         
     | 
| 
      
 229 
     | 
    
         
            +
                  end
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
                  def voice?
         
     | 
| 
      
 232 
     | 
    
         
            +
                    mode == :voice
         
     | 
| 
      
 233 
     | 
    
         
            +
                  end
         
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
                  def <<(arg)
         
     | 
| 
      
 236 
     | 
    
         
            +
                    raise InvalidChildError, "A Grammar can only accept Rule and Tag as children" unless VALID_CHILD_TYPES.include? arg.class
         
     | 
| 
      
 237 
     | 
    
         
            +
                    super
         
     | 
| 
      
 238 
     | 
    
         
            +
                  end
         
     | 
| 
      
 239 
     | 
    
         
            +
             
     | 
| 
       137 
240 
     | 
    
         
             
                  def eql?(o)
         
     | 
| 
       138 
241 
     | 
    
         
             
                    super o, :language, :base_uri, :mode, :root
         
     | 
| 
       139 
242 
     | 
    
         
             
                  end
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
                  def embed(other)
         
     | 
| 
      
 245 
     | 
    
         
            +
                    raise InvalidChildError, "Embedded grammars must have the same mode" if other.is_a?(self.class) && other.mode != mode
         
     | 
| 
      
 246 
     | 
    
         
            +
                    super
         
     | 
| 
      
 247 
     | 
    
         
            +
                  end
         
     | 
| 
      
 248 
     | 
    
         
            +
             
     | 
| 
      
 249 
     | 
    
         
            +
                  private
         
     | 
| 
      
 250 
     | 
    
         
            +
             
     | 
| 
      
 251 
     | 
    
         
            +
                  def has_matching_root_rule?
         
     | 
| 
      
 252 
     | 
    
         
            +
                    !root || root_rule
         
     | 
| 
      
 253 
     | 
    
         
            +
                  end
         
     | 
| 
      
 254 
     | 
    
         
            +
             
     | 
| 
      
 255 
     | 
    
         
            +
                  def interpret_utterance(utterance)
         
     | 
| 
      
 256 
     | 
    
         
            +
                    conversion = Hash.new { |hash, key| hash[key] = key }
         
     | 
| 
      
 257 
     | 
    
         
            +
                    conversion['*'] = 'star'
         
     | 
| 
      
 258 
     | 
    
         
            +
                    conversion['#'] = 'pound'
         
     | 
| 
      
 259 
     | 
    
         
            +
             
     | 
| 
      
 260 
     | 
    
         
            +
                    utterance.chars.inject [] do |array, digit|
         
     | 
| 
      
 261 
     | 
    
         
            +
                      array << "dtmf-#{conversion[digit]}"
         
     | 
| 
      
 262 
     | 
    
         
            +
                    end.join ' '
         
     | 
| 
      
 263 
     | 
    
         
            +
                  end
         
     | 
| 
      
 264 
     | 
    
         
            +
             
     | 
| 
      
 265 
     | 
    
         
            +
                  def split_tokens(element)
         
     | 
| 
      
 266 
     | 
    
         
            +
                    element.to_s.split(/(\".*\")/).reject(&:empty?).map do |string|
         
     | 
| 
      
 267 
     | 
    
         
            +
                      match = string.match /^\"(.*)\"$/
         
     | 
| 
      
 268 
     | 
    
         
            +
                      match ? match[1] : string.split(' ')
         
     | 
| 
      
 269 
     | 
    
         
            +
                    end.flatten
         
     | 
| 
      
 270 
     | 
    
         
            +
                  end
         
     | 
| 
       140 
271 
     | 
    
         
             
                end # Grammar
         
     | 
| 
       141 
272 
     | 
    
         
             
              end # GRXML
         
     | 
| 
       142 
273 
     | 
    
         
             
            end # RubySpeech
         
     |