ralyxa 1.5.0 → 1.5.2

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: 356706a000592a8cf4cd64652ef2f61cf2f3f257
4
- data.tar.gz: 3f7dbf9429193a8d2dcfbaa254a40fe1d6c80c19
3
+ metadata.gz: 2ba3b580559880302aba0c710a6d0e8f6b5acd21
4
+ data.tar.gz: c1b4afb09c6a7504f4abdd0e310996984724684a
5
5
  SHA512:
6
- metadata.gz: f4460af9eecb7d2e4114b168c3d79f80cdccbec3a3e200e664588f7d9654b87353505aad2755955fe212cce8b38206aa93d1100b85f572cb6a28ddc0aeae3f5f
7
- data.tar.gz: 0fdac2ee8f5e53bb5394b5bd06b290fafa0a95d265d74339ae90fd91aa38d21072eab9161318b2dd82766abb86b237fdb28bb1d48ec37dca4d7512866279ef48
6
+ metadata.gz: a14312a4070648259a5e690f5d818a14008fb7d229a61482a8d7c144e6fd1cbf68b6120674c676bf52e4b181fbaa35f21f41a9d515a1f358a226c98ac58ff481
7
+ data.tar.gz: 553d41cb7f590514db8ea25f5d9573fe4a64c02bd3eb02c0d45365525c22b59f4bbc736882aeeb7171c40d404c9a1bb85abd31b8ee09a073e8f8a0978a739f89
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.1
4
+ script: bundle exec rspec spec
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ralyxa (1.4.0)
4
+ ralyxa (1.5.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Ralyxa
2
2
 
3
+ [![Build Status](https://travis-ci.org/sjmog/ralyxa.svg?branch=master)](https://travis-ci.org/sjmog/ralyxa)
4
+
3
5
  A Ruby framework for interacting with Amazon Alexa. Designed to work with Sinatra, although can be used with a few other web frameworks.
4
6
 
5
7
  An example application implementing the gem can be played with [here](https://github.com/sjmog/ralyxa_example).
@@ -165,6 +167,29 @@ end
165
167
 
166
168
  After completing authentication, the user's access token is available via `request.user_access_token`. You can check for its existence with `request.user_access_token_exists?`.
167
169
 
170
+ If, for example, you wanted to require authorization for an intent called `SecretIntent`:
171
+
172
+ ```ruby
173
+ intent "SecretIntent" do
174
+ return tell("Please authorize via the Alexa app", card: link_account_card) unless request.user_access_token_exists?
175
+ ask("Welcome to the secret zone. What's next?")
176
+ end
177
+ ```
178
+
179
+ ## Ephemera
180
+
181
+ > Alexa says there's a problem if I just fail to reply to a prompt!
182
+
183
+ This is probably because your application is not handling the `SessionEndedRequest` intent. That's a built-in intent that kicks in after the user says 'exit', or nothing at all, in response to an ask. You'll probably see a warning in your server logs. To resolve it, implement the following intent:
184
+
185
+ ```ruby
186
+ intent "SessionEndedRequest" do
187
+ respond
188
+ end
189
+ ```
190
+
191
+ > You can't actually respond to a `SessionEndedRequest`, but you might want to do some tidying in this action.
192
+
168
193
  ## Development
169
194
 
170
195
  After checking out the repo, run `bundle install` to install dependencies. Then, run `rspec` to run the tests. You can also run `irb` for an interactive prompt that will allow you to experiment.
@@ -175,10 +200,9 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/sjmog/
175
200
 
176
201
  The main areas of focus are:
177
202
 
178
- - Account linking :construction:
179
203
  - Audio directives :construction:
180
204
  - Reprompts :construction:
181
- - Generators?
205
+ - Generators of built-in Intents e.g. `SessionEndedRequest`
182
206
 
183
207
  ## License
184
208
 
@@ -1,5 +1,5 @@
1
1
  require_relative './response_builder'
2
- require_relative './card'
2
+ require_relative './response_entities/card'
3
3
 
4
4
  # Handler Base Class. Each Intent Handler inherits from this, and overwrites the #handle method.
5
5
  module Ralyxa
@@ -20,11 +20,11 @@ module Ralyxa
20
20
  respond(response_text, response_details.merge(end_session: true))
21
21
  end
22
22
 
23
- def card(title, body, image_url = nil, card_class = Ralyxa::Card)
23
+ def card(title, body, image_url = nil, card_class = Ralyxa::ResponseEntities::Card)
24
24
  card_class.as_hash(title, body, image_url)
25
25
  end
26
26
 
27
- def link_account_card(card_class = Ralyxa::Card)
27
+ def link_account_card(card_class = Ralyxa::ResponseEntities::Card)
28
28
  card_class.link_account
29
29
  end
30
30
 
@@ -0,0 +1,44 @@
1
+ require 'json'
2
+ require 'forwardable'
3
+ require_relative './user'
4
+
5
+ module Ralyxa
6
+ module RequestEntities
7
+ class Request
8
+ extend Forwardable
9
+ INTENT_REQUEST_TYPE = "IntentRequest".freeze
10
+
11
+ def_delegator :@user, :id, :user_id
12
+ def_delegator :@user, :access_token, :user_access_token
13
+ def_delegator :@user, :access_token_exists?, :user_access_token_exists?
14
+
15
+ def initialize(original_request, user_class = Ralyxa::RequestEntities::User)
16
+ @request = JSON.parse(original_request.body.read)
17
+ @user = user_class.build(@request)
18
+ end
19
+
20
+ def intent_name
21
+ return @request["request"]["type"] unless intent_request?
22
+ @request["request"]["intent"]["name"]
23
+ end
24
+
25
+ def slot_value(slot_name)
26
+ @request["request"]["intent"]["slots"][slot_name]["value"]
27
+ end
28
+
29
+ def new_session?
30
+ @request["session"]["new"]
31
+ end
32
+
33
+ def session_attribute(attribute_name)
34
+ @request["session"]["attributes"][attribute_name]
35
+ end
36
+
37
+ private
38
+
39
+ def intent_request?
40
+ @request["request"]["type"] == INTENT_REQUEST_TYPE
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,23 @@
1
+ module Ralyxa
2
+ module RequestEntities
3
+ class User
4
+ attr_reader :id, :access_token
5
+
6
+ def initialize(id:, access_token: nil)
7
+ @id = id
8
+ @access_token = access_token
9
+ end
10
+
11
+ def self.build(request)
12
+ new(
13
+ id: request.dig("session", "user", "userId"),
14
+ access_token: request.dig("session", "user", "accessToken")
15
+ )
16
+ end
17
+
18
+ def access_token_exists?
19
+ !!@access_token
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,6 +1,5 @@
1
1
  require 'json'
2
- require_relative './response'
3
- require_relative './output_speech'
2
+ require_relative './response_entities/response'
4
3
 
5
4
  module Ralyxa
6
5
  class ResponseBuilder
@@ -10,7 +9,7 @@ module Ralyxa
10
9
  @options = options
11
10
  end
12
11
 
13
- def self.build(options = {}, response_class = Ralyxa::Response, output_speech_class = Ralyxa::OutputSpeech)
12
+ def self.build(options = {}, response_class = Ralyxa::ResponseEntities::Response, output_speech_class = Ralyxa::ResponseEntities::OutputSpeech)
14
13
  new(response_class, output_speech_class, options).build
15
14
  end
16
15
 
@@ -0,0 +1,72 @@
1
+ require_relative '../errors'
2
+
3
+ module Ralyxa
4
+ module ResponseEntities
5
+ class Card
6
+ LINK_ACCOUNT_CARD_TYPE = "LinkAccount"
7
+ SIMPLE_CARD_TYPE = "Simple"
8
+ STANDARD_CARD_TYPE = "Standard"
9
+
10
+ def initialize(options)
11
+ @options = options
12
+ end
13
+
14
+ def self.as_hash(title, body, image_url = nil)
15
+ new(title: title, body: body, image_url: image_url).to_h
16
+ end
17
+
18
+ def self.link_account
19
+ new(link_account: true).to_h
20
+ end
21
+
22
+ def to_h
23
+ Hash.new.tap do |card|
24
+ set_type(card)
25
+ set_title(card) if @options[:title]
26
+ set_body(card) if @options[:body]
27
+ set_image(card) if @options[:image_url]
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def set_type(card)
34
+ return card[:type] = LINK_ACCOUNT_CARD_TYPE if link_account?
35
+ card[:type] = SIMPLE_CARD_TYPE if simple?
36
+ card[:type] = STANDARD_CARD_TYPE if standard?
37
+ end
38
+
39
+ def set_title(card)
40
+ card[:title] = @options[:title]
41
+ end
42
+
43
+ def set_body(card)
44
+ card[:content] = @options[:body] if simple?
45
+ card[:text] = @options[:body] if standard?
46
+ end
47
+
48
+ def set_image(card)
49
+ raise UnsecureUrlError.new("Card images must be available at an SSL-enabled (HTTPS) endpoint. Your current image url is: #{ @options[:image_url] }") unless secure?
50
+ card[:image] = Hash.new
51
+ card[:image][:smallImageUrl] = @options[:image_url]
52
+ card[:image][:largeImageUrl] = @options[:image_url]
53
+ end
54
+
55
+ def link_account?
56
+ !!@options[:link_account]
57
+ end
58
+
59
+ def simple?
60
+ !@options[:image_url]
61
+ end
62
+
63
+ def standard?
64
+ !!@options[:image_url]
65
+ end
66
+
67
+ def secure?
68
+ URI.parse(@options[:image_url]).scheme == "https"
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,35 @@
1
+ module Ralyxa
2
+ module ResponseEntities
3
+ class OutputSpeech
4
+ DEFAULT_RESPONSE_TEXT = "Hello World"
5
+ DEFAULT_RESPONSE_SSML = "<speak>Hello World</speak>"
6
+
7
+ def initialize(speech, ssml)
8
+ @speech = speech
9
+ @ssml = ssml
10
+ end
11
+
12
+ def to_h
13
+ Hash.new.tap do |output_speech|
14
+ @ssml ? set_ssml(output_speech) : set_plaintext(output_speech)
15
+ end
16
+ end
17
+
18
+ def self.as_hash(speech: nil, ssml: false)
19
+ new(speech, ssml).to_h
20
+ end
21
+
22
+ private
23
+
24
+ def set_ssml(output_speech)
25
+ output_speech[:type] = "SSML"
26
+ output_speech[:ssml] = (@speech || DEFAULT_RESPONSE_SSML)
27
+ end
28
+
29
+ def set_plaintext(output_speech)
30
+ output_speech[:type] = "PlainText"
31
+ output_speech[:text] = (@speech || DEFAULT_RESPONSE_TEXT)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,46 @@
1
+ require_relative './output_speech'
2
+
3
+ module Ralyxa
4
+ module ResponseEntities
5
+ class Response
6
+ def initialize(output_speech, session_attributes, end_session, start_over, card)
7
+ @output_speech = output_speech
8
+ @session_attributes = session_attributes
9
+ @end_session = end_session
10
+ @start_over = start_over
11
+ @card = card
12
+ end
13
+
14
+ def to_h
15
+ Hash.new.tap do |response|
16
+ set_version(response)
17
+ set_session_attributes(response)
18
+ set_response(response)
19
+ end
20
+ end
21
+
22
+ def self.as_hash(output_speech: Ralyxa::OutputSpeech.as_hash, session_attributes: {}, end_session: false, start_over: false, card: false)
23
+ new(output_speech, session_attributes, end_session, start_over, card).to_h
24
+ end
25
+
26
+ private
27
+ attr_reader :response
28
+
29
+ def set_version(response)
30
+ response[:version] = "1.0"
31
+ end
32
+
33
+ def set_session_attributes(response)
34
+ return response[:sessionAttributes] = {} if @start_over
35
+ response[:sessionAttributes] = @session_attributes unless @session_attributes.empty?
36
+ end
37
+
38
+ def set_response(response)
39
+ response[:response] = Hash.new
40
+ response[:response][:outputSpeech] = @output_speech
41
+ response[:response][:card] = @card if @card
42
+ response[:response][:shouldEndSession] = @end_session
43
+ end
44
+ end
45
+ end
46
+ end
data/lib/ralyxa/skill.rb CHANGED
@@ -1,5 +1,4 @@
1
- require_relative './request'
2
- require_relative './response'
1
+ require_relative './request_entities/request'
3
2
  require_relative './handler'
4
3
 
5
4
  # Routes an incoming request to the correct Handler.
@@ -23,7 +22,7 @@ module Ralyxa
23
22
  @@handlers[intent_name] = intent_handler
24
23
  end
25
24
 
26
- def handle(request, alexa_request_wrapper = Ralyxa::Request)
25
+ def handle(request, alexa_request_wrapper = Ralyxa::RequestEntities::Request)
27
26
  new(alexa_request_wrapper.new(request)).handle
28
27
  end
29
28
 
@@ -1,3 +1,3 @@
1
1
  module Ralyxa
2
- VERSION = "1.5.0"
2
+ VERSION = "1.5.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ralyxa
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Morgan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-05-30 00:00:00.000000000 Z
11
+ date: 2017-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -62,6 +62,7 @@ extra_rdoc_files: []
62
62
  files:
63
63
  - ".gitignore"
64
64
  - ".rspec"
65
+ - ".travis.yml"
65
66
  - CODE_OF_CONDUCT.md
66
67
  - Gemfile
67
68
  - Gemfile.lock
@@ -71,16 +72,16 @@ files:
71
72
  - bin/console
72
73
  - bin/setup
73
74
  - lib/ralyxa.rb
74
- - lib/ralyxa/card.rb
75
75
  - lib/ralyxa/errors.rb
76
76
  - lib/ralyxa/handler.rb
77
- - lib/ralyxa/output_speech.rb
78
77
  - lib/ralyxa/register_intents.rb
79
- - lib/ralyxa/request.rb
80
- - lib/ralyxa/response.rb
78
+ - lib/ralyxa/request_entities/request.rb
79
+ - lib/ralyxa/request_entities/user.rb
81
80
  - lib/ralyxa/response_builder.rb
81
+ - lib/ralyxa/response_entities/card.rb
82
+ - lib/ralyxa/response_entities/output_speech.rb
83
+ - lib/ralyxa/response_entities/response.rb
82
84
  - lib/ralyxa/skill.rb
83
- - lib/ralyxa/user.rb
84
85
  - lib/ralyxa/version.rb
85
86
  - pkg/ralyxa-1.0.0.gem
86
87
  - ralyxa.gemspec
data/lib/ralyxa/card.rb DELETED
@@ -1,70 +0,0 @@
1
- require_relative './errors'
2
-
3
- module Ralyxa
4
- class Card
5
- LINK_ACCOUNT_CARD_TYPE = "LinkAccount"
6
- SIMPLE_CARD_TYPE = "Simple"
7
- STANDARD_CARD_TYPE = "Standard"
8
-
9
- def initialize(options)
10
- @options = options
11
- end
12
-
13
- def self.as_hash(title, body, image_url = nil)
14
- new(title: title, body: body, image_url: image_url).to_h
15
- end
16
-
17
- def self.link_account
18
- new(link_account: true).to_h
19
- end
20
-
21
- def to_h
22
- Hash.new.tap do |card|
23
- set_type(card)
24
- set_title(card) if @options[:title]
25
- set_body(card) if @options[:body]
26
- set_image(card) if @options[:image_url]
27
- end
28
- end
29
-
30
- private
31
-
32
- def set_type(card)
33
- return card[:type] = LINK_ACCOUNT_CARD_TYPE if link_account?
34
- card[:type] = SIMPLE_CARD_TYPE if simple?
35
- card[:type] = STANDARD_CARD_TYPE if standard?
36
- end
37
-
38
- def set_title(card)
39
- card[:title] = @options[:title]
40
- end
41
-
42
- def set_body(card)
43
- card[:content] = @options[:body] if simple?
44
- card[:text] = @options[:body] if standard?
45
- end
46
-
47
- def set_image(card)
48
- raise UnsecureUrlError.new("Card images must be available at an SSL-enabled (HTTPS) endpoint. Your current image url is: #{ @options[:image_url] }") unless secure?
49
- card[:image] = Hash.new
50
- card[:image][:smallImageUrl] = @options[:image_url]
51
- card[:image][:largeImageUrl] = @options[:image_url]
52
- end
53
-
54
- def link_account?
55
- !!@options[:link_account]
56
- end
57
-
58
- def simple?
59
- !@options[:image_url]
60
- end
61
-
62
- def standard?
63
- !!@options[:image_url]
64
- end
65
-
66
- def secure?
67
- URI.parse(@options[:image_url]).scheme == "https"
68
- end
69
- end
70
- end
@@ -1,33 +0,0 @@
1
- module Ralyxa
2
- class OutputSpeech
3
- DEFAULT_RESPONSE_TEXT = "Hello World"
4
- DEFAULT_RESPONSE_SSML = "<speak>Hello World</speak>"
5
-
6
- def initialize(speech, ssml)
7
- @speech = speech
8
- @ssml = ssml
9
- end
10
-
11
- def to_h
12
- Hash.new.tap do |output_speech|
13
- @ssml ? set_ssml(output_speech) : set_plaintext(output_speech)
14
- end
15
- end
16
-
17
- def self.as_hash(speech: nil, ssml: false)
18
- new(speech, ssml).to_h
19
- end
20
-
21
- private
22
-
23
- def set_ssml(output_speech)
24
- output_speech[:type] = "SSML"
25
- output_speech[:ssml] = (@speech || DEFAULT_RESPONSE_SSML)
26
- end
27
-
28
- def set_plaintext(output_speech)
29
- output_speech[:type] = "PlainText"
30
- output_speech[:text] = (@speech || DEFAULT_RESPONSE_TEXT)
31
- end
32
- end
33
- end
@@ -1,42 +0,0 @@
1
- require 'json'
2
- require 'forwardable'
3
- require_relative './user'
4
-
5
- module Ralyxa
6
- class Request
7
- extend Forwardable
8
- INTENT_REQUEST_TYPE = "IntentRequest".freeze
9
-
10
- def_delegator :@user, :id, :user_id
11
- def_delegator :@user, :access_token, :user_access_token
12
- def_delegator :@user, :access_token_exists?, :user_access_token_exists?
13
-
14
- def initialize(original_request, user_class = Ralyxa::User)
15
- @request = JSON.parse(original_request.body.read)
16
- @user = user_class.build(@request)
17
- end
18
-
19
- def intent_name
20
- return @request["request"]["type"] unless intent_request?
21
- @request["request"]["intent"]["name"]
22
- end
23
-
24
- def slot_value(slot_name)
25
- @request["request"]["intent"]["slots"][slot_name]["value"]
26
- end
27
-
28
- def new_session?
29
- @request["session"]["new"]
30
- end
31
-
32
- def session_attribute(attribute_name)
33
- @request["session"]["attributes"][attribute_name]
34
- end
35
-
36
- private
37
-
38
- def intent_request?
39
- @request["request"]["type"] == INTENT_REQUEST_TYPE
40
- end
41
- end
42
- end
@@ -1,44 +0,0 @@
1
- require_relative './output_speech'
2
-
3
- module Ralyxa
4
- class Response
5
- def initialize(output_speech, session_attributes, end_session, start_over, card)
6
- @output_speech = output_speech
7
- @session_attributes = session_attributes
8
- @end_session = end_session
9
- @start_over = start_over
10
- @card = card
11
- end
12
-
13
- def to_h
14
- Hash.new.tap do |response|
15
- set_version(response)
16
- set_session_attributes(response)
17
- set_response(response)
18
- end
19
- end
20
-
21
- def self.as_hash(output_speech: Ralyxa::OutputSpeech.as_hash, session_attributes: {}, end_session: false, start_over: false, card: false)
22
- new(output_speech, session_attributes, end_session, start_over, card).to_h
23
- end
24
-
25
- private
26
- attr_reader :response
27
-
28
- def set_version(response)
29
- response[:version] = "1.0"
30
- end
31
-
32
- def set_session_attributes(response)
33
- return response[:sessionAttributes] = {} if @start_over
34
- response[:sessionAttributes] = @session_attributes unless @session_attributes.empty?
35
- end
36
-
37
- def set_response(response)
38
- response[:response] = Hash.new
39
- response[:response][:outputSpeech] = @output_speech
40
- response[:response][:card] = @card if @card
41
- response[:response][:shouldEndSession] = @end_session
42
- end
43
- end
44
- end
data/lib/ralyxa/user.rb DELETED
@@ -1,21 +0,0 @@
1
- module Ralyxa
2
- class User
3
- attr_reader :id, :access_token
4
-
5
- def initialize(id:, access_token: nil)
6
- @id = id
7
- @access_token = access_token
8
- end
9
-
10
- def self.build(request)
11
- new(
12
- id: request.dig("session", "user", "userId"),
13
- access_token: request.dig("session", "user", "accessToken")
14
- )
15
- end
16
-
17
- def access_token_exists?
18
- !!@access_token
19
- end
20
- end
21
- end