alexa_skills_ruby 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +36 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +58 -0
- data/Rakefile +7 -0
- data/alexa_skills_ruby.gemspec +26 -0
- data/lib/alexa_skills_ruby.rb +27 -0
- data/lib/alexa_skills_ruby/errors.rb +4 -0
- data/lib/alexa_skills_ruby/handler.rb +87 -0
- data/lib/alexa_skills_ruby/json_object.rb +122 -0
- data/lib/alexa_skills_ruby/json_objects/application.rb +7 -0
- data/lib/alexa_skills_ruby/json_objects/base_request.rb +40 -0
- data/lib/alexa_skills_ruby/json_objects/card.rb +16 -0
- data/lib/alexa_skills_ruby/json_objects/image.rb +7 -0
- data/lib/alexa_skills_ruby/json_objects/intent.rb +11 -0
- data/lib/alexa_skills_ruby/json_objects/intent_request.rb +7 -0
- data/lib/alexa_skills_ruby/json_objects/launch_request.rb +7 -0
- data/lib/alexa_skills_ruby/json_objects/output_speech.rb +21 -0
- data/lib/alexa_skills_ruby/json_objects/reprompt.rb +7 -0
- data/lib/alexa_skills_ruby/json_objects/response.rb +29 -0
- data/lib/alexa_skills_ruby/json_objects/session.rb +9 -0
- data/lib/alexa_skills_ruby/json_objects/session_ended_request.rb +7 -0
- data/lib/alexa_skills_ruby/json_objects/skills_request.rb +9 -0
- data/lib/alexa_skills_ruby/json_objects/skills_response.rb +14 -0
- data/lib/alexa_skills_ruby/json_objects/user.rb +7 -0
- data/lib/alexa_skills_ruby/version.rb +3 -0
- data/spec/fixtures/example_intent.json +34 -0
- data/spec/fixtures/example_launch.json +19 -0
- data/spec/fixtures/example_response.json +28 -0
- data/spec/fixtures/example_session_ended.json +26 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/fixture_support.rb +11 -0
- data/spec/unit/handler_spec.rb +142 -0
- data/spec/unit/json_object_spec.rb +59 -0
- data/spec/unit/json_objects/skills_request_spec.rb +56 -0
- data/spec/unit/json_objects/skills_response_spec.rb +48 -0
- metadata +173 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1101b97d3f88c45eb43d643d75e3e8e8ca6b26c6
|
4
|
+
data.tar.gz: 0b6350b302c7ed1b643471986233069fe0a139c7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fc1a9404b923d9575c8a75aceed09e7bd0b9dda09230f08d475b199c7f7d53923160c39b9093d3d645872e8d0611eb3e805d31f40c35c11e56683a30aa9e2bdf
|
7
|
+
data.tar.gz: e3f2725899cd0147118eb291c6ba8f6753bb521d67232722695eaa78e9cd0eb6c58e9f4c1d12254da9d8796d7d36abe0a52a941a896cc88357f976a5f5869bbf
|
data/.gitignore
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
|
13
|
+
## Specific to RubyMotion:
|
14
|
+
.dat*
|
15
|
+
.repl_history
|
16
|
+
build/
|
17
|
+
|
18
|
+
## Documentation cache and generated files:
|
19
|
+
/.yardoc/
|
20
|
+
/_yardoc/
|
21
|
+
/doc/
|
22
|
+
/rdoc/
|
23
|
+
|
24
|
+
## Environment normalization:
|
25
|
+
/.bundle/
|
26
|
+
/vendor/bundle
|
27
|
+
/lib/bundler/man/
|
28
|
+
|
29
|
+
# for a library or gem, you might want to ignore these files since the code is
|
30
|
+
# intended to run in multiple environments; otherwise, check them in:
|
31
|
+
Gemfile.lock
|
32
|
+
# .ruby-version
|
33
|
+
# .ruby-gemset
|
34
|
+
|
35
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
36
|
+
.rvmrc
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Dan Elbert
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# alexa-skills-ruby
|
2
|
+
Simple library to interface with the Alexa Skills Kit
|
3
|
+
|
4
|
+
The primary way to interact with this library is by extending the `AlexaSkillsRuby::Handler` class. Create a subclass and
|
5
|
+
register event handlers.
|
6
|
+
|
7
|
+
The following handlers are available:
|
8
|
+
|
9
|
+
* `on_authenticate` - called before checking the ApplicationID
|
10
|
+
* `on_session_start` - called first if the request is flagged as a new session
|
11
|
+
* `on_launch` - called for a LaunchRequest
|
12
|
+
* `on_session_end` - called for a SessionEndedRequest
|
13
|
+
* `on_intent` called for an IntentRequest. Takes an optional string argument that specifies which intents it will be trigged on
|
14
|
+
|
15
|
+
In event handlers, the following methods are available:
|
16
|
+
|
17
|
+
* `request` - returns the current Request object, a `AlexaSkillsRuby::JsonObjects::BaseRequest`
|
18
|
+
* `session` - returns the current Session object, a `AlexaSkillsRuby::JsonObjects::Session`
|
19
|
+
* `session_attributes` - Hash containing the current session attributes. If the response is not flagged to end the session, all values will be sent with the response
|
20
|
+
* `response` - returns the current Response object, a `AlexaSkillsRuby::JsonObjects::Response`
|
21
|
+
* `application_id` - returns the value specified in the constructor options
|
22
|
+
* `logger` - returns the value specified in the constructor options
|
23
|
+
|
24
|
+
The `AlexaSkillsRuby::Handler` constructor takes an options hash and processes the following keys:
|
25
|
+
* `application_id` - If set, will raise a `AlexaSkillsRuby::InvalidApplicationId` if a request's application_id does not match
|
26
|
+
* `logger` - Will be available through the `logger` method in the handler; not otherwise used by the base class
|
27
|
+
|
28
|
+
## Example Sinatra App Using this Library
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
require 'sinatra'
|
32
|
+
require 'alexa_skills_ruby'
|
33
|
+
|
34
|
+
class CustomHandler < AlexaSkillsRuby::Handler
|
35
|
+
|
36
|
+
on_intent("GetZodiacHoroscopeIntent") do
|
37
|
+
slots = request.intent.slots
|
38
|
+
response.set_output_speech_text("Horiscope Text")
|
39
|
+
response.set_simple_card("title", "content")
|
40
|
+
logger.info 'GetZodiacHoroscopeIntent processed'
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
post '/' do
|
46
|
+
content_type :json
|
47
|
+
|
48
|
+
handler = CustomHandler.new(application_id: ENV['APPLICATION_ID'], logger: logger)
|
49
|
+
|
50
|
+
begin
|
51
|
+
handler.handle(request.body.read)
|
52
|
+
rescue AlexaSkillsRuby::InvalidApplicationId => e
|
53
|
+
logger.error e.to_s
|
54
|
+
403
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'alexa_skills_ruby/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "alexa_skills_ruby"
|
8
|
+
spec.version = AlexaSkillsRuby::VERSION
|
9
|
+
spec.authors = ["Dan Elbert"]
|
10
|
+
spec.email = ["dan.elbert@gmail.com"]
|
11
|
+
spec.homepage = 'https://github.com/DanElbert/alexa_skills_ruby'
|
12
|
+
spec.summary = %q{Simple library to interface with the Alexa Skills Kit}
|
13
|
+
|
14
|
+
spec.files = `git ls-files -z`.split("\x0")
|
15
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
16
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
|
19
|
+
spec.add_runtime_dependency 'activesupport', '~> 4.2'
|
20
|
+
spec.add_runtime_dependency "multi_json", "~> 1.0"
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.4.0"
|
25
|
+
spec.add_development_dependency "oj", "~> 2.10.2"
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
2
|
+
require 'active_support/callbacks'
|
3
|
+
require 'multi_json'
|
4
|
+
|
5
|
+
require 'alexa_skills_ruby/version'
|
6
|
+
require 'alexa_skills_ruby/json_object'
|
7
|
+
require 'alexa_skills_ruby/json_objects/application'
|
8
|
+
require 'alexa_skills_ruby/json_objects/user'
|
9
|
+
require 'alexa_skills_ruby/json_objects/session'
|
10
|
+
require 'alexa_skills_ruby/json_objects/intent'
|
11
|
+
require 'alexa_skills_ruby/json_objects/base_request'
|
12
|
+
require 'alexa_skills_ruby/json_objects/intent_request'
|
13
|
+
require 'alexa_skills_ruby/json_objects/launch_request'
|
14
|
+
require 'alexa_skills_ruby/json_objects/session_ended_request'
|
15
|
+
require 'alexa_skills_ruby/json_objects/image'
|
16
|
+
require 'alexa_skills_ruby/json_objects/card'
|
17
|
+
require 'alexa_skills_ruby/json_objects/output_speech'
|
18
|
+
require 'alexa_skills_ruby/json_objects/reprompt'
|
19
|
+
require 'alexa_skills_ruby/json_objects/response'
|
20
|
+
require 'alexa_skills_ruby/json_objects/skills_request'
|
21
|
+
require 'alexa_skills_ruby/json_objects/skills_response'
|
22
|
+
require 'alexa_skills_ruby/errors'
|
23
|
+
require 'alexa_skills_ruby/handler'
|
24
|
+
|
25
|
+
module AlexaSkillsRuby
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module AlexaSkillsRuby
|
2
|
+
class Handler
|
3
|
+
include ActiveSupport::Callbacks
|
4
|
+
define_callbacks :authenticate, :session_start, :launch, :intent, :session_end
|
5
|
+
|
6
|
+
attr_reader :request, :session, :response
|
7
|
+
attr_accessor :application_id, :logger
|
8
|
+
|
9
|
+
def initialize(opts = {})
|
10
|
+
if opts[:application_id]
|
11
|
+
@application_id = opts[:application_id]
|
12
|
+
end
|
13
|
+
|
14
|
+
if opts[:logger]
|
15
|
+
@logger = opts[:logger]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def session_attributes
|
20
|
+
@session.attributes ||= {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def handle(request_json)
|
24
|
+
@skill_request = JsonObjects::SkillsRequest.new(MultiJson.load(request_json))
|
25
|
+
@skill_response = JsonObjects::SkillsResponse.new
|
26
|
+
|
27
|
+
@session = @skill_request.session
|
28
|
+
@request = @skill_request.request
|
29
|
+
@response = @skill_response.response
|
30
|
+
|
31
|
+
|
32
|
+
run_callbacks :authenticate do
|
33
|
+
if @application_id
|
34
|
+
if @application_id != session.application.application_id
|
35
|
+
raise InvalidApplicationId, "Invalid: [#{session.application.application_id}]"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
if session.new
|
41
|
+
run_callbacks :session_start
|
42
|
+
end
|
43
|
+
|
44
|
+
case request
|
45
|
+
when JsonObjects::LaunchRequest
|
46
|
+
run_callbacks :launch
|
47
|
+
when JsonObjects::IntentRequest
|
48
|
+
run_callbacks :intent
|
49
|
+
when JsonObjects::SessionEndedRequest
|
50
|
+
run_callbacks :session_end
|
51
|
+
end
|
52
|
+
|
53
|
+
if response.should_end_session
|
54
|
+
@skill_response.session_attributes = {}
|
55
|
+
else
|
56
|
+
@skill_response.session_attributes = session_attributes
|
57
|
+
end
|
58
|
+
|
59
|
+
MultiJson.dump(@skill_response.as_json)
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.on_authenticate(&block)
|
63
|
+
set_callback :authenticate, :before, block
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.on_session_start(&block)
|
67
|
+
set_callback :session_start, :before, block
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.on_launch(&block)
|
71
|
+
set_callback :launch, :before, block
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.on_session_end(&block)
|
75
|
+
set_callback :session_end, :before, block
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.on_intent(intent_name = nil, &block)
|
79
|
+
opts = {}
|
80
|
+
if intent_name
|
81
|
+
opts[:if] = -> { request.intent_name == intent_name }
|
82
|
+
end
|
83
|
+
set_callback :intent, :before, block, opts
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module AlexaSkillsRuby
|
2
|
+
class JsonObject
|
3
|
+
|
4
|
+
class_attribute :_json_object_properties
|
5
|
+
class_attribute :_properties
|
6
|
+
self._json_object_properties = {}
|
7
|
+
self._properties = []
|
8
|
+
|
9
|
+
def self.json_object_attribute(*args)
|
10
|
+
klass = args.pop
|
11
|
+
raise "Invalid arguments" unless klass && klass.is_a?(Class) && args.length > 0
|
12
|
+
|
13
|
+
args.compact.map { |a| a.to_sym }.each do |a|
|
14
|
+
attr_accessor a
|
15
|
+
self._json_object_properties[a.to_sym] = klass
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.attribute(*attrs)
|
20
|
+
attrs.compact.map { |a| a.to_sym }.each do |a|
|
21
|
+
attr_accessor a
|
22
|
+
self._properties << a
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
alias_method :json_object_attributes, :json_object_attribute
|
28
|
+
alias_method :attributes, :attribute
|
29
|
+
end
|
30
|
+
|
31
|
+
# Copy properties on inheritance.
|
32
|
+
def self.inherited(subclass)
|
33
|
+
entities = _json_object_properties.dup
|
34
|
+
attrs = _properties.dup
|
35
|
+
subclass._json_object_properties = entities.each { |k, v| entities[k] = v.dup }
|
36
|
+
subclass._properties = attrs
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
def initialize(attrs = {})
|
41
|
+
populate_from_json(attrs)
|
42
|
+
end
|
43
|
+
|
44
|
+
def as_json(options = nil)
|
45
|
+
serialize_attributes(_properties + _json_object_properties.keys)
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_json(options = nil)
|
49
|
+
MultiJson.dump(as_json(options))
|
50
|
+
end
|
51
|
+
|
52
|
+
def populate_from_json(attrs)
|
53
|
+
return unless attrs
|
54
|
+
|
55
|
+
attrs.each do |k, v|
|
56
|
+
meth = "#{get_method_name(k)}=".to_sym
|
57
|
+
if self.respond_to? meth
|
58
|
+
if json_object_class = _json_object_properties[k.to_sym]
|
59
|
+
assign_json_object(meth, v, json_object_class)
|
60
|
+
else
|
61
|
+
self.send(meth, v)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def serialize_attributes(attrs)
|
68
|
+
json = {}
|
69
|
+
attrs.each do |k|
|
70
|
+
meth = k.to_sym
|
71
|
+
if self.respond_to?(meth)
|
72
|
+
if _json_object_properties[k.to_sym]
|
73
|
+
val = serialize_json_object(meth)
|
74
|
+
else
|
75
|
+
val = self.send(meth)
|
76
|
+
end
|
77
|
+
unless val.nil?
|
78
|
+
json[get_attribute_name(k)] = val
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
json
|
83
|
+
end
|
84
|
+
|
85
|
+
protected
|
86
|
+
|
87
|
+
def assign_json_object(assignment_method, value, klass)
|
88
|
+
|
89
|
+
if value.is_a? Array
|
90
|
+
data = value.map { |v| hydrate_entity(v, klass) }
|
91
|
+
else
|
92
|
+
data = hydrate_entity(value, klass)
|
93
|
+
end
|
94
|
+
|
95
|
+
self.send(assignment_method, data)
|
96
|
+
end
|
97
|
+
|
98
|
+
def hydrate_entity(json, klass)
|
99
|
+
klass.new(json)
|
100
|
+
end
|
101
|
+
|
102
|
+
def get_method_name(attr_name)
|
103
|
+
attr_name.to_s.gsub(/([a-z])([A-Z])([a-z]|^)/) { |m| "#{m[0]}_#{m[1].downcase}#{m[2]}" }
|
104
|
+
end
|
105
|
+
|
106
|
+
def get_attribute_name(meth_name)
|
107
|
+
meth_name.to_s.gsub(/([a-z])(_)([a-z])/) { |m| m[0] + m[2].upcase }
|
108
|
+
end
|
109
|
+
|
110
|
+
def serialize_json_object(method)
|
111
|
+
value = self.send(method)
|
112
|
+
case value
|
113
|
+
when nil
|
114
|
+
nil
|
115
|
+
when Array
|
116
|
+
value.map { |v| v.as_json }
|
117
|
+
else
|
118
|
+
value.as_json
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module AlexaSkillsRuby
|
2
|
+
module JsonObjects
|
3
|
+
class BaseRequest < JsonObject
|
4
|
+
attributes :type, :request_id, :timestamp
|
5
|
+
|
6
|
+
def self.new(*args, &block)
|
7
|
+
json = args.first
|
8
|
+
subclass = case
|
9
|
+
when self != BaseRequest
|
10
|
+
nil
|
11
|
+
when json.nil?
|
12
|
+
nil
|
13
|
+
when json['type'] == 'LaunchRequest'
|
14
|
+
LaunchRequest
|
15
|
+
when json['type'] == 'IntentRequest'
|
16
|
+
IntentRequest
|
17
|
+
when json['type'] == 'SessionEndedRequest'
|
18
|
+
SessionEndedRequest
|
19
|
+
else
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
if subclass
|
24
|
+
subclass.new(*args, &block)
|
25
|
+
else
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def intent_name
|
31
|
+
if self.is_a? IntentRequest
|
32
|
+
self.intent.name
|
33
|
+
else
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module AlexaSkillsRuby
|
2
|
+
module JsonObjects
|
3
|
+
class Card < JsonObject
|
4
|
+
attributes :type, :title, :content, :text
|
5
|
+
json_object_attributes :image, Image
|
6
|
+
|
7
|
+
def self.simple(title, content)
|
8
|
+
card = new
|
9
|
+
card.type = "Simple"
|
10
|
+
card.title = title
|
11
|
+
card.content = content
|
12
|
+
card
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module AlexaSkillsRuby
|
2
|
+
module JsonObjects
|
3
|
+
class OutputSpeech < JsonObject
|
4
|
+
attributes :type, :text, :ssml
|
5
|
+
|
6
|
+
def self.text(text)
|
7
|
+
os = new
|
8
|
+
os.text = text
|
9
|
+
os.type = 'PlainText'
|
10
|
+
os
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.ssml(ssml)
|
14
|
+
os = new
|
15
|
+
os.ssml = ssml
|
16
|
+
os.type = 'SSML'
|
17
|
+
os
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module AlexaSkillsRuby
|
2
|
+
module JsonObjects
|
3
|
+
class Response < JsonObject
|
4
|
+
attributes :should_end_session
|
5
|
+
json_object_attribute :output_speech, OutputSpeech
|
6
|
+
json_object_attribute :card, Card
|
7
|
+
json_object_attribute :reprompt, Reprompt
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
self.should_end_session = true
|
11
|
+
end
|
12
|
+
|
13
|
+
def set_output_speech_text(text)
|
14
|
+
self.output_speech = OutputSpeech.text(text)
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_simple_card(title, content)
|
18
|
+
self.card = Card.simple(title, content)
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_reprompt_speech_text(text)
|
22
|
+
os = OutputSpeech.text(text)
|
23
|
+
rp = Reprompt.new
|
24
|
+
rp.output_speech = os
|
25
|
+
self.reprompt = rp
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module AlexaSkillsRuby
|
2
|
+
module JsonObjects
|
3
|
+
class SkillsResponse < JsonObject
|
4
|
+
attributes :version, :session_attributes
|
5
|
+
json_object_attribute :response, Response
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
self.version = '1.0'
|
9
|
+
self.session_attributes = {}
|
10
|
+
self.response = JsonObjects::Response.new
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
{
|
2
|
+
"version": "1.0",
|
3
|
+
"session": {
|
4
|
+
"new": false,
|
5
|
+
"sessionId": "amzn1.echo-api.session.0000000-0000-0000-0000-00000000000",
|
6
|
+
"application": {
|
7
|
+
"applicationId": "amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe"
|
8
|
+
},
|
9
|
+
"attributes": {
|
10
|
+
"supportedHoroscopePeriods": {
|
11
|
+
"daily": true,
|
12
|
+
"weekly": false,
|
13
|
+
"monthly": false
|
14
|
+
}
|
15
|
+
},
|
16
|
+
"user": {
|
17
|
+
"userId": "amzn1.account.AM3B00000000000000000000000"
|
18
|
+
}
|
19
|
+
},
|
20
|
+
"request": {
|
21
|
+
"type": "IntentRequest",
|
22
|
+
"requestId": "amzn1.echo-api.request.0000000-0000-0000-0000-00000000000",
|
23
|
+
"timestamp": "2015-05-13T12:34:56Z",
|
24
|
+
"intent": {
|
25
|
+
"name": "GetZodiacHoroscopeIntent",
|
26
|
+
"slots": {
|
27
|
+
"ZodiacSign": {
|
28
|
+
"name": "ZodiacSign",
|
29
|
+
"value": "virgo"
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
{
|
2
|
+
"version": "1.0",
|
3
|
+
"session": {
|
4
|
+
"new": true,
|
5
|
+
"sessionId": "amzn1.echo-api.session.0000000-0000-0000-0000-00000000000",
|
6
|
+
"application": {
|
7
|
+
"applicationId": "amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe"
|
8
|
+
},
|
9
|
+
"attributes": {},
|
10
|
+
"user": {
|
11
|
+
"userId": "amzn1.account.AM3B00000000000000000000000"
|
12
|
+
}
|
13
|
+
},
|
14
|
+
"request": {
|
15
|
+
"type": "LaunchRequest",
|
16
|
+
"requestId": "amzn1.echo-api.request.0000000-0000-0000-0000-00000000000",
|
17
|
+
"timestamp": "2015-05-13T12:34:56Z"
|
18
|
+
}
|
19
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
{
|
2
|
+
"version": "1.0",
|
3
|
+
"sessionAttributes": {
|
4
|
+
"supportedHoriscopePeriods": {
|
5
|
+
"daily": true,
|
6
|
+
"weekly": false,
|
7
|
+
"monthly": false
|
8
|
+
}
|
9
|
+
},
|
10
|
+
"response": {
|
11
|
+
"outputSpeech": {
|
12
|
+
"type": "PlainText",
|
13
|
+
"text": "Today will provide you a new learning opportunity. Stick with it and the possibilities will be endless. Can I help you with anything else?"
|
14
|
+
},
|
15
|
+
"card": {
|
16
|
+
"type": "Simple",
|
17
|
+
"title": "Horoscope",
|
18
|
+
"content": "Today will provide you a new learning opportunity. Stick with it and the possibilities will be endless."
|
19
|
+
},
|
20
|
+
"reprompt": {
|
21
|
+
"outputSpeech": {
|
22
|
+
"type": "PlainText",
|
23
|
+
"text": "Can I help you with anything else?"
|
24
|
+
}
|
25
|
+
},
|
26
|
+
"shouldEndSession": false
|
27
|
+
}
|
28
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
{
|
2
|
+
"version": "1.0",
|
3
|
+
"session": {
|
4
|
+
"new": false,
|
5
|
+
"sessionId": "amzn1.echo-api.session.0000000-0000-0000-0000-00000000000",
|
6
|
+
"application": {
|
7
|
+
"applicationId": "amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe"
|
8
|
+
},
|
9
|
+
"attributes": {
|
10
|
+
"supportedHoroscopePeriods": {
|
11
|
+
"daily": true,
|
12
|
+
"weekly": false,
|
13
|
+
"monthly": false
|
14
|
+
}
|
15
|
+
},
|
16
|
+
"user": {
|
17
|
+
"userId": "amzn1.account.AM3B00000000000000000000000"
|
18
|
+
}
|
19
|
+
},
|
20
|
+
"request": {
|
21
|
+
"type": "SessionEndedRequest",
|
22
|
+
"requestId": "amzn1.echo-api.request.0000000-0000-0000-0000-00000000000",
|
23
|
+
"timestamp": "2015-05-13T12:34:56Z",
|
24
|
+
"reason": "USER_INITIATED"
|
25
|
+
}
|
26
|
+
}
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'oj'
|
4
|
+
require 'rspec'
|
5
|
+
require File.expand_path('../../lib/alexa_skills_ruby', __FILE__)
|
6
|
+
|
7
|
+
MultiJson.use :oj
|
8
|
+
|
9
|
+
Dir[File.expand_path('../support/**/*', __FILE__)].each { |f| require f }
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
|
13
|
+
config.include FixtureSupport
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe AlexaSkillsRuby::Handler do
|
4
|
+
|
5
|
+
class TestHandler < AlexaSkillsRuby::Handler
|
6
|
+
|
7
|
+
attr_reader :auths, :intents, :launch, :ends, :starts
|
8
|
+
|
9
|
+
def initialize(*args)
|
10
|
+
super
|
11
|
+
@auths = []
|
12
|
+
@intents = []
|
13
|
+
@launch = []
|
14
|
+
@ends = []
|
15
|
+
@starts = []
|
16
|
+
end
|
17
|
+
|
18
|
+
on_session_start do
|
19
|
+
@starts << request
|
20
|
+
end
|
21
|
+
|
22
|
+
on_authenticate do
|
23
|
+
@auths << request
|
24
|
+
end
|
25
|
+
|
26
|
+
on_launch do
|
27
|
+
@launch << request
|
28
|
+
end
|
29
|
+
|
30
|
+
on_intent do
|
31
|
+
@intents << request
|
32
|
+
end
|
33
|
+
|
34
|
+
on_intent('special') do
|
35
|
+
@intents << request
|
36
|
+
end
|
37
|
+
|
38
|
+
on_session_end do
|
39
|
+
@ends << request
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
let(:handler) { TestHandler.new }
|
44
|
+
|
45
|
+
describe 'with a launch request' do
|
46
|
+
let(:request_json) { load_json 'example_launch.json' }
|
47
|
+
|
48
|
+
it 'fires the handlers' do
|
49
|
+
handler.handle(request_json)
|
50
|
+
|
51
|
+
expect(handler.auths.count).to eq 1
|
52
|
+
expect(handler.intents.count).to eq 0
|
53
|
+
expect(handler.ends.count).to eq 0
|
54
|
+
expect(handler.starts.count).to eq 1
|
55
|
+
expect(handler.launch.count).to eq 1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'with an intent request' do
|
60
|
+
let(:request_json) { load_json 'example_intent.json' }
|
61
|
+
|
62
|
+
it 'fires the handlers' do
|
63
|
+
handler.handle(request_json)
|
64
|
+
|
65
|
+
expect(handler.auths.count).to eq 1
|
66
|
+
expect(handler.intents.count).to eq 1
|
67
|
+
expect(handler.ends.count).to eq 0
|
68
|
+
expect(handler.starts.count).to eq 0
|
69
|
+
expect(handler.launch.count).to eq 0
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'with a special intent request' do
|
74
|
+
let(:request_json) do
|
75
|
+
json = load_fixture 'example_intent.json'
|
76
|
+
json['request']['intent']['name'] = 'special'
|
77
|
+
Oj.dump(json)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'fires the handlers' do
|
81
|
+
handler.handle(request_json)
|
82
|
+
|
83
|
+
expect(handler.auths.count).to eq 1
|
84
|
+
expect(handler.intents.count).to eq 2
|
85
|
+
expect(handler.ends.count).to eq 0
|
86
|
+
expect(handler.starts.count).to eq 0
|
87
|
+
expect(handler.launch.count).to eq 0
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe 'with a session ended request' do
|
92
|
+
let(:request_json) { load_json 'example_session_ended.json' }
|
93
|
+
|
94
|
+
it 'fires the handlers' do
|
95
|
+
handler.handle(request_json)
|
96
|
+
|
97
|
+
expect(handler.auths.count).to eq 1
|
98
|
+
expect(handler.intents.count).to eq 0
|
99
|
+
expect(handler.ends.count).to eq 1
|
100
|
+
expect(handler.starts.count).to eq 0
|
101
|
+
expect(handler.launch.count).to eq 0
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe 'with an application_id set' do
|
106
|
+
|
107
|
+
let(:handler) { TestHandler.new({application_id: 'amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe'}) }
|
108
|
+
|
109
|
+
describe 'with a valid app id in request' do
|
110
|
+
let(:request_json) { load_json 'example_session_ended.json' }
|
111
|
+
|
112
|
+
it 'fires the handlers' do
|
113
|
+
handler.handle(request_json)
|
114
|
+
|
115
|
+
expect(handler.auths.count).to eq 1
|
116
|
+
expect(handler.intents.count).to eq 0
|
117
|
+
expect(handler.ends.count).to eq 1
|
118
|
+
expect(handler.starts.count).to eq 0
|
119
|
+
expect(handler.launch.count).to eq 0
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe 'with an invalid app id in request' do
|
124
|
+
let(:request_json) do
|
125
|
+
json = load_fixture 'example_intent.json'
|
126
|
+
json['session']['application']['applicationId'] = 'broke'
|
127
|
+
Oj.dump(json)
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'fires the handlers' do
|
131
|
+
expect { handler.handle(request_json) }.to raise_error AlexaSkillsRuby::InvalidApplicationId
|
132
|
+
|
133
|
+
expect(handler.auths.count).to eq 1
|
134
|
+
expect(handler.intents.count).to eq 0
|
135
|
+
expect(handler.ends.count).to eq 0
|
136
|
+
expect(handler.starts.count).to eq 0
|
137
|
+
expect(handler.launch.count).to eq 0
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe AlexaSkillsRuby::JsonObject do
|
4
|
+
|
5
|
+
class TestJsonObject < AlexaSkillsRuby::JsonObject
|
6
|
+
attributes :name, :id
|
7
|
+
json_object_attribute :attr1, AlexaSkillsRuby::JsonObjects::User
|
8
|
+
end
|
9
|
+
|
10
|
+
class ChildTestJsonObject < TestJsonObject
|
11
|
+
attribute :another_field
|
12
|
+
json_object_attribute :attr2, AlexaSkillsRuby::JsonObjects::User
|
13
|
+
end
|
14
|
+
|
15
|
+
class OtherTestJsonObject < AlexaSkillsRuby::JsonObject
|
16
|
+
json_object_attribute :attr3, AlexaSkillsRuby::JsonObjects::User
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '.json_object_attribute' do
|
20
|
+
|
21
|
+
it 'should keep separate lists for each type' do
|
22
|
+
expect(TestJsonObject._json_object_properties.keys).to contain_exactly :attr1
|
23
|
+
expect(ChildTestJsonObject._json_object_properties.keys).to contain_exactly :attr1, :attr2
|
24
|
+
expect(OtherTestJsonObject._json_object_properties.keys).to contain_exactly :attr3
|
25
|
+
|
26
|
+
expect(TestJsonObject._properties).to contain_exactly :name, :id
|
27
|
+
expect(ChildTestJsonObject._properties).to contain_exactly :name, :id, :another_field
|
28
|
+
expect(OtherTestJsonObject._properties.length).to eq 0
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'serialization' do
|
34
|
+
|
35
|
+
it 'serializes entities' do
|
36
|
+
json_object = TestJsonObject.new
|
37
|
+
json_object.attr1 = AlexaSkillsRuby::JsonObjects::User.new
|
38
|
+
json_object.attr1.user_id = 5
|
39
|
+
json_object.attr1.access_token = 'token'
|
40
|
+
json_object.name = 'name'
|
41
|
+
json_object.id = 1
|
42
|
+
|
43
|
+
json = json_object.as_json
|
44
|
+
expect(json).to eq({ 'attr1' => { 'userId' => 5, 'accessToken' => 'token'}, 'name' => 'name', 'id' => 1 })
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'deserialization' do
|
50
|
+
it 'populates the objects' do
|
51
|
+
json = { attr1: { id: 5, access_token: 'token'}, name: 'name', id: 1 }
|
52
|
+
json_object = TestJsonObject.new(json)
|
53
|
+
expect(json_object.name).to eq 'name'
|
54
|
+
expect(json_object.attr1).to be_a AlexaSkillsRuby::JsonObjects::User
|
55
|
+
expect(json_object.attr1.access_token).to eq 'token'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe AlexaSkillsRuby::JsonObjects::SkillsRequest do
|
4
|
+
|
5
|
+
let(:launch_request_json) do
|
6
|
+
load_fixture 'example_launch.json'
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:intent_request_json) do
|
10
|
+
load_fixture 'example_intent.json'
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:session_ended_request_json) do
|
14
|
+
load_fixture 'example_session_ended.json'
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'constructs a launch request' do
|
18
|
+
r = AlexaSkillsRuby::JsonObjects::SkillsRequest.new(launch_request_json)
|
19
|
+
expect(r).not_to be_nil
|
20
|
+
expect(r.version).to eq '1.0'
|
21
|
+
expect(r.session).to be_a AlexaSkillsRuby::JsonObjects::Session
|
22
|
+
expect(r.session.new).to eq true
|
23
|
+
expect(r.session.session_id).to eq 'amzn1.echo-api.session.0000000-0000-0000-0000-00000000000'
|
24
|
+
expect(r.session.application).to be_a AlexaSkillsRuby::JsonObjects::Application
|
25
|
+
expect(r.session.application.application_id).to eq 'amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe'
|
26
|
+
expect(r.session.attributes).to eq({})
|
27
|
+
expect(r.session.user).to be_a AlexaSkillsRuby::JsonObjects::User
|
28
|
+
expect(r.session.user.user_id).to eq 'amzn1.account.AM3B00000000000000000000000'
|
29
|
+
expect(r.request).to be_a AlexaSkillsRuby::JsonObjects::LaunchRequest
|
30
|
+
expect(r.request.type).to eq 'LaunchRequest'
|
31
|
+
expect(r.request.request_id).to eq 'amzn1.echo-api.request.0000000-0000-0000-0000-00000000000'
|
32
|
+
expect(r.request.timestamp).to eq '2015-05-13T12:34:56Z'
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'constructs an intent request' do
|
36
|
+
r = AlexaSkillsRuby::JsonObjects::SkillsRequest.new(intent_request_json)
|
37
|
+
expect(r.request).to be_a AlexaSkillsRuby::JsonObjects::IntentRequest
|
38
|
+
expect(r.request.type).to eq 'IntentRequest'
|
39
|
+
expect(r.request.request_id).to eq 'amzn1.echo-api.request.0000000-0000-0000-0000-00000000000'
|
40
|
+
expect(r.request.timestamp).to eq '2015-05-13T12:34:56Z'
|
41
|
+
expect(r.request.intent).to be_a AlexaSkillsRuby::JsonObjects::Intent
|
42
|
+
expect(r.request.intent.name).to eq 'GetZodiacHoroscopeIntent'
|
43
|
+
expect(r.request.intent.slots).to be_a Hash
|
44
|
+
expect(r.request.intent.slots['ZodiacSign']).to eq('virgo')
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'constructs a session ended request' do
|
48
|
+
r = AlexaSkillsRuby::JsonObjects::SkillsRequest.new(session_ended_request_json)
|
49
|
+
expect(r.request).to be_a AlexaSkillsRuby::JsonObjects::SessionEndedRequest
|
50
|
+
expect(r.request.type).to eq 'SessionEndedRequest'
|
51
|
+
expect(r.request.request_id).to eq 'amzn1.echo-api.request.0000000-0000-0000-0000-00000000000'
|
52
|
+
expect(r.request.timestamp).to eq '2015-05-13T12:34:56Z'
|
53
|
+
expect(r.request.reason).to eq 'USER_INITIATED'
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe AlexaSkillsRuby::JsonObjects::SkillsResponse do
|
4
|
+
|
5
|
+
let(:response_json) do
|
6
|
+
{
|
7
|
+
'version' => "1.0",
|
8
|
+
'sessionAttributes' => {
|
9
|
+
'supportedHoriscopePeriods' => {
|
10
|
+
'daily' => true,
|
11
|
+
'weekly' => false,
|
12
|
+
'monthly' => false
|
13
|
+
}
|
14
|
+
},
|
15
|
+
'response' => {
|
16
|
+
'outputSpeech' => {
|
17
|
+
'type' => "PlainText",
|
18
|
+
'text' => "Today will provide you a new learning opportunity. Stick with it and the possibilities will be endless. Can I help you with anything else?"
|
19
|
+
},
|
20
|
+
'card' => {
|
21
|
+
'type' => "Simple",
|
22
|
+
'title' => "Horoscope",
|
23
|
+
'content' => "Today will provide you a new learning opportunity. Stick with it and the possibilities will be endless."
|
24
|
+
},
|
25
|
+
'reprompt' => {
|
26
|
+
'outputSpeech' => {
|
27
|
+
'type' => "PlainText",
|
28
|
+
'text' => "Can I help you with anything else?"
|
29
|
+
}
|
30
|
+
},
|
31
|
+
'shouldEndSession' => false
|
32
|
+
}
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'generates example json' do
|
37
|
+
sr = AlexaSkillsRuby::JsonObjects::SkillsResponse.new
|
38
|
+
r = sr.response
|
39
|
+
sr.session_attributes = {'supportedHoriscopePeriods' => {'daily' => true, 'weekly' => false, 'monthly' => false}}
|
40
|
+
r.set_output_speech_text("Today will provide you a new learning opportunity. Stick with it and the possibilities will be endless. Can I help you with anything else?")
|
41
|
+
r.set_simple_card('Horoscope', 'Today will provide you a new learning opportunity. Stick with it and the possibilities will be endless.')
|
42
|
+
r.set_reprompt_speech_text('Can I help you with anything else?')
|
43
|
+
r.should_end_session = false
|
44
|
+
|
45
|
+
expect(sr.as_json).to eq response_json
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
metadata
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: alexa_skills_ruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dan Elbert
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-04-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: multi_json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
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: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 3.4.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 3.4.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: oj
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 2.10.2
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 2.10.2
|
97
|
+
description:
|
98
|
+
email:
|
99
|
+
- dan.elbert@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- ".gitignore"
|
105
|
+
- Gemfile
|
106
|
+
- LICENSE
|
107
|
+
- README.md
|
108
|
+
- Rakefile
|
109
|
+
- alexa_skills_ruby.gemspec
|
110
|
+
- lib/alexa_skills_ruby.rb
|
111
|
+
- lib/alexa_skills_ruby/errors.rb
|
112
|
+
- lib/alexa_skills_ruby/handler.rb
|
113
|
+
- lib/alexa_skills_ruby/json_object.rb
|
114
|
+
- lib/alexa_skills_ruby/json_objects/application.rb
|
115
|
+
- lib/alexa_skills_ruby/json_objects/base_request.rb
|
116
|
+
- lib/alexa_skills_ruby/json_objects/card.rb
|
117
|
+
- lib/alexa_skills_ruby/json_objects/image.rb
|
118
|
+
- lib/alexa_skills_ruby/json_objects/intent.rb
|
119
|
+
- lib/alexa_skills_ruby/json_objects/intent_request.rb
|
120
|
+
- lib/alexa_skills_ruby/json_objects/launch_request.rb
|
121
|
+
- lib/alexa_skills_ruby/json_objects/output_speech.rb
|
122
|
+
- lib/alexa_skills_ruby/json_objects/reprompt.rb
|
123
|
+
- lib/alexa_skills_ruby/json_objects/response.rb
|
124
|
+
- lib/alexa_skills_ruby/json_objects/session.rb
|
125
|
+
- lib/alexa_skills_ruby/json_objects/session_ended_request.rb
|
126
|
+
- lib/alexa_skills_ruby/json_objects/skills_request.rb
|
127
|
+
- lib/alexa_skills_ruby/json_objects/skills_response.rb
|
128
|
+
- lib/alexa_skills_ruby/json_objects/user.rb
|
129
|
+
- lib/alexa_skills_ruby/version.rb
|
130
|
+
- spec/fixtures/example_intent.json
|
131
|
+
- spec/fixtures/example_launch.json
|
132
|
+
- spec/fixtures/example_response.json
|
133
|
+
- spec/fixtures/example_session_ended.json
|
134
|
+
- spec/spec_helper.rb
|
135
|
+
- spec/support/fixture_support.rb
|
136
|
+
- spec/unit/handler_spec.rb
|
137
|
+
- spec/unit/json_object_spec.rb
|
138
|
+
- spec/unit/json_objects/skills_request_spec.rb
|
139
|
+
- spec/unit/json_objects/skills_response_spec.rb
|
140
|
+
homepage: https://github.com/DanElbert/alexa_skills_ruby
|
141
|
+
licenses: []
|
142
|
+
metadata: {}
|
143
|
+
post_install_message:
|
144
|
+
rdoc_options: []
|
145
|
+
require_paths:
|
146
|
+
- lib
|
147
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0'
|
152
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - ">="
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '0'
|
157
|
+
requirements: []
|
158
|
+
rubyforge_project:
|
159
|
+
rubygems_version: 2.4.6
|
160
|
+
signing_key:
|
161
|
+
specification_version: 4
|
162
|
+
summary: Simple library to interface with the Alexa Skills Kit
|
163
|
+
test_files:
|
164
|
+
- spec/fixtures/example_intent.json
|
165
|
+
- spec/fixtures/example_launch.json
|
166
|
+
- spec/fixtures/example_response.json
|
167
|
+
- spec/fixtures/example_session_ended.json
|
168
|
+
- spec/spec_helper.rb
|
169
|
+
- spec/support/fixture_support.rb
|
170
|
+
- spec/unit/handler_spec.rb
|
171
|
+
- spec/unit/json_object_spec.rb
|
172
|
+
- spec/unit/json_objects/skills_request_spec.rb
|
173
|
+
- spec/unit/json_objects/skills_response_spec.rb
|