ruby_speech 2.3.2 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
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: