ruby_speech 2.3.2 → 2.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bb37334ff6ea56b3b11705f1f8091c966de69ab4
4
- data.tar.gz: a9ef15cb9fe4fae5ae8a7b7731930d5ad7821fa7
3
+ metadata.gz: b584064437c31f1d9a90af218c8624a69c4c5149
4
+ data.tar.gz: d60362174787e23a94d6ef4b11449d3cc655febb
5
5
  SHA512:
6
- metadata.gz: 5ed551a6e78ef2e19ecf8ce194d5e1c5e04334f8974585ab7e101cbaef5bdece0c7cbb0156d721e6f682ab41170573f67a3d58eb7e0e7a7ce735d9f9d550f513
7
- data.tar.gz: 88c7b894a74862c146256c29970b67626072f837d81bd05108ce16ab93ee338d4c17d3a7455e4e5adf2dd4bef68520d2198e73628886125c9a4e9815e55de881
6
+ metadata.gz: ea4ced8154768936e7a3a3a7e580ecd1b7cabc0a949fa82f84eae374a17555d0974e4a6e29111fda0a9ea6f0878f27279f137ee15155f553d9a19e8a78813a90
7
+ data.tar.gz: 611147c468b4f36bb9cb6d1cbf3e760c055bf2a457e5db1209ce0fe6806171dbd319b90c1c6049fa7af17acbd69740bca0e9866d8e66a0f3ad3fb31da0d49e44
@@ -1,17 +1,38 @@
1
1
  language: ruby
2
2
 
3
- rvm:
4
- - 1.9.3
5
- - 2.0.0
6
- - 2.1.0
7
- - jruby
8
- - rbx
9
- - ruby-head
10
3
  matrix:
4
+ include:
5
+ - rvm: 1.9.3
6
+ - rvm: 2.0.0
7
+ - rvm: 2.1.0
8
+ - rvm: 2.2.0
9
+ - rvm: 2.3.0
10
+ - rvm: rbx-2
11
+ - rvm: rbx-3
12
+ - rvm: ruby-head
13
+ - rvm: jruby-1.7
14
+ jdk: openjdk7
15
+ - rvm: jruby-1.7
16
+ jdk: oraclejdk8
17
+ - rvm: jruby-head
18
+ jdk: oraclejdk8
19
+ - rvm: jruby-9.1.13.0
20
+ jdk: openjdk7
21
+ - rvm: jruby-9.1.13.0
22
+ jdk: oraclejdk8
11
23
  allow_failures:
24
+ - rvm: rbx-2
25
+ - rvm: rbx-3
12
26
  - rvm: ruby-head
27
+ sudo: false
28
+ addons:
29
+ apt:
30
+ packages:
31
+ - libpcre3
32
+ - libpcre3-dev
13
33
  before_install:
14
- - sudo apt-get install libpcre3 libpcre3-dev
34
+ - gem install bundler
35
+ env: JRUBY_OPTS="--server --debug -J-Xss1024k -J-Xmx652m -J-XX:+UseConcMarkSweepGC"
15
36
 
16
37
  notifications:
17
38
  irc: "irc.freenode.org#adhearsion"
@@ -1,5 +1,11 @@
1
1
  # [develop](https://github.com/benlangfeld/ruby_speech)
2
2
 
3
+ # [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)
4
+ * Feature: Permit percentage rate values for prosody tags
5
+ * Bugfix: Rulerefs referenced n-levels deep under Rulerefs should be expanded.
6
+ * Bugfix: Optimize performance of built-in number DTMF grammar
7
+ * Bugfix: Fix handling of millisecond values
8
+
3
9
  # [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)
4
10
  * Bugfix: String nodes should take non-strings and cast to a string (`#to_s`)
5
11
  * Bugfix: Cleanly handle NLSML with no input tag
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
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)
2
+ [![Build Status](https://secure.travis-ci.org/adhearsion/ruby_speech.png?branch=develop)](http://travis-ci.org/adhearsion/ruby_speech)
3
+ [![Dependency Status](https://gemnasium.com/adhearsion/ruby_speech.png?travis)](https://gemnasium.com/adhearsion/ruby_speech)
4
+ [![Code Climate](https://codeclimate.com/github/adhearsion/ruby_speech.png)](https://codeclimate.com/github/adhearsion/ruby_speech)
5
+ [![Coverage Status](https://coveralls.io/repos/adhearsion/ruby_speech/badge.png?branch=develop)](https://coveralls.io/r/adhearsion/ruby_speech)
6
6
 
7
7
  # RubySpeech
8
8
  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.
@@ -331,7 +331,7 @@ document.best_interpretation # => {
331
331
  }
332
332
  ```
333
333
 
334
- Check out the [YARD documentation](http://rdoc.info/github/benlangfeld/ruby_speech/master/frames) for more
334
+ Check out the [YARD documentation](http://rdoc.info/github/adhearsion/ruby_speech/master/frames) for more
335
335
 
336
336
  ## Features:
337
337
  ### SSML
@@ -374,10 +374,10 @@ Check out the [YARD documentation](http://rdoc.info/github/benlangfeld/ruby_spee
374
374
  * `<lexicon/>`
375
375
 
376
376
  ## Links:
377
- * [Source](https://github.com/benlangfeld/ruby_speech)
377
+ * [Source](https://github.com/adhearsion/ruby_speech)
378
378
  * [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)
379
+ * [Bug Tracker](https://github.com/adhearsion/ruby_speech/issues)
380
+ * [CI](https://travis-ci.org/#!/adhearsion/ruby_speech)
381
381
 
382
382
  ## Note on Patches/Pull Requests
383
383
 
@@ -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;
@@ -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'
@@ -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
 
@@ -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
@@ -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.2"
2
+ VERSION = "2.4.0"
3
3
  end
@@ -7,10 +7,10 @@ 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
-
13
+
14
14
  s.license = 'MIT'
15
15
 
16
16
  s.rubyforge_project = "ruby_speech"
@@ -27,18 +27,25 @@ Gem::Specification.new do |s|
27
27
  s.extensions = ['ext/ruby_speech/extconf.rb']
28
28
  end
29
29
 
30
- s.add_runtime_dependency %q<nokogiri>, ["~> 1.6"]
30
+ s.add_runtime_dependency %q<nokogiri>, ["~> 1.6.0"]
31
31
  s.add_runtime_dependency %q<activesupport>, [">= 3.0.7", "< 5.0.0"]
32
32
 
33
33
  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"]
34
+ s.add_development_dependency %q<rspec>, ["~> 2.99.0"]
35
+ s.add_development_dependency %q<rspec-its>, [">= 0"]
36
+ s.add_development_dependency %q<ci_reporter>, ["~> 1.6"]
36
37
  s.add_development_dependency %q<yard>, [">= 0.7.0"]
37
- s.add_development_dependency %q<rake>, [">= 0"]
38
+ s.add_development_dependency %q<rake>, ["< 11.0"]
38
39
  s.add_development_dependency %q<guard>, [">= 0.9.0"]
39
40
  s.add_development_dependency %q<guard-rspec>, [">= 0"]
41
+ s.add_development_dependency %q<listen>, ["< 3.1.0"]
40
42
  s.add_development_dependency %q<ruby_gntp>, [">= 0"]
41
43
  s.add_development_dependency %q<guard-rake>, [">= 0"]
42
44
  s.add_development_dependency %q<rake-compiler>, [">= 0"]
43
45
  s.add_development_dependency %q<coveralls>, [">= 0"]
46
+
47
+ if RUBY_VERSION < '2.0'
48
+ s.add_development_dependency %q<term-ansicolor>, ["< 1.3.1"]
49
+ s.add_development_dependency %q<tins>, ["~> 1.6.0"]
50
+ end
44
51
  end
@@ -119,22 +119,31 @@ describe RubySpeech::GRXML::Builtins do
119
119
  it { should not_match('#') }
120
120
  end
121
121
 
122
- describe "number" do
122
+ describe 'number' do
123
123
  subject(:grammar) { described_class.number }
124
124
 
125
- it { should match('0').and_interpret_as('dtmf-0') }
126
- it { should match('123').and_interpret_as('dtmf-1 dtmf-2 dtmf-3') }
127
- it { should match('1*01').and_interpret_as('dtmf-1 dtmf-star dtmf-0 dtmf-1') }
128
- it { should match('01*00').and_interpret_as('dtmf-0 dtmf-1 dtmf-star dtmf-0 dtmf-0') }
129
- it { should match('100000000000*00').and_interpret_as('dtmf-1 dtmf-0 dtmf-0 dtmf-0 dtmf-0 dtmf-0 dtmf-0 dtmf-0 dtmf-0 dtmf-0 dtmf-0 dtmf-0 dtmf-star dtmf-0 dtmf-0') }
130
- it { should match('0*08').and_interpret_as('dtmf-0 dtmf-star dtmf-0 dtmf-8') }
131
- it { should match('*59').and_interpret_as('dtmf-star dtmf-5 dtmf-9') }
132
- it { should match('0*0').and_interpret_as('dtmf-0 dtmf-star dtmf-0') }
133
- it { should match('10*5').and_interpret_as('dtmf-1 dtmf-0 dtmf-star dtmf-5') }
134
- it { should match('123*').and_interpret_as('dtmf-1 dtmf-2 dtmf-3 dtmf-star') }
135
- it { should match('123*2342').and_interpret_as('dtmf-1 dtmf-2 dtmf-3 dtmf-star dtmf-2 dtmf-3 dtmf-4 dtmf-2') }
125
+ it { should match('0').and_interpret_as 'dtmf-0' }
126
+ it { should match('123').and_interpret_as 'dtmf-1 dtmf-2 dtmf-3' }
127
+ it { should match('1*01').and_interpret_as dtmf_seq %w(1 star 0 1) }
128
+ it { should match('01*00').and_interpret_as dtmf_seq %w(0 1 star 0 0) }
129
+ it do
130
+ should match('100000000000*00')
131
+ .and_interpret_as dtmf_seq %w(1 0 0 0 0 0 0 0 0 0 0 0 star 0 0)
132
+ end
133
+ it { should match('0*08').and_interpret_as dtmf_seq %w(0 star 0 8) }
134
+ it { should match('*59').and_interpret_as 'dtmf-star dtmf-5 dtmf-9' }
135
+ it { should match('0*0').and_interpret_as 'dtmf-0 dtmf-star dtmf-0' }
136
+ it { should match('10*5').and_interpret_as dtmf_seq %w(1 0 star 5) }
137
+ it { should match('123*').and_interpret_as dtmf_seq %w(1 2 3 star) }
138
+ it do
139
+ should match('123*2342').and_interpret_as dtmf_seq %w(1 2 3 star 2 3 4 2)
140
+ end
136
141
 
137
- it { should not_match('#') }
142
+ it { should potentially_match '*' }
143
+
144
+ it { should not_match '#' }
145
+ it { should not_match '**' }
146
+ it { should not_match '0123*456*789' }
138
147
  end
139
148
 
140
149
  describe "phone" do
@@ -232,6 +232,140 @@ module RubySpeech
232
232
  grammar.inline!.should == inline_grammar
233
233
  grammar.should == inline_grammar
234
234
  end
235
+
236
+ context 'nested' do
237
+ let :expected_doc do
238
+ RubySpeech::GRXML.draw mode: :dtmf, root: 'main' do
239
+ rule id: :main, scope: 'public' do
240
+ string "How about an oatmeal cookie? You'll feel better."
241
+ end
242
+ end
243
+ end
244
+
245
+ context '1 level deep' do
246
+ subject do
247
+ RubySpeech::GRXML.draw mode: :dtmf, root: 'main' do
248
+ rule id: :main, scope: 'public' do
249
+ ruleref uri: '#rabbit_hole2'
250
+ end
251
+ rule id: 'rabbit_hole2' do
252
+ string "How about an oatmeal cookie? You'll feel better."
253
+ end
254
+ end.inline
255
+ end
256
+
257
+ it { should eq expected_doc }
258
+ end
259
+
260
+ context '2 levels deep' do
261
+ subject do
262
+ RubySpeech::GRXML.draw mode: :dtmf, root: 'main' do
263
+ rule id: :main, scope: 'public' do
264
+ ruleref uri: '#rabbit_hole2'
265
+ end
266
+ rule id: 'rabbit_hole2' do
267
+ ruleref uri: '#rabbit_hole3'
268
+ end
269
+ rule id: 'rabbit_hole3' do
270
+ string "How about an oatmeal cookie? You'll feel better."
271
+ end
272
+ end.inline
273
+ end
274
+
275
+ it { should eq expected_doc }
276
+ end
277
+
278
+ context '3 levels deep' do
279
+ subject do
280
+ RubySpeech::GRXML.draw mode: :dtmf, root: 'main' do
281
+ rule id: :main, scope: 'public' do
282
+ ruleref uri: '#rabbit_hole2'
283
+ end
284
+ rule id: 'rabbit_hole2' do
285
+ ruleref uri: '#rabbit_hole3'
286
+ end
287
+ rule id: 'rabbit_hole3' do
288
+ ruleref uri: '#rabbit_hole4'
289
+ end
290
+ rule id: 'rabbit_hole4' do
291
+ string "How about an oatmeal cookie? You'll feel better."
292
+ end
293
+ end.inline
294
+ end
295
+
296
+ it { should eq expected_doc }
297
+ end
298
+
299
+ context 'in a self-referencial infinite loop' do
300
+ subject do
301
+ RubySpeech::GRXML.draw mode: :dtmf, root: 'main' do
302
+ rule id: :main, scope: 'public' do
303
+ ruleref uri: '#paradox'
304
+ end
305
+ rule id: 'paradox' do
306
+ ruleref uri: '#paradox'
307
+ end
308
+ end.inline
309
+ end
310
+
311
+ it 'should raise an Exception' do
312
+ expect { subject }
313
+ .to raise_error RubySpeech::GRXML::ReferentialLoopError
314
+ end
315
+ end
316
+
317
+ context 'in a cross-referencial infinite loop' do
318
+ subject do
319
+ RubySpeech::GRXML.draw mode: :dtmf, root: 'main' do
320
+ rule id: :main, scope: 'public' do
321
+ ruleref uri: '#007'
322
+ end
323
+ rule id: '007' do
324
+ one_of do
325
+ item do
326
+ ruleref uri: '#bond'
327
+ end
328
+ end
329
+ end
330
+ rule id: 'bond' do
331
+ one_of do
332
+ item do
333
+ ruleref uri: '#james_bond'
334
+ end
335
+ end
336
+ end
337
+ rule id: 'james_bond' do
338
+ one_of do
339
+ item do
340
+ ruleref uri: '#007'
341
+ end
342
+ end
343
+ end
344
+ end.inline
345
+ end
346
+
347
+ it 'should raise an Exception' do
348
+ expect { subject }
349
+ .to raise_error RubySpeech::GRXML::ReferentialLoopError
350
+ end
351
+ end
352
+
353
+ context 'with an invalid-reference' do
354
+ subject do
355
+ RubySpeech::GRXML.draw mode: :dtmf, root: 'main' do
356
+ rule id: :main, scope: 'public' do
357
+ ruleref uri: '#lost'
358
+ end
359
+ end.inline
360
+ end
361
+
362
+ it 'should raise a descriptive exception' do
363
+ expect { subject }
364
+ .to raise_error RubySpeech::GRXML::MissingReferenceError,
365
+ "Ruleref '#lost' is referenced but not defined"
366
+ end
367
+ end
368
+ end
235
369
  end
236
370
 
237
371
  describe "#tokenize!" do
@@ -516,6 +516,50 @@ module RubySpeech
516
516
  end
517
517
  end
518
518
 
519
+ context "with a grammar that takes a a specific digit repeated within a range" do
520
+ let(:grammar) do
521
+ GRXML.draw :mode => :dtmf, :root => 'digits' do
522
+ rule :id => 'digits' do
523
+ item :repeat => 0..3 do
524
+ '6'
525
+ end
526
+ end
527
+ end
528
+ end
529
+
530
+ {
531
+ '' => '',
532
+ '6' => 'dtmf-6',
533
+ '66' => 'dtmf-6 dtmf-6',
534
+ }.each_pair do |input, interpretation|
535
+ it "should match '#{input}'" do
536
+ expected_match = GRXML::Match.new :mode => :dtmf,
537
+ :confidence => 1,
538
+ :utterance => input,
539
+ :interpretation => interpretation
540
+ subject.match(input).should == expected_match
541
+ end
542
+ end
543
+
544
+ {
545
+ '666' => 'dtmf-6 dtmf-6 dtmf-6',
546
+ }.each_pair do |input, interpretation|
547
+ it "should maximally match '#{input}'" do
548
+ expected_match = GRXML::MaxMatch.new :mode => :dtmf,
549
+ :confidence => 1,
550
+ :utterance => input,
551
+ :interpretation => interpretation
552
+ subject.match(input).should == expected_match
553
+ end
554
+ end
555
+
556
+ %w{6666 7}.each do |input|
557
+ it "should not match '#{input}'" do
558
+ subject.match(input).should == GRXML::NoMatch.new
559
+ end
560
+ end
561
+ end
562
+
519
563
  context "with a grammar that takes a a specific digit repeated within a range, followed by specific digit" do
520
564
  let(:grammar) do
521
565
  GRXML.draw :mode => :dtmf, :root => 'digits' do
@@ -21,14 +21,28 @@ module RubySpeech
21
21
  end
22
22
 
23
23
  describe "from a document" do
24
- let(:document) { '<break strength="strong" time="3"/>' }
25
-
26
24
  subject { Element.import document }
27
25
 
28
- it { should be_instance_of Break }
26
+ context 'with time of 3' do
27
+ let(:document) { '<break strength="strong" time="3"/>' }
29
28
 
30
- its(:strength) { should == :strong }
31
- its(:time) { should == 3 }
29
+ it { should be_instance_of Break }
30
+
31
+ its(:strength) { should == :strong }
32
+ its(:time) { should eql 3.0 }
33
+ end
34
+
35
+ context 'with time of 4s' do
36
+ let(:document) { '<break time="4s"/>' }
37
+
38
+ its(:time) { should eql 4.0 }
39
+ end
40
+
41
+ context 'with time of 5555ms' do
42
+ let(:document) { '<break time="5555ms"/>' }
43
+
44
+ its(:time) { should eql 5.555 }
45
+ end
32
46
  end
33
47
 
34
48
  describe "#strength" do
@@ -51,10 +65,16 @@ module RubySpeech
51
65
  end
52
66
 
53
67
  describe "#time" do
54
- context "with a valid value" do
68
+ context "with a valid whole seconds value of 3" do
55
69
  before { subject.time = 3 }
56
70
 
57
- its(:time) { should == 3 }
71
+ its(:time) { should eql 3.0 }
72
+ end
73
+
74
+ context "with a valid fractional seconds value of 3.5" do
75
+ before { subject.time = 3.5 }
76
+
77
+ its(:time) { should eql 3.5 }
58
78
  end
59
79
 
60
80
  context "with a negative value" do
@@ -16,7 +16,7 @@ module RubySpeech
16
16
  its(:contour) { should == 'something' }
17
17
  its(:range) { should == '20Hz' }
18
18
  its(:rate) { should == 2 }
19
- its(:duration) { should == 10 }
19
+ its(:duration) { should eql 10 }
20
20
  its(:volume) { should == :loud }
21
21
  end
22
22
 
@@ -35,7 +35,7 @@ module RubySpeech
35
35
  its(:contour) { should == 'something' }
36
36
  its(:range) { should == '20Hz' }
37
37
  its(:rate) { should == 2 }
38
- its(:duration) { should == 10 }
38
+ its(:duration) { should eql 10 }
39
39
  its(:volume) { should == :loud }
40
40
  end
41
41
 
@@ -149,6 +149,24 @@ module RubySpeech
149
149
  it "with a negative value" do
150
150
  lambda { subject.rate = -100 }.should raise_error(ArgumentError, "You must specify a valid rate ([positive-number](multiplier), :\"x-slow\", :slow, :medium, :fast, :\"x-fast\", :default)")
151
151
  end
152
+
153
+ describe "with a percentage" do
154
+ before { subject.rate = "22.5%" }
155
+
156
+ its(:rate) { should == "22.5%" }
157
+ end
158
+
159
+ describe "with a percentage and a plus sign" do
160
+ before { subject.rate = "+22.5%" }
161
+
162
+ its(:rate) { should == "+22.5%" }
163
+ end
164
+
165
+ describe "with a percentage and a minus sign" do
166
+ before { subject.rate = "-22.5%" }
167
+
168
+ its(:rate) { should == "-22.5%" }
169
+ end
152
170
  end
153
171
  end
154
172
 
@@ -156,7 +174,7 @@ module RubySpeech
156
174
  context "with a valid value" do
157
175
  before { subject.duration = 3 }
158
176
 
159
- its(:duration) { should == 3 }
177
+ its(:duration) { should eql 3 }
160
178
  end
161
179
 
162
180
  context "with a negative value" do
@@ -1,8 +1,14 @@
1
- require 'ruby_speech'
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
- require 'coveralls'
4
+ require "coveralls"
4
5
  Coveralls.wear!
5
6
 
7
+ %w{
8
+ rspec/its
9
+ ruby_speech
10
+ }.each { |f| require f }
11
+
6
12
  Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
7
13
 
8
14
  schema_file_path = File.expand_path File.join(__FILE__, '../../assets/synthesis.xsd')
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # Convert a simple DTMF string from "1 star 2" to "dtmf-1 dtmf-star dtmf-2".
6
+ #
7
+ # @param [Array] sequence A set of DTMF keys, such as `%w(1 star 2)`.
8
+ #
9
+ # @return [String] A string with "dtmf-" prefixed for each DTMF element.
10
+ # Example: "dtmf-1 dtmf-star dtmf-2".
11
+ #
12
+ def dtmf_seq(sequence)
13
+ sequence.map { |d| "dtmf-#{d}" }.join ' '
14
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_speech
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.2
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Langfeld
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-21 00:00:00.000000000 Z
11
+ date: 2018-02-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.6'
19
+ version: 1.6.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.6'
26
+ version: 1.6.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activesupport
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -60,32 +60,46 @@ dependencies:
60
60
  version: 1.0.0
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: rspec
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: 2.99.0
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: 2.99.0
75
+ - !ruby/object:Gem::Dependency
76
+ name: rspec-its
63
77
  requirement: !ruby/object:Gem::Requirement
64
78
  requirements:
65
79
  - - ">="
66
80
  - !ruby/object:Gem::Version
67
- version: '2.7'
81
+ version: '0'
68
82
  type: :development
69
83
  prerelease: false
70
84
  version_requirements: !ruby/object:Gem::Requirement
71
85
  requirements:
72
86
  - - ">="
73
87
  - !ruby/object:Gem::Version
74
- version: '2.7'
88
+ version: '0'
75
89
  - !ruby/object:Gem::Dependency
76
90
  name: ci_reporter
77
91
  requirement: !ruby/object:Gem::Requirement
78
92
  requirements:
79
- - - ">="
93
+ - - "~>"
80
94
  - !ruby/object:Gem::Version
81
- version: 1.6.3
95
+ version: '1.6'
82
96
  type: :development
83
97
  prerelease: false
84
98
  version_requirements: !ruby/object:Gem::Requirement
85
99
  requirements:
86
- - - ">="
100
+ - - "~>"
87
101
  - !ruby/object:Gem::Version
88
- version: 1.6.3
102
+ version: '1.6'
89
103
  - !ruby/object:Gem::Dependency
90
104
  name: yard
91
105
  requirement: !ruby/object:Gem::Requirement
@@ -104,16 +118,16 @@ dependencies:
104
118
  name: rake
105
119
  requirement: !ruby/object:Gem::Requirement
106
120
  requirements:
107
- - - ">="
121
+ - - "<"
108
122
  - !ruby/object:Gem::Version
109
- version: '0'
123
+ version: '11.0'
110
124
  type: :development
111
125
  prerelease: false
112
126
  version_requirements: !ruby/object:Gem::Requirement
113
127
  requirements:
114
- - - ">="
128
+ - - "<"
115
129
  - !ruby/object:Gem::Version
116
- version: '0'
130
+ version: '11.0'
117
131
  - !ruby/object:Gem::Dependency
118
132
  name: guard
119
133
  requirement: !ruby/object:Gem::Requirement
@@ -142,6 +156,20 @@ dependencies:
142
156
  - - ">="
143
157
  - !ruby/object:Gem::Version
144
158
  version: '0'
159
+ - !ruby/object:Gem::Dependency
160
+ name: listen
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - "<"
164
+ - !ruby/object:Gem::Version
165
+ version: 3.1.0
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - "<"
171
+ - !ruby/object:Gem::Version
172
+ version: 3.1.0
145
173
  - !ruby/object:Gem::Dependency
146
174
  name: ruby_gntp
147
175
  requirement: !ruby/object:Gem::Requirement
@@ -294,10 +322,11 @@ files:
294
322
  - spec/ruby_speech/ssml_spec.rb
295
323
  - spec/ruby_speech_spec.rb
296
324
  - spec/spec_helper.rb
325
+ - spec/support/dtmf_helper.rb
297
326
  - spec/support/grammar_matchers.rb
298
327
  - spec/support/match_examples.rb
299
328
  - spec/support/matchers.rb
300
- homepage: https://github.com/benlangfeld/ruby_speech
329
+ homepage: https://github.com/adhearsion/ruby_speech
301
330
  licenses:
302
331
  - MIT
303
332
  metadata: {}
@@ -317,7 +346,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
317
346
  version: '0'
318
347
  requirements: []
319
348
  rubyforge_project: ruby_speech
320
- rubygems_version: 2.2.2
349
+ rubygems_version: 2.5.1
321
350
  signing_key:
322
351
  specification_version: 4
323
352
  summary: A Ruby library for TTS & ASR document preparation
@@ -353,7 +382,7 @@ test_files:
353
382
  - spec/ruby_speech/ssml_spec.rb
354
383
  - spec/ruby_speech_spec.rb
355
384
  - spec/spec_helper.rb
385
+ - spec/support/dtmf_helper.rb
356
386
  - spec/support/grammar_matchers.rb
357
387
  - spec/support/match_examples.rb
358
388
  - spec/support/matchers.rb
359
- has_rdoc: