ruby_speech 2.3.1 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.hound.yml +2 -0
  4. data/.travis.yml +25 -9
  5. data/CHANGELOG.md +19 -1
  6. data/README.md +14 -15
  7. data/Rakefile +2 -0
  8. data/ext/ruby_speech/RubySpeechGRXMLMatcher.java +17 -12
  9. data/ext/ruby_speech/RubySpeechService.java +1 -1
  10. data/ext/ruby_speech/extconf.rb +1 -1
  11. data/lib/ruby_speech/generic_element.rb +2 -2
  12. data/lib/ruby_speech/grxml/builtins.rb +18 -11
  13. data/lib/ruby_speech/grxml/grammar.rb +26 -4
  14. data/lib/ruby_speech/grxml/matcher.rb +2 -2
  15. data/lib/ruby_speech/grxml.rb +2 -0
  16. data/lib/ruby_speech/nlsml/builder.rb +2 -1
  17. data/lib/ruby_speech/nlsml/document.rb +5 -0
  18. data/lib/ruby_speech/ssml/break.rb +1 -2
  19. data/lib/ruby_speech/ssml/element.rb +13 -1
  20. data/lib/ruby_speech/ssml/mark.rb +0 -1
  21. data/lib/ruby_speech/ssml/prosody.rb +8 -5
  22. data/lib/ruby_speech/version.rb +1 -1
  23. data/ruby_speech.gemspec +13 -8
  24. data/spec/ruby_speech/grxml/builtins_spec.rb +80 -71
  25. data/spec/ruby_speech/grxml/grammar_spec.rb +168 -34
  26. data/spec/ruby_speech/grxml/item_spec.rb +33 -33
  27. data/spec/ruby_speech/grxml/match_spec.rb +1 -1
  28. data/spec/ruby_speech/grxml/matcher_spec.rb +103 -59
  29. data/spec/ruby_speech/grxml/max_match_spec.rb +2 -2
  30. data/spec/ruby_speech/grxml/no_match_spec.rb +2 -2
  31. data/spec/ruby_speech/grxml/one_of_spec.rb +6 -6
  32. data/spec/ruby_speech/grxml/potential_match_spec.rb +2 -2
  33. data/spec/ruby_speech/grxml/rule_spec.rb +17 -17
  34. data/spec/ruby_speech/grxml/ruleref_spec.rb +10 -10
  35. data/spec/ruby_speech/grxml/tag_spec.rb +5 -5
  36. data/spec/ruby_speech/grxml/token_spec.rb +7 -7
  37. data/spec/ruby_speech/grxml_spec.rb +25 -25
  38. data/spec/ruby_speech/nlsml_spec.rb +58 -10
  39. data/spec/ruby_speech/ssml/audio_spec.rb +19 -19
  40. data/spec/ruby_speech/ssml/break_spec.rb +42 -22
  41. data/spec/ruby_speech/ssml/desc_spec.rb +7 -7
  42. data/spec/ruby_speech/ssml/emphasis_spec.rb +21 -21
  43. data/spec/ruby_speech/ssml/mark_spec.rb +5 -5
  44. data/spec/ruby_speech/ssml/p_spec.rb +17 -17
  45. data/spec/ruby_speech/ssml/phoneme_spec.rb +8 -8
  46. data/spec/ruby_speech/ssml/prosody_spec.rb +82 -64
  47. data/spec/ruby_speech/ssml/s_spec.rb +16 -16
  48. data/spec/ruby_speech/ssml/say_as_spec.rb +9 -9
  49. data/spec/ruby_speech/ssml/speak_spec.rb +29 -29
  50. data/spec/ruby_speech/ssml/sub_spec.rb +7 -7
  51. data/spec/ruby_speech/ssml/voice_spec.rb +31 -31
  52. data/spec/ruby_speech/ssml_spec.rb +41 -17
  53. data/spec/ruby_speech_spec.rb +3 -3
  54. data/spec/spec_helper.rb +8 -3
  55. data/spec/support/dtmf_helper.rb +14 -0
  56. data/spec/support/grammar_matchers.rb +6 -6
  57. data/spec/support/match_examples.rb +5 -5
  58. data/spec/support/matchers.rb +1 -1
  59. metadata +49 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: daffff8bc7ff4b9142bb4c02ebe5a86ea36af289
4
- data.tar.gz: 27fa66cc2be22d51bb2df0dd0b19d53cfdc37507
2
+ SHA256:
3
+ metadata.gz: 96deae2344c54438f2f612999f0b2492de80753501a53de1999f68f9eb83ab2a
4
+ data.tar.gz: 96f18cfbae078b156d40b9dcefd5b1a8e169899760116a08ea5e5b549e2c1353
5
5
  SHA512:
6
- metadata.gz: 0a9e0f01cc3967c4a6b77bbf45c9daae4f26b6e9e3fbae46367c670621ddcd522715d638aff7c325f8ea199a7cac150e541a25e4d868f8fe4c4e5d91c12a5d0b
7
- data.tar.gz: 3d041f2dfefc467fe83afb05fb7d1c88fda27d96aa6203e598e3fc134969c13e50c91f6ff13e936957434e91b75f40b4aa93d5b63500b8b577d91dd60c6dd040
6
+ metadata.gz: 4525211ca8ef6c50358366a4c76d53322401bdfd3c1e378012e2bba56f029c62ddba9bbe01d78eaa3721268497a251d222bce35a045bde0f02c72ea6ff7fc10e
7
+ data.tar.gz: f68220d2a3b3ed14114beaffbdea5591ef0026c36a86e025d4de6c3871f1eaa797244226b917cd85057592601368427c96f2bd2ec72f42ccfefa485300c90c79
data/.gitignore CHANGED
@@ -2,6 +2,7 @@
2
2
  *.gem
3
3
  *.bundle
4
4
  *.jar
5
+ *.so
5
6
  Gemfile.lock
6
7
  pkg/*
7
8
  spec/reports
data/.hound.yml ADDED
@@ -0,0 +1,2 @@
1
+ LineLength:
2
+ Enabled: false
data/.travis.yml CHANGED
@@ -1,17 +1,33 @@
1
+ dist: xenial
1
2
  language: ruby
2
-
3
3
  rvm:
4
- - 1.9.3
5
- - 2.0.0
6
- - 2.1.0
7
- - jruby-19mode
8
- - rbx-19mode
4
+ - 2.1.10
5
+ - 2.2.10
6
+ - 2.3.8
7
+ - 2.4.5
8
+ - 2.5.3
9
+ - 2.6.3
10
+ - jruby-9.1.17.0
11
+ - jruby-head
9
12
  - ruby-head
13
+ jdk:
14
+ - openjdk8 # for jruby
10
15
  matrix:
16
+ include:
17
+ - rvm: rbx-4
18
+ dist: trusty
19
+ name: Rubinius
11
20
  allow_failures:
21
+ - name: Rubinius
12
22
  - rvm: ruby-head
13
- before_install:
14
- - sudo apt-get install libpcre3 libpcre3-dev
15
-
23
+ addons:
24
+ apt:
25
+ packages:
26
+ - libpcre3
27
+ - libpcre3-dev
28
+ env:
29
+ global:
30
+ - JRUBY_OPTS='--debug'
31
+ before_install: rvm list
16
32
  notifications:
17
33
  irc: "irc.freenode.org#adhearsion"
data/CHANGELOG.md CHANGED
@@ -1,4 +1,22 @@
1
- # [develop](https://github.com/benlangfeld/ruby_speech)
1
+ # [3.0.1](https://github.com/benlangfeld/ruby_speech/compare/v3.0.0...v3.0.1) - [2022-02-15](https://rubygems.org/gems/ruby_speech/versions/3.0.1)
2
+ * Misc: Relax dependency limits to allow newer ActiveSupport versions and thus Ruby 3.0
3
+ * Bugfix: Misc performance improvements
4
+
5
+ # [3.0.0](https://github.com/benlangfeld/ruby_speech/compare/v2.4.0...v3.0.0) - [2018-07-10](https://rubygems.org/gems/ruby_speech/versions/3.0.0)
6
+ * Feature: Loosen and bump Nokogiri version to ~>1.8, >=1.8.3
7
+ * Feature: Bump RSpec to 3.x and convert specs with Transpec
8
+
9
+ # [2.4.0](https://github.com/benlangfeld/ruby_speech/compare/v2.3.2...v2.4.0) - [2018-02-23](https://rubygems.org/gems/ruby_speech/versions/2.4.0)
10
+ * Feature: Permit percentage rate values for prosody tags
11
+ * Bugfix: Rulerefs referenced n-levels deep under Rulerefs should be expanded.
12
+ * Bugfix: Optimize performance of built-in number DTMF grammar
13
+ * Bugfix: Fix handling of millisecond values
14
+
15
+ # [2.3.2](https://github.com/benlangfeld/ruby_speech/compare/v2.3.1...v2.3.2) - [2014-04-21](https://rubygems.org/gems/ruby_speech/versions/2.3.2)
16
+ * Bugfix: String nodes should take non-strings and cast to a string (`#to_s`)
17
+ * Bugfix: Cleanly handle NLSML with no input tag
18
+ * Bugfix: Drawing an NLSML doc should return something structured/parsed
19
+ * Bugfix: Cloning SSML documents no longer turns them into GRXML docs
2
20
 
3
21
  # [2.3.1](https://github.com/benlangfeld/ruby_speech/compare/v2.3.0...v2.3.1) - [2014-02-24](https://rubygems.org/gems/ruby_speech/versions/2.3.1)
4
22
  * Bugfix: Phone number grammar should only allow a single instance of '*'/'x'
data/README.md CHANGED
@@ -1,8 +1,7 @@
1
- [![Gem Version](https://badge.fury.io/rb/ruby_speech.png)](https://rubygems.org/gems/ruby_speech)
2
- [![Build Status](https://secure.travis-ci.org/benlangfeld/ruby_speech.png?branch=develop)](http://travis-ci.org/benlangfeld/ruby_speech)
3
- [![Dependency Status](https://gemnasium.com/benlangfeld/ruby_speech.png?travis)](https://gemnasium.com/benlangfeld/ruby_speech)
4
- [![Code Climate](https://codeclimate.com/github/benlangfeld/ruby_speech.png)](https://codeclimate.com/github/benlangfeld/ruby_speech)
5
- [![Coverage Status](https://coveralls.io/repos/benlangfeld/ruby_speech/badge.png?branch=develop)](https://coveralls.io/r/benlangfeld/ruby_speech)
1
+ [![Gem Version](https://badge.fury.io/rb/ruby_speech.svg)](https://rubygems.org/gems/ruby_speech)
2
+ [![Build Status](https://secure.travis-ci.org/adhearsion/ruby_speech.svg?branch=develop)](http://travis-ci.org/adhearsion/ruby_speech)
3
+ [![Code Climate](https://codeclimate.com/github/adhearsion/ruby_speech.svg)](https://codeclimate.com/github/adhearsion/ruby_speech)
4
+ [![Coverage Status](https://coveralls.io/repos/adhearsion/ruby_speech/badge.svg?branch=develop)](https://coveralls.io/r/adhearsion/ruby_speech)
6
5
 
7
6
  # RubySpeech
8
7
  RubySpeech is a library for constructing and parsing Text to Speech (TTS) and Automatic Speech Recognition (ASR) documents such as [SSML](http://www.w3.org/TR/speech-synthesis), [GRXML](http://www.w3.org/TR/speech-grammar/) and [NLSML](http://www.w3.org/TR/nl-spec/). Such documents can be constructed to be processed by TTS and ASR engines, parsed as the result from such, or used in the implementation of such engines.
@@ -30,8 +29,8 @@ sudo yum install pcre-devel
30
29
  gem install ruby_speech
31
30
 
32
31
  ## Ruby Version Compatability
33
- * CRuby 1.9.3+ (1.9.2 is unofficially supported, but not regularly tested)
34
- * JRuby 1.7+
32
+ * CRuby 2.1+
33
+ * JRuby 9.1+
35
34
 
36
35
  ## Library
37
36
 
@@ -259,7 +258,7 @@ require 'ruby_speech'
259
258
 
260
259
  nlsml = RubySpeech::NLSML.draw grammar: 'http://flight' do
261
260
  interpretation confidence: 0.6 do
262
- input "I want to go to Pittsburgh", mode: :speech
261
+ input "I want to go to Pittsburgh", mode: :voice
263
262
 
264
263
  instance do
265
264
  airline do
@@ -288,7 +287,7 @@ becomes:
288
287
  <?xml version="1.0"?>
289
288
  <result xmlns="http://www.ietf.org/xml/ns/mrcpv2" grammar="http://flight">
290
289
  <interpretation confidence="0.6">
291
- <input mode="speech">I want to go to Pittsburgh</input>
290
+ <input mode="voice">I want to go to Pittsburgh</input>
292
291
  <instance>
293
292
  <airline>
294
293
  <to_city>Pittsburgh</to_city>
@@ -315,7 +314,7 @@ document.match? # => true
315
314
  document.interpretations # => [
316
315
  {
317
316
  confidence: 0.6,
318
- input: { mode: :speech, content: 'I want to go to Pittsburgh' },
317
+ input: { mode: :voice, content: 'I want to go to Pittsburgh' },
319
318
  instance: { airline: { to_city: 'Pittsburgh' } }
320
319
  },
321
320
  {
@@ -326,12 +325,12 @@ document.interpretations # => [
326
325
  ]
327
326
  document.best_interpretation # => {
328
327
  confidence: 0.6,
329
- input: { mode: :speech, content: 'I want to go to Pittsburgh' },
328
+ input: { mode: :voice, content: 'I want to go to Pittsburgh' },
330
329
  instance: { airline: { to_city: 'Pittsburgh' } }
331
330
  }
332
331
  ```
333
332
 
334
- Check out the [YARD documentation](http://rdoc.info/github/benlangfeld/ruby_speech/master/frames) for more
333
+ Check out the [YARD documentation](http://rdoc.info/github/adhearsion/ruby_speech/master/frames) for more
335
334
 
336
335
  ## Features:
337
336
  ### SSML
@@ -374,10 +373,10 @@ Check out the [YARD documentation](http://rdoc.info/github/benlangfeld/ruby_spee
374
373
  * `<lexicon/>`
375
374
 
376
375
  ## Links:
377
- * [Source](https://github.com/benlangfeld/ruby_speech)
376
+ * [Source](https://github.com/adhearsion/ruby_speech)
378
377
  * [Documentation](http://rdoc.info/gems/ruby_speech/frames)
379
- * [Bug Tracker](https://github.com/benlangfeld/ruby_speech/issues)
380
- * [CI](https://travis-ci.org/#!/benlangfeld/ruby_speech)
378
+ * [Bug Tracker](https://github.com/adhearsion/ruby_speech/issues)
379
+ * [CI](https://travis-ci.org/#!/adhearsion/ruby_speech)
381
380
 
382
381
  ## Note on Patches/Pull Requests
383
382
 
data/Rakefile CHANGED
@@ -25,6 +25,8 @@ if RUBY_PLATFORM =~ /java/
25
25
  require 'rake/javaextensiontask'
26
26
  Rake::JavaExtensionTask.new 'ruby_speech' do |ext|
27
27
  ext.lib_dir = 'lib/ruby_speech'
28
+ ext.source_version = '1.6'
29
+ ext.target_version = '1.6'
28
30
  end
29
31
  else
30
32
  require 'rake/extensiontask'
@@ -1,4 +1,4 @@
1
- package com.benlangfeld.ruby_speech;
1
+ package com.adhearsion.ruby_speech;
2
2
 
3
3
  import org.jruby.Ruby;
4
4
  import org.jruby.RubyClass;
@@ -6,6 +6,7 @@ import org.jruby.RubyModule;
6
6
  import org.jruby.RubyObject;
7
7
  import org.jruby.anno.JRubyClass;
8
8
  import org.jruby.anno.JRubyMethod;
9
+ import org.jruby.runtime.Block;
9
10
  import org.jruby.runtime.ObjectAllocator;
10
11
  import org.jruby.runtime.ThreadContext;
11
12
  import org.jruby.runtime.Visibility;
@@ -43,22 +44,26 @@ public class RubySpeechGRXMLMatcher extends RubyObject {
43
44
  }
44
45
  return callMethod(context, "match_for_buffer", buffer);
45
46
  } else if (m.hitEnd()) {
46
- RubyModule potential_match = runtime.getClassFromPath("RubySpeech::GRXML::PotentialMatch");
47
- return potential_match.callMethod(context, "new");
47
+ return getGRXMLType(runtime, "PotentialMatch").newInstance(context, Block.NULL_BLOCK);
48
48
  }
49
- RubyModule nomatch = runtime.getClassFromPath("RubySpeech::GRXML::NoMatch");
50
- return nomatch.callMethod(context, "new");
49
+ return getGRXMLType(runtime, "NoMatch").newInstance(context, Block.NULL_BLOCK);
51
50
  }
52
51
 
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;
52
+ private boolean is_max_match(String buffer) {
53
+ final int len = buffer.length();
54
+ StringBuilder new_buffer = new StringBuilder(len + 1);
55
+ new_buffer.append(buffer).append('\0');
56
+ final String search_set = "0123456789#*ABCD";
57
+ for (int i = 0; i < search_set.length(); i++) {
58
+ new_buffer.setCharAt(len, search_set.charAt(i));
59
+ if (p.matcher(new_buffer).matches()) return false;
60
60
  }
61
61
  return true;
62
62
  }
63
63
 
64
+ private static RubyClass getGRXMLType(final Ruby runtime, final String name) {
65
+ RubyModule grxml = (RubyModule) runtime.getModule("RubySpeech").getConstantAt("GRXML");
66
+ return (RubyClass) grxml.getConstantAt(name);
67
+ }
68
+
64
69
  }
@@ -1,4 +1,4 @@
1
- package com.benlangfeld.ruby_speech;
1
+ package com.adhearsion.ruby_speech;
2
2
 
3
3
  import org.jruby.Ruby;
4
4
  import org.jruby.RubyClass;
@@ -3,7 +3,7 @@ require 'mkmf'
3
3
  $LIBS << " -lpcre"
4
4
 
5
5
  unless find_header('pcre.h')
6
- abort "-----\nPCRE is missing. You must install it as per the README @ https://github.com/benlangfeld/ruby_speech\n-----"
6
+ abort "-----\nPCRE is missing. You must install it as per the README @ https://github.com/adhearsion/ruby_speech\n-----"
7
7
  end
8
8
 
9
9
  create_makefile 'ruby_speech/ruby_speech'
@@ -172,11 +172,11 @@ module RubySpeech
172
172
  end
173
173
 
174
174
  def string(other)
175
- self << Nokogiri::XML::Text.new(other, document)
175
+ self << Nokogiri::XML::Text.new(other.to_s, document)
176
176
  end
177
177
 
178
178
  def clone
179
- GRXML.import to_xml
179
+ self.class.import to_xml
180
180
  end
181
181
 
182
182
  def traverse(&block)
@@ -57,7 +57,8 @@ module RubySpeech::GRXML::Builtins
57
57
  # @option options [#to_i] :maxlength Maximum length for the string of digits.
58
58
  # @option options [#to_i] :length Absolute length for the string of digits.
59
59
  #
60
- # @return [RubySpeech::GRXML::Grammar] a grammar for interpreting a boolean response.
60
+ # @return [RubySpeech::GRXML::Grammar] a grammar for interpreting an integer
61
+ # response.
61
62
  #
62
63
  # @raise [ArgumentError] if any of the length attributes logically conflict
63
64
  #
@@ -118,22 +119,28 @@ module RubySpeech::GRXML::Builtins
118
119
  def self.number(options = nil)
119
120
  RubySpeech::GRXML.draw mode: :dtmf, root: 'number' do
120
121
  rule id: 'number', scope: 'public' do
121
- item repeat: '0-' do
122
- ruleref uri: '#digit'
122
+ one_of do
123
+ item { ruleref uri: '#less_than_one' }
124
+ item { ruleref uri: '#one_or_more' }
123
125
  end
126
+ end
127
+
128
+ rule id: 'less_than_one' do
129
+ item { '*' }
130
+ item { ruleref uri: '#digit_series' }
131
+ end
132
+
133
+ rule id: 'one_or_more' do
134
+ item { ruleref uri: '#digit_series' }
124
135
  item repeat: '0-1' do
125
136
  item { '*' }
126
- item repeat: '0-' do
127
- ruleref uri: '#digit'
128
- end
137
+ item(repeat: '0-1') { ruleref uri: '#digit_series' }
129
138
  end
130
139
  end
131
140
 
132
- rule id: 'digit' do
133
- one_of do
134
- 0.upto(9) { |d| item { d.to_s } }
135
- end
136
- end
141
+ rule(id: 'digit_series') { item(repeat: '1-') { ruleref uri: '#digit' } }
142
+
143
+ rule(id: 'digit') { one_of { 0.upto(9) { |d| item { d.to_s } } } }
137
144
  end
138
145
  end
139
146
 
@@ -113,17 +113,39 @@ module RubySpeech
113
113
  # Replaces rulerefs in the document with a copy of the original rule.
114
114
  # Removes all top level rules except the root rule
115
115
  #
116
+ # @raises [MissingReferenceError] if a ruleref references a rule that is
117
+ # not defined.
118
+ # @raises [ReferentialLoopError] if rulerefs create a referencial cycle.
119
+ #
116
120
  # @return self
117
121
  #
118
122
  def inline!
119
- xpath("//ns:ruleref", :ns => GRXML_NAMESPACE).each do |ref|
120
- rule = rule_with_id ref[:uri].sub(/^#/, '')
121
- ref.swap rule.dup.children
123
+ previous_uris = {}
124
+ loop do
125
+ rule = nil
126
+ uris = {}
127
+ xpath('//ns:ruleref', ns: GRXML_NAMESPACE).each do |ref|
128
+ uri = ref[:uri].sub(/^#/, '')
129
+ uris[uri] = 1
130
+ rule = rule_with_id uri
131
+ unless rule
132
+ raise MissingReferenceError,
133
+ "Ruleref '##{uri}' is referenced but not defined"
134
+ end
135
+ ref.swap rule.dup.children
136
+ end
137
+ break unless rule
138
+ if previous_uris.keys.eql? uris.keys
139
+ raise ReferentialLoopError,
140
+ 'GRXML document contains cycles with ruleref(s): ' <<
141
+ uris.keys.join(', ')
142
+ end
143
+ previous_uris = uris
122
144
  end
123
145
 
124
146
  query = "./ns:rule[@id!='#{root}']"
125
147
  query += "|./ns:rule[@ns:id!='#{root}']" if Nokogiri.jruby?
126
- non_root_rules = xpath query, :ns => namespace_href
148
+ non_root_rules = xpath query, ns: namespace_href
127
149
  non_root_rules.remove
128
150
 
129
151
  self
@@ -6,7 +6,7 @@ require 'ruby_speech/ruby_speech'
6
6
 
7
7
  if RUBY_PLATFORM =~ /java/
8
8
  require 'jruby'
9
- com.benlangfeld.ruby_speech.RubySpeechService.new.basicLoad(JRuby.runtime)
9
+ com.adhearsion.ruby_speech.RubySpeechService.new.basicLoad(JRuby.runtime)
10
10
  end
11
11
 
12
12
  module RubySpeech
@@ -90,7 +90,7 @@ module RubySpeech
90
90
  # ```
91
91
  #
92
92
  def match(buffer)
93
- find_match buffer.dup
93
+ find_match buffer
94
94
  end
95
95
 
96
96
  private
@@ -4,6 +4,8 @@ require 'ruby_speech/grxml/element'
4
4
  module RubySpeech
5
5
  module GRXML
6
6
  InvalidChildError = Class.new StandardError
7
+ MissingReferenceError = Class.new StandardError
8
+ ReferentialLoopError = Class.new StandardError
7
9
 
8
10
  GRXML_NAMESPACE = 'http://www.w3.org/2001/06/grammar'
9
11
 
@@ -5,11 +5,12 @@ module RubySpeech
5
5
 
6
6
  def initialize(options = {}, &block)
7
7
  options = {'xmlns' => NLSML_NAMESPACE}.merge(options)
8
- @document = Nokogiri::XML::Builder.new do |builder|
8
+ xml_doc = Nokogiri::XML::Builder.new do |builder|
9
9
  builder.result options do |r|
10
10
  apply_block r, &block
11
11
  end
12
12
  end.doc
13
+ @document = RubySpeech::NLSML::Document.new xml_doc
13
14
  end
14
15
 
15
16
  def interpretation(*args, &block)
@@ -38,6 +38,10 @@ module RubySpeech
38
38
  noinput_elements.any?
39
39
  end
40
40
 
41
+ def to_xml
42
+ document.to_xml
43
+ end
44
+
41
45
  private
42
46
 
43
47
  def nomatch?
@@ -58,6 +62,7 @@ module RubySpeech
58
62
 
59
63
  def input_hash_for_interpretation(interpretation)
60
64
  input_element = interpretation.at_xpath 'ns:input', 'ns' => NLSML_NAMESPACE
65
+ return unless input_element
61
66
  { content: input_element.content }.tap do |h|
62
67
  h[:mode] = input_element['mode'].to_sym if input_element['mode']
63
68
  end
@@ -36,7 +36,7 @@ module RubySpeech
36
36
  # @return [Float]
37
37
  #
38
38
  def time
39
- read_attr :time, :to_f
39
+ get_time_attribute :time
40
40
  end
41
41
 
42
42
  ##
@@ -50,7 +50,6 @@ module RubySpeech
50
50
 
51
51
  def <<(*args)
52
52
  raise InvalidChildError, "A Break cannot contain children"
53
- super
54
53
  end
55
54
 
56
55
  def eql?(o)
@@ -23,9 +23,21 @@ module RubySpeech
23
23
 
24
24
  private
25
25
 
26
+ def get_time_attribute(key)
27
+ value = read_attr(key)
28
+
29
+ if value.nil?
30
+ nil
31
+ elsif value.end_with?('ms')
32
+ value.to_f / 1000
33
+ else
34
+ value.to_f
35
+ end
36
+ end
37
+
26
38
  def set_time_attribute(key, value)
27
39
  raise ArgumentError, "You must specify a valid #{key} (positive float value in seconds)" unless value.is_a?(Numeric) && value >= 0
28
- self[key] = "#{value}s"
40
+ self[key] = value == value.round ? "#{value.to_i}s" : "#{(value * 1000).to_i}ms"
29
41
  end
30
42
  end # Element
31
43
  end # SSML
@@ -34,7 +34,6 @@ module RubySpeech
34
34
 
35
35
  def <<(*args)
36
36
  raise InvalidChildError, "A Mark cannot contain children"
37
- super
38
37
  end
39
38
 
40
39
  def eql?(o)
@@ -102,27 +102,29 @@ module RubySpeech
102
102
  end
103
103
 
104
104
  ##
105
- # A change in the speaking rate for the contained text. Legal values are: a relative change or "x-slow", "slow", "medium", "fast", "x-fast", or "default". Labels "x-slow" through "x-fast" represent a sequence of monotonically non-decreasing speaking rates. When a number is used to specify a relative change it acts as a multiplier of the default rate. For example, a value of 1 means no change in speaking rate, a value of 2 means a speaking rate twice the default rate, and a value of 0.5 means a speaking rate of half the default rate. The default rate for a voice depends on the language and dialect and on the personality of the voice. The default rate for a voice should be such that it is experienced as a normal speaking rate for the voice when reading aloud text. Since voices are processor-specific, the default rate will be as well.
105
+ # A change in the speaking rate for the contained text. Legal values are: a relative change or "x-slow", "slow", "medium", "fast", "x-fast", or "default". Labels "x-slow" through "x-fast" represent a sequence of monotonically non-decreasing speaking rates. When a number is used to specify a relative change it acts as a multiplier of the default rate. For example, a value of 1 means no change in speaking rate, a value of 2 means a speaking rate twice the default rate, and a value of 0.5 means a speaking rate of half the default rate. Further, changes can be specified as percentages (e.g. '10%' or '+15%'), but these are the only string entries permitted. The default rate for a voice depends on the language and dialect and on the personality of the voice. The default rate for a voice should be such that it is experienced as a normal speaking rate for the voice when reading aloud text. Since voices are processor-specific, the default rate will be as well.
106
106
  #
107
- # @return [Symbol, Float]
107
+ # @return [Symbol, Float, String]
108
108
  #
109
109
  def rate
110
110
  value = read_attr :rate
111
111
  return unless value
112
112
  if VALID_RATES.include?(value.to_sym)
113
113
  value.to_sym
114
+ elsif value.include? "%"
115
+ value
114
116
  else
115
117
  value.to_f
116
118
  end
117
119
  end
118
120
 
119
121
  ##
120
- # @param [Symbol, Numeric] v
122
+ # @param [Symbol, Numeric, String] v
121
123
  #
122
124
  # @raises ArgumentError if v is not either a positive Numeric or one of VALID_RATES
123
125
  #
124
126
  def rate=(v)
125
- raise ArgumentError, "You must specify a valid rate ([positive-number](multiplier), #{VALID_RATES.map(&:inspect).join ', '})" unless (v.is_a?(Numeric) && v >= 0) || VALID_RATES.include?(v)
127
+ raise ArgumentError, "You must specify a valid rate ([positive-number](multiplier), #{VALID_RATES.map(&:inspect).join ', '})" unless (v.is_a?(Numeric) && v >= 0) || VALID_RATES.include?(v) || (v.is_a?(String) && v.include?("%"))
126
128
  self[:rate] = v
127
129
  end
128
130
 
@@ -132,7 +134,8 @@ module RubySpeech
132
134
  # @return [Integer]
133
135
  #
134
136
  def duration
135
- read_attr :duration, :to_i
137
+ value = get_time_attribute :duration
138
+ value.round if value
136
139
  end
137
140
 
138
141
  ##
@@ -1,3 +1,3 @@
1
1
  module RubySpeech
2
- VERSION = "2.3.1"
2
+ VERSION = "3.0.1"
3
3
  end
data/ruby_speech.gemspec CHANGED
@@ -7,13 +7,11 @@ Gem::Specification.new do |s|
7
7
  s.version = RubySpeech::VERSION
8
8
  s.authors = ["Ben Langfeld"]
9
9
  s.email = ["ben@langfeld.me"]
10
- s.homepage = "https://github.com/benlangfeld/ruby_speech"
10
+ s.homepage = "https://github.com/adhearsion/ruby_speech"
11
11
  s.summary = %q{A Ruby library for TTS & ASR document preparation}
12
12
  s.description = %q{Prepare SSML and GRXML documents with ease}
13
-
14
- s.license = 'MIT'
15
13
 
16
- s.rubyforge_project = "ruby_speech"
14
+ s.license = 'MIT'
17
15
 
18
16
  s.files = `git ls-files`.split("\n")
19
17
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -27,18 +25,25 @@ Gem::Specification.new do |s|
27
25
  s.extensions = ['ext/ruby_speech/extconf.rb']
28
26
  end
29
27
 
30
- s.add_runtime_dependency %q<nokogiri>, ["~> 1.6"]
31
- s.add_runtime_dependency %q<activesupport>, [">= 3.0.7", "< 5.0.0"]
28
+ s.add_runtime_dependency %q<nokogiri>, ["~> 1.8", ">= 1.8.3"]
29
+ s.add_runtime_dependency %q<activesupport>, [">= 3.0.7"]
32
30
 
33
31
  s.add_development_dependency %q<bundler>, [">= 1.0.0"]
34
- s.add_development_dependency %q<rspec>, [">= 2.7"]
35
- s.add_development_dependency %q<ci_reporter>, [">= 1.6.3"]
32
+ s.add_development_dependency %q<rspec>, ["~> 3.0"]
33
+ s.add_development_dependency %q<rspec-its>, [">= 0"]
34
+ s.add_development_dependency %q<ci_reporter>, ["~> 1.6"]
36
35
  s.add_development_dependency %q<yard>, [">= 0.7.0"]
37
36
  s.add_development_dependency %q<rake>, [">= 0"]
38
37
  s.add_development_dependency %q<guard>, [">= 0.9.0"]
39
38
  s.add_development_dependency %q<guard-rspec>, [">= 0"]
39
+ s.add_development_dependency %q<listen>, ["< 3.1.0"]
40
40
  s.add_development_dependency %q<ruby_gntp>, [">= 0"]
41
41
  s.add_development_dependency %q<guard-rake>, [">= 0"]
42
42
  s.add_development_dependency %q<rake-compiler>, [">= 0"]
43
43
  s.add_development_dependency %q<coveralls>, [">= 0"]
44
+
45
+ if RUBY_VERSION < '2.0'
46
+ s.add_development_dependency %q<term-ansicolor>, ["< 1.3.1"]
47
+ s.add_development_dependency %q<tins>, ["~> 1.6.0"]
48
+ end
44
49
  end