panda 0.6.4 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +10 -0
- data/README.md +388 -21
- data/Rakefile +4 -17
- data/VERSION +1 -1
- data/lib/panda.rb +21 -1
- data/lib/panda/api_authentication.rb +4 -4
- data/lib/panda/base.rb +102 -0
- data/lib/panda/connection.rb +189 -0
- data/lib/panda/error.rb +29 -0
- data/lib/panda/modules/associations.rb +55 -0
- data/lib/panda/modules/builders.rb +34 -0
- data/lib/panda/modules/cloud_connection.rb +7 -0
- data/lib/panda/modules/finders.rb +62 -0
- data/lib/panda/modules/router.rb +55 -0
- data/lib/panda/modules/short_status.rb +13 -0
- data/lib/panda/modules/updatable.rb +27 -0
- data/lib/panda/panda.rb +21 -170
- data/lib/panda/proxies/encoding_scope.rb +48 -0
- data/lib/panda/proxies/profile_scope.rb +7 -0
- data/lib/panda/proxies/proxy.rb +25 -0
- data/lib/panda/proxies/scope.rb +87 -0
- data/lib/panda/proxies/video_scope.rb +28 -0
- data/lib/panda/resources/cloud.rb +49 -0
- data/lib/panda/resources/encoding.rb +30 -0
- data/lib/panda/resources/profile.rb +22 -0
- data/lib/panda/resources/resource.rb +52 -0
- data/lib/panda/resources/video.rb +13 -0
- data/panda.gemspec +36 -12
- data/spec/cloud_spec.rb +80 -0
- data/spec/encoding_spec.rb +232 -0
- data/spec/heroku_spec.rb +22 -0
- data/spec/panda_spec.rb +17 -4
- data/spec/profile_spec.rb +117 -0
- data/spec/spec_helper.rb +8 -1
- data/spec/video_spec.rb +305 -0
- metadata +33 -23
- data/log/debug.log +0 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
module Panda
|
2
|
+
class Proxy
|
3
|
+
include Panda::Router::ClassMethods
|
4
|
+
include Panda::Finders::FindMany
|
5
|
+
include Panda::Finders::FindOne
|
6
|
+
include Panda::Builders::CreateBuilder
|
7
|
+
include Panda::CloudConnection
|
8
|
+
|
9
|
+
attr_accessor :parent, :klass
|
10
|
+
|
11
|
+
def initialize(parent, klass)
|
12
|
+
@parent = parent
|
13
|
+
@klass = klass
|
14
|
+
end
|
15
|
+
|
16
|
+
def cloud
|
17
|
+
@parent.is_a?(Cloud) ? @parent : @parent.cloud
|
18
|
+
end
|
19
|
+
|
20
|
+
def end_class_name
|
21
|
+
klass.end_class_name
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Panda
|
4
|
+
class Scope < Proxy
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def respond_to?(method)
|
8
|
+
scoped_methods = [].methods.map{|i| i.to_sym} - non_delegate_methods + [:reload, :non_delegate_methods]
|
9
|
+
!(scoped_methods).include?(method.to_sym)
|
10
|
+
end
|
11
|
+
|
12
|
+
def non_delegate_methods
|
13
|
+
[:nil?, :send, :object_id, :respond_to?, :class, :find, :find_by, :create, :create!, :all, :cloud, :connection]
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(parent, klass)
|
17
|
+
super
|
18
|
+
|
19
|
+
initialize_scope_attributes
|
20
|
+
initialize_scopes
|
21
|
+
end
|
22
|
+
|
23
|
+
# Overide the function to set the cloud_id as the same as the scope
|
24
|
+
def find_by_path(url, map={})
|
25
|
+
object = find_object_by_path(url, map)
|
26
|
+
|
27
|
+
if object.is_a?(Array)
|
28
|
+
object.map{|o| klass.new(o.merge("cloud_id" => cloud.id))}
|
29
|
+
elsif object["id"]
|
30
|
+
klass.new(object.merge("cloud_id" => cloud.id))
|
31
|
+
else
|
32
|
+
Error.new(object).raise!
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def create(attributes)
|
37
|
+
scoped_attrs = attributes.merge(@scoped_attributes)
|
38
|
+
super(scoped_attrs)
|
39
|
+
end
|
40
|
+
|
41
|
+
def all(attributes={})
|
42
|
+
@scoped_attributes.merge!(attributes)
|
43
|
+
trigger_request
|
44
|
+
end
|
45
|
+
|
46
|
+
def reload
|
47
|
+
@found = trigger_request
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def initialize_scope_attributes
|
53
|
+
@scoped_attributes={}
|
54
|
+
if @parent.is_a?(Panda::Resource)
|
55
|
+
@scoped_attributes[parent_relation_name.to_sym] = @parent.id
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def proxy_found
|
60
|
+
@found ||= trigger_request
|
61
|
+
end
|
62
|
+
|
63
|
+
def initialize_scopes
|
64
|
+
[].methods.each do |m|
|
65
|
+
unless m.to_s =~ /^__/ || non_delegate_methods.include?(m.to_sym)
|
66
|
+
self.class.class_eval do
|
67
|
+
def_delegators :proxy_found, m.to_sym
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def trigger_request
|
74
|
+
if @parent.is_a?(Resource)
|
75
|
+
path = build_hash_many_path(many_path, parent_relation_name)
|
76
|
+
else
|
77
|
+
path = many_path
|
78
|
+
end
|
79
|
+
|
80
|
+
find_by_path(path, @scoped_attributes)
|
81
|
+
end
|
82
|
+
|
83
|
+
def parent_relation_name
|
84
|
+
"#{@parent.class.end_class_name.downcase}_id"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Panda
|
2
|
+
class VideoScope < Scope
|
3
|
+
|
4
|
+
def initialize(parent)
|
5
|
+
super(parent, Video)
|
6
|
+
end
|
7
|
+
|
8
|
+
def non_delegate_methods
|
9
|
+
super + [:status, :page, :per_page]
|
10
|
+
end
|
11
|
+
|
12
|
+
def page(this_page)
|
13
|
+
@scoped_attributes[:page] = this_page
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def per_page(this_per_page)
|
18
|
+
@scoped_attributes[:per_page] = this_per_page
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def status(this_status)
|
23
|
+
@scoped_attributes[:status] = this_status
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Panda
|
2
|
+
class Cloud < Base
|
3
|
+
include Panda::Updatable
|
4
|
+
attr_reader :connection
|
5
|
+
|
6
|
+
def initialize(attributes={})
|
7
|
+
super(attributes)
|
8
|
+
connection_params = Panda.connection.to_hash.merge!(:cloud_id => id, :format => :hash)
|
9
|
+
@connection = Connection.new(connection_params)
|
10
|
+
Panda.clouds[id] = self
|
11
|
+
end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
include Panda::Finders::FindOne
|
15
|
+
|
16
|
+
def find(id, options=nil)
|
17
|
+
super(id)
|
18
|
+
end
|
19
|
+
|
20
|
+
def connection
|
21
|
+
Panda.connection
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def videos
|
26
|
+
VideoScope.new(self)
|
27
|
+
end
|
28
|
+
|
29
|
+
def encodings
|
30
|
+
EncodingScope.new(self)
|
31
|
+
end
|
32
|
+
|
33
|
+
def profiles
|
34
|
+
ProfileScope.new(self)
|
35
|
+
end
|
36
|
+
|
37
|
+
def method_missing(method_symbol, *arguments)
|
38
|
+
lazy_load
|
39
|
+
super
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def lazy_load
|
45
|
+
@found ||= reload
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Panda
|
2
|
+
class Encoding < Resource
|
3
|
+
include ShortStatus
|
4
|
+
|
5
|
+
belongs_to :video
|
6
|
+
has_one :profile
|
7
|
+
|
8
|
+
def url
|
9
|
+
"http://s3.amazonaws.com/#{cloud.s3_videos_bucket}/#{id}#{extname}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def screenshots
|
13
|
+
@screenshots ||=
|
14
|
+
if status == 'success'
|
15
|
+
(1..7).map do |i|
|
16
|
+
"http://s3.amazonaws.com/#{cloud.s3_videos_bucket}/#{id}_#{i}.jpg"
|
17
|
+
end
|
18
|
+
else
|
19
|
+
[]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class << self
|
24
|
+
def first
|
25
|
+
EncodingScope.new(self).per_page(1).first
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Panda
|
2
|
+
class Profile < Resource
|
3
|
+
include Panda::Updatable
|
4
|
+
|
5
|
+
has_many :encodings
|
6
|
+
|
7
|
+
def preset?
|
8
|
+
!preset_name
|
9
|
+
end
|
10
|
+
|
11
|
+
# override attributes command and preset_name
|
12
|
+
# to ovoid <method undefined> when profile is a preset or not
|
13
|
+
def command
|
14
|
+
@attributes['command']
|
15
|
+
end
|
16
|
+
|
17
|
+
def preset_name
|
18
|
+
@attributes['preset_name']
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Panda
|
2
|
+
class Resource < Base
|
3
|
+
include Panda::Builders
|
4
|
+
include Panda::Associations
|
5
|
+
include Panda::CloudConnection
|
6
|
+
|
7
|
+
def initialize(attributes={})
|
8
|
+
super(attributes)
|
9
|
+
@attributes['cloud_id'] ||= Panda.cloud.id
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
include Panda::Finders::FindMany
|
14
|
+
include Panda::CloudConnection
|
15
|
+
|
16
|
+
def cloud
|
17
|
+
Panda.cloud
|
18
|
+
end
|
19
|
+
|
20
|
+
# delegate to the scope if the method exists
|
21
|
+
def method_missing(method_symbol, *args, &block)
|
22
|
+
scope = Panda::const_get("#{end_class_name}Scope").new(self)
|
23
|
+
if scope.respond_to?(method_symbol)
|
24
|
+
scope.send(method_symbol, *args, &block)
|
25
|
+
else
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
def cloud
|
33
|
+
Panda.clouds[cloud_id]
|
34
|
+
end
|
35
|
+
|
36
|
+
def create
|
37
|
+
raise "Can't create attribute. Already have an id=#{attributes['id']}" if attributes['id']
|
38
|
+
response = connection.post(object_url_map(self.class.many_path), attributes)
|
39
|
+
load_response(response) ? (@changed_attributes = {}; true) : false
|
40
|
+
end
|
41
|
+
|
42
|
+
def create!
|
43
|
+
create || errors.last.raise!
|
44
|
+
end
|
45
|
+
|
46
|
+
def reload
|
47
|
+
perform_reload("cloud_id" => cloud_id)
|
48
|
+
reset_associations
|
49
|
+
self
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/panda.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{panda}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "1.0.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["New Bamboo"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-08-05}
|
13
13
|
s.description = %q{Panda Client}
|
14
14
|
s.email = %q{info@pandastream.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -18,18 +18,43 @@ Gem::Specification.new do |s|
|
|
18
18
|
]
|
19
19
|
s.files = [
|
20
20
|
".gitignore",
|
21
|
+
"Gemfile",
|
21
22
|
"LICENSE",
|
22
23
|
"README.md",
|
23
24
|
"Rakefile",
|
24
25
|
"VERSION",
|
25
26
|
"lib/panda.rb",
|
26
27
|
"lib/panda/api_authentication.rb",
|
28
|
+
"lib/panda/base.rb",
|
29
|
+
"lib/panda/connection.rb",
|
30
|
+
"lib/panda/error.rb",
|
31
|
+
"lib/panda/modules/associations.rb",
|
32
|
+
"lib/panda/modules/builders.rb",
|
33
|
+
"lib/panda/modules/cloud_connection.rb",
|
34
|
+
"lib/panda/modules/finders.rb",
|
35
|
+
"lib/panda/modules/router.rb",
|
36
|
+
"lib/panda/modules/short_status.rb",
|
37
|
+
"lib/panda/modules/updatable.rb",
|
27
38
|
"lib/panda/panda.rb",
|
28
|
-
"
|
39
|
+
"lib/panda/proxies/encoding_scope.rb",
|
40
|
+
"lib/panda/proxies/profile_scope.rb",
|
41
|
+
"lib/panda/proxies/proxy.rb",
|
42
|
+
"lib/panda/proxies/scope.rb",
|
43
|
+
"lib/panda/proxies/video_scope.rb",
|
44
|
+
"lib/panda/resources/cloud.rb",
|
45
|
+
"lib/panda/resources/encoding.rb",
|
46
|
+
"lib/panda/resources/profile.rb",
|
47
|
+
"lib/panda/resources/resource.rb",
|
48
|
+
"lib/panda/resources/video.rb",
|
29
49
|
"panda.gemspec",
|
50
|
+
"spec/cloud_spec.rb",
|
51
|
+
"spec/encoding_spec.rb",
|
52
|
+
"spec/heroku_spec.rb",
|
30
53
|
"spec/panda_spec.rb",
|
54
|
+
"spec/profile_spec.rb",
|
31
55
|
"spec/spec.opts",
|
32
|
-
"spec/spec_helper.rb"
|
56
|
+
"spec/spec_helper.rb",
|
57
|
+
"spec/video_spec.rb"
|
33
58
|
]
|
34
59
|
s.homepage = %q{http://github.com/newbamboo/panda_gem}
|
35
60
|
s.rdoc_options = ["--charset=UTF-8"]
|
@@ -37,8 +62,13 @@ Gem::Specification.new do |s|
|
|
37
62
|
s.rubygems_version = %q{1.3.5}
|
38
63
|
s.summary = %q{Panda Client}
|
39
64
|
s.test_files = [
|
40
|
-
"spec/
|
41
|
-
"spec/
|
65
|
+
"spec/cloud_spec.rb",
|
66
|
+
"spec/encoding_spec.rb",
|
67
|
+
"spec/heroku_spec.rb",
|
68
|
+
"spec/panda_spec.rb",
|
69
|
+
"spec/profile_spec.rb",
|
70
|
+
"spec/spec_helper.rb",
|
71
|
+
"spec/video_spec.rb"
|
42
72
|
]
|
43
73
|
|
44
74
|
if s.respond_to? :specification_version then
|
@@ -46,21 +76,15 @@ Gem::Specification.new do |s|
|
|
46
76
|
s.specification_version = 3
|
47
77
|
|
48
78
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
49
|
-
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
50
|
-
s.add_development_dependency(%q<webmock>, [">= 0"])
|
51
79
|
s.add_runtime_dependency(%q<ruby-hmac>, [">= 0.3.2"])
|
52
80
|
s.add_runtime_dependency(%q<rest-client>, [">= 1.4"])
|
53
81
|
s.add_runtime_dependency(%q<json>, [">= 1.2"])
|
54
82
|
else
|
55
|
-
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
56
|
-
s.add_dependency(%q<webmock>, [">= 0"])
|
57
83
|
s.add_dependency(%q<ruby-hmac>, [">= 0.3.2"])
|
58
84
|
s.add_dependency(%q<rest-client>, [">= 1.4"])
|
59
85
|
s.add_dependency(%q<json>, [">= 1.2"])
|
60
86
|
end
|
61
87
|
else
|
62
|
-
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
63
|
-
s.add_dependency(%q<webmock>, [">= 0"])
|
64
88
|
s.add_dependency(%q<ruby-hmac>, [">= 0.3.2"])
|
65
89
|
s.add_dependency(%q<rest-client>, [">= 1.4"])
|
66
90
|
s.add_dependency(%q<json>, [">= 1.2"])
|
data/spec/cloud_spec.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Panda::Video do
|
4
|
+
describe "Using configure bloc" do
|
5
|
+
before(:each) do
|
6
|
+
Panda.configure do |c|
|
7
|
+
c.access_key = "my_access_key"
|
8
|
+
c.secret_key = "my_secret_key"
|
9
|
+
c.api_host = "api.example.com"
|
10
|
+
c.cloud_id = 'my_cloud_id'
|
11
|
+
c.api_port = 85
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "using a cloud" do
|
16
|
+
before(:each) do
|
17
|
+
cloud_json = "{\"s3_videos_bucket\":\"my_bucket1\",\"id\":\"cloud1\"}"
|
18
|
+
stub_http_request(:get, /api.example.com:85\/v2\/clouds\/cloud1.json/).
|
19
|
+
to_return(:body => cloud_json)
|
20
|
+
@cloud = Panda::Cloud.find "cloud1"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should find all videos" do
|
24
|
+
videos_json = "[{\"source_url\":\"my_source_url\",\"id\":\"123\"}]"
|
25
|
+
stub_http_request(:get, /api.example.com:85\/v2\/videos.json/).
|
26
|
+
with{|r| r.uri.query =~ /cloud_id=cloud1/}.
|
27
|
+
to_return(:body => videos_json)
|
28
|
+
|
29
|
+
@cloud.videos.first.id.should == "123"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should find all videos with params" do
|
33
|
+
videos_json = "[{\"source_url\":\"my_source_url\",\"id\":\"134\"}]"
|
34
|
+
stub_http_request(:get, /api.example.com:85\/v2\/videos.json/).
|
35
|
+
with{|r| r.uri.query =~ /status=success/ && r.uri.query =~ /cloud_id=cloud1/}.
|
36
|
+
to_return(:body => videos_json)
|
37
|
+
videos = @cloud.videos.all(:status => "success")
|
38
|
+
videos.first.id.should == "134"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should find a video by id" do
|
42
|
+
video_json = "{\"source_url\":\"my_source_url\",\"id\":\"123\"}"
|
43
|
+
stub_http_request(:get, /api.example.com:85\/v2\/videos\/123.json/).
|
44
|
+
with{|r| r.uri.query =~ /cloud_id=cloud1/}.
|
45
|
+
to_return(:body => video_json)
|
46
|
+
|
47
|
+
video = @cloud.videos.find "123"
|
48
|
+
video.id.should == "123"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should find all video with params" do
|
52
|
+
videos_json = "{\"source_url\":\"my_source_url\",\"id\":\"123\"}"
|
53
|
+
stub_http_request(:post, /api.example.com:85\/v2\/videos.json/).
|
54
|
+
with{|r| r.body =~ /cloud_id=cloud1/}.
|
55
|
+
to_return(:body => videos_json)
|
56
|
+
@cloud.videos.create(:source_url => "my_source_url")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "Using options on find" do
|
61
|
+
|
62
|
+
it "should find a cloud" do
|
63
|
+
cloud_json = "{\"s3_videos_bucket\":\"my_bucket\",\"id\":\"my_cloud_id\"}"
|
64
|
+
stub_http_request(:get, /http:\/\/api.example.com:85\/v2\/clouds\/my_cloud_id.json/).
|
65
|
+
to_return(:body => cloud_json)
|
66
|
+
|
67
|
+
@cloud = Panda::Cloud.find "my_cloud_id", {
|
68
|
+
"access_key" => "my_access_key",
|
69
|
+
"secret_key" => "my_secret_key",
|
70
|
+
"api_host" => "api.example.com",
|
71
|
+
"api_port" => 85,
|
72
|
+
"format" => "json"
|
73
|
+
}
|
74
|
+
|
75
|
+
@cloud.s3_videos_bucket.should == "my_bucket"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|