ralyxa 1.5.0 → 1.5.2

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: 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