ruby_speech 2.1.0-java
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/.gitignore +12 -0
- data/.rspec +3 -0
- data/.travis.yml +17 -0
- data/CHANGELOG.md +144 -0
- data/Gemfile +3 -0
- data/Guardfile +9 -0
- data/LICENSE.md +20 -0
- data/README.md +314 -0
- data/Rakefile +34 -0
- data/assets/grammar-core.xsd +317 -0
- data/assets/grammar.xsd +37 -0
- data/assets/synthesis-core.xsd +445 -0
- data/assets/synthesis.xsd +63 -0
- data/assets/xml.xsd +287 -0
- data/ext/ruby_speech/RubySpeechGRXMLMatcher.java +64 -0
- data/ext/ruby_speech/RubySpeechService.java +23 -0
- data/ext/ruby_speech/extconf.rb +7 -0
- data/ext/ruby_speech/ruby_speech.c +97 -0
- data/lib/ruby_speech/generic_element.rb +169 -0
- data/lib/ruby_speech/grxml/element.rb +29 -0
- data/lib/ruby_speech/grxml/grammar.rb +189 -0
- data/lib/ruby_speech/grxml/item.rb +144 -0
- data/lib/ruby_speech/grxml/match.rb +16 -0
- data/lib/ruby_speech/grxml/matcher.rb +126 -0
- data/lib/ruby_speech/grxml/max_match.rb +6 -0
- data/lib/ruby_speech/grxml/no_match.rb +10 -0
- data/lib/ruby_speech/grxml/one_of.rb +31 -0
- data/lib/ruby_speech/grxml/potential_match.rb +10 -0
- data/lib/ruby_speech/grxml/rule.rb +73 -0
- data/lib/ruby_speech/grxml/ruleref.rb +69 -0
- data/lib/ruby_speech/grxml/tag.rb +29 -0
- data/lib/ruby_speech/grxml/token.rb +31 -0
- data/lib/ruby_speech/grxml.rb +39 -0
- data/lib/ruby_speech/nlsml/builder.rb +34 -0
- data/lib/ruby_speech/nlsml/document.rb +120 -0
- data/lib/ruby_speech/nlsml.rb +18 -0
- data/lib/ruby_speech/ruby_speech.jar +0 -0
- data/lib/ruby_speech/ssml/audio.rb +47 -0
- data/lib/ruby_speech/ssml/break.rb +62 -0
- data/lib/ruby_speech/ssml/desc.rb +24 -0
- data/lib/ruby_speech/ssml/element.rb +23 -0
- data/lib/ruby_speech/ssml/emphasis.rb +44 -0
- 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 +172 -0
- data/lib/ruby_speech/ssml/s.rb +25 -0
- data/lib/ruby_speech/ssml/say_as.rb +100 -0
- data/lib/ruby_speech/ssml/speak.rb +27 -0
- data/lib/ruby_speech/ssml/sub.rb +42 -0
- data/lib/ruby_speech/ssml/voice.rb +108 -0
- data/lib/ruby_speech/ssml.rb +39 -0
- data/lib/ruby_speech/version.rb +3 -0
- data/lib/ruby_speech/xml/language.rb +13 -0
- data/lib/ruby_speech/xml.rb +11 -0
- data/lib/ruby_speech.rb +36 -0
- data/ruby_speech.gemspec +42 -0
- data/spec/ruby_speech/grxml/grammar_spec.rb +341 -0
- data/spec/ruby_speech/grxml/item_spec.rb +192 -0
- data/spec/ruby_speech/grxml/match_spec.rb +15 -0
- data/spec/ruby_speech/grxml/matcher_spec.rb +688 -0
- data/spec/ruby_speech/grxml/max_match_spec.rb +17 -0
- data/spec/ruby_speech/grxml/no_match_spec.rb +17 -0
- data/spec/ruby_speech/grxml/one_of_spec.rb +49 -0
- data/spec/ruby_speech/grxml/potential_match_spec.rb +17 -0
- data/spec/ruby_speech/grxml/rule_spec.rb +125 -0
- data/spec/ruby_speech/grxml/ruleref_spec.rb +55 -0
- data/spec/ruby_speech/grxml/tag_spec.rb +41 -0
- data/spec/ruby_speech/grxml/token_spec.rb +62 -0
- data/spec/ruby_speech/grxml_spec.rb +339 -0
- data/spec/ruby_speech/nlsml_spec.rb +353 -0
- data/spec/ruby_speech/ssml/audio_spec.rb +121 -0
- data/spec/ruby_speech/ssml/break_spec.rb +100 -0
- data/spec/ruby_speech/ssml/desc_spec.rb +57 -0
- data/spec/ruby_speech/ssml/emphasis_spec.rb +110 -0
- 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 +309 -0
- data/spec/ruby_speech/ssml/s_spec.rb +92 -0
- data/spec/ruby_speech/ssml/say_as_spec.rb +71 -0
- data/spec/ruby_speech/ssml/speak_spec.rb +166 -0
- data/spec/ruby_speech/ssml/sub_spec.rb +57 -0
- data/spec/ruby_speech/ssml/voice_spec.rb +200 -0
- data/spec/ruby_speech/ssml_spec.rb +285 -0
- data/spec/ruby_speech_spec.rb +124 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/support/match_examples.rb +43 -0
- data/spec/support/matchers.rb +46 -0
- metadata +405 -0
data/assets/xml.xsd
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
<?xml version='1.0'?>
|
|
2
|
+
<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?>
|
|
3
|
+
<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace"
|
|
4
|
+
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
5
|
+
xmlns ="http://www.w3.org/1999/xhtml"
|
|
6
|
+
xml:lang="en">
|
|
7
|
+
|
|
8
|
+
<xs:annotation>
|
|
9
|
+
<xs:documentation>
|
|
10
|
+
<div>
|
|
11
|
+
<h1>About the XML namespace</h1>
|
|
12
|
+
|
|
13
|
+
<div class="bodytext">
|
|
14
|
+
<p>
|
|
15
|
+
This schema document describes the XML namespace, in a form
|
|
16
|
+
suitable for import by other schema documents.
|
|
17
|
+
</p>
|
|
18
|
+
<p>
|
|
19
|
+
See <a href="http://www.w3.org/XML/1998/namespace.html">
|
|
20
|
+
http://www.w3.org/XML/1998/namespace.html</a> and
|
|
21
|
+
<a href="http://www.w3.org/TR/REC-xml">
|
|
22
|
+
http://www.w3.org/TR/REC-xml</a> for information
|
|
23
|
+
about this namespace.
|
|
24
|
+
</p>
|
|
25
|
+
<p>
|
|
26
|
+
Note that local names in this namespace are intended to be
|
|
27
|
+
defined only by the World Wide Web Consortium or its subgroups.
|
|
28
|
+
The names currently defined in this namespace are listed below.
|
|
29
|
+
They should not be used with conflicting semantics by any Working
|
|
30
|
+
Group, specification, or document instance.
|
|
31
|
+
</p>
|
|
32
|
+
<p>
|
|
33
|
+
See further below in this document for more information about <a
|
|
34
|
+
href="#usage">how to refer to this schema document from your own
|
|
35
|
+
XSD schema documents</a> and about <a href="#nsversioning">the
|
|
36
|
+
namespace-versioning policy governing this schema document</a>.
|
|
37
|
+
</p>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</xs:documentation>
|
|
41
|
+
</xs:annotation>
|
|
42
|
+
|
|
43
|
+
<xs:attribute name="lang">
|
|
44
|
+
<xs:annotation>
|
|
45
|
+
<xs:documentation>
|
|
46
|
+
<div>
|
|
47
|
+
|
|
48
|
+
<h3>lang (as an attribute name)</h3>
|
|
49
|
+
<p>
|
|
50
|
+
denotes an attribute whose value
|
|
51
|
+
is a language code for the natural language of the content of
|
|
52
|
+
any element; its value is inherited. This name is reserved
|
|
53
|
+
by virtue of its definition in the XML specification.</p>
|
|
54
|
+
|
|
55
|
+
</div>
|
|
56
|
+
<div>
|
|
57
|
+
<h4>Notes</h4>
|
|
58
|
+
<p>
|
|
59
|
+
Attempting to install the relevant ISO 2- and 3-letter
|
|
60
|
+
codes as the enumerated possible values is probably never
|
|
61
|
+
going to be a realistic possibility.
|
|
62
|
+
</p>
|
|
63
|
+
<p>
|
|
64
|
+
See BCP 47 at <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
|
|
65
|
+
http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>
|
|
66
|
+
and the IANA language subtag registry at
|
|
67
|
+
<a href="http://www.iana.org/assignments/language-subtag-registry">
|
|
68
|
+
http://www.iana.org/assignments/language-subtag-registry</a>
|
|
69
|
+
for further information.
|
|
70
|
+
</p>
|
|
71
|
+
<p>
|
|
72
|
+
The union allows for the 'un-declaration' of xml:lang with
|
|
73
|
+
the empty string.
|
|
74
|
+
</p>
|
|
75
|
+
</div>
|
|
76
|
+
</xs:documentation>
|
|
77
|
+
</xs:annotation>
|
|
78
|
+
<xs:simpleType>
|
|
79
|
+
<xs:union memberTypes="xs:language">
|
|
80
|
+
<xs:simpleType>
|
|
81
|
+
<xs:restriction base="xs:string">
|
|
82
|
+
<xs:enumeration value=""/>
|
|
83
|
+
</xs:restriction>
|
|
84
|
+
</xs:simpleType>
|
|
85
|
+
</xs:union>
|
|
86
|
+
</xs:simpleType>
|
|
87
|
+
</xs:attribute>
|
|
88
|
+
|
|
89
|
+
<xs:attribute name="space">
|
|
90
|
+
<xs:annotation>
|
|
91
|
+
<xs:documentation>
|
|
92
|
+
<div>
|
|
93
|
+
|
|
94
|
+
<h3>space (as an attribute name)</h3>
|
|
95
|
+
<p>
|
|
96
|
+
denotes an attribute whose
|
|
97
|
+
value is a keyword indicating what whitespace processing
|
|
98
|
+
discipline is intended for the content of the element; its
|
|
99
|
+
value is inherited. This name is reserved by virtue of its
|
|
100
|
+
definition in the XML specification.</p>
|
|
101
|
+
|
|
102
|
+
</div>
|
|
103
|
+
</xs:documentation>
|
|
104
|
+
</xs:annotation>
|
|
105
|
+
<xs:simpleType>
|
|
106
|
+
<xs:restriction base="xs:NCName">
|
|
107
|
+
<xs:enumeration value="default"/>
|
|
108
|
+
<xs:enumeration value="preserve"/>
|
|
109
|
+
</xs:restriction>
|
|
110
|
+
</xs:simpleType>
|
|
111
|
+
</xs:attribute>
|
|
112
|
+
|
|
113
|
+
<xs:attribute name="base" type="xs:anyURI"> <xs:annotation>
|
|
114
|
+
<xs:documentation>
|
|
115
|
+
<div>
|
|
116
|
+
|
|
117
|
+
<h3>base (as an attribute name)</h3>
|
|
118
|
+
<p>
|
|
119
|
+
denotes an attribute whose value
|
|
120
|
+
provides a URI to be used as the base for interpreting any
|
|
121
|
+
relative URIs in the scope of the element on which it
|
|
122
|
+
appears; its value is inherited. This name is reserved
|
|
123
|
+
by virtue of its definition in the XML Base specification.</p>
|
|
124
|
+
|
|
125
|
+
<p>
|
|
126
|
+
See <a
|
|
127
|
+
href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a>
|
|
128
|
+
for information about this attribute.
|
|
129
|
+
</p>
|
|
130
|
+
</div>
|
|
131
|
+
</xs:documentation>
|
|
132
|
+
</xs:annotation>
|
|
133
|
+
</xs:attribute>
|
|
134
|
+
|
|
135
|
+
<xs:attribute name="id" type="xs:ID">
|
|
136
|
+
<xs:annotation>
|
|
137
|
+
<xs:documentation>
|
|
138
|
+
<div>
|
|
139
|
+
|
|
140
|
+
<h3>id (as an attribute name)</h3>
|
|
141
|
+
<p>
|
|
142
|
+
denotes an attribute whose value
|
|
143
|
+
should be interpreted as if declared to be of type ID.
|
|
144
|
+
This name is reserved by virtue of its definition in the
|
|
145
|
+
xml:id specification.</p>
|
|
146
|
+
|
|
147
|
+
<p>
|
|
148
|
+
See <a
|
|
149
|
+
href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a>
|
|
150
|
+
for information about this attribute.
|
|
151
|
+
</p>
|
|
152
|
+
</div>
|
|
153
|
+
</xs:documentation>
|
|
154
|
+
</xs:annotation>
|
|
155
|
+
</xs:attribute>
|
|
156
|
+
|
|
157
|
+
<xs:attributeGroup name="specialAttrs">
|
|
158
|
+
<xs:attribute ref="xml:base"/>
|
|
159
|
+
<xs:attribute ref="xml:lang"/>
|
|
160
|
+
<xs:attribute ref="xml:space"/>
|
|
161
|
+
<xs:attribute ref="xml:id"/>
|
|
162
|
+
</xs:attributeGroup>
|
|
163
|
+
|
|
164
|
+
<xs:annotation>
|
|
165
|
+
<xs:documentation>
|
|
166
|
+
<div>
|
|
167
|
+
|
|
168
|
+
<h3>Father (in any context at all)</h3>
|
|
169
|
+
|
|
170
|
+
<div class="bodytext">
|
|
171
|
+
<p>
|
|
172
|
+
denotes Jon Bosak, the chair of
|
|
173
|
+
the original XML Working Group. This name is reserved by
|
|
174
|
+
the following decision of the W3C XML Plenary and
|
|
175
|
+
XML Coordination groups:
|
|
176
|
+
</p>
|
|
177
|
+
<blockquote>
|
|
178
|
+
<p>
|
|
179
|
+
In appreciation for his vision, leadership and
|
|
180
|
+
dedication the W3C XML Plenary on this 10th day of
|
|
181
|
+
February, 2000, reserves for Jon Bosak in perpetuity
|
|
182
|
+
the XML name "xml:Father".
|
|
183
|
+
</p>
|
|
184
|
+
</blockquote>
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
</xs:documentation>
|
|
188
|
+
</xs:annotation>
|
|
189
|
+
|
|
190
|
+
<xs:annotation>
|
|
191
|
+
<xs:documentation>
|
|
192
|
+
<div xml:id="usage" id="usage">
|
|
193
|
+
<h2><a name="usage">About this schema document</a></h2>
|
|
194
|
+
|
|
195
|
+
<div class="bodytext">
|
|
196
|
+
<p>
|
|
197
|
+
This schema defines attributes and an attribute group suitable
|
|
198
|
+
for use by schemas wishing to allow <code>xml:base</code>,
|
|
199
|
+
<code>xml:lang</code>, <code>xml:space</code> or
|
|
200
|
+
<code>xml:id</code> attributes on elements they define.
|
|
201
|
+
</p>
|
|
202
|
+
<p>
|
|
203
|
+
To enable this, such a schema must import this schema for
|
|
204
|
+
the XML namespace, e.g. as follows:
|
|
205
|
+
</p>
|
|
206
|
+
<pre>
|
|
207
|
+
<schema . . .>
|
|
208
|
+
. . .
|
|
209
|
+
<import namespace="http://www.w3.org/XML/1998/namespace"
|
|
210
|
+
schemaLocation="http://www.w3.org/2001/xml.xsd"/>
|
|
211
|
+
</pre>
|
|
212
|
+
<p>
|
|
213
|
+
or
|
|
214
|
+
</p>
|
|
215
|
+
<pre>
|
|
216
|
+
<import namespace="http://www.w3.org/XML/1998/namespace"
|
|
217
|
+
schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
|
|
218
|
+
</pre>
|
|
219
|
+
<p>
|
|
220
|
+
Subsequently, qualified reference to any of the attributes or the
|
|
221
|
+
group defined below will have the desired effect, e.g.
|
|
222
|
+
</p>
|
|
223
|
+
<pre>
|
|
224
|
+
<type . . .>
|
|
225
|
+
. . .
|
|
226
|
+
<attributeGroup ref="xml:specialAttrs"/>
|
|
227
|
+
</pre>
|
|
228
|
+
<p>
|
|
229
|
+
will define a type which will schema-validate an instance element
|
|
230
|
+
with any of those attributes.
|
|
231
|
+
</p>
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
234
|
+
</xs:documentation>
|
|
235
|
+
</xs:annotation>
|
|
236
|
+
|
|
237
|
+
<xs:annotation>
|
|
238
|
+
<xs:documentation>
|
|
239
|
+
<div id="nsversioning" xml:id="nsversioning">
|
|
240
|
+
<h2><a name="nsversioning">Versioning policy for this schema document</a></h2>
|
|
241
|
+
<div class="bodytext">
|
|
242
|
+
<p>
|
|
243
|
+
In keeping with the XML Schema WG's standard versioning
|
|
244
|
+
policy, this schema document will persist at
|
|
245
|
+
<a href="http://www.w3.org/2009/01/xml.xsd">
|
|
246
|
+
http://www.w3.org/2009/01/xml.xsd</a>.
|
|
247
|
+
</p>
|
|
248
|
+
<p>
|
|
249
|
+
At the date of issue it can also be found at
|
|
250
|
+
<a href="http://www.w3.org/2001/xml.xsd">
|
|
251
|
+
http://www.w3.org/2001/xml.xsd</a>.
|
|
252
|
+
</p>
|
|
253
|
+
<p>
|
|
254
|
+
The schema document at that URI may however change in the future,
|
|
255
|
+
in order to remain compatible with the latest version of XML
|
|
256
|
+
Schema itself, or with the XML namespace itself. In other words,
|
|
257
|
+
if the XML Schema or XML namespaces change, the version of this
|
|
258
|
+
document at <a href="http://www.w3.org/2001/xml.xsd">
|
|
259
|
+
http://www.w3.org/2001/xml.xsd
|
|
260
|
+
</a>
|
|
261
|
+
will change accordingly; the version at
|
|
262
|
+
<a href="http://www.w3.org/2009/01/xml.xsd">
|
|
263
|
+
http://www.w3.org/2009/01/xml.xsd
|
|
264
|
+
</a>
|
|
265
|
+
will not change.
|
|
266
|
+
</p>
|
|
267
|
+
<p>
|
|
268
|
+
Previous dated (and unchanging) versions of this schema
|
|
269
|
+
document are at:
|
|
270
|
+
</p>
|
|
271
|
+
<ul>
|
|
272
|
+
<li><a href="http://www.w3.org/2009/01/xml.xsd">
|
|
273
|
+
http://www.w3.org/2009/01/xml.xsd</a></li>
|
|
274
|
+
<li><a href="http://www.w3.org/2007/08/xml.xsd">
|
|
275
|
+
http://www.w3.org/2007/08/xml.xsd</a></li>
|
|
276
|
+
<li><a href="http://www.w3.org/2004/10/xml.xsd">
|
|
277
|
+
http://www.w3.org/2004/10/xml.xsd</a></li>
|
|
278
|
+
<li><a href="http://www.w3.org/2001/03/xml.xsd">
|
|
279
|
+
http://www.w3.org/2001/03/xml.xsd</a></li>
|
|
280
|
+
</ul>
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
</xs:documentation>
|
|
284
|
+
</xs:annotation>
|
|
285
|
+
|
|
286
|
+
</xs:schema>
|
|
287
|
+
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
package com.benlangfeld.ruby_speech;
|
|
2
|
+
|
|
3
|
+
import org.jruby.Ruby;
|
|
4
|
+
import org.jruby.RubyClass;
|
|
5
|
+
import org.jruby.RubyModule;
|
|
6
|
+
import org.jruby.RubyObject;
|
|
7
|
+
import org.jruby.anno.JRubyClass;
|
|
8
|
+
import org.jruby.anno.JRubyMethod;
|
|
9
|
+
import org.jruby.runtime.ObjectAllocator;
|
|
10
|
+
import org.jruby.runtime.ThreadContext;
|
|
11
|
+
import org.jruby.runtime.Visibility;
|
|
12
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
|
13
|
+
import org.jruby.javasupport.util.RuntimeHelpers;
|
|
14
|
+
|
|
15
|
+
import java.util.regex.*;
|
|
16
|
+
|
|
17
|
+
@JRubyClass(name="RubySpeech::GRXML::Matcher")
|
|
18
|
+
public class RubySpeechGRXMLMatcher extends RubyObject {
|
|
19
|
+
|
|
20
|
+
Pattern p;
|
|
21
|
+
|
|
22
|
+
public RubySpeechGRXMLMatcher(final Ruby runtime, RubyClass rubyClass) {
|
|
23
|
+
super(runtime, rubyClass);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@JRubyMethod(visibility=Visibility.PRIVATE)
|
|
27
|
+
public IRubyObject compile_regex(ThreadContext context, IRubyObject regex) {
|
|
28
|
+
Ruby runtime = context.getRuntime();
|
|
29
|
+
p = Pattern.compile(regex.toString());
|
|
30
|
+
return runtime.getNil();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@JRubyMethod(visibility=Visibility.PUBLIC)
|
|
34
|
+
public IRubyObject find_match(ThreadContext context, IRubyObject buffer)
|
|
35
|
+
{
|
|
36
|
+
Ruby runtime = context.getRuntime();
|
|
37
|
+
String string_buffer = buffer.toString();
|
|
38
|
+
Matcher m = p.matcher(string_buffer);
|
|
39
|
+
|
|
40
|
+
if (m.matches()) {
|
|
41
|
+
if (is_max_match(string_buffer)) {
|
|
42
|
+
return RuntimeHelpers.invoke(context, this, "match_for_buffer", buffer, runtime.getTrue());
|
|
43
|
+
}
|
|
44
|
+
return callMethod(context, "match_for_buffer", buffer);
|
|
45
|
+
} else if (m.hitEnd()) {
|
|
46
|
+
RubyModule potential_match = runtime.getClassFromPath("RubySpeech::GRXML::PotentialMatch");
|
|
47
|
+
return potential_match.callMethod(context, "new");
|
|
48
|
+
}
|
|
49
|
+
RubyModule nomatch = runtime.getClassFromPath("RubySpeech::GRXML::NoMatch");
|
|
50
|
+
return nomatch.callMethod(context, "new");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public Boolean is_max_match(String buffer)
|
|
54
|
+
{
|
|
55
|
+
String search_set = "0123456789#*ABCD";
|
|
56
|
+
for (int i = 0; i < 16; i++) {
|
|
57
|
+
String new_buffer = buffer + search_set.charAt(i);
|
|
58
|
+
Matcher m = p.matcher(new_buffer);
|
|
59
|
+
if (m.matches()) return false;
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
package com.benlangfeld.ruby_speech;
|
|
2
|
+
|
|
3
|
+
import org.jruby.Ruby;
|
|
4
|
+
import org.jruby.RubyClass;
|
|
5
|
+
import org.jruby.RubyModule;
|
|
6
|
+
import org.jruby.RubyObject;
|
|
7
|
+
import org.jruby.runtime.ObjectAllocator;
|
|
8
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
|
9
|
+
import org.jruby.runtime.load.BasicLibraryService;
|
|
10
|
+
|
|
11
|
+
public class RubySpeechService implements BasicLibraryService {
|
|
12
|
+
public boolean basicLoad(Ruby ruby) {
|
|
13
|
+
RubyModule ruby_speech = ruby.defineModule("RubySpeech");
|
|
14
|
+
RubyModule grxml = ruby_speech.defineModuleUnder("GRXML");
|
|
15
|
+
RubyClass matcher = grxml.defineClassUnder("Matcher", ruby.getObject(), new ObjectAllocator() {
|
|
16
|
+
public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) {
|
|
17
|
+
return new RubySpeechGRXMLMatcher(runtime, rubyClass);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
matcher.defineAnnotatedMethods(RubySpeechGRXMLMatcher.class);
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#include "ruby.h"
|
|
2
|
+
#include "pcre.h"
|
|
3
|
+
#include <stdio.h>
|
|
4
|
+
|
|
5
|
+
static VALUE method_compile_regex(VALUE self, VALUE regex_string)
|
|
6
|
+
{
|
|
7
|
+
int erroffset = 0;
|
|
8
|
+
const char *errptr = "";
|
|
9
|
+
int options = 0;
|
|
10
|
+
const char *regex = StringValueCStr(regex_string);
|
|
11
|
+
|
|
12
|
+
pcre *compiled_regex = pcre_compile(regex, options, &errptr, &erroffset, NULL);
|
|
13
|
+
VALUE compiled_regex_wrapper = Data_Wrap_Struct(rb_cObject, 0, pcre_free, compiled_regex);
|
|
14
|
+
rb_iv_set(self, "@regex", compiled_regex_wrapper);
|
|
15
|
+
|
|
16
|
+
return Qnil;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#define MAX_INPUT_SIZE 128
|
|
20
|
+
#define OVECTOR_SIZE 30
|
|
21
|
+
#define WORKSPACE_SIZE 1024
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Check if no more digits can be added to input and match
|
|
25
|
+
* @param compiled_regex the regex used in the initial match
|
|
26
|
+
* @param input the input to check
|
|
27
|
+
* @return true if end of match (no more input can be added)
|
|
28
|
+
*/
|
|
29
|
+
static int is_match_end(pcre *compiled_regex, const char *input)
|
|
30
|
+
{
|
|
31
|
+
int ovector[OVECTOR_SIZE];
|
|
32
|
+
int input_size = (int)strlen(input);
|
|
33
|
+
char search_input[MAX_INPUT_SIZE + 2];
|
|
34
|
+
const char *search_set = "0123456789#*ABCD";
|
|
35
|
+
const char *search = strchr(search_set, input[input_size - 1]); /* start with last digit in input */
|
|
36
|
+
|
|
37
|
+
/* For each digit in search_set, check if input + search_set digit is a potential match.
|
|
38
|
+
If so, then this is not a match end.
|
|
39
|
+
*/
|
|
40
|
+
sprintf(search_input, "%sZ", input);
|
|
41
|
+
int i;
|
|
42
|
+
for (i = 0; i < 16; i++) {
|
|
43
|
+
int result;
|
|
44
|
+
if (!*search) {
|
|
45
|
+
search = search_set;
|
|
46
|
+
}
|
|
47
|
+
search_input[input_size] = *search++;
|
|
48
|
+
result = pcre_exec(compiled_regex, NULL, search_input, input_size + 1, 0, 0,
|
|
49
|
+
ovector, sizeof(ovector) / sizeof(ovector[0]));
|
|
50
|
+
if (result > 0) return 0;
|
|
51
|
+
}
|
|
52
|
+
return 1;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static VALUE method_find_match(VALUE self, VALUE buffer)
|
|
56
|
+
{
|
|
57
|
+
VALUE RubySpeech = rb_const_get(rb_cObject, rb_intern("RubySpeech"));
|
|
58
|
+
VALUE GRXML = rb_const_get(RubySpeech, rb_intern("GRXML"));
|
|
59
|
+
VALUE NoMatch = rb_const_get(GRXML, rb_intern("NoMatch"));
|
|
60
|
+
pcre *compiled_regex;
|
|
61
|
+
int result = 0;
|
|
62
|
+
int ovector[OVECTOR_SIZE];
|
|
63
|
+
int workspace[WORKSPACE_SIZE];
|
|
64
|
+
char *input = StringValueCStr(buffer);
|
|
65
|
+
|
|
66
|
+
Data_Get_Struct(rb_iv_get(self, "@regex"), pcre, compiled_regex);
|
|
67
|
+
|
|
68
|
+
if (!compiled_regex) {
|
|
69
|
+
return rb_class_new_instance(0, NULL, NoMatch);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
result = pcre_dfa_exec(compiled_regex, NULL, input, (int)strlen(input), 0, PCRE_PARTIAL,
|
|
73
|
+
ovector, sizeof(ovector) / sizeof(ovector[0]),
|
|
74
|
+
workspace, sizeof(workspace) / sizeof(workspace[0]));
|
|
75
|
+
|
|
76
|
+
if (result > 0) {
|
|
77
|
+
if (is_match_end(compiled_regex, input)) {
|
|
78
|
+
return rb_funcall(self, rb_intern("match_for_buffer"), 2, buffer, Qtrue);
|
|
79
|
+
}
|
|
80
|
+
return rb_funcall(self, rb_intern("match_for_buffer"), 1, buffer);
|
|
81
|
+
}
|
|
82
|
+
if (result == PCRE_ERROR_PARTIAL) {
|
|
83
|
+
VALUE PotentialMatch = rb_const_get(GRXML, rb_intern("PotentialMatch"));
|
|
84
|
+
return rb_class_new_instance(0, NULL, PotentialMatch);
|
|
85
|
+
}
|
|
86
|
+
return rb_class_new_instance(0, NULL, NoMatch);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
void Init_ruby_speech()
|
|
90
|
+
{
|
|
91
|
+
VALUE RubySpeech = rb_define_module("RubySpeech");
|
|
92
|
+
VALUE GRXML = rb_define_module_under(RubySpeech, "GRXML");
|
|
93
|
+
VALUE Matcher = rb_define_class_under(GRXML, "Matcher", rb_cObject);
|
|
94
|
+
|
|
95
|
+
rb_define_method(Matcher, "find_match", method_find_match, 1);
|
|
96
|
+
rb_define_method(Matcher, "compile_regex", method_compile_regex, 1);
|
|
97
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
|
2
|
+
|
|
3
|
+
module RubySpeech
|
|
4
|
+
module GenericElement
|
|
5
|
+
|
|
6
|
+
def self.included(klass)
|
|
7
|
+
klass.class_attribute :registered_ns, :registered_name, :defaults
|
|
8
|
+
klass.extend ClassMethods
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module ClassMethods
|
|
12
|
+
@@registrations = {}
|
|
13
|
+
|
|
14
|
+
# Register a new stanza class to a name and/or namespace
|
|
15
|
+
#
|
|
16
|
+
# This registers a namespace that is used when looking
|
|
17
|
+
# up the class name of the object to instantiate when a new
|
|
18
|
+
# stanza is received
|
|
19
|
+
#
|
|
20
|
+
# @param [#to_s] name the name of the node
|
|
21
|
+
#
|
|
22
|
+
def register(name)
|
|
23
|
+
self.registered_name = name.to_s
|
|
24
|
+
self.registered_ns = namespace
|
|
25
|
+
@@registrations[[self.registered_name, self.registered_ns]] = self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Find the class to use given the name and namespace of a stanza
|
|
29
|
+
#
|
|
30
|
+
# @param [#to_s] name the name to lookup
|
|
31
|
+
#
|
|
32
|
+
# @return [Class, nil] the class appropriate for the name
|
|
33
|
+
def class_from_registration(name)
|
|
34
|
+
@@registrations[[name.to_s, namespace]]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Import an XML::Node to the appropriate class
|
|
38
|
+
#
|
|
39
|
+
# Looks up the class the node should be then creates it based on the
|
|
40
|
+
# elements of the XML::Node
|
|
41
|
+
# @param [XML::Node] node the node to import
|
|
42
|
+
# @return the appropriate object based on the node name and namespace
|
|
43
|
+
def import(node)
|
|
44
|
+
node = Nokogiri::XML.parse(node, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root unless node.is_a?(Nokogiri::XML::Node)
|
|
45
|
+
return node.content if node.is_a?(Nokogiri::XML::Text)
|
|
46
|
+
klass = class_from_registration node.node_name
|
|
47
|
+
if klass && klass != self
|
|
48
|
+
klass.import node
|
|
49
|
+
else
|
|
50
|
+
new.inherit node
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def new(atts = {}, &block)
|
|
55
|
+
super(self.registered_name, nil, self.namespace) do |new_node|
|
|
56
|
+
(self.defaults || {}).merge(atts).each_pair { |k, v| new_node.send :"#{k}=", v }
|
|
57
|
+
block_return = new_node.eval_dsl_block &block
|
|
58
|
+
new_node.string block_return if block_return.is_a?(String) && block_return.present?
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
attr_writer :parent
|
|
64
|
+
|
|
65
|
+
def parent
|
|
66
|
+
@parent || super
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def inherit(node)
|
|
70
|
+
self.parent = node.parent
|
|
71
|
+
super
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def version
|
|
75
|
+
read_attr :version
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def version=(other)
|
|
79
|
+
self[:version] = other
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
##
|
|
83
|
+
# @return [String] the base URI to which relative URLs are resolved
|
|
84
|
+
#
|
|
85
|
+
def base_uri
|
|
86
|
+
read_attr 'xml:base'
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
##
|
|
90
|
+
# @param [String] uri the base URI to which relative URLs are resolved
|
|
91
|
+
#
|
|
92
|
+
def base_uri=(uri)
|
|
93
|
+
self['xml:base'] = uri
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def +(other)
|
|
97
|
+
self.class.new(:base_uri => base_uri).tap do |new_element|
|
|
98
|
+
(self.children + other.children).each do |child|
|
|
99
|
+
new_element << child
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def eval_dsl_block(&block)
|
|
105
|
+
return unless block_given?
|
|
106
|
+
@block_binding = eval "self", block.binding
|
|
107
|
+
instance_eval &block
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def children(type = nil, attributes = nil)
|
|
111
|
+
if type
|
|
112
|
+
expression = namespace_href ? 'ns:' : ''
|
|
113
|
+
expression << type.to_s
|
|
114
|
+
|
|
115
|
+
expression << '[' << attributes.inject([]) do |h, (key, value)|
|
|
116
|
+
h << "@#{namespace_href && Nokogiri.jruby? ? 'ns:' : ''}#{key}='#{value}'"
|
|
117
|
+
end.join(',') << ']' if attributes
|
|
118
|
+
|
|
119
|
+
xpath expression, :ns => namespace_href
|
|
120
|
+
else
|
|
121
|
+
super()
|
|
122
|
+
end.map { |c| self.class.import c }
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def embed(other)
|
|
126
|
+
case other
|
|
127
|
+
when String
|
|
128
|
+
string other
|
|
129
|
+
when self.class.root_element
|
|
130
|
+
other.children.each do |child|
|
|
131
|
+
self << child
|
|
132
|
+
end
|
|
133
|
+
when self.class.module::Element
|
|
134
|
+
self << other
|
|
135
|
+
else
|
|
136
|
+
raise ArgumentError, "Can only embed a String or a #{self.class.module} element, not a #{other}"
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def string(other)
|
|
141
|
+
self << Nokogiri::XML::Text.new(other, document)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def method_missing(method_name, *args, &block)
|
|
145
|
+
const_name = method_name.to_s.sub('ssml', '').titleize.gsub(' ', '')
|
|
146
|
+
if self.class.module.const_defined?(const_name)
|
|
147
|
+
const = self.class.module.const_get const_name
|
|
148
|
+
embed const.new(*args, &block)
|
|
149
|
+
elsif @block_binding && @block_binding.respond_to?(method_name)
|
|
150
|
+
@block_binding.send method_name, *args, &block
|
|
151
|
+
else
|
|
152
|
+
super
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def clone
|
|
157
|
+
GRXML.import to_xml
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def traverse(&block)
|
|
161
|
+
nokogiri_children.each { |j| j.traverse &block }
|
|
162
|
+
block.call self
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def eql?(o, *args)
|
|
166
|
+
super o, :content, :children, *args
|
|
167
|
+
end
|
|
168
|
+
end # Element
|
|
169
|
+
end # RubySpeech
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
|
2
|
+
|
|
3
|
+
module RubySpeech
|
|
4
|
+
module GRXML
|
|
5
|
+
class Element < Niceogiri::XML::Node
|
|
6
|
+
def self.namespace
|
|
7
|
+
GRXML_NAMESPACE
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.root_element
|
|
11
|
+
Grammar
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.module
|
|
15
|
+
GRXML
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
alias_method :nokogiri_children, :children
|
|
19
|
+
|
|
20
|
+
alias :to_doc :document
|
|
21
|
+
|
|
22
|
+
include GenericElement
|
|
23
|
+
|
|
24
|
+
def regexp_content # :nodoc:
|
|
25
|
+
"(#{children.map(&:regexp_content).join})"
|
|
26
|
+
end
|
|
27
|
+
end # Element
|
|
28
|
+
end # GRXML
|
|
29
|
+
end # RubySpeech
|