animoto 0.0.0.alpha9 → 0.1.0.beta0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/README.md +26 -13
  2. data/integration/test.rb +2 -3
  3. data/lib/animoto/assets/base.rb +29 -0
  4. data/lib/animoto/assets/footage.rb +34 -0
  5. data/lib/animoto/assets/image.rb +25 -0
  6. data/lib/animoto/assets/song.rb +27 -0
  7. data/lib/animoto/assets/title_card.rb +35 -0
  8. data/lib/animoto/callbacks/base.rb +45 -0
  9. data/lib/animoto/callbacks/directing.rb +7 -0
  10. data/lib/animoto/callbacks/directing_and_rendering.rb +7 -0
  11. data/lib/animoto/callbacks/rendering.rb +7 -0
  12. data/lib/animoto/client.rb +133 -80
  13. data/lib/animoto/http_engines/base.rb +40 -0
  14. data/lib/animoto/http_engines/curl_adapter.rb +17 -5
  15. data/lib/animoto/http_engines/net_http_adapter.rb +6 -4
  16. data/lib/animoto/http_engines/patron_adapter.rb +7 -2
  17. data/lib/animoto/http_engines/rest_client_adapter.rb +3 -3
  18. data/lib/animoto/http_engines/typhoeus_adapter.rb +4 -4
  19. data/lib/animoto/manifests/base.rb +18 -0
  20. data/lib/animoto/manifests/directing.rb +146 -0
  21. data/lib/animoto/manifests/directing_and_rendering.rb +51 -0
  22. data/lib/animoto/manifests/rendering.rb +71 -0
  23. data/lib/animoto/resources/base.rb +133 -0
  24. data/lib/animoto/resources/jobs/base.rb +61 -0
  25. data/lib/animoto/resources/jobs/directing.rb +27 -0
  26. data/lib/animoto/resources/jobs/directing_and_rendering.rb +28 -0
  27. data/lib/animoto/resources/jobs/rendering.rb +35 -0
  28. data/lib/animoto/resources/storyboard.rb +36 -0
  29. data/lib/animoto/resources/video.rb +50 -0
  30. data/lib/animoto/response_parsers/base.rb +44 -0
  31. data/lib/animoto/response_parsers/json_adapter.rb +8 -7
  32. data/lib/animoto/response_parsers/yajl_adapter.rb +9 -8
  33. data/lib/animoto/support/content_type.rb +49 -0
  34. data/lib/animoto/support/coverable.rb +31 -0
  35. data/lib/animoto/support/dynamic_class_loader.rb +166 -0
  36. data/lib/animoto/support/errors.rb +5 -0
  37. data/lib/animoto/support/standard_envelope.rb +66 -0
  38. data/lib/animoto/support/visual.rb +32 -0
  39. data/lib/animoto.rb +7 -1
  40. data/spec/animoto/assets/base_spec.rb +5 -0
  41. data/spec/animoto/{footage_spec.rb → assets/footage_spec.rb} +4 -4
  42. data/spec/animoto/{image_spec.rb → assets/image_spec.rb} +4 -4
  43. data/spec/animoto/{song_spec.rb → assets/song_spec.rb} +3 -3
  44. data/spec/animoto/{title_card_spec.rb → assets/title_card_spec.rb} +4 -4
  45. data/spec/animoto/callbacks/base_spec.rb +76 -0
  46. data/spec/animoto/callbacks/directing_and_rendering_spec.rb +5 -0
  47. data/spec/animoto/callbacks/directing_spec.rb +5 -0
  48. data/spec/animoto/callbacks/rendering_spec.rb +5 -0
  49. data/spec/animoto/client_spec.rb +29 -5
  50. data/spec/animoto/{http_engine_spec.rb → http_engines/base_spec.rb} +5 -5
  51. data/spec/animoto/{directing_and_rendering_manifest_spec.rb → manifests/directing_and_rendering_spec.rb} +3 -3
  52. data/spec/animoto/{directing_manifest_spec.rb → manifests/directing_spec.rb} +8 -8
  53. data/spec/animoto/{rendering_manifest_spec.rb → manifests/rendering_spec.rb} +7 -7
  54. data/spec/animoto/{resource_spec.rb → resources/base_spec.rb} +7 -7
  55. data/spec/animoto/{job_spec.rb → resources/jobs/base_spec.rb} +9 -5
  56. data/spec/animoto/{directing_and_rendering_job_spec.rb → resources/jobs/directing_and_rendering_spec.rb} +7 -7
  57. data/spec/animoto/{directing_job_spec.rb → resources/jobs/directing_spec.rb} +7 -7
  58. data/spec/animoto/{rendering_job_spec.rb → resources/jobs/rendering_spec.rb} +8 -8
  59. data/spec/animoto/resources/storyboard_spec.rb +8 -0
  60. data/spec/animoto/resources/video_spec.rb +5 -0
  61. data/spec/animoto/response_parsers/json_adapter_spec.rb +2 -2
  62. data/spec/animoto/response_parsers/yajl_adapter_spec.rb +2 -2
  63. data/spec/animoto/support/coverable_spec.rb +5 -0
  64. data/spec/animoto/support/standard_envelope_spec.rb +5 -0
  65. data/spec/animoto/support/visual_spec.rb +5 -0
  66. metadata +56 -48
  67. data/lib/animoto/asset.rb +0 -19
  68. data/lib/animoto/content_type.rb +0 -47
  69. data/lib/animoto/coverable.rb +0 -29
  70. data/lib/animoto/directing_and_rendering_job.rb +0 -19
  71. data/lib/animoto/directing_and_rendering_manifest.rb +0 -25
  72. data/lib/animoto/directing_job.rb +0 -18
  73. data/lib/animoto/directing_manifest.rb +0 -112
  74. data/lib/animoto/dynamic_class_loader.rb +0 -64
  75. data/lib/animoto/errors.rb +0 -3
  76. data/lib/animoto/footage.rb +0 -16
  77. data/lib/animoto/http_engine.rb +0 -34
  78. data/lib/animoto/image.rb +0 -16
  79. data/lib/animoto/job.rb +0 -37
  80. data/lib/animoto/manifest.rb +0 -14
  81. data/lib/animoto/rendering_job.rb +0 -24
  82. data/lib/animoto/rendering_manifest.rb +0 -37
  83. data/lib/animoto/resource.rb +0 -149
  84. data/lib/animoto/response_parser.rb +0 -38
  85. data/lib/animoto/song.rb +0 -14
  86. data/lib/animoto/standard_envelope.rb +0 -27
  87. data/lib/animoto/storyboard.rb +0 -22
  88. data/lib/animoto/title_card.rb +0 -26
  89. data/lib/animoto/video.rb +0 -29
  90. data/lib/animoto/visual.rb +0 -30
  91. data/spec/animoto/asset_spec.rb +0 -5
  92. data/spec/animoto/coverable_spec.rb +0 -5
  93. data/spec/animoto/standard_envelope_spec.rb +0 -5
  94. data/spec/animoto/storyboard_spec.rb +0 -8
  95. data/spec/animoto/video_spec.rb +0 -5
  96. data/spec/animoto/visual_spec.rb +0 -5
data/README.md CHANGED
@@ -31,6 +31,19 @@ This document does not cover the details of the Animoto API itself. For such inf
31
31
  <a name="getting_started_using_the_ruby_client"></a>
32
32
  ## Getting Started using the Ruby Client
33
33
 
34
+ ### Installation
35
+
36
+ You can install the Animoto API Ruby Client either through [RubyGems](http://rubygems.org):
37
+
38
+ gem install animoto -v 0.1.0.alpha0 --pre
39
+
40
+ Or by cloning [the repository](http://github.com/animoto/animoto_api_client_ruby) on [GitHub](http://github.com/) and building it from source:
41
+
42
+ git clone git://github.com/animoto/animoto_api_client_ruby.git
43
+ cd animoto_api_client_ruby
44
+ gem build animoto.gemspec
45
+ gem install animoto-0.1.0.alpha0.gem
46
+
34
47
  ### Prerequisites
35
48
 
36
49
  #### Readers of this document should be familiar with...
@@ -87,7 +100,7 @@ client and using HTTP callbacks for status updates.
87
100
  # create a directing and rendering manifest with the video title and
88
101
  # producer. Also include rendering parameters like resolution, framerate,
89
102
  # and format.
90
- manifest = DirectingAndRenderingManifest.new(
103
+ manifest = Manifests::DirectingAndRendering.new(
91
104
  :title => "Amazing Title!",
92
105
  :producer => "Fishy Joe",
93
106
  :resolution => "720p",
@@ -96,13 +109,13 @@ client and using HTTP callbacks for status updates.
96
109
  )
97
110
 
98
111
  # Add some images, text, and footage to our manifest.
99
- manifest << Image.new("http://website.com/picture.png")
100
- manifest << Image.new("http://website.com/hooray.png", :spotlit => true)
101
- manifest << TitleCard.new("Woohoo!", "Hooray for everything!")
102
- manifest << Footage.new("http://website.com/movie.mp4", :duration => 3.5)
112
+ manifest << Assets::Image.new("http://website.com/picture.png")
113
+ manifest << Assets::Image.new("http://website.com/hooray.png", :spotlit => true)
114
+ manifest << Assets::TitleCard.new("Woohoo!", "Hooray for everything!")
115
+ manifest << Assets::Footage.new("http://website.com/movie.mp4", :duration => 3.5)
103
116
 
104
117
  # Setup the soundtrack.
105
- manifest << Song.new("http://website.com/song.mp3", :artist => "Fishy Joe")
118
+ manifest << Assets::Song.new("http://website.com/song.mp3", :artist => "Fishy Joe")
106
119
 
107
120
  # Setup to get http callbacks for status notification (see below for
108
121
  # polling example).
@@ -128,16 +141,16 @@ status.
128
141
 
129
142
  # Create a directing manifest. The directing manifest controls the images
130
143
  # and other visual elements that will be in our final video.
131
- manifest = DirectingManifest.new(:title => "Amazing Title!")
144
+ manifest = Manifests::Directing.new(:title => "Amazing Title!")
132
145
 
133
146
  # Add some images, text, and footage to our manifest.
134
- manifest << Image.new("http://website.com/picture.png")
135
- manifest << Image.new("http://website.com/hooray.png", :spotlit => true)
136
- manifest << TitleCard.new("Woohoo!", "Hooray for everything!")
137
- manifest << Footage.new("http://website.com/movie.mp4", :duration => 3.5)
147
+ manifest << Assets::Image.new("http://website.com/picture.png")
148
+ manifest << Assets::Image.new("http://website.com/hooray.png", :spotlit => true)
149
+ manifest << Assets::TitleCard.new("Woohoo!", "Hooray for everything!")
150
+ manifest << Assets::Footage.new("http://website.com/movie.mp4", :duration => 3.5)
138
151
 
139
152
  # Setup the soundtrack.
140
- manifest << Song.new("http://website.com/song.mp3")
153
+ manifest << Assets::Song.new("http://website.com/song.mp3")
141
154
 
142
155
  # Request a new directing job by sending the API our directing manifest.
143
156
  directing_job = client.direct!(manifest)
@@ -154,7 +167,7 @@ status.
154
167
 
155
168
  # Now it's time to render the storyboard into a video. First we create
156
169
  # a rendering manifest.
157
- manifest = RenderingManifest.new(storyboard, :resolution => "720p", :framerate => 24, :format => 'h264')
170
+ manifest = Manifests::Rendering.new(storyboard, :resolution => "720p", :framerate => 24, :format => 'h264')
158
171
 
159
172
  # Send the manifest to the API.
160
173
  rendering_job = client.render!(manifest)
data/integration/test.rb CHANGED
@@ -33,7 +33,7 @@ raise "Example code not found in README (expected at xpath '#{example_code_path}
33
33
  code = code_node.text
34
34
 
35
35
  puts "Replacing example credentials with valid ones"
36
- code.sub!(/Client\.new\(.+\)/, %Q{Client.new("#{credentials[:key]}","#{credentials[:secret]}")})
36
+ code.sub!(/Client\.new\(.+\)/, %Q{Client.new("#{credentials[:key]}","#{credentials[:secret]}",:endpoint => "#{credentials[:endpoint]}")})
37
37
 
38
38
  puts "Replacing example assets with valid ones"
39
39
  code.gsub!(/Image\.new\(.+\)/) { %Q{Image.new("#{assets[:images].shift}")} }
@@ -46,5 +46,4 @@ puts "Executing example"
46
46
  eval code
47
47
 
48
48
  puts
49
- puts "If you're seeing this, things should have worked fine!"
50
- puts "Enjoy your video at #{video.download_url}"
49
+ puts "If you're seeing this, things should have worked fine!"
@@ -0,0 +1,29 @@
1
+ module Animoto
2
+ module Assets
3
+
4
+ # @abstract
5
+ class Base
6
+
7
+ # The URL of this asset.
8
+ # @return [String]
9
+ attr_accessor :source
10
+
11
+ # Creates a new asset.
12
+ #
13
+ # @param [String] source the URL of this asset
14
+ # @return [Assets::Base] the asset
15
+ def initialize source, options = {}
16
+ @source = source
17
+ end
18
+
19
+ # Returns a representation of this asset as a Hash. Used mainly for generating
20
+ # manifests.
21
+ #
22
+ # @return [Hash<String,Object>] this asset as a Hash
23
+ def to_hash
24
+ { 'source_url' => @source }
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,34 @@
1
+ module Animoto
2
+ module Assets
3
+ class Footage < Animoto::Assets::Base
4
+ include Support::Visual
5
+ include Support::Coverable
6
+
7
+ # Whether or not to mix the audio of this footage with the video's soundtrack.
8
+ # @return [Boolean]
9
+ attr_accessor :audio_mix
10
+
11
+ # The time in seconds of where to start extracting a clip from this footage to
12
+ # add to the video.
13
+ # @return [Float]
14
+ attr_accessor :start_time
15
+
16
+ # The duration in seconds of how long this footage should run in the video.
17
+ # @return [Float]
18
+ attr_accessor :duration
19
+
20
+ # Returns a representation of this Footage as a Hash.
21
+ #
22
+ # @return [Hash<String,Object>] this asset as a Hash
23
+ # @see Animoto::Support::Visual#to_hash
24
+ # @see Animoto::Assets::Base#to_hash
25
+ def to_hash
26
+ hash = super
27
+ hash['audio_mix'] = 'MIX' if audio_mix
28
+ hash['start_time'] = start_time if start_time
29
+ hash['duration'] = duration if duration
30
+ hash
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,25 @@
1
+ module Animoto
2
+ module Assets
3
+ class Image < Animoto::Assets::Base
4
+ include Support::Visual
5
+ include Support::Coverable
6
+
7
+ # The EXIF rotation value for how this image should be rotated in the video.
8
+ # @return [Integer]
9
+ attr_accessor :rotation
10
+
11
+ # Returns a representation of this Image as a Hash.
12
+ #
13
+ # @return [Hash<String,Object>] this asset as a Hash
14
+ # @see Animoto::Support::Visual#to_hash
15
+ # @see Animoto::Assets::Base#to_hash
16
+ def to_hash
17
+ hash = super
18
+ hash['rotation'] = rotation if rotation
19
+ hash['spotlit'] = spotlit? unless @spotlit.nil?
20
+ hash['cover'] = cover? unless @cover.nil?
21
+ hash
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ module Animoto
2
+ module Assets
3
+ class Song < Animoto::Assets::Base
4
+
5
+ # The offset in seconds from the beginning denoting where to start
6
+ # using this song in the video.
7
+ # @return [Float]
8
+ attr_accessor :start_time
9
+
10
+ # The duration in seconds of how long this song should play.
11
+ # @return [Float]
12
+ attr_accessor :duration
13
+
14
+ # Returns a representation of this Song as a Hash.
15
+ #
16
+ # @return [Hash<String,Object>] this asset as a Hash
17
+ # @see Animoto::Assets::Base#to_hash
18
+ def to_hash
19
+ hash = super
20
+ hash['start_time'] = start_time if start_time
21
+ hash['duration'] = duration if duration
22
+ hash
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,35 @@
1
+ module Animoto
2
+ module Assets
3
+ class TitleCard
4
+ include Support::Visual
5
+
6
+ # The main text of this title card.
7
+ # @return [String]
8
+ attr_accessor :title
9
+
10
+ # The secondary text of this title card.
11
+ # @return [String]
12
+ attr_accessor :subtitle
13
+
14
+ # Creates a new TitleCard.
15
+ #
16
+ # @param [String] title the main text
17
+ # @param [String] subtitle the secondary text
18
+ def initialize title, subtitle = nil
19
+ @title, @subtitle = title, subtitle
20
+ end
21
+
22
+ # Returns a representation of this TitleCard as a Hash.
23
+ #
24
+ # @return [Hash<String,Object>] this TitleCard as a Hash
25
+ # @see Animoto::Support::Visual#to_hash
26
+ def to_hash
27
+ hash = super
28
+ hash['h1'] = title
29
+ hash['h2'] = subtitle if subtitle
30
+ hash['spotlit'] = spotlit? unless @spotlit.nil?
31
+ hash
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,45 @@
1
+ module Animoto
2
+ module Callbacks
3
+
4
+ # @abstract
5
+ class Base
6
+ include Support::StandardEnvelope
7
+
8
+ # @return [String]
9
+ # @see Animoto::Support::StandardEnvelope::ClassMethods#payload_key
10
+ def self.payload_key
11
+ super + '_callback'
12
+ end
13
+
14
+ # @return [Hash<Symbol,Object>]
15
+ # @see Animoto::Support::StandardEnvelope::ClassMethods#unpack_standard_envelope
16
+ def self.unpack_standard_envelope body = {}
17
+ super.merge({ :state => body['response']['payload'][payload_key]['state'] })
18
+ end
19
+
20
+ # The state of the job when it completed.
21
+ # @return [String]
22
+ attr_reader :state
23
+
24
+ # Errors for the job.
25
+ # @return [Array<Animoto::Error>]
26
+ attr_reader :errors
27
+
28
+ # The url for this job.
29
+ # @return [String]
30
+ attr_reader :url
31
+
32
+ # Creates a new Callback.
33
+ #
34
+ # @param [String] body the request body of the HTTP callback
35
+ # @return [Callbacks::Base] the Callback
36
+ def initialize body
37
+ params = unpack_standard_envelope(body)
38
+ @state = params[:state]
39
+ @errors = params[:errors].collect { |e| Animoto::Error.new(e['message']) }
40
+ @url = params[:url]
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,7 @@
1
+ module Animoto
2
+ module Callbacks
3
+ class Directing < Animoto::Callbacks::Base
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Animoto
2
+ module Callbacks
3
+ class DirectingAndRendering < Animoto::Callbacks::Base
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Animoto
2
+ module Callbacks
3
+ class Rendering < Animoto::Callbacks::Base
4
+
5
+ end
6
+ end
7
+ end
@@ -2,30 +2,39 @@ require 'yaml'
2
2
  require 'uri'
3
3
  require 'logger'
4
4
 
5
- require 'animoto/errors'
6
- require 'animoto/content_type'
7
- require 'animoto/standard_envelope'
8
- require 'animoto/resource'
9
- require 'animoto/asset'
10
- require 'animoto/visual'
11
- require 'animoto/coverable'
12
- require 'animoto/footage'
13
- require 'animoto/image'
14
- require 'animoto/song'
15
- require 'animoto/title_card'
16
- require 'animoto/manifest'
17
- require 'animoto/directing_manifest'
18
- require 'animoto/rendering_manifest'
19
- require 'animoto/directing_and_rendering_manifest'
20
- require 'animoto/storyboard'
21
- require 'animoto/video'
22
- require 'animoto/job'
23
- require 'animoto/directing_and_rendering_job'
24
- require 'animoto/directing_job'
25
- require 'animoto/rendering_job'
26
- require 'animoto/dynamic_class_loader'
27
- require 'animoto/http_engine'
28
- require 'animoto/response_parser'
5
+ require 'animoto/support/content_type'
6
+ require 'animoto/support/coverable'
7
+ require 'animoto/support/dynamic_class_loader'
8
+ require 'animoto/support/errors'
9
+ require 'animoto/support/standard_envelope'
10
+ require 'animoto/support/visual'
11
+
12
+ require 'animoto/resources/base'
13
+ require 'animoto/resources/storyboard'
14
+ require 'animoto/resources/video'
15
+ require 'animoto/resources/jobs/base'
16
+ require 'animoto/resources/jobs/directing_and_rendering'
17
+ require 'animoto/resources/jobs/directing'
18
+ require 'animoto/resources/jobs/rendering'
19
+
20
+ require 'animoto/assets/base'
21
+ require 'animoto/assets/footage'
22
+ require 'animoto/assets/image'
23
+ require 'animoto/assets/song'
24
+ require 'animoto/assets/title_card'
25
+
26
+ require 'animoto/manifests/base'
27
+ require 'animoto/manifests/directing'
28
+ require 'animoto/manifests/directing_and_rendering'
29
+ require 'animoto/manifests/rendering'
30
+
31
+ require 'animoto/callbacks/base'
32
+ require 'animoto/callbacks/directing'
33
+ require 'animoto/callbacks/directing_and_rendering'
34
+ require 'animoto/callbacks/rendering'
35
+
36
+ require 'animoto/http_engines/base'
37
+ require 'animoto/response_parsers/base'
29
38
 
30
39
  module Animoto
31
40
  class Client
@@ -33,8 +42,54 @@ module Animoto
33
42
  API_VERSION = 1
34
43
  BASE_CONTENT_TYPE = "application/vnd.animoto"
35
44
 
36
- attr_accessor :key, :secret, :endpoint, :logger
37
- attr_reader :http_engine, :response_parser
45
+ # Your API key.
46
+ # @return [String]
47
+ attr_accessor :key
48
+
49
+ # Your API secret.
50
+ # @return [String]
51
+ attr_accessor :secret
52
+
53
+ # The base URL where all requests will be sent.
54
+ # @return [String]
55
+ attr_accessor :endpoint
56
+
57
+ # A logger.
58
+ # @return [Logger]
59
+ attr_accessor :logger
60
+
61
+ # The engine to handle HTTP requests.
62
+ # @return [HTTPEngines::Base]
63
+ # @overload http_engine
64
+ # Returns the HTTP engine.
65
+ # @return [HTTPEngines::Base]
66
+ # @overload http_engine=(engine)
67
+ # Sets the HTTP engine.
68
+ #
69
+ # @param [HTTPEngines::Base,Symbol,Class] engine you may pass a
70
+ # HTTPEngine instance to use, or the symbolic name of an adapter to use,
71
+ # or a Class whose instances respond to #request and return a String of
72
+ # the response body
73
+ # @see Animoto::HTTPEngines::Base
74
+ # @return [HTTPEngines::Base] the engine instance
75
+ # @raise [ArgumentError] if given a class without the correct interface
76
+ attr_reader :http_engine
77
+
78
+ # The engine to handle parsing XML or JSON responses.
79
+ # @return [ResponseParsers::Base]
80
+ # @overload response_parser
81
+ # Returns the parser.
82
+ # @return [ResponseParsers::Base]
83
+ # @overload response_parser=(parser)
84
+ # Sets the parser.
85
+ #
86
+ # @param [ResponseParsers::Base,Symbol,Class] parser you may pass a
87
+ # ResponseParser instance to use, or the symbolic name of an adapter to use,
88
+ # or a Class whose instances respond to #parse, #unparse, and #format.
89
+ # @see Animoto::ResponseParsers::Base
90
+ # @return [ResponseParsers::Base] the parser instance
91
+ # @raise [ArgumentError] if given a class without the correct interface
92
+ attr_reader :response_parser
38
93
 
39
94
  # Creates a new Client object which handles credentials, versioning, making requests, and
40
95
  # parsing responses.
@@ -60,18 +115,9 @@ module Animoto
60
115
  __send__ :response_parser=, options[:response_parser] || :json
61
116
  end
62
117
 
63
- # Set the HTTP engine this client will use.
64
- #
65
- # @param [HTTPEngine, Symbol, Class] engine you may pass a
66
- # HTTPEngine instance to use, or the symbolic name of a adapter to use,
67
- # or a Class whose instances respond to #request and return a String of
68
- # the response body
69
- # @see Animoto::HTTPEngine
70
- # @return [HTTPEngine] the engine instance
71
- # @raise [ArgumentError] if given a class without the correct interface
72
118
  def http_engine= engine
73
119
  @http_engine = case engine
74
- when Animoto::HTTPEngine
120
+ when Animoto::HTTPEngines::Base
75
121
  engine
76
122
  when Class
77
123
  if engine.instance_methods.include?('request')
@@ -80,21 +126,13 @@ module Animoto
80
126
  raise ArgumentError
81
127
  end
82
128
  else
83
- Animoto::HTTPEngine[engine].new
129
+ Animoto::HTTPEngines[engine].new
84
130
  end
85
131
  end
86
132
 
87
- # Set the response parser this client will use.
88
- #
89
- # @param [ResponseParser, Symbol, Class] parser you may pass a
90
- # ResponseParser instance to use, or the symbolic name of a adapter to use,
91
- # or a Class whose instances respond to #parse, #unparse, and #format.
92
- # @see Animoto::ResponseParser
93
- # @return [ResponseParser] the parser instance
94
- # @raise [ArgumentError] if given a class without the correct interface
95
133
  def response_parser= parser
96
134
  @response_parser = case parser
97
- when Animoto::ResponseParser
135
+ when Animoto::ResponseParsers::Base
98
136
  parser
99
137
  when Class
100
138
  if %{format parse unparse}.all? { |m| parser.instance_methods.include? m }
@@ -103,53 +141,62 @@ module Animoto
103
141
  raise ArgumentError
104
142
  end
105
143
  else
106
- Animoto::ResponseParser[parser].new
144
+ Animoto::ResponseParsers[parser].new
107
145
  end
108
146
  end
109
147
 
110
148
  # Finds a resource by its URL.
111
149
  #
112
- # @param [Class] klass the Resource class you're finding
150
+ # @param [Class] klass the resource class you're finding
113
151
  # @param [String] url the URL of the resource you want
114
- # @param [Hash] options
115
- # @return [Resource] the Resource object found
152
+ # @param [Hash<Symbol,Object>] options
153
+ # @return [Resources::Base] the resource object found
116
154
  def find klass, url, options = {}
117
155
  klass.load(find_request(klass, url, options))
118
156
  end
119
157
 
158
+ # Returns a callback object of the specified type given the callback body.
159
+ #
160
+ # @param [Class] klass the callback class
161
+ # @param [String] body the HTTP body of the callback
162
+ # @return [Callbacks::Base] the callback object
163
+ def process_callback klass, body
164
+ klass.new(response_parser.parse(body))
165
+ end
166
+
120
167
  # Sends a request to start directing a storyboard.
121
168
  #
122
- # @param [DirectingManifest] manifest the manifest to direct
123
- # @param [Hash] options
124
- # @return [DirectingJob] a job to monitor the status of the directing
169
+ # @param [Manifests::Directing] manifest the manifest to direct
170
+ # @param [Hash<Symbol,Object>] options
171
+ # @return [Jobs::Directing] a job to monitor the status of the directing
125
172
  def direct! manifest, options = {}
126
- DirectingJob.load(send_manifest(manifest, DirectingJob.endpoint, options))
173
+ Resources::Jobs::Directing.load(send_manifest(manifest, Resources::Jobs::Directing.endpoint, options))
127
174
  end
128
175
 
129
176
  # Sends a request to start rendering a video.
130
177
  #
131
- # @param [RenderingManifest] manifest the manifest to render
132
- # @param [Hash] options
133
- # @return [RenderingJob] a job to monitor the status of the rendering
178
+ # @param [Manifests::Rendering] manifest the manifest to render
179
+ # @param [Hash<Symbol,Object>] options
180
+ # @return [Jobs::Rendering] a job to monitor the status of the rendering
134
181
  def render! manifest, options = {}
135
- RenderingJob.load(send_manifest(manifest, RenderingJob.endpoint, options))
182
+ Resources::Jobs::Rendering.load(send_manifest(manifest, Resources::Jobs::Rendering.endpoint, options))
136
183
  end
137
184
 
138
185
  # Sends a request to start directing and rendering a video.
139
186
  #
140
- # @param [DirectingAndRenderingManifest] manifest the manifest to direct and render
141
- # @param [Hash] options
142
- # @return [DirectingAndRenderingJob] a job to monitor the status of the directing and rendering
187
+ # @param [Manifests::DirectingAndRendering] manifest the manifest to direct and render
188
+ # @param [Hash<Symbol,Object>] options
189
+ # @return [Jobs::DirectingAndRendering] a job to monitor the status of the directing and rendering
143
190
  def direct_and_render! manifest, options = {}
144
- DirectingAndRenderingJob.load(send_manifest(manifest, DirectingAndRenderingJob.endpoint, options))
191
+ Resources::Jobs::DirectingAndRendering.load(send_manifest(manifest, Resources::Jobs::DirectingAndRendering.endpoint, options))
145
192
  end
146
193
 
147
194
  # Update a resource with the latest attributes. Useful to update the state of a Job to
148
195
  # see if it's ready if you are not using HTTP callbacks.
149
196
  #
150
- # @param [Resource] resource the resource to update
151
- # @param [Hash] options
152
- # @return [Resource] the given resource with the latest attributes
197
+ # @param [Resources::Base] resource the resource to update
198
+ # @param [Hash<Symbol,Object>] options
199
+ # @return [Resources::Base] the given resource with the latest attributes
153
200
  def reload! resource, options = {}
154
201
  resource.load(find_request(resource.class, resource.url, options))
155
202
  end
@@ -159,6 +206,7 @@ module Animoto
159
206
  # Sets the API credentials from an .animotorc file. First looks for one in the current
160
207
  # directory, then checks ~/.animotorc, then finally /etc/.animotorc.
161
208
  #
209
+ # @return [void]
162
210
  # @raise [ArgumentError] if none of the files are found
163
211
  def configure_from_rc_file
164
212
  current_path = Dir.pwd + '/.animotorc'
@@ -183,18 +231,18 @@ module Animoto
183
231
  #
184
232
  # @param [Class] klass the Resource class you're looking for
185
233
  # @param [String] url the URL of the resource
186
- # @param [Hash] options
187
- # @return [Hash] deserialized response body
234
+ # @param [Hash<Symbol,Object>] options
235
+ # @return [Hash<String,Object>] deserialized response body
188
236
  def find_request klass, url, options = {}
189
237
  request(:get, url, nil, { "Accept" => content_type_of(klass) }, options)
190
238
  end
191
239
 
192
240
  # Builds a request requiring a manifest.
193
241
  #
194
- # @param [Manifest] manifest the manifest being acted on
242
+ # @param [Manifests::Base] manifest the manifest being acted on
195
243
  # @param [String] endpoint the endpoint to send the request to
196
- # @param [Hash] options
197
- # @return [Hash] deserialized response body
244
+ # @param [Hash<Symbol,Object>] options
245
+ # @return [Hash<String,Object>] deserialized response body
198
246
  def send_manifest manifest, endpoint, options = {}
199
247
  u = URI.parse(self.endpoint)
200
248
  u.path = endpoint
@@ -211,25 +259,30 @@ module Animoto
211
259
  #
212
260
  # @param [Symbol] method which HTTP method to use (should be lowercase, i.e. :get instead of :GET)
213
261
  # @param [String] url the URL of the request
214
- # @param [String, nil] body the request body
262
+ # @param [String,nil] body the request body
215
263
  # @param [Hash<String,String>] headers the request headers (will be sent as-is, which means you should
216
264
  # specify "Content-Type" => "..." instead of, say, :content_type => "...")
217
- # @param [Hash] options
218
- # @return [Hash] deserialized response body
265
+ # @param [Hash<Symbol,Object>] options
266
+ # @return [Hash<String,Object>] deserialized response body
219
267
  # @raise [Error]
220
268
  def request method, url, body, headers = {}, options = {}
221
- error = catch(:fail) do
269
+ code, body = catch(:fail) do
222
270
  options = { :username => @key, :password => @secret }.merge(options)
223
271
  @logger.info "Sending request to #{url.inspect} with body #{body}"
224
272
  response = http_engine.request(method, url, body, headers, options)
225
273
  @logger.info "Received response #{response}"
226
274
  return response_parser.parse(response)
227
275
  end
228
- if error
229
- errors = response_parser.parse(error)['response']['status']['errors']
230
- err_string = errors.collect { |e| e['message'] }.join(', ')
231
- @logger.error "Error response from server: #{err_string}"
232
- raise Animoto::Error.new(err_string)
276
+ if code
277
+ if body.empty?
278
+ @logger.error "HTTP error (#{code})"
279
+ raise Animoto::Error.new("HTTP error (#{code})")
280
+ else
281
+ errors = response_parser.parse(body)['response']['status']['errors']
282
+ err_string = errors.collect { |e| e['message'] }.join(', ')
283
+ @logger.error "Error response from server: #{err_string}"
284
+ raise Animoto::Error.new(err_string)
285
+ end
233
286
  else
234
287
  @logger.error "Error sending request to #{url.inspect}"
235
288
  raise Animoto::Error
@@ -240,7 +293,7 @@ module Animoto
240
293
  end
241
294
 
242
295
  # Creates the full content type string given a Resource class or instance
243
- # @param [Class,ContentType] klass_or_instance the class or instance to build the
296
+ # @param [Class,Support::ContentType] klass_or_instance the class or instance to build the
244
297
  # content type for
245
298
  # @return [String] the full content type with the version and format included (i.e.
246
299
  # "application/vnd.animoto.storyboard-v1+json")