alexa_toolbox 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 410e7ebcc29c183541f1c4d5ad5b13e898ca1263
4
+ data.tar.gz: 3507752cb6aa7791bf0c99db20fd00ceaf063e7a
5
+ SHA512:
6
+ metadata.gz: a21accae38d9aad6543ace3ab03eddd6d327b88999aee89c87b8e3deeba4b5a32b7ab03de1413022ebe0da3cbb0631ff58d5bf9a10955ca39a9fa77ef6a6cbb8
7
+ data.tar.gz: 56918a9a6c88a5b562e5514b2e0b80dbbdc779ddc8c0869ef28696fbd9e5abda5e196c2889c17bafce50198bb64ed44ed21467d3a067f7d3bb60f211b7cbc488
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in alexa_toolbox.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,38 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ alexa_toolbox (1.0.0)
5
+ bundler (~> 1.14)
6
+ deep_merge
7
+ rake
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ deep_merge (1.1.1)
13
+ diff-lcs (1.3)
14
+ rake (12.0.0)
15
+ rspec (3.6.0)
16
+ rspec-core (~> 3.6.0)
17
+ rspec-expectations (~> 3.6.0)
18
+ rspec-mocks (~> 3.6.0)
19
+ rspec-core (3.6.0)
20
+ rspec-support (~> 3.6.0)
21
+ rspec-expectations (3.6.0)
22
+ diff-lcs (>= 1.2.0, < 2.0)
23
+ rspec-support (~> 3.6.0)
24
+ rspec-mocks (3.6.0)
25
+ diff-lcs (>= 1.2.0, < 2.0)
26
+ rspec-support (~> 3.6.0)
27
+ rspec-support (3.6.0)
28
+
29
+ PLATFORMS
30
+ ruby
31
+
32
+ DEPENDENCIES
33
+ alexa_toolbox!
34
+ rspec (~> 3.6, >= 3.6.0)
35
+ rspec-mocks (~> 3.6, >= 3.6.0)
36
+
37
+ BUNDLED WITH
38
+ 1.14.6
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2017 Paul McMahon
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,169 @@
1
+ # AlexaToolbox
2
+
3
+ This gem implements a full suite of tools for deploying applications for Amazon's Alexa.
4
+
5
+ ## Installation
6
+
7
+ ### For Ruby Projects:
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'alexa_toolbox'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install alexa_toolbox
22
+
23
+ ## Usage
24
+
25
+ This Gem provides methods to create and handle requests, create response objects, and miscellaneous support functions for Alexa skills.
26
+
27
+ ### Requests
28
+
29
+ [Amazon Request Documentation](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/alexa-skills-kit-interface-reference#request-format)
30
+
31
+ #### Handling Request JSON:
32
+
33
+ ```ruby
34
+ require 'alexa_toolbox'
35
+ request = AlexaToolbox::Request.new(params,{ :application_id => 'YOUR_APP_ID' })
36
+ # params variable is json request retrieved by server (default is params in Ruby on Rails)
37
+ # request application IDs are checked vs your application ID to ensure they are valid requests as per Amazon's guidelines
38
+ ```
39
+ #### Check Request Validity:
40
+
41
+ You should always check request validity as per Amazon's guidelines
42
+ [Amazon Guidelines](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/handling-requests-sent-by-alexa#verifying-that-the-request-is-intended-for-your-service)
43
+
44
+ ```ruby
45
+ require 'alexa_toolbox'
46
+ request = AlexaToolbox::Request.new(params,{ :application_id => 'YOUR_APP_ID' })
47
+ if !request.valid?
48
+ # return 500 status
49
+ end
50
+ ```
51
+ #### Getting Information From the Request
52
+
53
+ ```ruby
54
+ require 'alexa_toolbox'
55
+ request = AlexaToolbox::Request.new(params,{ :application_id => 'YOUR_APP_ID' })
56
+
57
+ request.type
58
+ # Returns request type:
59
+ # LaunchRequest
60
+ # IntentRequest
61
+ # SessionEndedRequest
62
+ # AudioPlayer
63
+ # PlaybackController
64
+ # System.ExceptionEncountered
65
+
66
+ # Check if new session
67
+ request.session.new?
68
+ # Get sessionId
69
+ request.session.session_id
70
+ # Get userId
71
+ request.session.user_id
72
+ ```
73
+
74
+ #### Utilizing Request Hash
75
+
76
+ If you are more comfortable navigating the request hash and are familiar with the setup you can still acces it.
77
+
78
+ ```ruby
79
+ require 'alexa_toolbox'
80
+ request = AlexaToolbox::Request.new(params,{ :application_id => 'YOUR_APP_ID' })
81
+
82
+ # Get Session
83
+ request.json[:session]
84
+ # Get sessionId
85
+ request.json[:session][:sessionId]
86
+ ```
87
+
88
+ #### Utilizing Address Consent
89
+
90
+ [Alexa Documentation on Address Data](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/device-address-api)
91
+
92
+ If you want to access the user's address, you'll first require their permission and then you'll receive a consent token and deviceId in the request.
93
+ Once you have those, you will need to utilize Amazon's API to retrieve the address data. (Supporting feature a WIP.)
94
+
95
+ ```ruby
96
+ require 'alexa_toolbox'
97
+ request = AlexaToolbox::Request.new(params,{ :application_id => 'YOUR_APP_ID' })
98
+
99
+ consent_token = request.session.consent_token
100
+ device_id = request.session.device_id
101
+ ```
102
+
103
+
104
+ ### Responses
105
+
106
+ [Amazon Response Documentation](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/alexa-skills-kit-interface-reference#response-format)
107
+
108
+ #### Simple Response Object Example:
109
+
110
+ ```ruby
111
+ require 'alexa_toolbox'
112
+ response = AlexaToolbox::Response.new
113
+ response.add_speech('Creating a response is so easy!')
114
+ response.build_response
115
+ ```
116
+
117
+ #### If you want to utilize SSML (will add speak tags if you forget!):
118
+
119
+ ```ruby
120
+ require 'alexa_toolbox'
121
+ response = AlexaToolbox::Response.new
122
+ response.add_speech('Creating a response is so easy!',true)
123
+ # or
124
+ # response.add_speech('<speak>Creating a response is so easy!</speak>',true)
125
+ response.build_response
126
+ ```
127
+
128
+ #### To add a card to your response:
129
+
130
+ ```ruby
131
+ require 'alexa_toolbox'
132
+ response = AlexaToolbox::Response.new
133
+ # add_card(type,title,subtitle,content)
134
+ # or
135
+ # add_hash_card({ :type => type, :title => title, :subtitle => subtitle, :content => content })
136
+ response.add_card("PlainText","Card Title","Card Subtitle","This card should have some interesting content for your user.")
137
+ response.build_response
138
+ ```
139
+
140
+ #### Will generate a valid outputspeech response in JSON format:
141
+
142
+ ```JSON
143
+ {
144
+ "version": "1.0",
145
+ "response": {
146
+ "outputSpeech": {
147
+ "type": "PlainText",
148
+ "text": "Ruby is running ready!"
149
+ },
150
+ "shouldEndSession": true
151
+ }
152
+ }
153
+ ```
154
+
155
+ ## Troubleshooting
156
+
157
+
158
+ ## Contributing
159
+
160
+ 1. Fork it
161
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
162
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
163
+ 4. Push to the branch (`git push origin my-new-feature`)
164
+ 5. Create a new Pull Request
165
+
166
+ Please make sure to write specs for any new features!
167
+
168
+ # Team Members
169
+ * "Paul McMahon" <colpan@sircolpaniusjackson.com>
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,106 @@
1
+ module AlexaToolbox
2
+ # Handles the retrieving address information about a device.
3
+ class Address
4
+ require 'net/http'
5
+ attr_reader :json
6
+ attr_accessor :consent_token, :device_id, :full_address, :app_location
7
+
8
+ def initialize (consent_token = nil, device_id = nil, app_location = "US", full_address = false)
9
+ @consent_token = consent_token
10
+ @device_id = device_id
11
+ @country_code = nil
12
+ @postal_code = nil
13
+ @city = nil
14
+ @state_or_region = nil
15
+ @address_line_1 = nil
16
+ @address_line_2 = nil
17
+ @address_line_3 = nil
18
+ @district_or_county = nil
19
+ @status = nil
20
+ @full_address = full_address
21
+ @app_location = app_location
22
+ @json = nil
23
+ end
24
+
25
+ def add_request(request)
26
+ @consent_token = request.session.consent_token
27
+ @device_id = request.session.device_id
28
+ end
29
+
30
+ def add_token(token)
31
+ @consent_token = token
32
+ end
33
+
34
+ def add_device(device)
35
+ @device_id = device
36
+ end
37
+
38
+ def retrieve_full_address(consent_token = nil, device_id = nil)
39
+ token = consent_token.nil? ? @consent_token : consent_token
40
+ device = device_id.nil? ? @device_id : device_id
41
+ if !token.nil? && !device.nil?
42
+ if self.base_uri.nil?
43
+ raise ArgumentError, 'Invalid Request, Invalid app_location set'
44
+ else
45
+ full_uri = self.base_uri + "/v1/devices/" + device + "/settings/address"
46
+ self.execute_request(full_uri,token)
47
+ end
48
+ else
49
+ raise ArgumentError, 'Invalid Request, No Token or Device'
50
+ end
51
+ end
52
+
53
+ def retrieve_partial_address(consent_token = nil, device_id = nil)
54
+ token = consent_token.nil? ? @consent_token : consent_token
55
+ device = device_id.nil? ? @device_id : device_id
56
+ if !token.nil? && !device.nil?
57
+ if self.base_uri.nil?
58
+ raise ArgumentError, 'Invalid Request, Invalid app_location set'
59
+ else
60
+ full_uri = self.base_uri + "/v1/devices/" + device + "/settings/address/countryAndPostalCode"
61
+ self.execute_request(full_uri,token)
62
+ end
63
+ else
64
+ raise ArgumentError, 'Invalid Request, No Token or Device'
65
+ end
66
+ end
67
+
68
+ def execute_request(endpoint,token)
69
+ uri = URI(endpoint)
70
+
71
+ Net::HTTP.start(uri.hostname, uri.port, :use_ssl => uri.scheme == 'https') do |http|
72
+ request = Net::HTTP::Get.new(uri)
73
+ request['Authorization'] = token
74
+
75
+ response = http.request(request)
76
+ self.status = response.code
77
+ self.json = response.body
78
+ if response.code == 200
79
+ res_body = response.body
80
+ @country_code = res_body.key?("countryCode") ? res_body["countryCode"] : self.country_code
81
+ @postal_code = res_body.key?("postalCode") ? res_body["postalCode"] : self.postal_code
82
+ @city = res_body.key?("city") ? res_body["city"] : self.city
83
+ @state_or_region = res_body.key?("stateOrRegion") ? res_body["stateOrRegion"] : self.state_or_region
84
+ @address_line_1 = res_body.key?("addressLine1") ? res_body["addressLine1"] : self.address_line_1
85
+ @address_line_2 = res_body.key?("addressLine2") ? res_body["addressLine2"] : self.address_line_2
86
+ @address_line_3 = res_body.key?("addressLine3") ? res_body["addressLine3"] : self.address_line_3
87
+ @district_or_county = res_body.key?("districtOrCounty") ? res_body["districtOrCounty"] : self.district_or_county
88
+ else
89
+ end
90
+ end
91
+ end
92
+
93
+ def base_uri
94
+ case self.app_location
95
+ when "US"
96
+ return "https://api.amazonalexa.com"
97
+ when "UK"
98
+ return "https://api.eu.amazonalexa.com"
99
+ when "DE"
100
+ return "https://api.eu.amazonalexa.com"
101
+ else
102
+ return nil
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,16 @@
1
+ module AlexaToolbox
2
+ # Handles the audioplayer object in requests.
3
+ class AudioPlayer
4
+ attr_reader :type, :offset_in_milliseconds, :token, :current_playback_state, :error, :json
5
+
6
+ def initialize (audioplayer)
7
+ raise ArgumentError, 'Invalid AudioPlayer' if !audioplayer.key?(:type) && audioplayer[:type][0..10] != "AudioPlayer"
8
+ @type = audioplayer[:type][12..-1]
9
+ @offset_in_milliseconds = audioplayer[:offsetInMilliseconds]
10
+ @token = audioplayer[:token]
11
+ @current_playback_state = audioplayer[:currentPlaybackState]
12
+ @json = audioplayer
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ module AlexaToolbox
2
+ # Handles the session object in requests.
3
+ class Context
4
+ require 'alexa_toolbox/audioplayer'
5
+ attr_reader :audioplayer, :system, :json
6
+
7
+ def initialize (context)
8
+ raise ArgumentError, 'Invalid Context' if false
9
+ @system = context[:System]
10
+ @audioplayer = context.key?(:AudioPlayer) ? AlexaToolbox::AudioPlayer.new(context[:AudioPlayer]) : nil
11
+ @json = context
12
+ end
13
+
14
+ def application_id
15
+ return self.system[:application][:applicationId]
16
+ end
17
+
18
+ def user_id
19
+ return self.system[:user][:userId]
20
+ end
21
+
22
+ def device_id
23
+ return self.system[:device][:deviceId]
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ module AlexaToolbox
2
+ # Handles the intent object in requests.
3
+ class Intent
4
+ attr_reader :name, :confirmation_status, :json
5
+
6
+ def initialize (intent)
7
+ raise ArgumentError, 'Invalid Intent' if intent[:name].empty?
8
+ @name = intent[:name]
9
+ @confirmation_status = intent[:confirmationStatus]
10
+ @json = intent
11
+ end
12
+
13
+ def has_slots?
14
+ return self.slots != {}
15
+ end
16
+
17
+ def slots
18
+ return self.json[:slots]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,59 @@
1
+ module AlexaToolbox
2
+ # Echo can send 3 types of requests
3
+ # - LaunchRequest: The app was launched using phrasing such as 'Alexa open ______'.
4
+ # - IntentRequest: An intent was requested.
5
+ # - SessionEndedRequest: Session was closed either by user or timeout.
6
+
7
+ class Request
8
+ require 'json'
9
+ require 'deep_merge'
10
+ require 'alexa_toolbox/session'
11
+ require 'alexa_toolbox/intent'
12
+ require 'alexa_toolbox/audioplayer'
13
+ require 'alexa_toolbox/context'
14
+ attr_reader :version, :session, :json, :options, :request_id, :locale, :type, :intent, :audioplayer, :error, :cause, :context
15
+
16
+ def self.default_options
17
+ @default_options ||= {
18
+ :application_id => ''
19
+ }
20
+ end
21
+
22
+ def initialize(json_request, options = {})
23
+ options = options.deep_merge(self.class.default_options)
24
+ @options = options
25
+
26
+ @request_id = json_request[:request][:requestId]
27
+ raise ArgumentError, 'Request ID not present' if @request_id.nil?
28
+ @version = json_request[:version]
29
+ @locale = json_request[:request][:locale]
30
+ @error = json_request[:request][:error]
31
+ @cause = json_request[:request][:cause]
32
+ @json = json_request
33
+ @type = json_request[:request][:type][0..10] == "AudioPlayer" ? "AudioPlayer" : json_request[:request][:type]
34
+
35
+ @intent = @type == "IntentRequest" ? AlexaToolbox::Intent.new(json_request[:request][:intent]) : nil
36
+ @audioplayer = @type == "AudioPlayer" ? AlexaToolbox::AudioPlayer.new(json_request[:request]) : nil
37
+ @session = json_request.key?(:session) ? AlexaToolbox::Session.new(json_request[:session]) : nil
38
+ @context = json_request.key?(:context) ? AlexaToolbox::Context.new(json_request[:context]) : nil
39
+ end
40
+
41
+ def valid?
42
+ self.options[:application_id] && ((!self.session.nil? && self.options[:application_id] == self.session.application_id) || (!self.context.nil? && self.options[:application_id] == self.context.application_id))
43
+ end
44
+
45
+ def user_terminated?
46
+ if self.type != "SessionEndedRequest"
47
+ return nil
48
+ end
49
+ return self.json[:request][:reason] == "USER_INITIATED"
50
+ end
51
+ end
52
+
53
+ # Builds a new request for Alexa, primarily for testing purposes
54
+ def self.build_request(json_request, application_id = "")
55
+ json_request = self.transform_keys_to_symbols(json_request)
56
+ raise ArgumentError, 'Invalid Alexa Request. Missing session, request, version, or application id.' unless AlexaToolbox.valid_alexa?(json_request)
57
+ Request.new(json_request,{ :application_id => application_id })
58
+ end
59
+ end
@@ -0,0 +1,161 @@
1
+ module AlexaToolbox
2
+ class Response
3
+ require 'json'
4
+ attr_reader :version, :reprompt, :speech, :response, :session_attributes, :card
5
+ attr_accessor :player_response, :session_end
6
+
7
+ # Every response will have a version, response, and shouldEndSession
8
+ def initialize(player_response = false, ssml = false, version = '1.0')
9
+ @session_attributes = Hash.new
10
+ @version = version
11
+ @directives = []
12
+ @player_response = player_response
13
+ @ssml = ssml
14
+ @session_end = true
15
+ @reprompt = nil
16
+ @speech = nil
17
+ end
18
+
19
+ # Adds a key,value pair to the session object.
20
+ def add_session_attribute(key, value)
21
+ @session_attributes[key.to_sym] = AlexaToolbox.transform_keys_to_symbols(value)
22
+ end
23
+
24
+ def add_speech(speech_text, ssml = nil)
25
+ ssml = ssml.nil? ? @ssml : ssml
26
+ if ssml
27
+ @speech = { :type => 'SSML', :ssml => check_ssml(speech_text) }
28
+ else
29
+ @speech = { :type => 'PlainText', :text => speech_text }
30
+ end
31
+ end
32
+
33
+ def add_plain_speech(speech_text)
34
+ @speech = { :type => 'PlainText', :text => speech_text }
35
+ end
36
+
37
+ def add_ssml_speech(speech_text)
38
+ @speech = { :type => 'SSML', :ssml => check_ssml(speech_text) }
39
+ end
40
+
41
+ def add_reprompt(speech_text, ssml = nil)
42
+ ssml = ssml.nil? ? @ssml : ssml
43
+ if ssml
44
+ @reprompt = { "outputSpeech" => { :type => 'SSML', :ssml => check_ssml(speech_text) } }
45
+ else
46
+ @reprompt = { "outputSpeech" => { :type => 'PlainText', :text => speech_text } }
47
+ end
48
+ end
49
+
50
+ def add_ssml_reprompt(speech_text)
51
+ @reprompt = { "outputSpeech" => { :type => 'SSML', :ssml => check_ssml(speech_text) } }
52
+ end
53
+
54
+ def add_audio_play_directive(url, play_behavior = '', token = '', expected_previous_token = '', offset = 0)
55
+ directive = {
56
+ 'type' => 'AudioPlayer.Play',
57
+ 'playBehavior' => play_behavior,
58
+ 'audioItem' => {
59
+ 'stream' => {
60
+ 'token' => token,
61
+ 'url' => url,
62
+ 'offsetInMilliseconds' => offset
63
+ }
64
+ }
65
+ }
66
+ directive['audioItem']['stream']['expectedPreviousToken'] = expected_previous_token if play_behavior == "ENQUEUE"
67
+ @directives << directive
68
+ end
69
+
70
+ def add_audio_clear_directive(clear_all = false)
71
+ @directives << {
72
+ 'type' => 'AudioPlayer.ClearQueue',
73
+ 'clearBehavior' => clear_all ? "CLEAR_ALL" : "CLEAR_ENQUEUED"
74
+ }
75
+ end
76
+
77
+ def add_audio_stop_directive
78
+ @directives << {
79
+ 'type' => 'AudioPlayer.Stop'
80
+ }
81
+ end
82
+
83
+ # "type": "string",
84
+ # "title": "string",
85
+ # "content": "string"
86
+ # Standard uses :text instead of :content
87
+ def add_card(type = nil, title = nil, content = nil, smallImageUrl = nil, largeImageUrl = nil)
88
+ @card = Hash.new
89
+ @card[:type] = type.nil? ? 'Simple' : type
90
+ if @card[:type] != "LinkAccount"
91
+ @card[:title] = title unless title.nil?
92
+ @card[:type] = 'Simple' if smallImageUrl.nil? && largeImageUrl.nil?
93
+ if @card[:type] == 'Simple'
94
+ @card[:content] = content unless content.nil?
95
+ else
96
+ @card[:text] = content unless content.nil?
97
+ @card[:image] = {
98
+ :smallImageUrl => smallImageUrl,
99
+ :largeImageUrl => largeImageUrl
100
+ }
101
+ end
102
+ end
103
+ end
104
+
105
+ # Add Permission Card for Location Information
106
+ def add_permission_card(full_address = false)
107
+ @card = Hash.new
108
+ @card[:type] = 'AskForPermissionsConsent'
109
+ permission = full_address ? "read::alexa:device:all:address" : "read::alexa:device:all:address:country_and_postal_code"
110
+ @card[:permissions] = [permission]
111
+ end
112
+
113
+ # Add a card as a single hash
114
+ def add_hash_card(card)
115
+ card[:type] = 'Simple' if card[:type].nil?
116
+ @card = card
117
+ end
118
+
119
+ # The response object as hash (with outputspeech, cards and session end)
120
+ def build_standard_response_object(session_end = true)
121
+ @response = Hash.new
122
+ @response[:outputSpeech] = @speech unless @speech.nil?
123
+ @response[:directives] = @directives unless @directives.empty?
124
+ @response[:card] = @card unless @card.nil?
125
+ @response[:reprompt] = @reprompt unless @reprompt.nil?
126
+ @response[:shouldEndSession] = session_end
127
+ @response
128
+ end
129
+
130
+ # For Responses to AudioPlayer or PlaybackController Requests
131
+ # Cannot Include: outputSpeech, card, reprompt, shouldEndSession
132
+ def build_player_response_object(session_end = true)
133
+ @response = Hash.new
134
+ @response[:directives] = @directives unless @directives.empty?
135
+ @response
136
+ end
137
+
138
+ # Builds a response object, can be json or hash if json is false
139
+ def build_response(session_end = nil, player_response = nil, json = true)
140
+ is_player_response = player_response.nil? ? @player_response : player_response
141
+ end_session = session_end.nil? ? @session_end : session_end
142
+ response = Hash.new
143
+ if is_player_response
144
+ response_object = build_player_response_object(end_session)
145
+ else
146
+ response_object = build_standard_response_object(end_session)
147
+ response[:sessionAttributes] = @session_attributes unless @session_attributes.empty?
148
+ end
149
+ response[:version] = @version
150
+ response[:response] = response_object
151
+ json ? JSON.parse(response.to_json) : response
152
+ end
153
+
154
+ private
155
+
156
+ def check_ssml(ssml_string)
157
+ ssml_string = ssml_string.strip[0..6] == "<speak>" ? ssml_string : "<speak>" + ssml_string
158
+ ssml_string.strip[-8..1] == "</speak>" ? ssml_string : ssml_string + "</speak>"
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,61 @@
1
+ module AlexaToolbox
2
+ # Handles the session object in requests.
3
+ class Session
4
+ attr_reader :new, :session_id, :attributes, :user, :application_id, :device
5
+
6
+ def initialize (session)
7
+ raise ArgumentError, 'Invalid Session' if session.nil? || session[:new].nil? || session[:sessionId].nil?
8
+ @new = session[:new]
9
+ @session_id = session[:sessionId]
10
+ @attributes = session[:attributes].nil? ? Hash.new : session[:attributes]
11
+ @user = session[:user]
12
+ @application_id = session[:application][:applicationId]
13
+ @device = session[:device]
14
+ end
15
+
16
+ # Checks whether this is a new session
17
+ def new?
18
+ @new
19
+ end
20
+
21
+ # Checks if user is defined
22
+ def user_defined?
23
+ !@user.nil? || !@user[:userId].nil?
24
+ end
25
+
26
+ # Returns user's id
27
+ def user_id
28
+ @user[:userId] if @user
29
+ end
30
+
31
+ def access_token?
32
+ @user.key?(:accessToken) && !@user[:accessToken].empty?
33
+ end
34
+
35
+ # Returns user's access token if provided
36
+ def access_token
37
+ @user[:accessToken] if @user
38
+ end
39
+
40
+ def consent_token?
41
+ @user.key?(:permissions) && @user[:permissions].key?(:consentToken) && !@user[:permissions][:consentToken].empty?
42
+ end
43
+
44
+ def consent_token
45
+ @user[:permissions][:consentToken] if @user && @user.key?(:permissions) && @user[:permissions].key?(:consentToken)
46
+ end
47
+
48
+ def device_id
49
+ @device[:deviceId]
50
+ end
51
+
52
+ def supported_interfaces
53
+ @device[:supportedInterfaces]
54
+ end
55
+
56
+ # Check to see if attributes are present.
57
+ def has_attributes?
58
+ !@attributes.empty?
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ module AlexaToolbox
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,28 @@
1
+ require 'alexa_toolbox/request'
2
+ require 'alexa_toolbox/version'
3
+ require 'alexa_toolbox/response'
4
+ require 'alexa_toolbox/address'
5
+
6
+ module AlexaToolbox
7
+ # Prints a JSON object.
8
+ def self.print_json(json)
9
+ p json
10
+ end
11
+
12
+ # Prints the Gem version.
13
+ def self.print_version
14
+ p AlexaToolbox::VERSION
15
+ end
16
+
17
+ # Returns true if all the Alexa objects are set.
18
+ def self.valid_alexa?(request_json)
19
+ !request_json.nil? && !request_json[:version].nil? && !request_json[:request].nil?
20
+ end
21
+
22
+ # Take keys of hash and transform those to a symbols
23
+ def self.transform_keys_to_symbols(input)
24
+ return input if not input.is_a?(Hash)
25
+ hash = input.inject({}){|store,(key,val)| store[key.to_sym] = self.transform_keys_to_symbols(val); store}
26
+ return hash
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: alexa_toolbox
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Paul McMahon
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-05-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.14'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.14'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: deep_merge
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.6'
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 3.6.0
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - "~>"
70
+ - !ruby/object:Gem::Version
71
+ version: '3.6'
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 3.6.0
75
+ - !ruby/object:Gem::Dependency
76
+ name: rspec-mocks
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.6'
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 3.6.0
85
+ type: :development
86
+ prerelease: false
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: '3.6'
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 3.6.0
95
+ description: Full top to bottom toolbox for creating a custom Alexa skill.
96
+ email:
97
+ - colpan@sircolpaniusjackson.com
98
+ executables: []
99
+ extensions: []
100
+ extra_rdoc_files: []
101
+ files:
102
+ - Gemfile
103
+ - Gemfile.lock
104
+ - LICENSE.txt
105
+ - README.md
106
+ - Rakefile
107
+ - lib/alexa_toolbox.rb
108
+ - lib/alexa_toolbox/address.rb
109
+ - lib/alexa_toolbox/audioplayer.rb
110
+ - lib/alexa_toolbox/context.rb
111
+ - lib/alexa_toolbox/intent.rb
112
+ - lib/alexa_toolbox/request.rb
113
+ - lib/alexa_toolbox/response.rb
114
+ - lib/alexa_toolbox/session.rb
115
+ - lib/alexa_toolbox/version.rb
116
+ homepage: https://github.com/colpan/alexa-toolbox
117
+ licenses:
118
+ - MIT
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 2.4.5.1
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: Full top to bottom toolbox for creating a custom Alexa skill.
140
+ test_files: []