animoto 0.0.0.alpha3 → 0.0.0.alpha4
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.
- data/lib/animoto/asset.rb +0 -6
- data/lib/animoto/client.rb +106 -112
- data/lib/animoto/dynamic_class_loader.rb +64 -0
- data/lib/animoto/http_engine.rb +34 -0
- data/lib/animoto/http_engines/curl_adapter.rb +39 -0
- data/lib/animoto/http_engines/net_http_adapter.rb +55 -0
- data/lib/animoto/http_engines/patron_adapter.rb +27 -0
- data/lib/animoto/http_engines/rest_client_adapter.rb +25 -0
- data/lib/animoto/http_engines/typhoeus_adapter.rb +24 -0
- data/lib/animoto/manifest.rb +0 -7
- data/lib/animoto/resource.rb +3 -3
- data/lib/animoto/response_parser.rb +38 -0
- data/lib/animoto/response_parsers/json_adapter.rb +21 -0
- data/lib/animoto/response_parsers/yajl_adapter.rb +21 -0
- data/lib/animoto/standard_envelope.rb +1 -1
- data/lib/animoto.rb +1 -1
- data/spec/animoto/client_spec.rb +43 -20
- data/spec/animoto/http_engine_spec.rb +27 -0
- data/spec/animoto/response_parsers/json_adapter_spec.rb +93 -0
- data/spec/animoto/response_parsers/yajl_adapter_spec.rb +93 -0
- data/spec/spec_helper.rb +1 -1
- metadata +17 -4
data/lib/animoto/asset.rb
CHANGED
data/lib/animoto/client.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
|
-
require 'uri'
|
2
|
-
require 'net/http'
|
3
|
-
require 'net/https'
|
4
|
-
require 'json'
|
5
1
|
require 'yaml'
|
2
|
+
require 'uri'
|
6
3
|
|
7
4
|
require 'animoto/errors'
|
8
5
|
require 'animoto/content_type'
|
@@ -25,19 +22,18 @@ require 'animoto/job'
|
|
25
22
|
require 'animoto/directing_and_rendering_job'
|
26
23
|
require 'animoto/directing_job'
|
27
24
|
require 'animoto/rendering_job'
|
25
|
+
require 'animoto/dynamic_class_loader'
|
26
|
+
require 'animoto/http_engine'
|
27
|
+
require 'animoto/response_parser'
|
28
28
|
|
29
29
|
module Animoto
|
30
30
|
class Client
|
31
31
|
API_ENDPOINT = "https://api2-staging.animoto.com/"
|
32
32
|
API_VERSION = 1
|
33
33
|
BASE_CONTENT_TYPE = "application/vnd.animoto"
|
34
|
-
HTTP_METHOD_MAP = {
|
35
|
-
:get => Net::HTTP::Get,
|
36
|
-
:post => Net::HTTP::Post
|
37
|
-
}
|
38
34
|
|
39
35
|
attr_accessor :key, :secret, :endpoint
|
40
|
-
attr_reader
|
36
|
+
attr_reader :http_engine, :response_parser
|
41
37
|
|
42
38
|
# Creates a new Client object which handles credentials, versioning, making requests, and
|
43
39
|
# parsing responses.
|
@@ -52,27 +48,61 @@ module Animoto
|
|
52
48
|
# @return [Client]
|
53
49
|
# @raise [ArgumentError] if no credentials are supplied
|
54
50
|
def initialize *args
|
55
|
-
@debug = ENV['DEBUG']
|
56
51
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
57
52
|
@key = args[0]
|
58
53
|
@secret = args[1]
|
59
54
|
@endpoint = options[:endpoint]
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
55
|
+
configure_from_rc_file
|
56
|
+
@endpoint ||= API_ENDPOINT
|
57
|
+
__send__ :http_engine=, options[:http_engine] || :net_http
|
58
|
+
__send__ :response_parser=, options[:response_parser] || :json
|
59
|
+
end
|
60
|
+
|
61
|
+
# Set the HTTP engine this client will use.
|
62
|
+
#
|
63
|
+
# @param [HTTPEngine, Symbol, Class] engine you may pass a
|
64
|
+
# HTTPEngine instance to use, or the symbolic name of a adapter to use,
|
65
|
+
# or a Class whose instances respond to #request and return a String of
|
66
|
+
# the response body
|
67
|
+
# @see Animoto::HTTPEngine
|
68
|
+
# @return [HTTPEngine] the engine instance
|
69
|
+
# @raise [ArgumentError] if given a class without the correct interface
|
70
|
+
def http_engine= engine
|
71
|
+
@http_engine = case engine
|
72
|
+
when Animoto::HTTPEngine
|
73
|
+
engine
|
74
|
+
when Class
|
75
|
+
if engine.instance_methods.include?('request')
|
76
|
+
engine.new
|
77
|
+
else
|
78
|
+
raise ArgumentError
|
79
|
+
end
|
80
|
+
else
|
81
|
+
Animoto::HTTPEngine[engine].new
|
66
82
|
end
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
83
|
+
end
|
84
|
+
|
85
|
+
# Set the response parser this client will use.
|
86
|
+
#
|
87
|
+
# @param [ResponseParser, Symbol, Class] parser you may pass a
|
88
|
+
# ResponseParser instance to use, or the symbolic name of a adapter to use,
|
89
|
+
# or a Class whose instances respond to #parse, #unparse, and #format.
|
90
|
+
# @see Animoto::ResponseParser
|
91
|
+
# @return [ResponseParser] the parser instance
|
92
|
+
# @raise [ArgumentError] if given a class without the correct interface
|
93
|
+
def response_parser= parser
|
94
|
+
@response_parser = case parser
|
95
|
+
when Animoto::ResponseParser
|
96
|
+
parser
|
97
|
+
when Class
|
98
|
+
if %{format parse unparse}.all? { |m| parser.instance_methods.include? m }
|
99
|
+
parser.new
|
100
|
+
else
|
101
|
+
raise ArgumentError
|
102
|
+
end
|
103
|
+
else
|
104
|
+
Animoto::ResponseParser[parser].new
|
72
105
|
end
|
73
|
-
|
74
|
-
@endpoint ||= API_ENDPOINT
|
75
|
-
@format = 'json'
|
76
106
|
end
|
77
107
|
|
78
108
|
# Finds a resource by its URL.
|
@@ -124,15 +154,40 @@ module Animoto
|
|
124
154
|
|
125
155
|
private
|
126
156
|
|
157
|
+
# Sets the API credentials from an .animotorc file. First looks for one in the current
|
158
|
+
# directory, then checks ~/.animotorc, then finally /etc/.animotorc.
|
159
|
+
#
|
160
|
+
# @raise [ArgumentError] if none of the files are found
|
161
|
+
def configure_from_rc_file
|
162
|
+
catch(:done) do
|
163
|
+
current_path = Dir.pwd + '/.animotorc'
|
164
|
+
home_path = File.expand_path('~/.animotorc')
|
165
|
+
config = if File.exist?(current_path)
|
166
|
+
YAML.load(File.read(current_path))
|
167
|
+
elsif File.exist?(home_path)
|
168
|
+
home_path = File.expand_path '~/.animotorc'
|
169
|
+
YAML.load(File.read(home_path))
|
170
|
+
elsif File.exist?('/etc/.animotorc')
|
171
|
+
YAML.load(File.read('/etc/.animotorc'))
|
172
|
+
end
|
173
|
+
if config
|
174
|
+
@key ||= config['key']
|
175
|
+
@secret ||= config['secret']
|
176
|
+
@endpoint ||= config['endpoint']
|
177
|
+
throw :done if @key && @secret
|
178
|
+
end
|
179
|
+
raise ArgumentError, "You must supply your key and secret"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
127
183
|
# Builds a request to find a resource.
|
128
184
|
#
|
129
185
|
# @param [Class] klass the Resource class you're looking for
|
130
186
|
# @param [String] url the URL of the resource
|
131
187
|
# @param [Hash] options
|
132
|
-
# @return [Hash] deserialized
|
188
|
+
# @return [Hash] deserialized response body
|
133
189
|
def find_request klass, url, options = {}
|
134
|
-
|
135
|
-
request(:get, URI.parse(url), nil, { "Accept" => content_type_of(klass) }, options)
|
190
|
+
request(:get, url, nil, { "Accept" => content_type_of(klass) }, options)
|
136
191
|
end
|
137
192
|
|
138
193
|
# Builds a request requiring a manifest.
|
@@ -140,104 +195,43 @@ module Animoto
|
|
140
195
|
# @param [Manifest] manifest the manifest being acted on
|
141
196
|
# @param [String] endpoint the endpoint to send the request to
|
142
197
|
# @param [Hash] options
|
143
|
-
# @return [Hash] deserialized
|
198
|
+
# @return [Hash] deserialized response body
|
144
199
|
def send_manifest manifest, endpoint, options = {}
|
145
|
-
# request(:post, endpoint, manifest.to_json, { "Accept" => "application/#{format}", "Content-Type" => content_type_of(manifest) }, options)
|
146
200
|
u = URI.parse(endpoint)
|
147
201
|
u.path = endpoint
|
148
|
-
request(
|
202
|
+
request(
|
203
|
+
:post,
|
204
|
+
u.to_s,
|
205
|
+
response_parser.unparse(manifest.to_hash),
|
206
|
+
{ "Accept" => "application/#{response_parser.format}", "Content-Type" => content_type_of(manifest) },
|
207
|
+
options
|
208
|
+
)
|
149
209
|
end
|
150
210
|
|
151
211
|
# Makes a request and parses the response.
|
152
212
|
#
|
153
213
|
# @param [Symbol] method which HTTP method to use (should be lowercase, i.e. :get instead of :GET)
|
154
|
-
# @param [
|
214
|
+
# @param [String] url the URL of the request
|
155
215
|
# @param [String, nil] body the request body
|
156
216
|
# @param [Hash<String,String>] headers the request headers (will be sent as-is, which means you should
|
157
217
|
# specify "Content-Type" => "..." instead of, say, :content_type => "...")
|
158
218
|
# @param [Hash] options
|
159
|
-
# @return [Hash] deserialized
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
puts "********************* REQUEST *******************"
|
167
|
-
puts "#{req.method} #{uri.to_s} HTTP/#{http.instance_variable_get(:@curr_http_version)}\r\n"
|
168
|
-
req.each_capitalized { |header, value| puts "#{header}: #{value}\r\n" }
|
169
|
-
puts "\r\n"
|
170
|
-
puts req.body unless req.method == 'GET'
|
219
|
+
# @return [Hash] deserialized response body
|
220
|
+
# @raise [Error]
|
221
|
+
def request method, url, body, headers = {}, options = {}
|
222
|
+
error = catch(:fail) do
|
223
|
+
options = { :username => @key, :password => @secret }.merge(options)
|
224
|
+
response = http_engine.request(method, url, body, headers, options)
|
225
|
+
return response_parser.parse(response)
|
171
226
|
end
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
puts "\r\n"
|
178
|
-
body = response.body
|
179
|
-
if body.nil? || body.empty?
|
180
|
-
puts "(No content)"
|
181
|
-
else
|
182
|
-
puts body
|
183
|
-
end
|
227
|
+
if error
|
228
|
+
errors = response_parser.parse(error)['response']['status']['errors']
|
229
|
+
raise Animoto::Error.new(errors.collect { |e| e['message'] }.join(', '))
|
230
|
+
else
|
231
|
+
raise Animoto::Error
|
184
232
|
end
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
# Builds the request object.
|
189
|
-
#
|
190
|
-
# @param [Symbol] method which HTTP method to use (should be lowercase, i.e. :get instead of :GET)
|
191
|
-
# @param [String] uri the request path
|
192
|
-
# @param [String, nil] body the request body
|
193
|
-
# @param [Hash<String,String>] headers the request headers (will be sent as-is, which means you should
|
194
|
-
# specify "Content-Type" => "..." instead of, say, :content_type => "...")
|
195
|
-
# @param [Hash] options
|
196
|
-
# @return [Net::HTTPRequest] the request object
|
197
|
-
def build_request method, uri, body, headers, options
|
198
|
-
req = HTTP_METHOD_MAP[method].new uri.path
|
199
|
-
req.body = body
|
200
|
-
req.initialize_http_header headers
|
201
|
-
req.basic_auth key, secret
|
202
|
-
req
|
203
|
-
end
|
204
|
-
|
205
|
-
# Verifies and parses the response.
|
206
|
-
#
|
207
|
-
# @param [Net::HTTPResponse] response the response object
|
208
|
-
# @return [Hash] deserialized JSON response body
|
209
|
-
def read_response response
|
210
|
-
check_status response
|
211
|
-
parse_response response
|
212
|
-
end
|
213
|
-
|
214
|
-
# Checks the status of the response to make sure it's successful.
|
215
|
-
#
|
216
|
-
# @param [Net::HTTPResponse] response the response object
|
217
|
-
# @return [nil]
|
218
|
-
# @raise [Error,RuntimeError] if the response code isn't in the 200 range
|
219
|
-
def check_status response
|
220
|
-
unless (200..299).include?(response.code.to_i)
|
221
|
-
if response.body
|
222
|
-
begin
|
223
|
-
json = JSON.parse(response.body)
|
224
|
-
errors = json['response']['status']['errors']
|
225
|
-
rescue => e
|
226
|
-
raise response.message
|
227
|
-
else
|
228
|
-
raise Animoto::Error.new(errors.collect { |e| e['message'] }.join(', '))
|
229
|
-
end
|
230
|
-
else
|
231
|
-
raise response.message
|
232
|
-
end
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
# Parses a JSON response body into a Hash.
|
237
|
-
# @param [Net::HTTPResponse] response the response object
|
238
|
-
# @return [Hash] deserialized JSON response body
|
239
|
-
def parse_response response
|
240
|
-
JSON.parse(response.body)
|
233
|
+
rescue NoMethodError => e
|
234
|
+
raise Animoto::Error.new("Invalid response (#{error.inspect})")
|
241
235
|
end
|
242
236
|
|
243
237
|
# Creates the full content type string given a Resource class or instance
|
@@ -247,7 +241,7 @@ module Animoto
|
|
247
241
|
# "application/vnd.animoto.storyboard-v1+json")
|
248
242
|
def content_type_of klass_or_instance
|
249
243
|
klass = klass_or_instance.is_a?(Class) ? klass_or_instance : klass_or_instance.class
|
250
|
-
"#{BASE_CONTENT_TYPE}.#{klass.content_type}-v#{API_VERSION}+#{format}"
|
244
|
+
"#{BASE_CONTENT_TYPE}.#{klass.content_type}-v#{API_VERSION}+#{response_parser.format}"
|
251
245
|
end
|
252
246
|
|
253
247
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Animoto
|
2
|
+
module DynamicClassLoader
|
3
|
+
|
4
|
+
# If a reference is made to a class under this one that hasn't been initialized yet,
|
5
|
+
# this will attempt to require a file with that class' name (underscored). If one is
|
6
|
+
# found, and the file defines the class requested, will return that class object.
|
7
|
+
#
|
8
|
+
# @param [Symbol] const the uninitialized class' name
|
9
|
+
# @return [Class] the class found
|
10
|
+
# @raise [NameError] if the file defining the class isn't found, or if the file required
|
11
|
+
# doesn't define the class.
|
12
|
+
def const_missing const
|
13
|
+
engine_name = underscore_class_name(const.to_s)
|
14
|
+
file_name = File.dirname(__FILE__) + "/#{search_path}/#{engine_name}.rb"
|
15
|
+
if File.exist?(file_name)
|
16
|
+
require file_name
|
17
|
+
const_defined?(const) ? const_get(const) : super
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the adapter class for the given symbol. If the file defining the class
|
24
|
+
# hasn't been loaded, will try to load it.
|
25
|
+
#
|
26
|
+
# @param [Symbol] engine the symbolic name of the adapter
|
27
|
+
# @return [Class] the class
|
28
|
+
# @raise [NameError] if the class isn't found
|
29
|
+
def [] engine
|
30
|
+
require(File.dirname(__FILE__) + "/#{search_path}/#{engine.to_s.gsub(/[^\w]/,'.?')}_adapter.rb") unless $".grep(/#{engine.to_s}_adapter/).first
|
31
|
+
rescue LoadError
|
32
|
+
raise NameError, "Couldn't locate adapter named \"#{engine}\""
|
33
|
+
else
|
34
|
+
adapter_map[engine]
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# Returns the path relative to this file where dynamically loaded files can be found.
|
40
|
+
# Defaults to the underscored class name plus 's'.
|
41
|
+
#
|
42
|
+
# @return [String] the path
|
43
|
+
def search_path
|
44
|
+
"#{underscore_class_name(self)}s"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns a Hash mapping the symbolic names for adapters to their classes.
|
48
|
+
#
|
49
|
+
# @return [Hash] the map of adapters
|
50
|
+
def adapter_map
|
51
|
+
@adapter_map ||= {}
|
52
|
+
end
|
53
|
+
|
54
|
+
# Turns a camel-cased class name into an underscored version. Will only affect the base name
|
55
|
+
# of the class, so, for example, Animoto::DirectingAndRenderingJob becomes 'directing_and_rendering_job'
|
56
|
+
#
|
57
|
+
# @param [Class, String] klass a class or name of a class
|
58
|
+
# @return [String] the underscored version of the name
|
59
|
+
def underscore_class_name klass
|
60
|
+
klass_name = klass.is_a?(Class) ? klass.name.split('::').last : klass
|
61
|
+
klass_name.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Animoto
|
2
|
+
class HTTPEngine
|
3
|
+
extend DynamicClassLoader
|
4
|
+
|
5
|
+
# Make a request.
|
6
|
+
#
|
7
|
+
# @param [Symbol] method the HTTP method to use, should be lower-case (that is, :get
|
8
|
+
# instead of :GET)
|
9
|
+
# @param [String] url the URL to request
|
10
|
+
# @param [String,nil] body the request body
|
11
|
+
# @param [Hash<String,String>] headers request headers to send; names will be sent as-is
|
12
|
+
# (for example, use keys like "Content-Type" and not :content_type)
|
13
|
+
# @param [Hash<Symbol,Object>] options
|
14
|
+
# @option options :timeout set a timeout
|
15
|
+
# @option options :username the authentication username
|
16
|
+
# @option options :password the authentication password
|
17
|
+
# @return [String] the response body
|
18
|
+
# @raise [NotImplementedError] if called on the abstract class
|
19
|
+
def request method, url, body = nil, headers = {}, options = {}
|
20
|
+
raise NotImplementedError
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# Checks the response and raises an error if the status isn't success.
|
26
|
+
#
|
27
|
+
# @param [Fixnum] code the HTTP status code
|
28
|
+
# @param [String] body the HTTP response body
|
29
|
+
# @raise [Animoto::Error] if the status isn't between 200 and 299
|
30
|
+
def check_response code, body
|
31
|
+
throw(:fail, body) unless (200..299).include?(code)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'curl'
|
2
|
+
|
3
|
+
module Animoto
|
4
|
+
class HTTPEngine
|
5
|
+
class CurlAdapter < Animoto::HTTPEngine
|
6
|
+
|
7
|
+
def request method, url, body = nil, headers = {}, options = {}
|
8
|
+
curl = build_curl method, url, body, headers, options
|
9
|
+
perform curl, method
|
10
|
+
check_response curl.response_code, curl.body_str
|
11
|
+
curl.body_str
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def build_curl method, url, body, headers, options
|
17
|
+
::Curl::Easy.new(url) do |c|
|
18
|
+
c.username = options[:username]
|
19
|
+
c.password = options[:password]
|
20
|
+
c.timeout = options[:timeout]
|
21
|
+
c.post_body = body
|
22
|
+
headers.each { |header, value| c.headers[header] = value }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def perform curl, method
|
27
|
+
case method
|
28
|
+
when :get
|
29
|
+
curl.http_get
|
30
|
+
when :post
|
31
|
+
curl.http_post(body)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
adapter_map.merge! :curl => CurlAdapter
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
|
4
|
+
module Animoto
|
5
|
+
class HTTPEngine
|
6
|
+
class NetHTTPAdapter < Animoto::HTTPEngine
|
7
|
+
|
8
|
+
HTTP_METHOD_MAP = {
|
9
|
+
:get => Net::HTTP::Get,
|
10
|
+
:post => Net::HTTP::Post
|
11
|
+
}
|
12
|
+
|
13
|
+
def request method, url, body = nil, headers = {}, options = {}
|
14
|
+
uri = URI.parse(url)
|
15
|
+
http = build_http uri
|
16
|
+
req = build_request method, uri, body, headers, options
|
17
|
+
response = http.request req
|
18
|
+
check_response response.code.to_i, response.body
|
19
|
+
response.body
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Makes a new HTTP object.
|
25
|
+
#
|
26
|
+
# @param [URI] uri a URI object of the request URL
|
27
|
+
# @return [Net::HTTP] the HTTP object
|
28
|
+
def build_http uri
|
29
|
+
http = Net::HTTP.new uri.host, uri.port
|
30
|
+
http.use_ssl = true
|
31
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
32
|
+
http
|
33
|
+
end
|
34
|
+
|
35
|
+
# Builds the request object.
|
36
|
+
#
|
37
|
+
# @param [Symbol] method which HTTP method to use (should be lowercase, i.e. :get instead of :GET)
|
38
|
+
# @param [String] uri the request path
|
39
|
+
# @param [String, nil] body the request body
|
40
|
+
# @param [Hash<String,String>] headers the request headers (will be sent as-is, which means you should
|
41
|
+
# specify "Content-Type" => "..." instead of, say, :content_type => "...")
|
42
|
+
# @param [Hash] options
|
43
|
+
# @return [Net::HTTPRequest] the request object
|
44
|
+
def build_request method, uri, body, headers, options
|
45
|
+
req = HTTP_METHOD_MAP[method].new uri.path
|
46
|
+
req.body = body
|
47
|
+
req.initialize_http_header headers
|
48
|
+
req.basic_auth options[:username], options[:password]
|
49
|
+
req
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
adapter_map.merge! :net_http => NetHTTPAdapter
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'patron'
|
2
|
+
|
3
|
+
module Animoto
|
4
|
+
class HTTPEngine
|
5
|
+
class PatronAdapter < Animoto::HTTPEngine
|
6
|
+
|
7
|
+
def request method, url, body = nil, headers = {}, options = {}
|
8
|
+
session = build_session options
|
9
|
+
response = session.request method, url, headers, :data => body
|
10
|
+
check_response response.status, response.body
|
11
|
+
response.body
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def build_session options
|
17
|
+
session = ::Patron::Session.new
|
18
|
+
session.timeout = options[:timeout]
|
19
|
+
session.username = options[:username]
|
20
|
+
session.password = options[:password]
|
21
|
+
session
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
adapter_map.merge! :patron => PatronAdapter
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'restclient'
|
2
|
+
|
3
|
+
module Animoto
|
4
|
+
class HTTPEngine
|
5
|
+
class RestClientAdapter < Animoto::HTTPEngine
|
6
|
+
|
7
|
+
def request method, url, body = nil, headers = {}, options = {}
|
8
|
+
response = ::RestClient::Request.execute({
|
9
|
+
:method => method,
|
10
|
+
:url => url,
|
11
|
+
:headers => headers,
|
12
|
+
:payload => body,
|
13
|
+
:user => options[:username],
|
14
|
+
:password => options[:password],
|
15
|
+
:timeout => options[:timeout]
|
16
|
+
})
|
17
|
+
check_response response.code, response.body
|
18
|
+
response.body
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
adapter_map.merge! :rest_client => RestClientAdapter
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'typhoeus'
|
2
|
+
|
3
|
+
module Animoto
|
4
|
+
class HTTPEngine
|
5
|
+
class TyphoeusAdapter < Animoto::HTTPEngine
|
6
|
+
|
7
|
+
def request method, url, body = nil, headers = {}, options = {}
|
8
|
+
response = ::Typhoeus::Request.run(url, {
|
9
|
+
:method => method,
|
10
|
+
:body => body,
|
11
|
+
:headers => headers,
|
12
|
+
:timeout => options[:timeout],
|
13
|
+
:username => options[:username],
|
14
|
+
:password => options[:password]
|
15
|
+
})
|
16
|
+
check_response response.code, response.body
|
17
|
+
response.body
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
adapter_map.merge! :typhoeus => TyphoeusAdapter
|
23
|
+
end
|
24
|
+
end
|
data/lib/animoto/manifest.rb
CHANGED
data/lib/animoto/resource.rb
CHANGED
@@ -50,13 +50,13 @@ module Animoto
|
|
50
50
|
self.class.payload_key
|
51
51
|
end
|
52
52
|
|
53
|
-
# Makes a new instance of this class from a deserialized
|
53
|
+
# Makes a new instance of this class from a deserialized response body. Note that
|
54
54
|
# it assumes the hash you're passing is structured correctly and does no format checking
|
55
55
|
# at all, so if the hash is not in the "standard envelope", this method will most likely
|
56
56
|
# raise an error.
|
57
57
|
#
|
58
58
|
# @private
|
59
|
-
# @param [Hash] body the deserialized
|
59
|
+
# @param [Hash] body the deserialized response body
|
60
60
|
# @return [Resource] an instance of this class
|
61
61
|
def self.load body
|
62
62
|
new unpack_standard_envelope(body)
|
@@ -116,7 +116,7 @@ module Animoto
|
|
116
116
|
# Update this instance with new attributes from the response body.
|
117
117
|
#
|
118
118
|
# @private
|
119
|
-
# @param [Hash] body deserialized
|
119
|
+
# @param [Hash] body deserialized from a response body
|
120
120
|
# @return [self] this instance, updated
|
121
121
|
def load body = {}
|
122
122
|
instantiate unpack_standard_envelope(body)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Animoto
|
2
|
+
class ResponseParser
|
3
|
+
extend DynamicClassLoader
|
4
|
+
|
5
|
+
# Returns the format of this parser class.
|
6
|
+
#
|
7
|
+
# @return [String] the format
|
8
|
+
def self.format
|
9
|
+
@format
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns the format of this parser.
|
13
|
+
#
|
14
|
+
# @return [String] the format
|
15
|
+
def format
|
16
|
+
self.class.format
|
17
|
+
end
|
18
|
+
|
19
|
+
# Parses a response body into a usable Hash.
|
20
|
+
#
|
21
|
+
# @param [String] body the HTTP response body
|
22
|
+
# @return [Hash] the parsed response
|
23
|
+
# @raise [NotImplementedError] if called on the abstract class
|
24
|
+
def parse body
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
27
|
+
|
28
|
+
# Serializes a Hash into the format for this parser.
|
29
|
+
#
|
30
|
+
# @param [Hash] hash the hash to serialize
|
31
|
+
# @return [String] the serialized data
|
32
|
+
# @raise [NotImplementedError] if called on the abstract class
|
33
|
+
def unparse hash
|
34
|
+
raise NotImplementedError
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Animoto
|
4
|
+
class ResponseParser
|
5
|
+
class JSONAdapter < Animoto::ResponseParser
|
6
|
+
|
7
|
+
@format = 'json'
|
8
|
+
|
9
|
+
def parse body
|
10
|
+
::JSON.parse body
|
11
|
+
end
|
12
|
+
|
13
|
+
def unparse hash
|
14
|
+
::JSON.unparse hash
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
adapter_map.merge! :json => JSONAdapter
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'yajl'
|
2
|
+
|
3
|
+
module Animoto
|
4
|
+
class ResponseParser
|
5
|
+
class YajlAdapter < Animoto::ResponseParser
|
6
|
+
|
7
|
+
@format = 'json'
|
8
|
+
|
9
|
+
def parse body
|
10
|
+
::Yajl::Parser.parse body
|
11
|
+
end
|
12
|
+
|
13
|
+
def unparse hash
|
14
|
+
::Yajl::Encoder.encode hash
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
adapter_map.merge! :yajl => YajlAdapter
|
20
|
+
end
|
21
|
+
end
|
data/lib/animoto.rb
CHANGED
data/spec/animoto/client_spec.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'base64'
|
1
2
|
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
2
3
|
|
3
4
|
describe Animoto::Client do
|
@@ -42,15 +43,16 @@ describe Animoto::Client do
|
|
42
43
|
|
43
44
|
describe "automatically" do
|
44
45
|
before do
|
46
|
+
@here_path = File.expand_path("./.animotorc")
|
45
47
|
@home_path = File.expand_path("~/.animotorc")
|
46
48
|
@etc_path = "/etc/.animotorc"
|
47
49
|
@config = "key: joe\nsecret: secret\nendpoint: https://api.animoto.com/"
|
48
50
|
end
|
49
51
|
|
50
|
-
describe "when
|
52
|
+
describe "when ./.animotorc exists" do
|
51
53
|
before do
|
52
|
-
File.stubs(:exist?).with(@
|
53
|
-
File.stubs(:read).with(@
|
54
|
+
File.stubs(:exist?).with(@here_path).returns(true)
|
55
|
+
File.stubs(:read).with(@here_path).returns(@config)
|
54
56
|
end
|
55
57
|
|
56
58
|
it "should configure itself based on the options in ~/.animotorc" do
|
@@ -61,28 +63,47 @@ describe Animoto::Client do
|
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
64
|
-
describe "when
|
66
|
+
describe "when ./.animotorc doesn't exist" do
|
65
67
|
before do
|
66
|
-
File.stubs(:exist?).with(@
|
68
|
+
File.stubs(:exist?).with(@here_path).returns(false)
|
67
69
|
end
|
68
70
|
|
69
|
-
describe "when
|
71
|
+
describe "when ~/.animotorc exists" do
|
70
72
|
before do
|
71
|
-
File.stubs(:exist?).with(@
|
72
|
-
File.stubs(:read).with(@
|
73
|
+
File.stubs(:exist?).with(@home_path).returns(true)
|
74
|
+
File.stubs(:read).with(@home_path).returns(@config)
|
73
75
|
end
|
74
|
-
|
75
|
-
it "should configure itself based on the options in
|
76
|
+
|
77
|
+
it "should configure itself based on the options in ~/.animotorc" do
|
76
78
|
c = Animoto::Client.new
|
77
79
|
c.key.should == "joe"
|
78
80
|
c.secret.should == "secret"
|
79
81
|
c.endpoint.should == "https://api.animoto.com/"
|
80
82
|
end
|
81
83
|
end
|
84
|
+
|
85
|
+
describe "when ~/.animotorc doesn't exist" do
|
86
|
+
before do
|
87
|
+
File.stubs(:exist?).with(@home_path).returns(false)
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "when /etc/.animotorc exists" do
|
91
|
+
before do
|
92
|
+
File.stubs(:exist?).with(@etc_path).returns(true)
|
93
|
+
File.stubs(:read).with(@etc_path).returns(@config)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should configure itself based on the options in /etc/.animotorc" do
|
97
|
+
c = Animoto::Client.new
|
98
|
+
c.key.should == "joe"
|
99
|
+
c.secret.should == "secret"
|
100
|
+
end
|
101
|
+
end
|
82
102
|
|
83
|
-
|
84
|
-
|
85
|
-
|
103
|
+
describe "when /etc/.animotorc doesn't exist" do
|
104
|
+
it "should raise an error" do
|
105
|
+
lambda { Animoto::Client.new }.should raise_error
|
106
|
+
end
|
86
107
|
end
|
87
108
|
end
|
88
109
|
end
|
@@ -91,9 +112,10 @@ describe Animoto::Client do
|
|
91
112
|
|
92
113
|
describe "finding an instance by identifier" do
|
93
114
|
before do
|
94
|
-
@url = "https://api.animoto.com/storyboards/1"
|
95
|
-
|
96
|
-
|
115
|
+
@url = "https://joe:secret@api.animoto.com/storyboards/1"
|
116
|
+
hash = {'response'=>{'status'=>{'code'=>200},'payload'=>{'storyboard'=>{'links'=>{'self'=>@url,'preview'=>'http://animoto.com/preview/1.mp4'},'metadata'=>{'duration'=>100,'visuals_count'=>1}}}}}
|
117
|
+
body = client.response_parser.unparse(hash)
|
118
|
+
stub_request(:get, @url).to_return(:body => body, :status => [200,"OK"])
|
97
119
|
end
|
98
120
|
|
99
121
|
it "should make a GET request to the given url" do
|
@@ -103,7 +125,7 @@ describe Animoto::Client do
|
|
103
125
|
|
104
126
|
it "should ask for a response in the proper format" do
|
105
127
|
client.find(Animoto::Storyboard, @url)
|
106
|
-
WebMock.should have_requested(:get, @url).with(:headers => { 'Accept' => "application/vnd.animoto.storyboard-v1+json"})
|
128
|
+
WebMock.should have_requested(:get, @url).with(:headers => { 'Accept' => "application/vnd.animoto.storyboard-v1+json" })
|
107
129
|
end
|
108
130
|
|
109
131
|
it "should not sent a request body" do
|
@@ -118,10 +140,11 @@ describe Animoto::Client do
|
|
118
140
|
|
119
141
|
describe "reloading an instance" do
|
120
142
|
before do
|
121
|
-
@url = 'https://api.animoto.com/jobs/directing/1'
|
143
|
+
@url = 'https://joe:secret@api.animoto.com/jobs/directing/1'
|
122
144
|
@job = Animoto::DirectingJob.new :state => 'initial', :url => @url
|
123
|
-
|
124
|
-
|
145
|
+
hash = {'response'=>{'status'=>{'code'=>200},'payload'=>{'directing_job'=>{'state'=>'retrieving_assets','links'=>{'self'=>@url,'storyboard'=>'http://api.animoto.com/storyboards/1'}}}}}
|
146
|
+
body = client.response_parser.unparse(hash)
|
147
|
+
stub_request(:get, @url).to_return(:body => body, :status => [200,"OK"])
|
125
148
|
@job.state.should == 'initial' # sanity check
|
126
149
|
end
|
127
150
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Animoto::HTTPEngine do
|
4
|
+
|
5
|
+
describe "autoloading subclasses" do
|
6
|
+
before do
|
7
|
+
Animoto::HTTPEngine.const_defined?(:BeefHearts).should be_false
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
after do
|
13
|
+
Animoto::HTTPEngine.remove_const(:BeefHearts)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "making a request" do
|
18
|
+
before do
|
19
|
+
@engine = Animoto::HTTPEngine.new
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should raise an implementation error" do
|
23
|
+
lambda { @engine.request(:get, "http://www.example.com/thing") }.should raise_error(NotImplementedError)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe Animoto::ResponseParser::JSONAdapter do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@parser = Animoto::ResponseParser::JSONAdapter.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should be JSON format" do
|
10
|
+
@parser.format.should == 'json'
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "parsing" do
|
14
|
+
before do
|
15
|
+
@json = %Q!{"result":{"rank":1,"score":1.9,"tags":["hooray","for","dolphins"],"message":"woohoo"}}!
|
16
|
+
@hash = @parser.parse(@json)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should return a hash" do
|
20
|
+
@hash.should be_an_instance_of(Hash)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should turn the object root into a hash" do
|
24
|
+
@hash.should have_key('result')
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should turn array elements into an array" do
|
28
|
+
@hash['result'].should have_key('tags')
|
29
|
+
@hash['result']['tags'].should be_an_instance_of(Array)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should preserve the order of elements in an array" do
|
33
|
+
@hash['result']['tags'].should == ["hooray", "for", "dolphins"]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should turn each object attribute into a key/value pair in the hash" do
|
37
|
+
@hash['result'].should have_key('rank')
|
38
|
+
@hash['result']['rank'].should be_an_instance_of(Fixnum)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should turn attributes with strictly numeric values into integers" do
|
42
|
+
@hash['result']['rank'].should eql(1)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should turn attributes with content representing floats into floats" do
|
46
|
+
@hash['result']['score'].should eql(1.9)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should turn strings into strings" do
|
50
|
+
@hash['result']['message'].should be_an_instance_of(String)
|
51
|
+
@hash['result']['message'].should == "woohoo"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "unparsing" do
|
56
|
+
before do
|
57
|
+
@obj = {
|
58
|
+
'result' => {
|
59
|
+
'tags' => [ 'hooray', 'for', 'dolphins' ],
|
60
|
+
'message' => 'woohoo',
|
61
|
+
'rank' => 1,
|
62
|
+
'score' => 1.9
|
63
|
+
}
|
64
|
+
}
|
65
|
+
@json_str = @parser.unparse(@obj)
|
66
|
+
@json = ::JSON.parse(@json_str)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should turn hashes into objects with attributes" do
|
70
|
+
@json.should have_key('result')
|
71
|
+
@json['result'].should_not be_empty
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should turn arrays into arrays" do
|
75
|
+
@json['result'].should have_key('tags')
|
76
|
+
@json['result']['tags'].should be_an_instance_of(Array)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should turn strings into text content" do
|
80
|
+
@json['result'].should have_key('message')
|
81
|
+
@json['result']['message'].should == "woohoo"
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should turn integers into integers" do
|
85
|
+
@json_str.should =~ /"rank"\s*:\s*1/
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should turn floats into floats" do
|
89
|
+
@json_str.should =~ /"score"\s*:\s*1\.9/
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe Animoto::ResponseParser::YajlAdapter do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@parser = Animoto::ResponseParser::YajlAdapter.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should be JSON format" do
|
10
|
+
@parser.format.should == 'json'
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "parsing" do
|
14
|
+
before do
|
15
|
+
@json = %Q!{"result":{"rank":1,"score":1.9,"tags":["hooray","for","dolphins"],"message":"woohoo"}}!
|
16
|
+
@hash = @parser.parse(@json)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should return a hash" do
|
20
|
+
@hash.should be_an_instance_of(Hash)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should turn the object root into a hash" do
|
24
|
+
@hash.should have_key('result')
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should turn array elements into an array" do
|
28
|
+
@hash['result'].should have_key('tags')
|
29
|
+
@hash['result']['tags'].should be_an_instance_of(Array)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should preserve the order of elements in an array" do
|
33
|
+
@hash['result']['tags'].should == ["hooray", "for", "dolphins"]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should turn each object attribute into a key/value pair in the hash" do
|
37
|
+
@hash['result'].should have_key('rank')
|
38
|
+
@hash['result']['rank'].should be_an_instance_of(Fixnum)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should turn attributes with strictly numeric values into integers" do
|
42
|
+
@hash['result']['rank'].should eql(1)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should turn attributes with content representing floats into floats" do
|
46
|
+
@hash['result']['score'].should eql(1.9)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should turn strings into strings" do
|
50
|
+
@hash['result']['message'].should be_an_instance_of(String)
|
51
|
+
@hash['result']['message'].should == "woohoo"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "unparsing" do
|
56
|
+
before do
|
57
|
+
@obj = {
|
58
|
+
'result' => {
|
59
|
+
'tags' => [ 'hooray', 'for', 'dolphins' ],
|
60
|
+
'message' => 'woohoo',
|
61
|
+
'rank' => 1,
|
62
|
+
'score' => 1.9
|
63
|
+
}
|
64
|
+
}
|
65
|
+
@json_str = @parser.unparse(@obj)
|
66
|
+
@json = ::JSON.parse(@json_str)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should turn hashes into objects with attributes" do
|
70
|
+
@json.should have_key('result')
|
71
|
+
@json['result'].should_not be_empty
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should turn arrays into arrays" do
|
75
|
+
@json['result'].should have_key('tags')
|
76
|
+
@json['result']['tags'].should be_an_instance_of(Array)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should turn strings into text content" do
|
80
|
+
@json['result'].should have_key('message')
|
81
|
+
@json['result']['message'].should == "woohoo"
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should turn integers into integers" do
|
85
|
+
@json_str.should =~ /"rank"\s*:\s*1/
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should turn floats into floats" do
|
89
|
+
@json_str.should =~ /"score"\s*:\s*1\.9/
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: animoto
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: -
|
4
|
+
hash: -1710980402
|
5
5
|
prerelease: true
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
9
|
- 0
|
10
|
-
-
|
11
|
-
version: 0.0.0.
|
10
|
+
- alpha4
|
11
|
+
version: 0.0.0.alpha4
|
12
12
|
platform: ruby
|
13
13
|
authors:
|
14
14
|
- Animoto
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-09-
|
19
|
+
date: 2010-09-08 00:00:00 -04:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -53,14 +53,24 @@ files:
|
|
53
53
|
- ./lib/animoto/directing_and_rendering_manifest.rb
|
54
54
|
- ./lib/animoto/directing_job.rb
|
55
55
|
- ./lib/animoto/directing_manifest.rb
|
56
|
+
- ./lib/animoto/dynamic_class_loader.rb
|
56
57
|
- ./lib/animoto/errors.rb
|
57
58
|
- ./lib/animoto/footage.rb
|
59
|
+
- ./lib/animoto/http_engine.rb
|
60
|
+
- ./lib/animoto/http_engines/curl_adapter.rb
|
61
|
+
- ./lib/animoto/http_engines/net_http_adapter.rb
|
62
|
+
- ./lib/animoto/http_engines/patron_adapter.rb
|
63
|
+
- ./lib/animoto/http_engines/rest_client_adapter.rb
|
64
|
+
- ./lib/animoto/http_engines/typhoeus_adapter.rb
|
58
65
|
- ./lib/animoto/image.rb
|
59
66
|
- ./lib/animoto/job.rb
|
60
67
|
- ./lib/animoto/manifest.rb
|
61
68
|
- ./lib/animoto/rendering_job.rb
|
62
69
|
- ./lib/animoto/rendering_manifest.rb
|
63
70
|
- ./lib/animoto/resource.rb
|
71
|
+
- ./lib/animoto/response_parser.rb
|
72
|
+
- ./lib/animoto/response_parsers/json_adapter.rb
|
73
|
+
- ./lib/animoto/response_parsers/yajl_adapter.rb
|
64
74
|
- ./lib/animoto/song.rb
|
65
75
|
- ./lib/animoto/standard_envelope.rb
|
66
76
|
- ./lib/animoto/storyboard.rb
|
@@ -76,11 +86,14 @@ files:
|
|
76
86
|
- ./spec/animoto/directing_job_spec.rb
|
77
87
|
- ./spec/animoto/directing_manifest_spec.rb
|
78
88
|
- ./spec/animoto/footage_spec.rb
|
89
|
+
- ./spec/animoto/http_engine_spec.rb
|
79
90
|
- ./spec/animoto/image_spec.rb
|
80
91
|
- ./spec/animoto/job_spec.rb
|
81
92
|
- ./spec/animoto/rendering_job_spec.rb
|
82
93
|
- ./spec/animoto/rendering_manifest_spec.rb
|
83
94
|
- ./spec/animoto/resource_spec.rb
|
95
|
+
- ./spec/animoto/response_parsers/json_adapter_spec.rb
|
96
|
+
- ./spec/animoto/response_parsers/yajl_adapter_spec.rb
|
84
97
|
- ./spec/animoto/song_spec.rb
|
85
98
|
- ./spec/animoto/standard_envelope_spec.rb
|
86
99
|
- ./spec/animoto/storyboard_spec.rb
|