videojuicer-vj-sdk 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/LICENSE +20 -0
  2. data/README.markdown +0 -0
  3. data/README.rdoc +7 -0
  4. data/VERSION.yml +4 -0
  5. data/lib/core_ext/hash.rb +40 -0
  6. data/lib/sdk_connection_harness.rb +87 -0
  7. data/lib/videojuicer/asset/audio.rb +11 -0
  8. data/lib/videojuicer/asset/base.rb +50 -0
  9. data/lib/videojuicer/asset/image.rb +12 -0
  10. data/lib/videojuicer/asset/text.rb +8 -0
  11. data/lib/videojuicer/asset/video.rb +13 -0
  12. data/lib/videojuicer/campaign.rb +8 -0
  13. data/lib/videojuicer/oauth/multipart_helper.rb +96 -0
  14. data/lib/videojuicer/oauth/proxy_factory.rb +18 -0
  15. data/lib/videojuicer/oauth/request_proxy.rb +234 -0
  16. data/lib/videojuicer/presentation.rb +32 -0
  17. data/lib/videojuicer/resource/base.rb +174 -0
  18. data/lib/videojuicer/resource/collection.rb +34 -0
  19. data/lib/videojuicer/resource/errors.rb +17 -0
  20. data/lib/videojuicer/resource/inferrable.rb +81 -0
  21. data/lib/videojuicer/resource/property_registry.rb +126 -0
  22. data/lib/videojuicer/resource/relationships/belongs_to.rb +38 -0
  23. data/lib/videojuicer/session.rb +74 -0
  24. data/lib/videojuicer/shared/configurable.rb +103 -0
  25. data/lib/videojuicer/shared/exceptions.rb +20 -0
  26. data/lib/videojuicer/user.rb +43 -0
  27. data/lib/videojuicer.rb +97 -0
  28. data/spec/audio_spec.rb +43 -0
  29. data/spec/belongs_to_spec.rb +45 -0
  30. data/spec/campaign_spec.rb +37 -0
  31. data/spec/collection_spec.rb +25 -0
  32. data/spec/files/audio.mp3 +0 -0
  33. data/spec/files/empty_file +0 -0
  34. data/spec/files/image.jpg +0 -0
  35. data/spec/files/text.txt +1 -0
  36. data/spec/files/video.mov +0 -0
  37. data/spec/helpers/spec_helper.rb +50 -0
  38. data/spec/image_spec.rb +44 -0
  39. data/spec/presentation_spec.rb +38 -0
  40. data/spec/property_registry_spec.rb +130 -0
  41. data/spec/request_proxy_spec.rb +94 -0
  42. data/spec/session_spec.rb +96 -0
  43. data/spec/shared/configurable_spec.rb +75 -0
  44. data/spec/shared/resource_spec.rb +170 -0
  45. data/spec/spec.opts +3 -0
  46. data/spec/text_spec.rb +42 -0
  47. data/spec/user_spec.rb +64 -0
  48. data/spec/video_spec.rb +45 -0
  49. data/spec/videojuicer_spec.rb +122 -0
  50. metadata +136 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 danski
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
File without changes
data/README.rdoc ADDED
@@ -0,0 +1,7 @@
1
+ = vj-sdk
2
+
3
+ Description goes here.
4
+
5
+ == Copyright
6
+
7
+ Copyright (c) 2009 danski. See LICENSE for details.
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 1
4
+ :patch: 0
@@ -0,0 +1,40 @@
1
+ class Hash
2
+
3
+ # Returns a new hash just like this one, but with all the string keys expressed as symbols.
4
+ # Also applies to hashes within self.
5
+ # Based on an implementation within Rails 2.x, thanks Rails!
6
+ def deep_symbolize
7
+ target = dup
8
+ target.inject({}) do |memo, (key, value)|
9
+ value = value.deep_symbolize if value.is_a?(Hash)
10
+ memo[(key.to_sym rescue key) || key] = value
11
+ memo
12
+ end
13
+ end
14
+
15
+ # Merges self with another hash, recursively.
16
+ #
17
+ # This code was lovingly stolen from some random gem:
18
+ # http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html
19
+ #
20
+ # Thanks to whoever made it.
21
+ def deep_merge(hash)
22
+ target = dup
23
+
24
+ hash.keys.each do |key|
25
+ if hash[key].is_a? Hash and self[key].is_a? Hash
26
+ target[key] = target[key].deep_merge(hash[key])
27
+ next
28
+ end
29
+ target[key] = hash[key]
30
+ end
31
+ target
32
+ end
33
+
34
+ def to_xml
35
+ inject("") do |memo, (key, value)|
36
+ memo << "<#{key}>#{(value.respond_to?(:to_xml))? value.to_xml : value}</#{key}>"
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,87 @@
1
+ require 'mash'
2
+ require 'yaml'
3
+ class SDKConnectionHarness
4
+ class << self
5
+
6
+ attr_accessor :server_pid
7
+ attr_accessor :fixtures
8
+
9
+ def core_directory
10
+ File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "vj-core"))
11
+ end
12
+
13
+ def start!
14
+ stop! if running?
15
+ puts "Starting vj-core from #{core_directory}\n"
16
+ Thread.new do
17
+ cur_dir = Dir.pwd
18
+ Dir.chdir(core_directory) do
19
+ `merb -d -p #{port} -e test --log .log/sdk-development.log`
20
+ end
21
+ Dir.chdir(cur_dir)
22
+ end
23
+ end
24
+
25
+ def stop!
26
+ Thread.new do
27
+ `killall -9 "merb : worker (port #{port})"`
28
+ end
29
+ end
30
+
31
+ def running?
32
+ uri = URI.parse("http://localhost:#{port}/")
33
+ req = Net::HTTP::Get.new(uri.path)
34
+
35
+ begin
36
+ resp = Net::HTTP.start(uri.host, uri.port) do |http|
37
+ http.request(req)
38
+ end
39
+ return true
40
+ rescue Exception => e
41
+ # Connection refused means the daemon isn't running
42
+ return false
43
+ end
44
+ end
45
+
46
+ def load_fixtures
47
+ Dir.chdir(core_directory) do
48
+ out = `rake videojuicer:sdk:setup MERB_ENV=test`
49
+ out = out.match(/!!!([^!]+)!!!/m)
50
+ self.fixtures = out[1]
51
+ end
52
+ end
53
+
54
+ def write_fixtures
55
+ f = File.open(File.join(File.dirname(__FILE__), "..", "core-fixtures.yml"), "w+")
56
+ f.rewind
57
+ f.write(self.fixtures)
58
+ f.close
59
+ end
60
+
61
+ def port
62
+ 5555
63
+ end
64
+
65
+ def connect(overrides={})
66
+ fixtures = Mash.new(YAML.load(load_fixtures)).merge(overrides)
67
+ configure_test_settings(overrides)
68
+ Videojuicer.enter_scope :seed_name => fixtures.seed.name,
69
+ :consumer_key=>fixtures["write-master"].consumer.consumer_key,
70
+ :consumer_secret=>fixtures["write-master"].consumer.consumer_secret,
71
+ :token=>fixtures["write-master"].authorized_token.oauth_token,
72
+ :token_secret=>fixtures["write-master"].authorized_token.oauth_token_secret
73
+ end
74
+
75
+ def configure_test_settings(overrides={})
76
+ Videojuicer.configure!({
77
+ :consumer_key => nil,
78
+ :consumer_secret => nil,
79
+ :api_version => 1,
80
+ :protocol => "http",
81
+ :host => "localhost",
82
+ :port => 5555
83
+ }.merge(overrides))
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,11 @@
1
+ require File.join(File.dirname(__FILE__), "base")
2
+
3
+ module Videojuicer
4
+ module Asset
5
+ class Audio < Base
6
+
7
+ property :bit_rate, Integer
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,50 @@
1
+ module Videojuicer
2
+ module Asset
3
+ class Base
4
+
5
+ def self.inherited(base)
6
+ base.send(:include, Videojuicer::Resource)
7
+ base.send(:extend, Videojuicer::Asset::Base::ClassMethods)
8
+ base.send(:include, Videojuicer::Asset::Base::InstanceMethods)
9
+
10
+ base.property :user_id, Integer
11
+ # - generic file handling
12
+ base.property :file, File
13
+ base.property :file_name, String
14
+ base.property :file_size, Integer, :writer=>:private
15
+ # - common metadata
16
+ base.property :duration, Integer # milliseconds
17
+ base.property :licensed_at, Date
18
+ base.property :licensed_by, String
19
+ base.property :licensed_under, String
20
+ base.property :published_at, Date
21
+ # - access control / workflow
22
+ base.property :disclosure, String
23
+ base.property :state, String, :writer => :private
24
+ base.property :url, String, :writer => :private
25
+
26
+ base.property :created_at, DateTime
27
+ base.property :updated_at, DateTime
28
+ end
29
+
30
+ module ClassMethods
31
+ def singular_name
32
+ "asset"
33
+ end
34
+
35
+ def base_path
36
+ "/assets/#{self.to_s.downcase.split("::").last}"
37
+ end
38
+ end
39
+
40
+ module InstanceMethods
41
+ def returnable_attributes
42
+ attrs = super
43
+ attrs.delete(:file) unless new_record?
44
+ attrs
45
+ end
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,12 @@
1
+ require File.join(File.dirname(__FILE__), "base")
2
+
3
+ module Videojuicer
4
+ module Asset
5
+ class Image < Base
6
+
7
+ property :width, Integer # pixels
8
+ property :height, Integer # pixels
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ require File.join(File.dirname(__FILE__), "base")
2
+
3
+ module Videojuicer
4
+ module Asset
5
+ class Text < Base
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ require File.join(File.dirname(__FILE__), "base")
2
+
3
+ module Videojuicer
4
+ module Asset
5
+ class Video < Base
6
+
7
+ property :width, Integer # pixels
8
+ property :height, Integer # pixels
9
+ property :bit_rate, Integer # bits per second
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ module Videojuicer
2
+ class Campaign
3
+ include Videojuicer::Resource
4
+ include Videojuicer::Exceptions
5
+
6
+ property :name, String
7
+ end
8
+ end
@@ -0,0 +1,96 @@
1
+ # Cribbed almost entirely from Merb's multipart request helper.
2
+ # Thanks, Yehuda!
3
+
4
+ module Videojuicer
5
+ module OAuth
6
+ module Multipart
7
+
8
+ require 'rubygems'
9
+ gem "mime-types"
10
+ require 'mime/types'
11
+
12
+ class Param
13
+ attr_accessor :key, :value
14
+
15
+ # ==== Parameters
16
+ # key<~to_s>:: The parameter key.
17
+ # value<~to_s>:: The parameter value.
18
+ def initialize(key, value)
19
+ @key = key
20
+ @value = value
21
+ end
22
+
23
+ # ==== Returns
24
+ # String:: The parameter in a form suitable for a multipart request.
25
+ def to_multipart
26
+ return %(Content-Disposition: form-data; name="#{key}"\r\n\r\n#{value}\r\n)
27
+ end
28
+ end
29
+
30
+ class FileParam
31
+ attr_accessor :key, :filename, :content
32
+
33
+ # ==== Parameters
34
+ # key<~to_s>:: The parameter key.
35
+ # filename<~to_s>:: Name of the file for this parameter.
36
+ # content<~to_s>:: Content of the file for this parameter.
37
+ def initialize(key, filename, content)
38
+ @key = key
39
+ @filename = filename
40
+ @content = content
41
+ end
42
+
43
+ # ==== Returns
44
+ # String::
45
+ # The file parameter in a form suitable for a multipart request.
46
+ def to_multipart
47
+ return %(Content-Disposition: form-data; name="#{key}"; filename="#{filename}"\r\n) + "Content-Type: #{MIME::Types.type_for(@filename).first}\r\n\r\n" + content + "\r\n"
48
+ end
49
+ end
50
+
51
+ class Post
52
+ BOUNDARY = '----------0xKhTmLbOuNdArY'
53
+ CONTENT_TYPE = "multipart/form-data, boundary=" + BOUNDARY
54
+
55
+ # ==== Parameters
56
+ # params<Hash>:: Optional params for the controller.
57
+ def initialize(params = {})
58
+ @multipart_params = []
59
+ push_params(params)
60
+ end
61
+
62
+ # Saves the params in an array of multipart params as Param and
63
+ # FileParam objects.
64
+ #
65
+ # ==== Parameters
66
+ # params<Hash>:: The params to add to the multipart params.
67
+ # prefix<~to_s>:: An optional prefix for the request string keys.
68
+ def push_params(params, prefix = nil)
69
+ params.sort_by {|k| k.to_s}.each do |key, value|
70
+ param_key = prefix.nil? ? key : "#{prefix}[#{key}]"
71
+ if value.respond_to?(:read)
72
+ @multipart_params << FileParam.new(param_key, value.path, value.read)
73
+ value.rewind
74
+ else
75
+ if value.is_a?(Hash) || value.is_a?(Mash)
76
+ value.keys.each do |k|
77
+ push_params(value, param_key)
78
+ end
79
+ else
80
+ @multipart_params << Param.new(param_key, value)
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ # ==== Returns
87
+ # Array[String, String]:: The query and the content type.
88
+ def to_multipart
89
+ query = @multipart_params.collect { |param| "--" + BOUNDARY + "\r\n" + param.to_multipart }.join("") + "--" + BOUNDARY + "--"
90
+ return query, CONTENT_TYPE
91
+ end
92
+ end
93
+
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,18 @@
1
+ =begin rdoc
2
+
3
+ ProxyFactory is a mixin that provides a convenience DSL for creating
4
+ new RequestProxy objects. It is intended for internal use within the SDK.
5
+
6
+ =end
7
+
8
+ module Videojuicer
9
+ module OAuth
10
+ module ProxyFactory
11
+
12
+ def proxy_for(options={})
13
+ Videojuicer::OAuth::RequestProxy.new(options)
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,234 @@
1
+ =begin rdoc
2
+
3
+ The RequestProxy is, as the name suggests, a proxy through which HTTP requests are made
4
+ in order to have them correctly signed for verification under the OAuth protocol.
5
+
6
+ More information on OAuth: http://oauth.net
7
+
8
+
9
+
10
+ =end
11
+
12
+ require 'cgi'
13
+ require 'hmac'
14
+ require File.join(File.dirname(__FILE__), 'multipart_helper')
15
+
16
+ module Videojuicer
17
+ module OAuth
18
+
19
+ class RequestProxy
20
+
21
+ include Videojuicer::Exceptions
22
+ include Videojuicer::Configurable
23
+
24
+ # Initializes a new RequestProxy object which can be used to make requests.
25
+ # Accepts all the same options as Videojuicer::configure! as well as:
26
+ # +token+ - The OAuth token to use in requests made through this proxy.
27
+ # +token_secret+ - The OAuth token secret to use when encrypting the request signature.
28
+ def initialize(options={})
29
+ configure!(options)
30
+ end
31
+
32
+ # Makes a GET request given path and params.
33
+ # The host will be ascertained from the configuration options.
34
+ def get(path, params={}); make_request(:get, host, port, path, params); end
35
+
36
+ # Makes a POST request given path and params.
37
+ # The host will be ascertained from the configuration options.
38
+ def post(path, params={}); make_request(:post, host, port, path, params); end
39
+
40
+ # Makes a PUT request given path and params.
41
+ # The host will be ascertained from the configuration options.
42
+ def put(path, params={}); make_request(:put, host, port, path, params); end
43
+
44
+ # Makes a DELETE request given path and params.
45
+ # The host will be ascertained from the configuration options.
46
+ def delete(path, params={}); make_request(:delete, host, port, path, params); end
47
+
48
+ # Does the actual work of making a request. Returns a Net::HTTPResponse object.
49
+ def make_request(method, host, port, path, params={})
50
+ # Strip the files from the parameters to determine what, from the whole bundle, needs signing
51
+ signature_params, multipart_params = split_by_signature_eligibility(params)
52
+
53
+ if multipart_params.any?
54
+ # Sign the params and include the as multipart
55
+ multipart_params = flatten_params(
56
+ authify_params(method, path, signature_params).deep_merge(multipart_params)
57
+ )
58
+ query_string = ""
59
+ else
60
+ # Use the query string
61
+ query_string = authified_query_string(method, path, signature_params)
62
+ end
63
+
64
+ # Generate the HTTP Request and handle the response
65
+ url = "#{protocol}://#{host}:#{port}#{path}?#{query_string}"
66
+ request = request_class_for_method(method).new("#{path}?#{query_string}")
67
+ # Generate the multipart body and headers
68
+ if multipart_params.any?
69
+ post_body, content_type = Multipart::Post.new(multipart_params).to_multipart
70
+ request.content_length = post_body.length
71
+ request.content_type = content_type
72
+ request.body = post_body
73
+ end
74
+
75
+ begin
76
+ #response = HTTPClient.send(method, url, multipart_params)
77
+ response = Net::HTTP.start(host, port) {|http| http.request(request) }
78
+ rescue Errno::ECONNREFUSED => e
79
+ raise "Could not connect to #{url.inspect}"
80
+ end
81
+
82
+ return handle_response(response, request)
83
+ end
84
+
85
+ # Handles an HTTPResponse object appropriately. Redirects are followed,
86
+ # error states raise errors and success responses are returned directly.
87
+ def handle_response(response, request)
88
+ c = response.code.to_i
89
+ case c
90
+ when 415
91
+ response
92
+ when 403
93
+ response_error Forbidden, response
94
+ when 400..499
95
+ response_error NoResource, response
96
+ when 500..600
97
+ response_error RemoteApplicationError, response
98
+ else
99
+ response
100
+ end
101
+ end
102
+
103
+ # Handles the response as an error of the desired type.
104
+ def response_error(exception_klass, response)
105
+ begin
106
+ e = JSON.parse(response.body)
107
+ e = e["error"]
108
+ raise exception_klass, "#{e["message"]} \n #{(e["backtrace"] || []).join("\n")}"
109
+ rescue JSON::ParserError
110
+ raise exception_klass
111
+ end
112
+
113
+ end
114
+
115
+ # Splits a given parameter hash into two hashes - one containing all
116
+ # string and non-binary parameters, and one containing all file/binary parameters.
117
+ # This action is performed recursively so that:
118
+ # params = {:user=>{:attributes=>{:file=>some_file, :name=>"user name"}}, :foo=>"bar"}
119
+ # normal, multipart = split_multipart_params(params)
120
+ # normal.inspect # => {:user=>{:attributes=>{:name=>"user name"}}, :foo=>"bar"}
121
+ # multipart.inspect # => {:user=>{:attributes=>{:file=>some_file}}}
122
+ def split_by_signature_eligibility(params, *hash_path)
123
+ strings = {}
124
+ files = {}
125
+ params.each do |key, value|
126
+ if value.is_a?(Hash)
127
+ # Call recursively
128
+ s, f = split_by_signature_eligibility(value, *(hash_path+[key]))
129
+ strings = strings.deep_merge(s)
130
+ files = files.deep_merge(f)
131
+ else
132
+ # Insert it into files at the current key path if it is a binary,
133
+ # and into strings if it is not.
134
+ pwd = (value.respond_to?(:read))? files : strings
135
+ hash_path.each do |component|
136
+ pwd[component] ||= {}
137
+ pwd = pwd[component]
138
+ end
139
+ pwd[key] = value
140
+ end
141
+ end
142
+ return strings, files
143
+ end
144
+
145
+ def signed_url(method, path, params={})
146
+ "#{protocol}://#{host}:#{port}#{path}?#{authified_query_string(method, path, params)}"
147
+ end
148
+
149
+ # Authifies the given parameters and converts them into a query string.
150
+ def authified_query_string(method, path, params={})
151
+ normalize_params(authify_params(method, path, params))
152
+ end
153
+
154
+ # Takes a set of business parameters you want sent to the provider, and merges them
155
+ # with the proxy configuration to produce a set of parameters that will be accepted
156
+ # by the OAuth provider.
157
+ def authify_params(method, path, params)
158
+ params = {
159
+ :oauth_consumer_key=>consumer_key,
160
+ :oauth_token=>token,
161
+ :api_version=>api_version,
162
+ :oauth_timestamp=>Time.now.to_i,
163
+ :oauth_nonce=>rand(9999),
164
+ :oauth_signature_method=>"HMAC-SHA1",
165
+ :seed_name=>seed_name,
166
+ :user_id=>user_id
167
+ }.merge(params)
168
+ params.delete_if {|k,v| (!v) or (v.to_s.empty?) }
169
+ params[:oauth_signature] = signature(method, path, params)
170
+ return params
171
+ end
172
+
173
+ # Calculates and returns the encrypted signature for this proxy object and the
174
+ # given request properties.
175
+ def signature(method, path, params)
176
+ base = signature_base_string(method, path, params)
177
+ signature_octet = HMAC::SHA1.digest(signature_secret, base)
178
+ signature_base64 = [signature_octet].pack('m').chomp.gsub(/\n/, '')
179
+ end
180
+
181
+ # Calculates and returns the signature secret to be used for this proxy object.
182
+ def signature_secret
183
+ [consumer_secret, token_secret].collect {|e| CGI.escape(e.to_s)}.join("&")
184
+ end
185
+
186
+ # Returns the unencrypted signature base string for this proxy object and the
187
+ # given request properties.
188
+ def signature_base_string(method, path, params)
189
+ s = [method.to_s.upcase, "#{protocol}://#{host}#{path}", normalize_params(params)].collect {|e| CGI.escape(e)}.join("&")
190
+ end
191
+
192
+ # Returns a string representing a normalised parameter hash. Supports nesting for
193
+ # rails or merb-style object[attr] properties supplied as nested hashes. For instance,
194
+ # the key 'bar inside {:foo=>{:bar=>"baz"}} will be named foo[bar] in the signature
195
+ # and in the eventual request object.
196
+ def normalize_params(params, *hash_path)
197
+ flatten_params(params).sort {|a,b| a.to_s <=> b.to_s}.collect {|k, v| "#{CGI.escape(k)}=#{CGI.escape(v.to_s)}" }.join("&")
198
+ end
199
+
200
+ def flatten_params(params, *hash_path)
201
+ op = {}
202
+ params.sort {|a,b| a.to_s<=>b.to_s}.each do |key, value|
203
+ path = hash_path.dup
204
+ path << key.to_s
205
+
206
+ if value.is_a?(Hash)
207
+ op.merge! flatten_params(value, *path)
208
+ elsif value
209
+ key_path = path.first + path[1..(path.length-1)].collect {|h| "[#{h}]"}.join("")
210
+ op[key_path] = value
211
+ end
212
+ end
213
+ return op
214
+ end
215
+
216
+ # Returns the Net::HTTPRequest subclass needed to make a request for the given method.
217
+ def request_class_for_method(m, in_module=Net::HTTP)
218
+ case (m.is_a?(Symbol) ? m : m.downcase.to_sym rescue :get)
219
+ when :post
220
+ in_module::Post
221
+ when :put
222
+ in_module::Put
223
+ when :head
224
+ in_module::Head
225
+ when :delete
226
+ in_module::Delete
227
+ else
228
+ in_module::Get
229
+ end
230
+ end
231
+
232
+ end
233
+ end
234
+ end
@@ -0,0 +1,32 @@
1
+ module Videojuicer
2
+ class Presentation
3
+ include Videojuicer::Resource
4
+ include Videojuicer::Exceptions
5
+
6
+ property :slug, String
7
+ property :title, String
8
+ property :author, String
9
+ property :author_url, String
10
+ property :abstract, String
11
+ property :user_id, Integer, :writer=>:private
12
+ belongs_to :user, :class=>Videojuicer::User
13
+ property :callback_url, String
14
+
15
+ property :state, String, :default=>"ready" # see the STATES constant for values
16
+ property :disclosure, String, :default=>"public" # see DISCLOSURES constant for values
17
+ property :publish_from, DateTime
18
+ property :publish_until, DateTime
19
+
20
+ property :document_layout, String
21
+ property :document_content, String # the presentation document
22
+ property :document_type, String, :default=>"SMIL 3.0"
23
+
24
+ property :created_at, DateTime
25
+ property :updated_at, DateTime
26
+
27
+ property :image_asset_id, Integer # FIXME make me a relationship helper
28
+
29
+ property :tag_list, String
30
+
31
+ end
32
+ end