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.
Files changed (90) hide show
  1. data/.gitignore +12 -0
  2. data/.rspec +3 -0
  3. data/.travis.yml +17 -0
  4. data/CHANGELOG.md +144 -0
  5. data/Gemfile +3 -0
  6. data/Guardfile +9 -0
  7. data/LICENSE.md +20 -0
  8. data/README.md +314 -0
  9. data/Rakefile +34 -0
  10. data/assets/grammar-core.xsd +317 -0
  11. data/assets/grammar.xsd +37 -0
  12. data/assets/synthesis-core.xsd +445 -0
  13. data/assets/synthesis.xsd +63 -0
  14. data/assets/xml.xsd +287 -0
  15. data/ext/ruby_speech/RubySpeechGRXMLMatcher.java +64 -0
  16. data/ext/ruby_speech/RubySpeechService.java +23 -0
  17. data/ext/ruby_speech/extconf.rb +7 -0
  18. data/ext/ruby_speech/ruby_speech.c +97 -0
  19. data/lib/ruby_speech/generic_element.rb +169 -0
  20. data/lib/ruby_speech/grxml/element.rb +29 -0
  21. data/lib/ruby_speech/grxml/grammar.rb +189 -0
  22. data/lib/ruby_speech/grxml/item.rb +144 -0
  23. data/lib/ruby_speech/grxml/match.rb +16 -0
  24. data/lib/ruby_speech/grxml/matcher.rb +126 -0
  25. data/lib/ruby_speech/grxml/max_match.rb +6 -0
  26. data/lib/ruby_speech/grxml/no_match.rb +10 -0
  27. data/lib/ruby_speech/grxml/one_of.rb +31 -0
  28. data/lib/ruby_speech/grxml/potential_match.rb +10 -0
  29. data/lib/ruby_speech/grxml/rule.rb +73 -0
  30. data/lib/ruby_speech/grxml/ruleref.rb +69 -0
  31. data/lib/ruby_speech/grxml/tag.rb +29 -0
  32. data/lib/ruby_speech/grxml/token.rb +31 -0
  33. data/lib/ruby_speech/grxml.rb +39 -0
  34. data/lib/ruby_speech/nlsml/builder.rb +34 -0
  35. data/lib/ruby_speech/nlsml/document.rb +120 -0
  36. data/lib/ruby_speech/nlsml.rb +18 -0
  37. data/lib/ruby_speech/ruby_speech.jar +0 -0
  38. data/lib/ruby_speech/ssml/audio.rb +47 -0
  39. data/lib/ruby_speech/ssml/break.rb +62 -0
  40. data/lib/ruby_speech/ssml/desc.rb +24 -0
  41. data/lib/ruby_speech/ssml/element.rb +23 -0
  42. data/lib/ruby_speech/ssml/emphasis.rb +44 -0
  43. data/lib/ruby_speech/ssml/mark.rb +43 -0
  44. data/lib/ruby_speech/ssml/p.rb +25 -0
  45. data/lib/ruby_speech/ssml/phoneme.rb +72 -0
  46. data/lib/ruby_speech/ssml/prosody.rb +172 -0
  47. data/lib/ruby_speech/ssml/s.rb +25 -0
  48. data/lib/ruby_speech/ssml/say_as.rb +100 -0
  49. data/lib/ruby_speech/ssml/speak.rb +27 -0
  50. data/lib/ruby_speech/ssml/sub.rb +42 -0
  51. data/lib/ruby_speech/ssml/voice.rb +108 -0
  52. data/lib/ruby_speech/ssml.rb +39 -0
  53. data/lib/ruby_speech/version.rb +3 -0
  54. data/lib/ruby_speech/xml/language.rb +13 -0
  55. data/lib/ruby_speech/xml.rb +11 -0
  56. data/lib/ruby_speech.rb +36 -0
  57. data/ruby_speech.gemspec +42 -0
  58. data/spec/ruby_speech/grxml/grammar_spec.rb +341 -0
  59. data/spec/ruby_speech/grxml/item_spec.rb +192 -0
  60. data/spec/ruby_speech/grxml/match_spec.rb +15 -0
  61. data/spec/ruby_speech/grxml/matcher_spec.rb +688 -0
  62. data/spec/ruby_speech/grxml/max_match_spec.rb +17 -0
  63. data/spec/ruby_speech/grxml/no_match_spec.rb +17 -0
  64. data/spec/ruby_speech/grxml/one_of_spec.rb +49 -0
  65. data/spec/ruby_speech/grxml/potential_match_spec.rb +17 -0
  66. data/spec/ruby_speech/grxml/rule_spec.rb +125 -0
  67. data/spec/ruby_speech/grxml/ruleref_spec.rb +55 -0
  68. data/spec/ruby_speech/grxml/tag_spec.rb +41 -0
  69. data/spec/ruby_speech/grxml/token_spec.rb +62 -0
  70. data/spec/ruby_speech/grxml_spec.rb +339 -0
  71. data/spec/ruby_speech/nlsml_spec.rb +353 -0
  72. data/spec/ruby_speech/ssml/audio_spec.rb +121 -0
  73. data/spec/ruby_speech/ssml/break_spec.rb +100 -0
  74. data/spec/ruby_speech/ssml/desc_spec.rb +57 -0
  75. data/spec/ruby_speech/ssml/emphasis_spec.rb +110 -0
  76. data/spec/ruby_speech/ssml/mark_spec.rb +53 -0
  77. data/spec/ruby_speech/ssml/p_spec.rb +96 -0
  78. data/spec/ruby_speech/ssml/phoneme_spec.rb +65 -0
  79. data/spec/ruby_speech/ssml/prosody_spec.rb +309 -0
  80. data/spec/ruby_speech/ssml/s_spec.rb +92 -0
  81. data/spec/ruby_speech/ssml/say_as_spec.rb +71 -0
  82. data/spec/ruby_speech/ssml/speak_spec.rb +166 -0
  83. data/spec/ruby_speech/ssml/sub_spec.rb +57 -0
  84. data/spec/ruby_speech/ssml/voice_spec.rb +200 -0
  85. data/spec/ruby_speech/ssml_spec.rb +285 -0
  86. data/spec/ruby_speech_spec.rb +124 -0
  87. data/spec/spec_helper.rb +21 -0
  88. data/spec/support/match_examples.rb +43 -0
  89. data/spec/support/matchers.rb +46 -0
  90. 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
+ &lt;schema . . .>
208
+ . . .
209
+ &lt;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
+ &lt;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
+ &lt;type . . .>
225
+ . . .
226
+ &lt;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,7 @@
1
+ require 'mkmf'
2
+
3
+ $LIBS << " -lpcre"
4
+
5
+ abort "-----\n#{lib} is missing.\n-----" unless find_header('pcre.h')
6
+
7
+ create_makefile 'ruby_speech/ruby_speech'
@@ -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