videojuicer-vj-sdk 0.1.5 → 0.1.12
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +3 -3
- data/VERSION.yml +1 -1
- data/lib/core_ext/hash.rb +13 -1
- data/lib/core_ext/object.rb +15 -0
- data/lib/core_ext/string.rb +11 -0
- data/lib/sdk_connection_harness.rb +25 -11
- data/lib/videojuicer.rb +13 -9
- data/lib/videojuicer/asset/audio.rb +5 -4
- data/lib/videojuicer/asset/base.rb +30 -15
- data/lib/videojuicer/asset/flash.rb +8 -0
- data/lib/videojuicer/asset/image.rb +2 -2
- data/lib/videojuicer/asset/video.rb +12 -9
- data/lib/videojuicer/campaign.rb +10 -1
- data/lib/videojuicer/campaign_policy.rb +116 -0
- data/lib/videojuicer/criterion/base.rb +56 -0
- data/lib/videojuicer/criterion/date_range.rb +7 -17
- data/lib/videojuicer/criterion/geolocation.rb +11 -20
- data/lib/videojuicer/criterion/request.rb +8 -17
- data/lib/videojuicer/criterion/time.rb +8 -18
- data/lib/videojuicer/criterion/week_day.rb +13 -17
- data/lib/videojuicer/oauth/request_proxy.rb +19 -13
- data/lib/videojuicer/presentation.rb +6 -0
- data/lib/videojuicer/promo/base.rb +72 -0
- data/lib/videojuicer/resource/base.rb +17 -15
- data/lib/videojuicer/resource/embeddable.rb +30 -0
- data/lib/videojuicer/resource/inferrable.rb +67 -7
- data/lib/videojuicer/resource/property_registry.rb +19 -0
- data/lib/videojuicer/resource/relationships/belongs_to.rb +2 -1
- data/lib/videojuicer/resource/types.rb +28 -0
- data/spec/assets/audio_spec.rb +24 -0
- data/spec/assets/flash_spec.rb +24 -0
- data/spec/assets/image_spec.rb +24 -0
- data/spec/assets/text_spec.rb +24 -0
- data/spec/assets/video_spec.rb +24 -0
- data/spec/campaign_policy_spec.rb +41 -0
- data/spec/campaign_spec.rb +0 -12
- data/spec/criterion/date_range_spec.rb +24 -0
- data/spec/criterion/geolocation_spec.rb +23 -0
- data/spec/criterion/request_spec.rb +23 -0
- data/spec/criterion/time_spec.rb +23 -0
- data/spec/criterion/week_day_spec.rb +23 -0
- data/spec/files/flash.swf +0 -0
- data/spec/helpers/be_equal_to.rb +26 -0
- data/spec/helpers/spec_fixtures.rb +214 -0
- data/spec/helpers/spec_helper.rb +27 -25
- data/spec/presentation_spec.rb +2 -15
- data/spec/promos/audio_spec.rb +23 -0
- data/spec/promos/image_spec.rb +24 -0
- data/spec/promos/text_spec.rb +23 -0
- data/spec/promos/video_spec.rb +23 -0
- data/spec/request_proxy_spec.rb +8 -12
- data/spec/session_spec.rb +3 -1
- data/spec/shared/dependent_spec.rb +40 -0
- data/spec/shared/embeddable_spec.rb +34 -0
- data/spec/shared/model_spec.rb +74 -0
- data/spec/shared/resource_spec.rb +12 -41
- data/spec/spec.opts +1 -1
- data/spec/user_spec.rb +5 -27
- data/tasks/vj-core.rb +3 -2
- data/vj-sdk.gemspec +56 -24
- metadata +53 -23
- data/lib/videojuicer/criterion/affiliate.rb +0 -21
- data/lib/videojuicer/criterion/embed.rb +0 -12
- data/spec/audio_spec.rb +0 -45
- data/spec/criteria/date_range_spec.rb +0 -37
- data/spec/criteria/geolocation_spec.rb +0 -38
- data/spec/criteria/request_spec.rb +0 -36
- data/spec/criteria/time_spec.rb +0 -37
- data/spec/criteria/week_day_spec.rb +0 -39
- data/spec/image_spec.rb +0 -44
- data/spec/text_spec.rb +0 -42
- data/spec/video_spec.rb +0 -50
@@ -0,0 +1,56 @@
|
|
1
|
+
module Videojuicer
|
2
|
+
module Criterion
|
3
|
+
def self.model_map
|
4
|
+
{ :date_criteria => Videojuicer::Criterion::DateRange,
|
5
|
+
:geolocation_criteria => Videojuicer::Criterion::Geolocation,
|
6
|
+
:request_criteria => Videojuicer::Criterion::Request,
|
7
|
+
:time_criteria => Videojuicer::Criterion::Time,
|
8
|
+
:week_day_criteria => Videojuicer::Criterion::WeekDay
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
class Base
|
13
|
+
def self.inherited(base)
|
14
|
+
base.send(:include, Videojuicer::Resource)
|
15
|
+
base.send(:extend, Videojuicer::Criterion::Base::ClassMethods)
|
16
|
+
base.send(:include, Videojuicer::Criterion::Base::InstanceMethods)
|
17
|
+
end
|
18
|
+
|
19
|
+
module ClassMethods
|
20
|
+
def singular_name
|
21
|
+
"criterion"
|
22
|
+
end
|
23
|
+
|
24
|
+
def base_path(options={})
|
25
|
+
"/criteria/#{self.to_s.split("::").last.snake_case}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def get(*args); raise NoMethodError; end
|
29
|
+
def all(*args); raise NoMethodError; end
|
30
|
+
def first(*args); raise NoMethodError; end
|
31
|
+
end
|
32
|
+
|
33
|
+
module InstanceMethods
|
34
|
+
def save(*args); raise NoMethodError; end
|
35
|
+
def destroy(*args); raise NoMethodError; end
|
36
|
+
def ==(other); self.attributes == other.attributes; end
|
37
|
+
def eql?(other); self.attributes.eql?(other.attributes) end
|
38
|
+
def matcher_attributes; end
|
39
|
+
|
40
|
+
def matcher_attributes
|
41
|
+
result = {}
|
42
|
+
self.matcher_keys.each do |key|
|
43
|
+
result[key] = self.send(key)
|
44
|
+
end
|
45
|
+
return result
|
46
|
+
end
|
47
|
+
|
48
|
+
def matcher_keys
|
49
|
+
raise NoMethodError, "Matcher Attributes needs to be implemented for #{self.class}";
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -1,24 +1,14 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "base")
|
2
|
+
|
1
3
|
module Videojuicer
|
2
4
|
module Criterion
|
3
|
-
class DateRange
|
4
|
-
|
5
|
-
include Videojuicer::Exceptions
|
6
|
-
|
5
|
+
class DateRange < Base
|
6
|
+
|
7
7
|
property :until, DateTime
|
8
|
-
property :
|
9
|
-
property :created_at, DateTime
|
10
|
-
property :updated_at, DateTime
|
11
|
-
|
12
|
-
def self.plural_name
|
13
|
-
"criteria"
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.singular_name
|
17
|
-
"criterion"
|
18
|
-
end
|
8
|
+
property :from, DateTime
|
19
9
|
|
20
|
-
def
|
21
|
-
|
10
|
+
def matcher_keys
|
11
|
+
[:until, :from]
|
22
12
|
end
|
23
13
|
end
|
24
14
|
end
|
@@ -1,27 +1,18 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "base")
|
2
|
+
|
1
3
|
module Videojuicer
|
2
4
|
module Criterion
|
3
|
-
class Geolocation
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
property :city,
|
8
|
-
property :
|
9
|
-
property :country, String
|
10
|
-
#property :exclude, Boolean
|
11
|
-
property :created_at, DateTime
|
12
|
-
property :updated_at, DateTime
|
13
|
-
|
14
|
-
def self.plural_name
|
15
|
-
"criteria"
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.singular_name
|
19
|
-
"criterion"
|
20
|
-
end
|
5
|
+
class Geolocation < Base
|
6
|
+
|
7
|
+
property :country, String
|
8
|
+
property :region, String
|
9
|
+
property :city, String
|
10
|
+
property :exclude, Boolean
|
21
11
|
|
22
|
-
def
|
23
|
-
|
12
|
+
def matcher_keys
|
13
|
+
[:country, :region, :city, :exclude]
|
24
14
|
end
|
15
|
+
|
25
16
|
end
|
26
17
|
end
|
27
18
|
end
|
@@ -1,23 +1,14 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "base")
|
2
|
+
|
1
3
|
module Videojuicer
|
2
4
|
module Criterion
|
3
|
-
class Request
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
property :referrer, String
|
8
|
-
property :created_at, DateTime
|
9
|
-
property :updated_at, DateTime
|
10
|
-
|
11
|
-
def self.plural_name
|
12
|
-
"criteria"
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.singular_name
|
16
|
-
"criterion"
|
17
|
-
end
|
5
|
+
class Request < Base
|
6
|
+
|
7
|
+
property :referrer, String, :nullable => false
|
8
|
+
property :exclude, Boolean
|
18
9
|
|
19
|
-
def
|
20
|
-
|
10
|
+
def matcher_keys
|
11
|
+
[:referrer, :exclude]
|
21
12
|
end
|
22
13
|
end
|
23
14
|
end
|
@@ -1,24 +1,14 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "base")
|
2
|
+
|
1
3
|
module Videojuicer
|
2
4
|
module Criterion
|
3
|
-
class Time
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
property :until, String
|
8
|
-
property :after, String
|
9
|
-
property :created_at, DateTime
|
10
|
-
property :updated_at, DateTime
|
11
|
-
|
12
|
-
def self.plural_name
|
13
|
-
"criteria"
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.singular_name
|
17
|
-
"criterion"
|
18
|
-
end
|
5
|
+
class Time < Base
|
6
|
+
|
7
|
+
property :until, DateTime
|
8
|
+
property :from, DateTime
|
19
9
|
|
20
|
-
def
|
21
|
-
|
10
|
+
def matcher_keys
|
11
|
+
[:until, :from]
|
22
12
|
end
|
23
13
|
end
|
24
14
|
end
|
@@ -1,23 +1,19 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "base")
|
2
|
+
|
1
3
|
module Videojuicer
|
2
4
|
module Criterion
|
3
|
-
class WeekDay
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
property :
|
8
|
-
property :
|
9
|
-
property :
|
10
|
-
|
11
|
-
|
12
|
-
"criteria"
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.singular_name
|
16
|
-
"criterion"
|
17
|
-
end
|
5
|
+
class WeekDay < Base
|
6
|
+
property :monday, Boolean
|
7
|
+
property :tuesday, Boolean
|
8
|
+
property :wednesday, Boolean
|
9
|
+
property :thursday, Boolean
|
10
|
+
property :friday, Boolean
|
11
|
+
property :saturday, Boolean
|
12
|
+
property :sunday, Boolean
|
13
|
+
property :exclude, Boolean
|
18
14
|
|
19
|
-
def
|
20
|
-
|
15
|
+
def matcher_keys
|
16
|
+
[:monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday, :exclude]
|
21
17
|
end
|
22
18
|
end
|
23
19
|
end
|
@@ -62,7 +62,7 @@ module Videojuicer
|
|
62
62
|
end
|
63
63
|
|
64
64
|
# Generate the HTTP Request and handle the response
|
65
|
-
url = "#{
|
65
|
+
url = "#{host_stub}#{path}"
|
66
66
|
request = request_class_for_method(method).new("#{path}?#{query_string}")
|
67
67
|
# Generate the multipart body and headers
|
68
68
|
if multipart_params.any?
|
@@ -85,6 +85,8 @@ module Videojuicer
|
|
85
85
|
begin
|
86
86
|
#response = HTTPClient.send(method, url, multipart_params)
|
87
87
|
response = Net::HTTP.start(host, port) {|http| http.request(request) }
|
88
|
+
rescue EOFError => e
|
89
|
+
raise "EOF error when accessing #{url.inspect}"
|
88
90
|
rescue Errno::ECONNREFUSED => e
|
89
91
|
raise "Could not connect to #{url.inspect}"
|
90
92
|
end
|
@@ -92,6 +94,10 @@ module Videojuicer
|
|
92
94
|
return handle_response(response, request)
|
93
95
|
end
|
94
96
|
|
97
|
+
def host_stub
|
98
|
+
"#{protocol}://#{host}:#{port}"
|
99
|
+
end
|
100
|
+
|
95
101
|
# Handles an HTTPResponse object appropriately. Redirects are followed,
|
96
102
|
# error states raise errors and success responses are returned directly.
|
97
103
|
def handle_response(response, request)
|
@@ -105,35 +111,35 @@ module Videojuicer
|
|
105
111
|
response
|
106
112
|
when 401
|
107
113
|
# Authentication problem
|
108
|
-
response_error Unauthenticated, response
|
114
|
+
response_error Unauthenticated, request, response
|
109
115
|
when 403
|
110
116
|
# Attempted to perform a forbidden action
|
111
|
-
response_error Forbidden, response
|
117
|
+
response_error Forbidden, request, response
|
112
118
|
when 404
|
113
119
|
# Resource URL not valid
|
114
|
-
response_error NoResource, response
|
120
|
+
response_error NoResource, request, response
|
115
121
|
when 406
|
116
122
|
# Excuse me WTF r u doin
|
117
|
-
response_error NotAcceptable, response
|
123
|
+
response_error NotAcceptable, request, response
|
118
124
|
when 411
|
119
125
|
# App-side server error where request is not properly constructed.
|
120
|
-
response_error ContentLengthRequired, response
|
126
|
+
response_error ContentLengthRequired, request, response
|
121
127
|
when 500..600
|
122
128
|
# Remote application failure
|
123
|
-
response_error RemoteApplicationError, response
|
129
|
+
response_error RemoteApplicationError, request, response
|
124
130
|
else
|
125
|
-
response_error UnhandledHTTPStatus, response
|
131
|
+
response_error UnhandledHTTPStatus, request, response
|
126
132
|
end
|
127
133
|
end
|
128
134
|
|
129
135
|
# Handles the response as an error of the desired type.
|
130
|
-
def response_error(exception_klass, response)
|
136
|
+
def response_error(exception_klass, request, response)
|
131
137
|
begin
|
132
138
|
e = JSON.parse(response.body)
|
133
139
|
e = e["error"]
|
134
140
|
raise exception_klass, "#{e["message"]} \n #{(e["backtrace"] || []).join("\n")}"
|
135
141
|
rescue JSON::ParserError
|
136
|
-
raise exception_klass, "#{exception_klass.to_s} : Response code was #{response.code}"
|
142
|
+
raise exception_klass, "#{exception_klass.to_s} : Response code was #{response.code} for request: #{request.path}"
|
137
143
|
end
|
138
144
|
|
139
145
|
end
|
@@ -206,13 +212,13 @@ module Videojuicer
|
|
206
212
|
|
207
213
|
# Calculates and returns the signature secret to be used for this proxy object.
|
208
214
|
def signature_secret
|
209
|
-
[consumer_secret, token_secret].collect {|e| CGI.
|
215
|
+
[consumer_secret, token_secret].collect {|e| CGI.rfc3986_escape(e.to_s)}.join("&")
|
210
216
|
end
|
211
217
|
|
212
218
|
# Returns the unencrypted signature base string for this proxy object and the
|
213
219
|
# given request properties.
|
214
220
|
def signature_base_string(method, path, params)
|
215
|
-
s = [method.to_s.upcase, "#{protocol}://#{host}#{path}", normalize_params(params)].collect {|e| CGI.
|
221
|
+
s = [method.to_s.upcase, "#{protocol}://#{host}#{path}", normalize_params(params)].collect {|e| CGI.rfc3986_escape(e)}.join("&")
|
216
222
|
end
|
217
223
|
|
218
224
|
# Returns a string representing a normalised parameter hash. Supports nesting for
|
@@ -220,7 +226,7 @@ module Videojuicer
|
|
220
226
|
# the key 'bar inside {:foo=>{:bar=>"baz"}} will be named foo[bar] in the signature
|
221
227
|
# and in the eventual request object.
|
222
228
|
def normalize_params(params, *hash_path)
|
223
|
-
flatten_params(params).sort {|a,b| a.to_s <=> b.to_s}.collect {|k, v| "#{CGI.
|
229
|
+
flatten_params(params).sort {|a,b| a.to_s <=> b.to_s}.collect {|k, v| "#{CGI.rfc3986_escape(k)}=#{CGI.rfc3986_escape(v.to_s)}" }.join("&")
|
224
230
|
end
|
225
231
|
|
226
232
|
def flatten_params(params, *hash_path)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Videojuicer
|
2
2
|
class Presentation
|
3
3
|
include Videojuicer::Resource
|
4
|
+
include Videojuicer::Resource::Embeddable
|
4
5
|
include Videojuicer::Exceptions
|
5
6
|
|
6
7
|
property :slug, String
|
@@ -28,5 +29,10 @@ module Videojuicer
|
|
28
29
|
|
29
30
|
property :tag_list, String
|
30
31
|
|
32
|
+
def permalink
|
33
|
+
proxy = proxy_for(config)
|
34
|
+
"#{proxy.host_stub}/presentations/#{id}.html?seed_name=#{seed_name}".gsub(":80/","/")
|
35
|
+
end
|
36
|
+
|
31
37
|
end
|
32
38
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Videojuicer
|
2
|
+
module Promo
|
3
|
+
def self.model_map
|
4
|
+
{ :audio => Videojuicer::Promo::Audio,
|
5
|
+
:images => Videojuicer::Promo::Image,
|
6
|
+
:texts => Videojuicer::Promo::Text,
|
7
|
+
:videos => Videojuicer::Promo::Video
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
class Base
|
12
|
+
|
13
|
+
def self.inherited(base)
|
14
|
+
base.send(:include, Videojuicer::Resource)
|
15
|
+
base.send(:extend, Videojuicer::Promo::Base::ClassMethods)
|
16
|
+
base.send(:include, Videojuicer::Promo::Base::InstanceMethods)
|
17
|
+
|
18
|
+
base.property :campaign_policy_id, Integer
|
19
|
+
base.property :asset_id, Integer
|
20
|
+
base.property :role, String
|
21
|
+
base.property :href, String
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
def singular_name
|
26
|
+
"promo"
|
27
|
+
end
|
28
|
+
|
29
|
+
def base_path(options={})
|
30
|
+
"/promos/#{self.to_s.split("::").last.snake_case}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def get(*args); raise NoMethodError; end
|
34
|
+
def all(*args); raise NoMethodError; end
|
35
|
+
def first(*args); raise NoMethodError; end
|
36
|
+
end
|
37
|
+
|
38
|
+
module InstanceMethods
|
39
|
+
def save(*args); raise NoMethodError; end
|
40
|
+
def destroy(*args); raise NoMethodError; end
|
41
|
+
def asset
|
42
|
+
Videojuicer::Asset.const_get(self.class.to_s.split("::").last).get(asset_id)
|
43
|
+
end
|
44
|
+
def matcher_keys
|
45
|
+
[:campaign_policy_id, :asset_id, :role, :href]
|
46
|
+
end
|
47
|
+
def matcher_attributes
|
48
|
+
matcher_keys.inject({}) do |memo, attr|
|
49
|
+
memo.update(attr => self.send(attr))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
class Audio < Base
|
57
|
+
end
|
58
|
+
|
59
|
+
class Image < Base
|
60
|
+
end
|
61
|
+
|
62
|
+
class Text < Base
|
63
|
+
end
|
64
|
+
|
65
|
+
class Video < Base
|
66
|
+
end
|
67
|
+
|
68
|
+
class Heart < Base
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -17,6 +17,7 @@ module Videojuicer
|
|
17
17
|
include Videojuicer::OAuth::ProxyFactory
|
18
18
|
include Videojuicer::Resource::Inferrable
|
19
19
|
include Videojuicer::Resource::PropertyRegistry
|
20
|
+
include Videojuicer::Resource::Types
|
20
21
|
include Videojuicer::Resource::Relationships::BelongsTo
|
21
22
|
|
22
23
|
def self.included(base)
|
@@ -57,9 +58,9 @@ module Videojuicer
|
|
57
58
|
proxy = proxy_for(config)
|
58
59
|
param_key = self.class.parameter_name
|
59
60
|
response = if new_record?
|
60
|
-
proxy.post(resource_path(:validate), param_key=>returnable_attributes)
|
61
|
+
proxy.post(resource_path(:validate, :nested=>false), param_key=>returnable_attributes)
|
61
62
|
else
|
62
|
-
proxy.put(resource_path(:validate), param_key=>returnable_attributes)
|
63
|
+
proxy.put(resource_path(:validate, :nested=>false), param_key=>returnable_attributes)
|
63
64
|
end
|
64
65
|
|
65
66
|
# Parse and handle response
|
@@ -98,20 +99,11 @@ module Videojuicer
|
|
98
99
|
return save
|
99
100
|
end
|
100
101
|
|
101
|
-
# Returns the appropriate resource path for this object.
|
102
|
-
# If the object is a new record, then the root object type path
|
103
|
-
# will be given. If the object is not new (has an ID) then the
|
104
|
-
# specific ID will be used.
|
105
|
-
def resource_path(action=nil)
|
106
|
-
action_stem = (action)? "/#{action}" : ""
|
107
|
-
(new_record?)? self.class.resource_path(action) : "#{self.class.resource_path}/#{id}#{action_stem}.json"
|
108
|
-
end
|
109
|
-
|
110
102
|
# Makes a call to the API for the current attributes on this object.
|
111
103
|
# Overwrites the current instance attribute values.
|
112
104
|
def reload
|
113
105
|
raise NoResource, "Cannot load remote attributes for new records" if new_record?
|
114
|
-
response = proxy_for(config).get(resource_path)
|
106
|
+
response = proxy_for(config).get(resource_path(nil, :nested=>false))
|
115
107
|
return validate_response(response)
|
116
108
|
end
|
117
109
|
|
@@ -135,7 +127,7 @@ module Videojuicer
|
|
135
127
|
def all(options={})
|
136
128
|
# Get a proxy
|
137
129
|
options = (options.empty?)? {} : {parameter_name=>options} # FIXME this is a hacky workaround for singleton scope.
|
138
|
-
response = instance_proxy.get(
|
130
|
+
response = instance_proxy.get(base_path(:nested=>false), options)
|
139
131
|
op = JSON.parse(response.body)
|
140
132
|
|
141
133
|
items = (op["items"] rescue op) # If "items" is on the returned object then this is a collection hash.
|
@@ -151,11 +143,21 @@ module Videojuicer
|
|
151
143
|
all(options.merge(:limit=>1)).first
|
152
144
|
end
|
153
145
|
|
146
|
+
def create(attrs={})
|
147
|
+
o = new(attrs)
|
148
|
+
o.save
|
149
|
+
return o
|
150
|
+
end
|
151
|
+
|
154
152
|
# Fetches an object given an ID. Straight forward.
|
155
153
|
def get(id)
|
156
154
|
o = new(:id=>id)
|
157
|
-
|
158
|
-
|
155
|
+
begin
|
156
|
+
o.reload
|
157
|
+
o
|
158
|
+
rescue Videojuicer::Exceptions::NoResource
|
159
|
+
nil
|
160
|
+
end
|
159
161
|
end
|
160
162
|
|
161
163
|
def destroy(id)
|