alexa_ruby 0.2.0 → 1.0.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 +4 -4
- data/Gemfile +0 -1
- data/Gemfile.lock +24 -21
- data/README.md +26 -14
- data/Rakefile +6 -4
- data/lib/alexa_ruby/alexa.rb +52 -0
- data/lib/alexa_ruby/request/audio_player_request.rb +18 -25
- data/lib/alexa_ruby/request/base_request/context/device.rb +28 -0
- data/lib/alexa_ruby/request/base_request/context/user.rb +28 -0
- data/lib/alexa_ruby/request/base_request/context.rb +45 -0
- data/lib/alexa_ruby/request/base_request/session.rb +60 -0
- data/lib/alexa_ruby/request/base_request.rb +53 -0
- data/lib/alexa_ruby/request/intent_request/slot.rb +28 -11
- data/lib/alexa_ruby/request/intent_request.rb +41 -42
- data/lib/alexa_ruby/request/launch_request.rb +3 -10
- data/lib/alexa_ruby/request/session_ended_request.rb +12 -12
- data/lib/alexa_ruby/response/audio_player.rb +25 -32
- data/lib/alexa_ruby/response/card.rb +67 -12
- data/lib/alexa_ruby/response.rb +155 -127
- data/lib/alexa_ruby/version.rb +1 -1
- data/lib/alexa_ruby.rb +40 -66
- data/spec/request_spec.rb +197 -0
- data/spec/response_spec.rb +201 -0
- data/spec/spec_helper.rb +7 -0
- metadata +57 -19
- data/lib/alexa_ruby/request.rb +0 -28
- data/lib/alexa_ruby/session.rb +0 -55
data/lib/alexa_ruby.rb
CHANGED
@@ -1,85 +1,59 @@
|
|
1
|
+
# Utilities
|
1
2
|
require 'oj'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
require 'alexa_ruby/
|
6
|
-
require 'alexa_ruby/request/
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
# Gem core
|
6
|
+
require 'alexa_ruby/alexa'
|
7
|
+
require 'alexa_ruby/request/base_request'
|
8
|
+
require 'alexa_ruby/request/base_request/context'
|
9
|
+
require 'alexa_ruby/request/base_request/context/device'
|
10
|
+
require 'alexa_ruby/request/base_request/context/user'
|
11
|
+
require 'alexa_ruby/request/base_request/session'
|
12
|
+
require 'alexa_ruby/request/audio_player_request'
|
7
13
|
require 'alexa_ruby/request/launch_request'
|
14
|
+
require 'alexa_ruby/request/intent_request'
|
15
|
+
require 'alexa_ruby/request/intent_request/slot'
|
8
16
|
require 'alexa_ruby/request/session_ended_request'
|
9
|
-
require 'alexa_ruby/
|
17
|
+
require 'alexa_ruby/response'
|
18
|
+
require 'alexa_ruby/response/audio_player'
|
19
|
+
require 'alexa_ruby/response/card'
|
20
|
+
require 'alexa_ruby/version'
|
10
21
|
|
11
22
|
# AlexaRuby implements a back-end service for interaction with Amazon Alexa API
|
12
23
|
module AlexaRuby
|
13
24
|
class << self
|
14
|
-
#
|
25
|
+
# Validate HTTP/S request body and initialize new Alexa Assistant
|
15
26
|
#
|
16
|
-
# @param
|
17
|
-
|
18
|
-
|
27
|
+
# @param request [Object] request from Amazon Alexa web service,
|
28
|
+
# can be hash or JSON encoded string
|
29
|
+
# @return [Object] new Request object instance
|
30
|
+
# @raise [ArgumentError] if given object isn't a valid JSON object
|
31
|
+
def new(request)
|
32
|
+
obj = build_json(request)
|
33
|
+
Alexa.new(obj)
|
19
34
|
end
|
20
35
|
|
21
|
-
|
22
|
-
def print_version
|
23
|
-
p AlexaRuby::VERSION
|
24
|
-
end
|
36
|
+
private
|
25
37
|
|
26
|
-
#
|
38
|
+
# Build JSON from received request
|
27
39
|
#
|
28
|
-
# @param
|
29
|
-
#
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
@request = define_request(json)
|
38
|
-
raise ArgumentError, 'Invalid Request Type' if @request.nil?
|
39
|
-
@request
|
40
|
+
# @param obj [Object] request from Amazon Alexa web service,
|
41
|
+
# can be hash or JSON encoded string
|
42
|
+
# @return [Hash] valid builded JSON
|
43
|
+
# @raise [ArgumentError] if given object isn't a valid JSON object
|
44
|
+
def build_json(obj)
|
45
|
+
obj = Oj.generate(obj) if hash?(obj)
|
46
|
+
Oj.load(obj, symbol_keys: true)
|
47
|
+
rescue StandardError
|
48
|
+
raise ArgumentError, 'Request must be a valid JSON object'
|
40
49
|
end
|
41
50
|
|
42
|
-
# Check if
|
51
|
+
# Check if object is a Hash or not
|
43
52
|
#
|
44
|
-
# @param
|
53
|
+
# @param obj [Object] some object
|
45
54
|
# @return [Boolean]
|
46
|
-
def
|
47
|
-
|
48
|
-
if json[:request].nil? || /AudioPlayer/.match(json[:request][:type])
|
49
|
-
true
|
50
|
-
else
|
51
|
-
!json[:session].nil?
|
52
|
-
end
|
53
|
-
!json.nil? && session && !json[:version].nil? && !json[:request].nil?
|
54
|
-
end
|
55
|
-
|
56
|
-
# Define proper request class and instantinate it
|
57
|
-
#
|
58
|
-
# @param json [JSON] json request from Amazon Alexa
|
59
|
-
# @return [Object] instance of request class
|
60
|
-
def define_request(json)
|
61
|
-
case json[:request][:type]
|
62
|
-
when /Launch/
|
63
|
-
LaunchRequest.new(json)
|
64
|
-
when /Intent/
|
65
|
-
IntentRequest.new(json)
|
66
|
-
when /SessionEnded/
|
67
|
-
SessionEndedRequest.new(json)
|
68
|
-
when /AudioPlayer/
|
69
|
-
AudioPlayerRequest.new(json)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
private
|
74
|
-
|
75
|
-
# Parse JSON request, validate it and convert it to hash
|
76
|
-
#
|
77
|
-
# @param request [String] json request from Amazon Alexa
|
78
|
-
# @return [Hash] loaded and validated request
|
79
|
-
def load_json(request)
|
80
|
-
Oj.load(request, symbol_keys: true)
|
81
|
-
rescue StandardError
|
82
|
-
raise ArgumentError, 'Invalid JSON in request'
|
55
|
+
def hash?(obj)
|
56
|
+
obj.is_a? Hash
|
83
57
|
end
|
84
58
|
end
|
85
59
|
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Amazon Alexa request handling' do
|
4
|
+
before do
|
5
|
+
@fpath = 'spec/fixtures/request'
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'General request handling' do
|
9
|
+
before do
|
10
|
+
@json = File.read("#{@fpath}/launch_request.json")
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'Request' do
|
14
|
+
it 'should build a Request object for valid JSON' do
|
15
|
+
alexa = AlexaRuby.new(@json)
|
16
|
+
alexa.request.wont_be_nil
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should build a Response object for valid JSON' do
|
20
|
+
alexa = AlexaRuby.new(@json)
|
21
|
+
alexa.response.wont_be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should build a Request object for valid Hash' do
|
25
|
+
alexa = AlexaRuby.new(Oj.load(@json))
|
26
|
+
alexa.request.wont_be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should build a Response object for valid Hash' do
|
30
|
+
alexa = AlexaRuby.new(Oj.load(@json))
|
31
|
+
alexa.response.wont_be_nil
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should raise ArgumentError in case of invalid JSON' do
|
35
|
+
err = proc { AlexaRuby.new('{"test":}') }.must_raise ArgumentError
|
36
|
+
err.message.must_equal 'Request must be a valid JSON object'
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should raise ArgumentError in case of invalid Hash' do
|
40
|
+
err = proc { AlexaRuby.new('{"test":}') }.must_raise ArgumentError
|
41
|
+
err.message.must_equal 'Request must be a valid JSON object'
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should setup all request parameters' do
|
45
|
+
alexa = AlexaRuby.new(@json)
|
46
|
+
alexa.request.version.wont_be_nil
|
47
|
+
alexa.request.type.wont_be_nil
|
48
|
+
alexa.request.context.wont_be_nil
|
49
|
+
alexa.request.id.wont_be_nil
|
50
|
+
alexa.request.timestamp.wont_be_nil
|
51
|
+
alexa.request.locale.wont_be_nil
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should raise ArgumentError if request ID is missing' do
|
55
|
+
req = Oj.load(@json, symbol_keys: true)
|
56
|
+
req[:request][:requestId] = nil
|
57
|
+
err = proc { AlexaRuby.new(req) }.must_raise ArgumentError
|
58
|
+
err.message.must_equal 'Missing request ID'
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should raise ArgumentError if request timestamp is missing' do
|
62
|
+
req = Oj.load(@json, symbol_keys: true)
|
63
|
+
req[:request][:timestamp] = nil
|
64
|
+
err = proc { AlexaRuby.new(req) }.must_raise ArgumentError
|
65
|
+
err.message.must_equal 'Missing request timestamp'
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should raise ArgumentError if request type unknown' do
|
69
|
+
req = Oj.load(@json, symbol_keys: true)
|
70
|
+
req[:request][:type] = 'dummy'
|
71
|
+
err = proc { AlexaRuby.new(req) }.must_raise ArgumentError
|
72
|
+
err.message.must_equal 'Unknown type of Alexa request'
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should raise ArgumentError if request structure isn\'t valid' do
|
76
|
+
req = Oj.load(@json, symbol_keys: true)
|
77
|
+
req[:request] = nil
|
78
|
+
msg = 'Invalid request structure, ' \
|
79
|
+
'please, refer to the Amazon Alexa manual: ' \
|
80
|
+
'https://developer.amazon.com/public/solutions' \
|
81
|
+
'/alexa/alexa-skills-kit/docs/alexa-skills-kit-interface-reference'
|
82
|
+
err = proc { AlexaRuby.new(req) }.must_raise ArgumentError
|
83
|
+
err.message.must_equal msg
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'Session' do
|
88
|
+
it 'should set correct session params' do
|
89
|
+
alexa = AlexaRuby.new(@json)
|
90
|
+
alexa.request.session.state.wont_be_nil
|
91
|
+
alexa.request.session.id.wont_be_nil
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should raise ArgumentError if session isn\'t valid' do
|
95
|
+
req = Oj.load(@json, symbol_keys: true)
|
96
|
+
req[:session] = nil
|
97
|
+
err = proc { AlexaRuby.new(req) }.must_raise ArgumentError
|
98
|
+
err.message.must_equal 'Empty user session'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe 'Context' do
|
103
|
+
it 'should set correct context params' do
|
104
|
+
alexa = AlexaRuby.new(@json)
|
105
|
+
alexa.request.context.app_id.wont_be_nil
|
106
|
+
alexa.request.context.user.wont_be_nil
|
107
|
+
alexa.request.context.user.id.wont_be_nil
|
108
|
+
alexa.request.context.device.wont_be_nil
|
109
|
+
alexa.request.context.device.id.wont_be_nil
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should raise ArgumentError if application ID is missing' do
|
113
|
+
req = Oj.load(@json, symbol_keys: true)
|
114
|
+
req[:context][:System][:application][:applicationId] = nil
|
115
|
+
err = proc { AlexaRuby.new(req) }.must_raise ArgumentError
|
116
|
+
err.message.must_equal 'Missing application ID'
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should raise ArgumentError if user ID is missing' do
|
120
|
+
req = Oj.load(@json, symbol_keys: true)
|
121
|
+
req[:context][:System][:user][:userId] = nil
|
122
|
+
err = proc { AlexaRuby.new(req) }.must_raise ArgumentError
|
123
|
+
err.message.must_equal 'Missing user ID'
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should raise ArgumentError if device ID is missing' do
|
127
|
+
req = Oj.load(@json, symbol_keys: true)
|
128
|
+
req[:context][:System][:device][:deviceId] = nil
|
129
|
+
err = proc { AlexaRuby.new(req) }.must_raise ArgumentError
|
130
|
+
err.message.must_equal 'Missing device ID'
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe 'LaunchRequest' do
|
136
|
+
before do
|
137
|
+
@json = File.read("#{@fpath}/launch_request.json")
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'should parse valid LaunchRequest correctly' do
|
141
|
+
alexa = AlexaRuby.new(@json)
|
142
|
+
alexa.request.type.must_equal :launch
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe 'IntentRequest' do
|
147
|
+
before do
|
148
|
+
@json = File.read("#{@fpath}/intent_request.json")
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should parse valid IntentRequest correctly' do
|
152
|
+
alexa = AlexaRuby.new(@json)
|
153
|
+
alexa.request.type.must_equal :intent
|
154
|
+
alexa.request.intent_name.must_equal 'GetZodiacHoroscopeIntent'
|
155
|
+
alexa.request.confirmation_status.must_equal :unknown
|
156
|
+
alexa.request.dialog_state.must_equal :completed
|
157
|
+
alexa.request.slots[0].name.must_equal 'ZodiacSign'
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'should raise an ArgumentError if intent is undefined' do
|
161
|
+
req = Oj.load(@json, symbol_keys: true)
|
162
|
+
req[:request][:intent] = nil
|
163
|
+
err = proc { AlexaRuby.new(req) }.must_raise ArgumentError
|
164
|
+
err.message.must_equal 'Intent must be defined'
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe 'SessionEndedRequest' do
|
169
|
+
before do
|
170
|
+
@json = File.read("#{@fpath}/session_ended_request.json")
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'should parse valid SessionEndedRequest correctly' do
|
174
|
+
alexa = AlexaRuby.new(@json)
|
175
|
+
alexa.request.type.must_equal :session_ended
|
176
|
+
alexa.request.session.state.must_equal :ended
|
177
|
+
alexa.request.session.end_reason.must_equal :user_quit
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
describe 'AudioPlayerRequest' do
|
182
|
+
before do
|
183
|
+
@json = File.read("#{@fpath}/audio_player_request.json")
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should parse valid AudioPlayerRequest correctly' do
|
187
|
+
alexa = AlexaRuby.new(@json)
|
188
|
+
alexa.request.type.must_equal :audio_player
|
189
|
+
alexa.request.playback_state.must_equal 'PlaybackFailed'
|
190
|
+
alexa.request.playback_offset.must_equal 0
|
191
|
+
alexa.request.error_type.must_equal 'string'
|
192
|
+
alexa.request.error_message.must_equal 'string'
|
193
|
+
alexa.request.error_playback_token.must_equal 'string'
|
194
|
+
alexa.request.error_player_activity.must_equal 'string'
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Build response to Amazon Alexa service' do
|
4
|
+
before do
|
5
|
+
@req_path = 'spec/fixtures/request'
|
6
|
+
@resp_path = 'spec/fixtures/response'
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'General response handling' do
|
10
|
+
before do
|
11
|
+
@json = File.read("#{@req_path}/launch_request.json")
|
12
|
+
@alexa = AlexaRuby.new(@json)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should build a Response object for valid JSON' do
|
16
|
+
@alexa.response.wont_be_nil
|
17
|
+
resp = Oj.load(@alexa.response.json, symbol_keys: true)
|
18
|
+
resp[:version].wont_be_nil
|
19
|
+
resp[:response][:shouldEndSession].must_equal true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'Session parameters management' do
|
24
|
+
before do
|
25
|
+
@json = File.read("#{@req_path}/launch_request.json")
|
26
|
+
@alexa = AlexaRuby.new(@json)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should add one session attribute correctly' do
|
30
|
+
@alexa.response.add_session_attribute(:id, 'djsdhdsjhdsjhdsjh')
|
31
|
+
resp = Oj.load(@alexa.response.json, symbol_keys: true)
|
32
|
+
resp[:sessionAttributes][:id].must_equal 'djsdhdsjhdsjhdsjh'
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should add pack of session attributes correctly' do
|
36
|
+
@alexa.response.add_session_attributes(
|
37
|
+
id: 'djsdhdsjhdsjhdsjh',
|
38
|
+
test: 'test'
|
39
|
+
)
|
40
|
+
resp = Oj.load(@alexa.response.json, symbol_keys: true)
|
41
|
+
resp[:sessionAttributes][:id].must_equal 'djsdhdsjhdsjhdsjh'
|
42
|
+
resp[:sessionAttributes][:test].must_equal 'test'
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should merge pack of session attributes correctly' do
|
46
|
+
@alexa.response.add_session_attributes(
|
47
|
+
id: 'djsdhdsjhdsjhdsjh',
|
48
|
+
test: 'test'
|
49
|
+
)
|
50
|
+
@alexa.response.merge_session_attributes(token: '7783y3h43hg4ghh')
|
51
|
+
resp = Oj.load(@alexa.response.json, symbol_keys: true)
|
52
|
+
resp[:sessionAttributes][:id].must_equal 'djsdhdsjhdsjhdsjh'
|
53
|
+
resp[:sessionAttributes][:test].must_equal 'test'
|
54
|
+
resp[:sessionAttributes][:token].must_equal '7783y3h43hg4ghh'
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should raise ArgumentError if duplicate attribute found' do
|
58
|
+
@alexa.response.add_session_attribute(:id, 'djsdhdsjhdsjhdsjh')
|
59
|
+
err = proc {
|
60
|
+
@alexa.response.add_session_attribute(:id, '833hj33jh3hj')
|
61
|
+
}.must_raise ArgumentError
|
62
|
+
err.message.must_equal 'Duplicate session attributes not allowed'
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should raise ArgumentError if attributes pack isn\'t a Hash' do
|
66
|
+
err = proc {
|
67
|
+
@alexa.response.add_session_attributes('Test')
|
68
|
+
}.must_raise ArgumentError
|
69
|
+
err.message.must_equal 'Attributes must be a Hash'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'Cards management' do
|
74
|
+
before do
|
75
|
+
@json = File.read("#{@req_path}/launch_request.json")
|
76
|
+
@card = Oj.load(
|
77
|
+
File.read("#{@resp_path}/sample_card.json"),
|
78
|
+
symbol_keys: true
|
79
|
+
)
|
80
|
+
@alexa = AlexaRuby.new(@json)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should add card to response' do
|
84
|
+
@alexa.response.add_card(@card)
|
85
|
+
resp = Oj.load(@alexa.response.json, symbol_keys: true)
|
86
|
+
resp[:response][:card][:type].must_equal 'Simple'
|
87
|
+
resp[:response][:card][:title].must_equal 'title'
|
88
|
+
resp[:response][:card][:content].must_equal 'text'
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should add "text" and "image" nodes if card type is Standard' do
|
92
|
+
@card[:type] = 'Standard'
|
93
|
+
@alexa.response.add_card(@card)
|
94
|
+
resp = Oj.load(@alexa.response.json, symbol_keys: true)
|
95
|
+
small_url = 'https://test.ru/example_small.jpg'
|
96
|
+
large_url = 'https://test.ru/example_large.jpg'
|
97
|
+
resp[:response][:card][:type].must_equal 'Standard'
|
98
|
+
resp[:response][:card][:text].must_equal 'text'
|
99
|
+
resp[:response][:card][:image][:smallImageUrl].must_equal small_url
|
100
|
+
resp[:response][:card][:image][:largeImageUrl].must_equal large_url
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should raise ArgumentError if no title given' do
|
104
|
+
@card[:title] = nil
|
105
|
+
err = proc { @alexa.response.add_card(@card) }.must_raise ArgumentError
|
106
|
+
err.message.must_equal 'Card need a title'
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should raise ArgumentError if card type unknown' do
|
110
|
+
@card[:type] = 'Test'
|
111
|
+
err = proc { @alexa.response.add_card(@card) }.must_raise ArgumentError
|
112
|
+
err.message.must_equal 'Unknown card type'
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe 'Audio directives management' do
|
117
|
+
before do
|
118
|
+
@json = File.read("#{@req_path}/launch_request.json")
|
119
|
+
@audio = Oj.load(
|
120
|
+
File.read("#{@resp_path}/sample_audio.json"),
|
121
|
+
symbol_keys: true
|
122
|
+
)
|
123
|
+
@alexa = AlexaRuby.new(@json)
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should add AudioPlayer.Play directive' do
|
127
|
+
@alexa.response.add_audio_player_directive(:start, @audio)
|
128
|
+
resp = Oj.load(@alexa.response.json, symbol_keys: true)
|
129
|
+
directive = resp[:response][:directives][0]
|
130
|
+
directive[:type].must_equal 'AudioPlayer.Play'
|
131
|
+
directive[:playBehavior].must_equal 'REPLACE_ALL'
|
132
|
+
stream = directive[:audioItem][:stream]
|
133
|
+
stream[:url].must_equal @audio[:url]
|
134
|
+
stream[:token].must_equal @audio[:token]
|
135
|
+
stream[:offsetInMilliseconds].must_equal @audio[:offset]
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should add AudioPlayer.Stop directive' do
|
139
|
+
@alexa.response.add_audio_player_directive(:stop)
|
140
|
+
resp = Oj.load(@alexa.response.json, symbol_keys: true)
|
141
|
+
resp[:response][:directives][0][:type].must_equal 'AudioPlayer.Stop'
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe 'Speech management' do
|
146
|
+
before do
|
147
|
+
@json = File.read("#{@req_path}/launch_request.json")
|
148
|
+
@alexa = AlexaRuby.new(@json)
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should add plain text output to response' do
|
152
|
+
@alexa.response.tell('Test')
|
153
|
+
resp = Oj.load(@alexa.response.json, symbol_keys: true)
|
154
|
+
resp[:response][:outputSpeech][:type].must_equal 'PlainText'
|
155
|
+
resp[:response][:outputSpeech][:text].must_equal 'Test'
|
156
|
+
resp[:response][:outputSpeech][:ssml].must_be_nil
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'should add SSML output to response' do
|
160
|
+
@alexa.response.tell('Test', nil, true)
|
161
|
+
resp = Oj.load(@alexa.response.json, symbol_keys: true)
|
162
|
+
resp[:response][:outputSpeech][:type].must_equal 'SSML'
|
163
|
+
resp[:response][:outputSpeech][:ssml].must_equal '<speak>Test</speak>'
|
164
|
+
resp[:response][:outputSpeech][:text].must_be_nil
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should add output with repromt' do
|
168
|
+
@alexa.response.tell('Test', 'One more test')
|
169
|
+
resp = Oj.load(@alexa.response.json, symbol_keys: true)
|
170
|
+
resp[:response][:outputSpeech][:type].must_equal 'PlainText'
|
171
|
+
resp[:response][:outputSpeech][:text].must_equal 'Test'
|
172
|
+
resp[:response][:outputSpeech][:ssml].must_be_nil
|
173
|
+
repromt = resp[:response][:reprompt][:outputSpeech]
|
174
|
+
repromt[:type].must_equal 'PlainText'
|
175
|
+
repromt[:text].must_equal 'One more test'
|
176
|
+
repromt[:ssml].must_be_nil
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'should add output speech and return JSON' do
|
180
|
+
sample = Oj.to_json(
|
181
|
+
Oj.load(File.read("#{@resp_path}/sample_response.json"))
|
182
|
+
)
|
183
|
+
@alexa.response.tell!('Test').must_equal sample
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should add output speech without closing session' do
|
187
|
+
@alexa.response.ask('Test')
|
188
|
+
resp = Oj.load(@alexa.response.json, symbol_keys: true)
|
189
|
+
resp[:response][:shouldEndSession].must_equal false
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'should add output speech without closing session and return JSON' do
|
193
|
+
sample = Oj.load(
|
194
|
+
File.read("#{@resp_path}/sample_response.json"),
|
195
|
+
symbol_keys: true
|
196
|
+
)
|
197
|
+
sample[:response][:shouldEndSession] = false
|
198
|
+
@alexa.response.ask!('Test').must_equal Oj.to_json(sample)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alexa_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Mulev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
11
|
+
date: 2017-05-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 1.6.9
|
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:
|
26
|
+
version: 1.6.9
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,45 +53,73 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: minitest
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '5.10'
|
62
62
|
- - ">="
|
63
63
|
- !ruby/object:Gem::Version
|
64
|
-
version:
|
64
|
+
version: 5.10.2
|
65
65
|
type: :development
|
66
66
|
prerelease: false
|
67
67
|
version_requirements: !ruby/object:Gem::Requirement
|
68
68
|
requirements:
|
69
69
|
- - "~>"
|
70
70
|
- !ruby/object:Gem::Version
|
71
|
-
version: '
|
71
|
+
version: '5.10'
|
72
72
|
- - ">="
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version:
|
74
|
+
version: 5.10.2
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
|
-
name:
|
76
|
+
name: minitest-reporters
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
78
78
|
requirements:
|
79
79
|
- - "~>"
|
80
80
|
- !ruby/object:Gem::Version
|
81
|
-
version: '
|
81
|
+
version: '1.1'
|
82
82
|
- - ">="
|
83
83
|
- !ruby/object:Gem::Version
|
84
|
-
version:
|
84
|
+
version: 1.1.14
|
85
85
|
type: :development
|
86
86
|
prerelease: false
|
87
87
|
version_requirements: !ruby/object:Gem::Requirement
|
88
88
|
requirements:
|
89
89
|
- - "~>"
|
90
90
|
- !ruby/object:Gem::Version
|
91
|
-
version: '
|
91
|
+
version: '1.1'
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 1.1.14
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: simplecov
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
92
106
|
- - ">="
|
93
107
|
- !ruby/object:Gem::Version
|
94
|
-
version:
|
108
|
+
version: '0'
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
name: codeclimate-test-reporter
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - "~>"
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: 1.0.0
|
116
|
+
type: :development
|
117
|
+
prerelease: false
|
118
|
+
version_requirements: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - "~>"
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: 1.0.0
|
95
123
|
description: Ruby toolkit for Amazon Alexa API
|
96
124
|
email:
|
97
125
|
- m.mulev@gmail.com
|
@@ -105,8 +133,13 @@ files:
|
|
105
133
|
- README.md
|
106
134
|
- Rakefile
|
107
135
|
- lib/alexa_ruby.rb
|
108
|
-
- lib/alexa_ruby/
|
136
|
+
- lib/alexa_ruby/alexa.rb
|
109
137
|
- lib/alexa_ruby/request/audio_player_request.rb
|
138
|
+
- lib/alexa_ruby/request/base_request.rb
|
139
|
+
- lib/alexa_ruby/request/base_request/context.rb
|
140
|
+
- lib/alexa_ruby/request/base_request/context/device.rb
|
141
|
+
- lib/alexa_ruby/request/base_request/context/user.rb
|
142
|
+
- lib/alexa_ruby/request/base_request/session.rb
|
110
143
|
- lib/alexa_ruby/request/intent_request.rb
|
111
144
|
- lib/alexa_ruby/request/intent_request/slot.rb
|
112
145
|
- lib/alexa_ruby/request/launch_request.rb
|
@@ -114,8 +147,10 @@ files:
|
|
114
147
|
- lib/alexa_ruby/response.rb
|
115
148
|
- lib/alexa_ruby/response/audio_player.rb
|
116
149
|
- lib/alexa_ruby/response/card.rb
|
117
|
-
- lib/alexa_ruby/session.rb
|
118
150
|
- lib/alexa_ruby/version.rb
|
151
|
+
- spec/request_spec.rb
|
152
|
+
- spec/response_spec.rb
|
153
|
+
- spec/spec_helper.rb
|
119
154
|
homepage: https://github.com/mulev/alexa-ruby
|
120
155
|
licenses:
|
121
156
|
- MIT
|
@@ -140,4 +175,7 @@ rubygems_version: 2.6.12
|
|
140
175
|
signing_key:
|
141
176
|
specification_version: 4
|
142
177
|
summary: Ruby toolkit for Amazon Alexa API
|
143
|
-
test_files:
|
178
|
+
test_files:
|
179
|
+
- spec/request_spec.rb
|
180
|
+
- spec/response_spec.rb
|
181
|
+
- spec/spec_helper.rb
|