animoto 0.0.0.alpha0

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.
Files changed (44) hide show
  1. data/README.md +39 -0
  2. data/lib/animoto/asset.rb +25 -0
  3. data/lib/animoto/client.rb +226 -0
  4. data/lib/animoto/content_type.rb +47 -0
  5. data/lib/animoto/directing_and_rendering_job.rb +19 -0
  6. data/lib/animoto/directing_and_rendering_manifest.rb +25 -0
  7. data/lib/animoto/directing_job.rb +18 -0
  8. data/lib/animoto/directing_manifest.rb +115 -0
  9. data/lib/animoto/errors.rb +3 -0
  10. data/lib/animoto/footage.rb +15 -0
  11. data/lib/animoto/image.rb +14 -0
  12. data/lib/animoto/job.rb +37 -0
  13. data/lib/animoto/manifest.rb +21 -0
  14. data/lib/animoto/rendering_job.rb +24 -0
  15. data/lib/animoto/rendering_manifest.rb +37 -0
  16. data/lib/animoto/resource.rb +153 -0
  17. data/lib/animoto/song.rb +16 -0
  18. data/lib/animoto/standard_envelope.rb +27 -0
  19. data/lib/animoto/storyboard.rb +22 -0
  20. data/lib/animoto/title_card.rb +26 -0
  21. data/lib/animoto/video.rb +29 -0
  22. data/lib/animoto/visual.rb +30 -0
  23. data/lib/animoto.rb +5 -0
  24. data/spec/animoto/asset_spec.rb +1 -0
  25. data/spec/animoto/client_spec.rb +119 -0
  26. data/spec/animoto/directing_and_rendering_job_spec.rb +45 -0
  27. data/spec/animoto/directing_and_rendering_manifest_spec.rb +143 -0
  28. data/spec/animoto/directing_job_spec.rb +48 -0
  29. data/spec/animoto/directing_manifest_spec.rb +186 -0
  30. data/spec/animoto/footage_spec.rb +56 -0
  31. data/spec/animoto/image_spec.rb +41 -0
  32. data/spec/animoto/job_spec.rb +128 -0
  33. data/spec/animoto/rendering_job_spec.rb +57 -0
  34. data/spec/animoto/rendering_manifest_spec.rb +115 -0
  35. data/spec/animoto/resource_spec.rb +55 -0
  36. data/spec/animoto/song_spec.rb +54 -0
  37. data/spec/animoto/standard_envelope_spec.rb +0 -0
  38. data/spec/animoto/storyboard_spec.rb +8 -0
  39. data/spec/animoto/title_card_spec.rb +42 -0
  40. data/spec/animoto/video_spec.rb +1 -0
  41. data/spec/animoto/visual_spec.rb +0 -0
  42. data/spec/animoto_spec.rb +5 -0
  43. data/spec/spec_helper.rb +10 -0
  44. metadata +127 -0
@@ -0,0 +1,153 @@
1
+ module Animoto
2
+ class Resource
3
+ include ContentType
4
+ include StandardEnvelope
5
+
6
+ # @overload endpoint(path)
7
+ # Sets the endpoint for this class. This is the URL where all requests related
8
+ # to this service will go.
9
+ #
10
+ # @param [String] path the path to set
11
+ # @return [String] the endpoint
12
+ #
13
+ # @overload endpoint()
14
+ # Returns the endpoint for this class.
15
+ #
16
+ # @return [String] the endpoint
17
+ def self.endpoint path = nil
18
+ @endpoint = path if path
19
+ @endpoint
20
+ end
21
+
22
+ # Returns the endpoint for this class.
23
+ #
24
+ # @return [String] the endpoint
25
+ def endpoint
26
+ self.class.endpoint
27
+ end
28
+
29
+ # @overload payload_key(key)
30
+ # Sets the payload key for this class. When building an instance of this class from
31
+ # a response body, the payload key determines which object in the response payload
32
+ # holds the attributes for the instance.
33
+ #
34
+ # @param [String] key the key to set
35
+ # @return [String] the key
36
+ #
37
+ # @overload payload_key()
38
+ # Returns the payload key for this class.
39
+ #
40
+ # @return [String] the key
41
+ def self.payload_key key = nil
42
+ @payload_key = key if key
43
+ @payload_key || infer_content_type
44
+ end
45
+
46
+ # Returns the payload key for this class.
47
+ #
48
+ # @return [String] the key
49
+ def payload_key
50
+ self.class.payload_key
51
+ end
52
+
53
+ # @private
54
+ #
55
+ # Makes a new instance of this class from a deserialized JSON response body. Note that
56
+ # it assumes the hash you're passing is structured correctly and does no format checking
57
+ # at all, so if the hash is not in the "standard envelope", this method will most likely
58
+ # raise an error.
59
+ #
60
+ # @param [Hash] body the deserialized JSON response body
61
+ # @return [Resource] an instance of this class
62
+ def self.load body
63
+ new unpack_standard_envelope(body)
64
+ end
65
+
66
+ class << self
67
+
68
+ # If an instance is instantiated with the same unique identifier (i.e. URL) as another,
69
+ # instead of creating a brand new object, will instead update and return the existing
70
+ # object. This way there should only be one object representing any one resource.
71
+ #
72
+ # @example
73
+ # client = Animoto::Client.new
74
+ # storyboard1 = Animoto::Storyboard.new :url => "https://api.animoto.com/storyboards/1"
75
+ # storyboard2 = client.find! Animoto::Storyboard, "https://api.animoto.com/storyboards/1"
76
+ # storyboard1.equal?(storyboard2) # => true
77
+ #
78
+ # @param [Hash] attributes a hash of attributes for this resource
79
+ # @return [Resource] either a new Resource instance, or an existing one with updated
80
+ # attributes
81
+ alias_method :original_new, :new
82
+ def new attributes = {}
83
+ if attributes[:url] && instances[attributes[:url]]
84
+ instances[attributes[:url]].instantiate attributes
85
+ else
86
+ original_new attributes
87
+ end
88
+ end
89
+
90
+ # @private
91
+ #
92
+ # Registers an instance in the identity map so that subsequent finds or instantiations
93
+ # of this resource with the same URL will return the same object.
94
+ #
95
+ # @param [Resource] instance the instance to register
96
+ # @raise [ArgumentError] if the instance isn't of this class
97
+ def register instance
98
+ raise ArgumentError unless instance.is_a?(self)
99
+ instances[instance.url] = instance
100
+ end
101
+
102
+ private
103
+
104
+ # Returns (or vivifies) the identity map for this class.
105
+ #
106
+ # @return [Hash<String,Resource>] the identity map
107
+ def instances
108
+ @instances ||= {}
109
+ end
110
+ end
111
+
112
+ attr_reader :url, :errors
113
+
114
+ def initialize attributes = {}
115
+ instantiate attributes
116
+ end
117
+
118
+ # @private
119
+ #
120
+ # Update this instance with new attributes from the response body.
121
+ #
122
+ # @param [Hash] body deserialized JSON from a response body
123
+ # @return [self] this instance, updated
124
+ def load body = {}
125
+ instantiate unpack_standard_envelope(body)
126
+ end
127
+
128
+ # @private
129
+ #
130
+ # Since Resources can be created a number of different ways, this method does
131
+ # the actual attribute setting for a Resource, acting much like a public version
132
+ # of #initialize.
133
+ #
134
+ # @param [Hash] attributes hash of attributes for this resource
135
+ # @return [self] this instance
136
+ def instantiate attributes = {}
137
+ @errors = (attributes[:errors] || []).collect { |e| wrap_error e }
138
+ @url = attributes[:url]
139
+ self.class.register(self) if @url
140
+ self
141
+ end
142
+
143
+ private
144
+
145
+ # Turns an error from a response body into a Ruby object.
146
+ #
147
+ # @param [Hash] error the error "object" from a response body
148
+ # @return [Error] a Ruby error object
149
+ def wrap_error error
150
+ Animoto::Error.new error['message']
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,16 @@
1
+ module Animoto
2
+ class Song < Animoto::Asset
3
+
4
+ attr_accessor :start_time, :duration, :title, :artist
5
+
6
+ def to_hash
7
+ hash = super
8
+ hash['start_time'] = start_time if start_time
9
+ hash['duration'] = duration if duration
10
+ hash['title'] = title if title
11
+ hash['artist'] = artist if artist
12
+ hash
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ module Animoto
2
+ module StandardEnvelope
3
+
4
+ def self.included base
5
+ base.class_eval {
6
+ include Animoto::StandardEnvelope::InstanceMethods
7
+ extend Animoto::StandardEnvelope::ClassMethods
8
+ }
9
+ end
10
+
11
+ module InstanceMethods
12
+ def unpack_standard_envelope body = {}
13
+ self.class.unpack_standard_envelope body
14
+ end
15
+ end
16
+
17
+ module ClassMethods
18
+ protected
19
+ def unpack_standard_envelope body = {}
20
+ {
21
+ :url => body['response']['payload'][payload_key]['links']['self'],
22
+ :errors => body['response']['status']['errors'] || []
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ module Animoto
2
+ class Storyboard < Animoto::Resource
3
+
4
+ def self.unpack_standard_envelope body = {}
5
+ super.merge({
6
+ :duration => body['response']['payload'][payload_key]['metadata']['duration'],
7
+ :visuals_count => body['response']['payload'][payload_key]['metadata']['visuals_count'],
8
+ :preview_url => body['response']['payload'][payload_key]['links']['preview']
9
+ })
10
+ end
11
+
12
+ attr_reader :duration, :visuals_count, :preview_url
13
+
14
+ def instantiate attributes = {}
15
+ @duration = attributes[:duration]
16
+ @visuals_count = attributes[:visuals_count]
17
+ @preview_url = attributes[:preview_url]
18
+ super
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ module Animoto
2
+ class TitleCard
3
+ include Animoto::Visual
4
+
5
+ attr_accessor :title, :subtitle
6
+
7
+ # Creates a new TitleCard.
8
+ #
9
+ # @param [String] title the main text
10
+ # @param [String] subtitle the secondary text
11
+ def initialize title, subtitle = nil
12
+ @title, @subtitle = title, subtitle
13
+ end
14
+
15
+ # Returns a representation of this TitleCard as a Hash.
16
+ #
17
+ # @return [Hash] this TitleCard as a Hash
18
+ def to_hash
19
+ hash = super
20
+ hash['h1'] = title
21
+ hash['h2'] = subtitle if subtitle
22
+ hash['spotlit'] = spotlit? unless @spotlit.nil?
23
+ hash
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,29 @@
1
+ module Animoto
2
+ class Video < Animoto::Resource
3
+
4
+ def self.unpack_standard_envelope body
5
+ super.merge({
6
+ :download_url => body['response']['payload'][payload_key]['links']['download'],
7
+ :storyboard_url => body['response']['payload'][payload_key]['links']['storyboard'],
8
+ :duration => body['response']['payload'][payload_key]['metadata']['duration'],
9
+ :format => body['response']['payload'][payload_key]['metadata']['format'],
10
+ :framerate => body['response']['payload'][payload_key]['metadata']['framerate'],
11
+ :resolution => body['response']['payload'][payload_key]['metadata']['vertical_resolution']
12
+ })
13
+ end
14
+
15
+ attr_reader :download_url, :storyboard_url, :storyboard, :duration, :format, :framerate, :resolution
16
+
17
+ def instantiate attributes = {}
18
+ @download_url = attributes[:download_url]
19
+ @storyboard_url = attributes[:storyboard_url]
20
+ @storyboard = Animoto::Storyboard.new(:url => @storyboard_url) if @storyboard_url
21
+ @duration = attributes[:duration]
22
+ @format = attributes[:format]
23
+ @framerate = attributes[:framerate]
24
+ @resolution = attributes[:resolution]
25
+ super
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,30 @@
1
+ module Animoto
2
+ module Visual
3
+
4
+ # Setter for spotlighting, which instructs the director to give special attention
5
+ # to this visual when directing.
6
+ #
7
+ # @param [Boolean] bool true if this visual should receive special attention
8
+ def spotlit= bool
9
+ @spotlit = bool
10
+ end
11
+
12
+ # Returns true if this visual is spotlit.
13
+ #
14
+ # @return [Boolean] whether or not this visual is spotlit
15
+ def spotlit?
16
+ @spotlit
17
+ end
18
+
19
+ # Returns a representation of this Visual as a Hash
20
+ #
21
+ # @return [Hash] this Visual as a Hash
22
+ def to_hash
23
+ hash = super rescue {}
24
+ hash['spotlit'] = spotlit? unless @spotlit.nil?
25
+ hash['type'] = self.class.name.split('::').last.gsub(/(^)?([A-Z])/) { "#{'_' unless $1}#{$2.downcase}" }
26
+ hash
27
+ end
28
+
29
+ end
30
+ end
data/lib/animoto.rb ADDED
@@ -0,0 +1,5 @@
1
+ module Animoto
2
+ def self.version
3
+ "0.0.0.alpha0"
4
+ end
5
+ end
@@ -0,0 +1 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
@@ -0,0 +1,119 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Animoto::Client do
4
+ def client options = {}
5
+ @client ||= Animoto::Client.new "joe", "secret", options
6
+ end
7
+
8
+ def object
9
+ @object ||= Object.new
10
+ end
11
+
12
+ describe "supplying credentials" do
13
+ describe "manually" do
14
+ it "should accept the key and secret as the first two parameters on initialization" do
15
+ c = Animoto::Client.new "key", "secret"
16
+ c.key.should == "key"
17
+ c.secret.should == "secret"
18
+ end
19
+
20
+ describe "when the secret isn't specified (i.e. only 1 parameter was passed)" do
21
+ before do
22
+ File.stubs(:exist?).returns(false) # <= to keep it from finding our .animotorc files
23
+ end
24
+
25
+ it "should raise an error" do
26
+ lambda { Animoto::Client.new "key" }.should raise_error
27
+ end
28
+ end
29
+ end
30
+
31
+ describe "automatically" do
32
+ before do
33
+ @home_path = File.expand_path("~/.animotorc")
34
+ @etc_path = "/etc/.animotorc"
35
+ @config = "key: joe\nsecret: secret"
36
+ end
37
+
38
+ describe "when ~/.animotorc exists" do
39
+ before do
40
+ File.stubs(:exist?).with(@home_path).returns(true)
41
+ File.stubs(:read).with(@home_path).returns(@config)
42
+ end
43
+
44
+ it "should configure itself based on the options in ~/.animotorc" do
45
+ c = Animoto::Client.new
46
+ c.key.should == "joe"
47
+ c.secret.should == "secret"
48
+ end
49
+ end
50
+
51
+ describe "when ~/.animotorc doesn't exist" do
52
+ before do
53
+ File.stubs(:exist?).with(@home_path).returns(false)
54
+ end
55
+
56
+ describe "when /etc/.animotorc exists" do
57
+ before do
58
+ File.stubs(:exist?).with(@etc_path).returns(true)
59
+ File.stubs(:read).with(@etc_path).returns(@config)
60
+ end
61
+
62
+ it "should configure itself based on the options in /etc/.animotorc" do
63
+ c = Animoto::Client.new
64
+ c.key.should == "joe"
65
+ c.secret.should == "secret"
66
+ end
67
+ end
68
+
69
+ describe "when /etc/.animotorc doesn't exist" do
70
+ it "should raise an error" do
71
+ lambda { Animoto::Client.new }.should raise_error
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ describe "finding an instance by identifier" do
79
+ before do
80
+ @url = "https://api.animoto.com/storyboards/1"
81
+ @body = {'response'=>{'status'=>{'code'=>200}},'payload'=>{'storyboard'=>{'links'=>{'self'=>@url}}}}
82
+ stub_request(:get, @url).to_return(:body => @body.to_json, :status => [200,"OK"])
83
+ end
84
+
85
+ it "should make a GET request to the given url" do
86
+ client.find(Animoto::Storyboard, @url)
87
+ WebMock.should have_requested(:get, @url)
88
+ end
89
+
90
+ it "should ask for a response in the proper format" do
91
+ client.find(Animoto::Storyboard, @url)
92
+ WebMock.should have_requested(:get, @url).with(:headers => { 'Accept' => "application/vnd.animoto.storyboard-v1+json"})
93
+ end
94
+
95
+ it "should not sent a request body" do
96
+ client.find(Animoto::Storyboard, @url)
97
+ WebMock.should have_requested(:get, @url).with(:body => "")
98
+ end
99
+
100
+ it "should return an instance of the correct resource type" do
101
+ client.find(Animoto::Storyboard, @url).should be_an_instance_of(Animoto::Storyboard)
102
+ end
103
+ end
104
+
105
+ describe "reloading an instance" do
106
+ before do
107
+ @url = 'https://api.animoto.com/jobs/directing/1'
108
+ @job = Animoto::DirectingJob.new :state => 'initial', :url => @url
109
+ @body = {'response'=>{'status'=>{'code'=>200}},'payload'=>{'directing_job'=>{'state'=>'retrieving_assets','links'=>{'self'=>@url}}}}
110
+ stub_request(:get, @url).to_return(:body => @body.to_json, :status => [200,"OK"])
111
+ @job.state.should == 'initial' # sanity check
112
+ end
113
+
114
+ it "should update the resource's attributes" do
115
+ client.reload!(@job)
116
+ @job.state.should == 'retrieving_assets'
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,45 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Animoto::DirectingAndRenderingJob do
4
+
5
+ it "should have endpoint '/jobs/directing_and_rendering'" do
6
+ Animoto::DirectingAndRenderingJob.endpoint.should == '/jobs/directing_and_rendering'
7
+ end
8
+
9
+ it "should have content_type 'application/vnd.animoto.directing_and_rendering_job'" do
10
+ Animoto::DirectingAndRenderingJob.content_type.should == 'directing_and_rendering_job'
11
+ end
12
+
13
+ it "should have payload key 'directing_and_rendering_job'" do
14
+ Animoto::DirectingAndRenderingJob.payload_key.should == 'directing_and_rendering_job'
15
+ end
16
+
17
+ describe "loading from a response body" do
18
+ before do
19
+ @body = {
20
+ 'response' => {
21
+ 'status' => { 'code' => 200 },
22
+ 'payload' => {
23
+ 'directing_and_rendering_job' => {
24
+ 'state' => 'completed',
25
+ 'links' => {
26
+ 'self' => 'http://animoto.com/jobs/directing_and_rendering/1',
27
+ 'video' => 'http://animoto.com/videos/1'
28
+ }
29
+ }
30
+ }
31
+ }
32
+ }
33
+ @job = Animoto::DirectingAndRenderingJob.load @body
34
+ end
35
+
36
+ it "should set the video url from the body" do
37
+ @job.video_url.should == 'http://animoto.com/videos/1'
38
+ end
39
+
40
+ it "should create a video from the video url" do
41
+ @job.video.should be_an_instance_of(Animoto::Video)
42
+ @job.video.url.should == @job.video_url
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,143 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Animoto::DirectingAndRenderingManifest do
4
+
5
+ def manifest options = {}
6
+ @manifest ||= Animoto::DirectingAndRenderingManifest.new options
7
+ end
8
+
9
+ describe "generating a hash" do
10
+ before do
11
+ manifest(:title => 'Funderful Wonderment', :producer => 'Senor Spielbergo', :pacing => 'double',
12
+ :resolution => "720p", :framerate => 24, :format => 'flv')
13
+ @image = manifest.add_image 'http://website.com/image.png'
14
+ @title_card = manifest.add_title_card 'woohoo', 'this is awesome'
15
+ @footage = manifest.add_footage 'http://website.com/movie.mp4'
16
+ @song_obj = manifest.add_song 'http://website.com/song.mp3'
17
+ end
18
+
19
+ it "should have top-level 'directing_and_rendering_job' object" do
20
+ manifest.to_hash.should have_key('directing_and_rendering_job')
21
+ manifest.to_hash['directing_and_rendering_job'].should be_a(Hash)
22
+ end
23
+
24
+ describe "when the callback url is set" do
25
+ before do
26
+ manifest.http_callback_url = 'http://website.com/callback'
27
+ end
28
+
29
+ describe "but the callback format isn't" do
30
+ it "should raise an error" do
31
+ lambda { manifest.to_hash }.should raise_error(ArgumentError)
32
+ end
33
+ end
34
+
35
+ describe "as well as the format" do
36
+ before do
37
+ manifest.http_callback_format = 'xml'
38
+ end
39
+
40
+ it "should have the HTTP callback URL in the job" do
41
+ manifest.to_hash['directing_and_rendering_job'].should have_key('http_callback')
42
+ manifest.to_hash['directing_and_rendering_job']['http_callback'].should == manifest.http_callback_url
43
+ end
44
+
45
+ it "should have the HTTP callback format in the job" do
46
+ manifest.to_hash['directing_and_rendering_job'].should have_key('http_callback_format')
47
+ manifest.to_hash['directing_and_rendering_job']['http_callback_format'].should == manifest.http_callback_format
48
+ end
49
+ end
50
+ end
51
+
52
+ it "should have a 'directing_manifest' object within the job" do
53
+ manifest.to_hash['directing_and_rendering_job'].should have_key('directing_manifest')
54
+ manifest.to_hash['directing_and_rendering_job']['directing_manifest'].should be_a(Hash)
55
+ end
56
+
57
+ describe "directing_manifest" do
58
+ before do
59
+ @hash = manifest.to_hash['directing_and_rendering_job']['directing_manifest']
60
+ end
61
+
62
+ it "should have a 'style' key in the manifest" do
63
+ @hash.should have_key('style')
64
+ @hash['style'].should == manifest.style
65
+ end
66
+
67
+ it "should have a 'pacing' key in the manifest" do
68
+ @hash.should have_key('pacing')
69
+ @hash['pacing'].should == manifest.pacing
70
+ end
71
+
72
+ it "should have a 'producer_name' key in the manifest" do
73
+ @hash.should have_key('producer_name')
74
+ @hash['producer_name'].should == manifest.producer
75
+ end
76
+
77
+ it "should have a 'visuals' key in the manifest" do
78
+ @hash.should have_key('visuals')
79
+ end
80
+
81
+ it "should have a 'song' object in the manifest" do
82
+ @hash.should have_key('song')
83
+ @hash['song'].should be_a(Hash)
84
+ end
85
+
86
+ describe "visuals array" do
87
+ before do
88
+ @visuals = @hash['visuals']
89
+ end
90
+
91
+ it "should have the visuals in the order they were added" do
92
+ @visuals[0].should == @image.to_hash
93
+ @visuals[1].should == @title_card.to_hash
94
+ @visuals[2].should == @footage.to_hash
95
+ end
96
+ end
97
+
98
+ describe "song" do
99
+ before do
100
+ @song = @hash['song']
101
+ end
102
+
103
+ it "should have info about the song" do
104
+ @song.should == @song_obj.to_hash
105
+ end
106
+ end
107
+ end
108
+
109
+ it "should have a 'rendering_manifest' object within the job" do
110
+ manifest.to_hash['directing_and_rendering_job'].should have_key('rendering_manifest')
111
+ manifest.to_hash['directing_and_rendering_job']['rendering_manifest'].should be_a(Hash)
112
+ end
113
+
114
+ describe "rendering_manifest" do
115
+ before do
116
+ @hash = manifest.to_hash['directing_and_rendering_job']['rendering_manifest']
117
+ end
118
+
119
+ it "should have a 'rendering_profile' object in the manifest" do
120
+ @hash.should have_key('rendering_profile')
121
+ @hash['rendering_profile'].should be_a(Hash)
122
+ end
123
+
124
+ describe "rendering_profile" do
125
+ before do
126
+ @profile = @hash['rendering_profile']
127
+ end
128
+
129
+ it "should have a 'vertical_resolution' key" do
130
+ @profile['vertical_resolution'].should == manifest.resolution
131
+ end
132
+
133
+ it "should have a 'framerate' key" do
134
+ @profile['framerate'].should == manifest.framerate
135
+ end
136
+
137
+ it "should have a 'format' key" do
138
+ @profile['format'].should == manifest.format
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,48 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Animoto::DirectingJob do
4
+
5
+ it "should have endpoint '/jobs/directing'" do
6
+ Animoto::DirectingJob.endpoint.should == '/jobs/directing'
7
+ end
8
+
9
+ it "should have content type 'application/vnd.animoto.directing_job'" do
10
+ Animoto::DirectingJob.content_type.should == 'directing_job'
11
+ end
12
+
13
+ it "should have payload key 'directing_job'" do
14
+ Animoto::DirectingJob.payload_key.should == 'directing_job'
15
+ end
16
+
17
+ describe "loading from a response body" do
18
+ before do
19
+ @body = {
20
+ 'response' => {
21
+ 'status' => {
22
+ 'code' => 200
23
+ },
24
+ 'payload' => {
25
+ 'directing_job' => {
26
+ 'state' => 'completed',
27
+ 'links' => {
28
+ 'self' => 'http://animoto.com/jobs/directing/1',
29
+ 'storyboard' => 'http://animoto.com/storyboards/1'
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
35
+ @job = Animoto::DirectingJob.load @body
36
+ end
37
+
38
+ it "should set the storyboard url from the body" do
39
+ @job.storyboard_url.should == 'http://animoto.com/storyboards/1'
40
+ end
41
+
42
+ it "should create a storyboard from the storyboard url" do
43
+ @job.storyboard.should be_an_instance_of(Animoto::Storyboard)
44
+ @job.storyboard.url.should == @job.storyboard_url
45
+ end
46
+ end
47
+
48
+ end