transloadit 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ .bundle
2
+ .rvmrc
3
+ .yardoc
4
+
5
+ Gemfile.lock
6
+
7
+ coverage
8
+ doc
9
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # transloadit
2
+
3
+ Fantastic file uploading for your web application.
4
+
5
+ ## Description
6
+
7
+ This is the official Ruby gem for [Transloadit](transloadit.com). It allows
8
+ you to automate uploading files through the Transloadit REST API.
9
+
10
+ ## Install
11
+
12
+ gem install transloadit
13
+
14
+ ## Getting started
15
+
16
+ To get started, you need to require the 'transloadit' gem:
17
+
18
+ $ irb -rubygems
19
+ >> require 'transloadit'
20
+ => true
21
+
22
+ Then create a Transloadit instance, which will maintain your authentication
23
+ credentials and allow us to make requests to the API.
24
+
25
+ transloadit = Transloadit.new(
26
+ key: 'transloadit-auth-key',
27
+ secret: 'transloadit-auth-secret'
28
+ )
29
+
30
+ ### 1. Resize and store an image
31
+
32
+ This example demonstrates how you can create an assembly to resize an image
33
+ and store the result on [Amazon S3](http://aws.amazon.com/s3/).
34
+
35
+ First, we create two steps: one to resize the image to 320x240, and another to
36
+ store the image in our S3 bucket.
37
+
38
+ resize = transloadit.step '/image/resize',
39
+ width: 320,
40
+ height: 240
41
+
42
+ store = transloadit.step '/s3/store',
43
+ key: 'aws-access-key-id',
44
+ secret: 'aws-secret-access-key',
45
+ bucket: 's3-bucket-name'
46
+
47
+ Now that we have the steps, we create an assembly (which is just a request to
48
+ process a file or set of files) and let Transloadit do the rest.
49
+
50
+ assembly = transloadit.assembly(
51
+ steps: [ resize, store ]
52
+ )
53
+
54
+ response = assembly.submit! open('lolcat.jpg')
55
+
56
+ When the `submit!` method returns, the file has been uploaded but may not yet
57
+ be done processing. We can use the returned object to check if processing has
58
+ completed, or examine other attributes of the request.
59
+
60
+ # returns the unique API ID of the assembly
61
+ response[:assembly_id] # => '9bd733a...'
62
+
63
+ # returns the API URL endpoint for the assembly
64
+ response[:assembly_url] # => 'http://api2.vivian.transloadit.com/assemblies/9bd733a...'
65
+
66
+ # checks how many bytes were expected / received by transloadit
67
+ response[:bytes_expected] # => 92933
68
+ response[:bytes_received] # => 92933
69
+
70
+ # checks if all processing has been completed
71
+ response.completed? # => false
72
+
73
+ # cancels further processing on the assembly
74
+ response.cancel! # => true
75
+
76
+ It's important to note that none of these queries are "live" (with the
77
+ exception of the `cancel!` method). They all check the response given by the
78
+ API at the time the assembly was created. You have to explicitly ask the
79
+ assembly to reload its results from the API.
80
+
81
+ # reloads the response's contents from the REST API
82
+ response.reload!
83
+
84
+ In general, you use hash accessor syntax to query any direct attribute from
85
+ the [response](http://transloadit.com/docs/assemblies#response-format).
86
+ Methods suffixed by a question mark provide a more readable way of quering
87
+ state (e.g., `assembly.completed?` vs. checking the result of
88
+ `assembly[:ok]`). Methods suffixed by a bang make a live query against the
89
+ Transloadit HTTP API.
90
+
91
+ ### 2. Uploading multiple files
92
+
93
+ Multiple files can be given to the `submit!` method in order to upload more
94
+ than one file in the same request. You can also pass a single step for the
95
+ `steps` parameter, without having to wrap it in an Array.
96
+
97
+ assembly = transloadit.assembly(steps: store)
98
+
99
+ response = assembly.submit!(
100
+ open('puppies.jpg'),
101
+ open('kittens.jpg'),
102
+ open('ferrets.jpg')
103
+ )
104
+
105
+ ### 3. Parallel Assembly
106
+
107
+ Transloadit allows you to perform several processing steps in parallel. You
108
+ simply need to `use` other steps. Following
109
+ [their example](http://transloadit.com/docs/assemblies#special-parameters):
110
+
111
+ encode = transloadit.step '/video/encode', { ... }
112
+ thumbs = transloadit.step '/video/thumbs', { ... }
113
+ export = transloadit.step '/s3/store', { ... }
114
+
115
+ export.use [ encode, thumbs ]
116
+
117
+ transloadit.assembly(
118
+ steps: [ encode, thumbs, export ]
119
+ ).submit! open('ninja-cat.mpg')
120
+
121
+ You can also tell a step to use the original uploaded file by passing the
122
+ Symbol `:original` instead of another step.
123
+
124
+ Check the YARD documentation for more information on using
125
+ [use](http://rubydoc.info/gems/transloadit/frames/Transloadit/Step#use-instance_method).
126
+
127
+ ## Documentation
128
+
129
+ Up-to-date YARD documentation is automatically generated. You can view the
130
+ docs for the [released gem](http://rubydoc.info/gems/transloadit/frames) or
131
+ for the latest [git master](http://rubydoc.info/github/transloadit/ruby-sdk/master/frames).
132
+
133
+ ## Compatibility
134
+
135
+ At a minimum, this gem should work on MRI 1.9.2, 1.8.7, 1.8.6, and Rubinius
136
+ 1.2.0. If it doesn't, please file a [bug report](https://github.com/transloadit/ruby-sdk/issues).
137
+ Compatibility patches for other Rubies are welcomed.
138
+
139
+ You can run `rake test:multiruby` to test transloadit against all supported
140
+ Rubies. Run `rake test:multiruby:setup` once beforehand, though, to set up the
141
+ RVM environments. [RVM](rvm.beginrescueend.com/) must be installed in order to
142
+ test against multiple Rubies.
data/Rakefile ADDED
@@ -0,0 +1,62 @@
1
+ require 'rake/gempackagetask'
2
+ require 'rake/testtask'
3
+
4
+ RUBIES = %w{ 1.9.2 1.8.7 1.8.6 rbx-1.2.0 }
5
+
6
+ GEMSPEC = 'transloadit.gemspec'
7
+
8
+ spec = eval open(GEMSPEC).read
9
+ Rake::GemPackageTask.new(spec) do |gem|
10
+ gem.need_tar = true
11
+ end
12
+
13
+ Rake::TestTask.new do |test|
14
+ test.libs << 'test'
15
+ test.pattern = 'test/**/test_*.rb'
16
+ end
17
+
18
+ namespace :test do
19
+ begin
20
+ `rvm -v` # raise an exception if RVM isn't installed
21
+
22
+ desc 'Run tests against all supported Rubies'
23
+ task :multiruby do
24
+ system "rvm #{RUBIES.join(',')} ruby bundle exec rake -s test"
25
+
26
+ # clean up after Rubinius
27
+ require 'pathname'
28
+ Pathname.glob('**/*.rbc').each {|path| path.unlink }
29
+ end
30
+
31
+ namespace :multiruby do
32
+ desc 'Prepare supported rubiesfor testing'
33
+ task :setup do
34
+ warn 'Preparing multiruby. This may take awhile...'
35
+
36
+ # create gemsets, install bundler, bundle
37
+ RUBIES.each {|ruby| system "rvm #{ruby} gemset create transloadit" }
38
+ system "rvm #{RUBIES.join(',')} gem install bundler --no-ri --no-rdoc"
39
+ system "rvm #{RUBIES.join(',')} ruby bundle install"
40
+ end
41
+ end
42
+ rescue Errno::ENOENT
43
+ desc 'You need `rvm` installed to test against multiple Rubies'
44
+ task :multiruby
45
+ end
46
+ end
47
+
48
+ begin
49
+ require 'yard'
50
+ require 'yard/rake/yardoc_task'
51
+
52
+ YARD::Rake::YardocTask.new :doc do |yard|
53
+ yard.options = %w{
54
+ --title Transloadit
55
+ --readme README.md
56
+ --markup rdoc
57
+ }
58
+ end
59
+ rescue
60
+ desc 'You need the `yard` gem to generate documentation'
61
+ task :doc
62
+ end
@@ -0,0 +1,114 @@
1
+ require 'json'
2
+
3
+ #
4
+ # Implements the Transloadit REST API in Ruby. Check the {file:README.md README}
5
+ # for usage instructions.
6
+ #
7
+ class Transloadit
8
+ autoload :Assembly, 'transloadit/assembly'
9
+ autoload :Request, 'transloadit/request'
10
+ autoload :Response, 'transloadit/response'
11
+ autoload :Step, 'transloadit/step'
12
+ autoload :VERSION, 'transloadit/version'
13
+
14
+ # @return [String] your Transloadit auth key
15
+ attr_accessor :key
16
+
17
+ # @return [String] your Transloadit auth secret, for signing requests
18
+ attr_accessor :secret
19
+
20
+ #
21
+ # Creates a new instance of the Transloadit API.
22
+ #
23
+ # @param [Hash] options a hash of options, which can be any of:
24
+ # @option options [String] :key your auth key from the
25
+ # {credentials}[https://transloadit.com/accounts/credentials] page
26
+ # (required)
27
+ # @option options [String] :secret your auth secret from the
28
+ # {credentials}[https://transloadit.com/accounts/credentials] page, for
29
+ # signing requests (optional)
30
+ #
31
+ def initialize(options = {})
32
+ self.key = options[:key]
33
+ self.secret = options[:secret]
34
+
35
+ _ensure_key_provided
36
+ end
37
+
38
+ #
39
+ # Creates a Transloadit::Step describing a step in an upload assembly.
40
+ #
41
+ # @param [String] robot the robot to use in this step (e.g., '/image/resize')
42
+ # @param [Hash] options a hash of options to customize the robot's
43
+ # operation; see the {online documentation}[http://transloadit.com/docs/building-assembly-instructions]
44
+ # for robot-specific options
45
+ # @return [Step] the created Step
46
+ #
47
+ def step(robot, options = {})
48
+ Transloadit::Step.new(robot, options)
49
+ end
50
+
51
+ #
52
+ # Creates a Transloadit::Assembly ready to be sent to the REST API.
53
+ #
54
+ # @param [Hash] options additional parameters to send with the assembly
55
+ # submission; for a full list of parameters, see the official
56
+ # documentation on {templates}[http://transloadit.com/docs/templates].
57
+ # @option options [Step, Array<Step>] :steps the steps to perform in this
58
+ # assembly
59
+ # @option options [String] :notify_url A URL to be POSTed when the assembly
60
+ # has finished processing
61
+ # @option options [String] :template_id the ID of a
62
+ # {template}[https://transloadit.com/templates] to use instead of
63
+ # specifying options here directly
64
+ #
65
+ def assembly(options = {})
66
+ Transloadit::Assembly.new(self, options)
67
+ end
68
+
69
+ #
70
+ # @return [String] a human-readable version of the Transloadit.
71
+ #
72
+ def inspect
73
+ self.to_hash.inspect
74
+ end
75
+
76
+ #
77
+ # @return [Hash] a Transloadit-compatible Hash of the instance's contents
78
+ #
79
+ def to_hash
80
+ result = { :key => self.key }
81
+ result.update(:expires => _generate_expiry) unless self.secret.nil?
82
+ result
83
+ end
84
+
85
+ #
86
+ # @return [String] JSON-encoded String containing the object's hash contents
87
+ #
88
+ def to_json
89
+ self.to_hash.to_json
90
+ end
91
+
92
+ private
93
+
94
+ #
95
+ # Raises an ArgumentError if no {#key} has been assigned.
96
+ #
97
+ def _ensure_key_provided
98
+ unless self.key
99
+ raise ArgumentError, 'an authentication key must be provided'
100
+ end
101
+ end
102
+
103
+ #
104
+ # Automatically generates API-compatible request expiration times 5 minutes
105
+ # from now.
106
+ #
107
+ # @param [Integer] duration the number of seconds from now to set the
108
+ # expiry time
109
+ # @return [String] an API-compatible timestamp
110
+ #
111
+ def _generate_expiry(duration = 5 * 60)
112
+ (Time.now + duration).utc.strftime('%Y/%m/%d %H:%M:%S+00:00')
113
+ end
114
+ end
@@ -0,0 +1,122 @@
1
+ require 'transloadit'
2
+
3
+ #
4
+ # Represents a Assembly ready to be sent to the REST API for processing. An
5
+ # Assembly can contain one or more Steps for processing or point to a
6
+ # server-side template. It's submitted along with a list of files to process,
7
+ # at which point Transloadit will process and store the files according to the
8
+ # rules in the Assembly.
9
+ #
10
+ # See the Transloadit {documentation}[http://transloadit.com/docs/building-assembly-instructions]
11
+ # for futher information on Assemblies and their parameters.
12
+ #
13
+ class Transloadit::Assembly
14
+ # @return [Transloadit] the associated Transloadit instance
15
+ attr_reader :transloadit
16
+
17
+ # @return [Hash] the options describing the Assembly
18
+ attr_accessor :options
19
+
20
+ #
21
+ # Creates a new Assembly authenticated using the given +transloadit+
22
+ # instance.
23
+ #
24
+ # @param [Transloadit] transloadit the associated Transloadit instance
25
+ # @param [Hash] options the configuration for the Assembly;
26
+ # see {Transloadit#assembly}
27
+ #
28
+ def initialize(transloadit, options = {})
29
+ self.transloadit = transloadit
30
+ self.options = options
31
+ end
32
+
33
+ #
34
+ # @return [Hash] the processing steps, formatted for sending to Transloadit
35
+ #
36
+ def steps
37
+ _wrap_steps_in_hash options[:steps]
38
+ end
39
+
40
+ #
41
+ # Submits the assembly for processing. Accepts as many IO objects as you
42
+ # wish to process in the assembly. The last argument is an optional Hash
43
+ # of parameters to send along with the request.
44
+ #
45
+ # @overload submit!(*ios)
46
+ # @param [Array<IO>] *ios the files for the assembly to process
47
+ #
48
+ # @overload submit!(*ios, params = {})
49
+ # @param [Array<IO>] *ios the files for the assembly to process
50
+ # @param [Hash] params additional POST data to submit with the request
51
+ #
52
+ def submit!(*ios)
53
+ params = self.to_hash.update _extract_options!(*ios)
54
+
55
+ ios.each_with_index do |f, i|
56
+ params.update "file_#{i}" => f
57
+ end
58
+
59
+ request = Transloadit::Request.new '/assemblies',
60
+ self.transloadit.secret
61
+
62
+ request.post(params).extend!(Transloadit::Response::Assembly)
63
+ end
64
+
65
+ #
66
+ # @return [String] a human-readable version of the Assembly
67
+ #
68
+ def inspect
69
+ self.to_hash.inspect
70
+ end
71
+
72
+ #
73
+ # @return [Hash] a Transloadit-compatible Hash of the Assembly's contents
74
+ #
75
+ def to_hash
76
+ self.options.merge(
77
+ :auth => self.transloadit.to_hash,
78
+ :steps => self.steps
79
+ ).delete_if {|k,v| v.nil? }
80
+ end
81
+
82
+ #
83
+ # @return [String] JSON-encoded String containing the Assembly's contents
84
+ #
85
+ def to_json
86
+ self.to_hash.to_json
87
+ end
88
+
89
+ protected
90
+
91
+ attr_writer :transloadit
92
+
93
+ private
94
+
95
+ #
96
+ # Returns a Transloadit-compatible Hash wrapping the +steps+ passed to it.
97
+ # Accepts any supported format the +steps+ could come in.
98
+ #
99
+ # @param [nil, Hash, Step, Array] steps the steps to encode
100
+ # @return [Hash] the Transloadit-compatible hash of steps
101
+ #
102
+ def _wrap_steps_in_hash(steps)
103
+ case steps
104
+ when nil then steps
105
+ when Hash then steps
106
+ when Transloadit::Step then steps.to_hash
107
+ else
108
+ steps.inject({}) {|h, s| h.update s }
109
+ end
110
+ end
111
+
112
+ #
113
+ # Extracts the last argument from a set of arguments if it's a hash.
114
+ # Otherwise, returns an empty hash.
115
+ #
116
+ # @param *args the arguments to search for an options hash
117
+ # @return [Hash] the options passed, otherwise an empty hash
118
+ #
119
+ def _extract_options!(*args)
120
+ args.last.is_a?(Hash) ? args.pop : {}
121
+ end
122
+ end
@@ -0,0 +1,123 @@
1
+ require 'transloadit'
2
+
3
+ require 'rest-client'
4
+ require 'openssl'
5
+
6
+ #
7
+ # Wraps requests to the Transloadit API. Ensures all API requests return a
8
+ # parsed Transloadit::Response, and abstracts away finding a lightly-used
9
+ # instance on startup.
10
+ #
11
+ class Transloadit::Request
12
+ # The default Transloadit API endpoint.
13
+ API_ENDPOINT = URI.parse('http://api2.transloadit.com/')
14
+
15
+ # The default headers to send to the API.
16
+ API_HEADERS = { 'User-Agent' => %{Transloadit Ruby SDK #{Transloadit::VERSION}} }
17
+
18
+ # The HMAC algorithm used for calculation request signatures.
19
+ HMAC_ALGORITHM = OpenSSL::Digest::Digest.new('sha1')
20
+
21
+ # @return [String] the API endpoint for the request
22
+ attr_reader :url
23
+
24
+ # @return [String] the authentication secret to sign the request with
25
+ attr_accessor :secret
26
+
27
+ def self.bored!
28
+ self.api(self.bored)
29
+ end
30
+
31
+ def initialize(url, secret = nil)
32
+ self.url = URI.parse(url.to_s)
33
+ self.secret = secret
34
+ end
35
+
36
+ def get(params = {})
37
+ self.request! do
38
+ self.api[url.path + self.to_query(params)].get(API_HEADERS)
39
+ end
40
+ end
41
+
42
+ def delete(params = {})
43
+ self.request! do
44
+ self.api[url.path + self.to_query(params)].delete(API_HEADERS)
45
+ end
46
+ end
47
+
48
+ def post(payload = {})
49
+ self.request! do
50
+ self.api[url.path].post(self.to_payload(payload), API_HEADERS)
51
+ end
52
+ end
53
+
54
+ def inspect
55
+ self.url.to_s.inspect
56
+ end
57
+
58
+ def to_hash
59
+ { :signature => self.signature }.delete_if {|k,v| v.nil? }
60
+ end
61
+
62
+ def to_json
63
+ self.to_hash.to_json
64
+ end
65
+
66
+ protected
67
+
68
+ attr_writer :url
69
+
70
+ def self.bored
71
+ self.new(API_ENDPOINT + '/instances/bored').get['api2_host']
72
+ end
73
+
74
+ def self.api(uri = nil)
75
+ @api = RestClient::Resource.new(uri) if uri
76
+ @api ||= RestClient::Resource.new(self.bored)
77
+ end
78
+
79
+ def api
80
+ @api ||= begin
81
+ case self.url.host
82
+ when String then RestClient::Resource.new(self.url.host)
83
+ else self.class.api
84
+ end
85
+ end
86
+ end
87
+
88
+ def to_payload(params = nil)
89
+ return self.to_hash if params.nil?
90
+ return self.to_hash if params.respond_to?(:empty?) and params.empty?
91
+
92
+ self.to_hash.update(:params => params.to_json)
93
+ end
94
+
95
+ def to_query(params = nil)
96
+ return '' if params.nil?
97
+ return '' if params.respond_to?(:empty?) and params.empty?
98
+
99
+ escape = Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")
100
+ params = URI.escape(params.to_json, escape)
101
+
102
+ '?' + self.to_hash.
103
+ update(:params => params).
104
+ map {|k,v| "#{k}=#{v}" }.
105
+ join('&')
106
+ end
107
+
108
+ def request!(&request)
109
+ Transloadit::Response.new request.call
110
+ rescue RestClient::Exception => e
111
+ Transloadit::Response.new e.response
112
+ end
113
+
114
+ def signature
115
+ self.class._hmac(self.secret, self.params.to_json) if self.secret
116
+ end
117
+
118
+ private
119
+
120
+ def self._hmac(key, message)
121
+ OpenSSL::HMAC.hexdigest HMAC_ALGORITHM, key, message
122
+ end
123
+ end
@@ -0,0 +1,43 @@
1
+ require 'transloadit'
2
+ require 'delegate'
3
+
4
+ class Transloadit::Response < Delegator
5
+ autoload :Assembly, 'transloadit/response/assembly'
6
+
7
+ def initialize(response, &extension)
8
+ self.__setobj__(response)
9
+
10
+ instance_eval(&extension) if block_given?
11
+ end
12
+
13
+ def [](attribute)
14
+ self.body[attribute]
15
+ end
16
+
17
+ def body
18
+ JSON.parse self.__getobj__.body
19
+ end
20
+
21
+ def inspect
22
+ self.body.inspect
23
+ end
24
+
25
+ def extend!(mod)
26
+ self.extend(mod)
27
+ self
28
+ end
29
+
30
+ protected
31
+
32
+ def __getobj__
33
+ @response
34
+ end
35
+
36
+ def __setobj__(response)
37
+ @response = response
38
+ end
39
+
40
+ def replace(other)
41
+ self.__setobj__ other.__getobj__
42
+ end
43
+ end
@@ -0,0 +1,15 @@
1
+ require 'transloadit'
2
+
3
+ module Transloadit::Response::Assembly
4
+ def reload!
5
+ self.replace Transloadit::Request.new(self['assembly_url']).get
6
+ end
7
+
8
+ def cancel!
9
+ self.replace Transloadit::Request.new(self['assembly_url']).delete
10
+ end
11
+
12
+ def completed?
13
+ r['ok'] == 'ASSEMBLY_COMPLETED'
14
+ end
15
+ end
@@ -0,0 +1,92 @@
1
+ require 'transloadit'
2
+
3
+ #
4
+ # Implements the concept of a step in the Transloadit API. Each Step has a
5
+ # +robot+ (e.g., '/image/resize' or '/video/thumbnail') and a hash of
6
+ # +options+ specific to the chosen robot.
7
+ #
8
+ # See the Transloadit {documentation}[http://transloadit.com/docs/building-assembly-instructions]
9
+ # for futher information on robot types and their parameters.
10
+ #
11
+ class Transloadit::Step
12
+ # @return [String] the robot to use
13
+ attr_reader :robot
14
+
15
+ # @return [Hash] the robot's options
16
+ attr_accessor :options
17
+
18
+ #
19
+ # Creates a new Step with the given +robot+.
20
+ #
21
+ # @param [String] robot the robot to use
22
+ # @param [Hash] options the configuration options for the robot; see
23
+ # {Transloadit#step} for possible values
24
+ #
25
+ def initialize(robot, options = {})
26
+ self.robot = robot
27
+ self.options = options
28
+ end
29
+
30
+ #
31
+ # Automatically generates a unique, 32-character hex name for the step that
32
+ # uses this robot.
33
+ #
34
+ # @return [String] a randomly generated name
35
+ #
36
+ def name
37
+ # rand() is "good enough" for this; we generate 128 random bits (same
38
+ # length as a UUID for future compatibility) and convert it to hex
39
+ @name ||= rand(2 ** 128).to_s(16).rjust(32, '0')
40
+ end
41
+
42
+ #
43
+ # Specifies that this Step should process the provided +input+ instead of
44
+ # the output of the Step before it.
45
+ #
46
+ # @param [Step, Array<Step>, Symbol, nil] input The input
47
+ # step to use. Follows the conventions outlined in the
48
+ # online {documentation}[http://transloadit.com/docs/building-assembly-instructions#special-parameters].
49
+ # The symbol +:original+ specifies that the original file should be sent
50
+ # to the robot. A Step indicates that this Step's output should be used
51
+ # as the input to this one. Likewise, an array of Steps tells Transloadit
52
+ # to use pass each of their outputs to this Step. And lastly, an explicit
53
+ # nil clears the setting and restores it to its default input.
54
+ #
55
+ # @return [String, Array<String>, nil> The value for the +:use+ parameter
56
+ # that will actually be sent to the REST API.
57
+ #
58
+ def use(input)
59
+ self.options.delete(:use) and return if input.nil?
60
+
61
+ self.options[:use] = case input
62
+ when Symbol then input.inspect
63
+ when Array then input.map {|i| i.name }
64
+ else [ input.name ]
65
+ end
66
+ end
67
+
68
+ #
69
+ # @return [String] a human-readable version of the Step
70
+ #
71
+ def inspect
72
+ self.to_hash[self.name].inspect
73
+ end
74
+
75
+ #
76
+ # @return [Hash] a Transloadit-compatible Hash of the Step's contents
77
+ #
78
+ def to_hash
79
+ { self.name => options.merge(:robot => self.robot) }
80
+ end
81
+
82
+ #
83
+ # @return [String] JSON-encoded String containing the Step's hash contents
84
+ #
85
+ def to_json
86
+ self.to_hash.to_json
87
+ end
88
+
89
+ protected
90
+
91
+ attr_writer :robot
92
+ end
@@ -0,0 +1,4 @@
1
+ class Transloadit
2
+ # The current version of Transloadit.
3
+ VERSION = '0.1.0'
4
+ end
@@ -0,0 +1,67 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :get
5
+ uri: http://api2.transloadit.com:80/instances/bored
6
+ body:
7
+ headers:
8
+ accept:
9
+ - "*/*; q=0.5, application/xml"
10
+ accept-encoding:
11
+ - gzip, deflate
12
+ user-agent:
13
+ - Transloadit Ruby SDK 0.0.1
14
+ response: !ruby/struct:VCR::Response
15
+ status: !ruby/struct:VCR::ResponseStatus
16
+ code: 200
17
+ message: OK
18
+ headers:
19
+ access-control-allow-headers:
20
+ - X-Requested-With, Content-Type, Accept, Content-Length
21
+ access-control-allow-methods:
22
+ - POST, GET, PUT, DELETE, OPTIONS
23
+ access-control-allow-origin:
24
+ - "*"
25
+ content-type:
26
+ - text/plain
27
+ content-length:
28
+ - "98"
29
+ connection:
30
+ - keep-alive
31
+ body: "{\"ok\":\"BORED_INSTANCE_FOUND\",\"host\":\"vivian.transloadit.com\",\"api2_host\":\"vivian.transloadit.com\"}"
32
+ http_version: "1.1"
33
+ - !ruby/struct:VCR::HTTPInteraction
34
+ request: !ruby/struct:VCR::Request
35
+ method: :post
36
+ uri: http://vivian.transloadit.com:80/assemblies
37
+ body: params=%7B%22steps%22%3A%7B%22a479db2c601661d8f914caf9cf258c0b%22%3A%7B%22robot%22%3A%22%2Fvideo%2Fthumbs%22%7D%7D%2C%22redirect_url%22%3A%22http%3A%2F%2Ffoo.bar%2F%22%2C%22auth%22%3A%7B%22key%22%3A%22%22%7D%2C%22file_0%22%3A%22%23%3CFile%3A0x00000100c63738%3E%22%7D
38
+ headers:
39
+ accept:
40
+ - "*/*; q=0.5, application/xml"
41
+ accept-encoding:
42
+ - gzip, deflate
43
+ user-agent:
44
+ - Transloadit Ruby SDK 0.0.1
45
+ content-length:
46
+ - "298"
47
+ content-type:
48
+ - application/x-www-form-urlencoded
49
+ response: !ruby/struct:VCR::Response
50
+ status: !ruby/struct:VCR::ResponseStatus
51
+ code: 302
52
+ message: Moved Temporarily
53
+ headers:
54
+ content-type:
55
+ - text/plain
56
+ access-control-allow-origin:
57
+ - "*"
58
+ access-control-allow-methods:
59
+ - POST, GET, PUT, DELETE, OPTIONS
60
+ access-control-allow-headers:
61
+ - X-Requested-With, Content-Type, Accept, Content-Length
62
+ location:
63
+ - http://foo.bar/?assembly_id=177c56e5435176f4877fbc1b397fa4f0&assembly_url=http://api2.vivian.transloadit.com/assemblies/177c56e5435176f4877fbc1b397fa4f0
64
+ transfer-encoding:
65
+ - chunked
66
+ body: "{\"ok\":\"ASSEMBLY_COMPLETED\",\"message\":\"The assembly was successfully completed.\",\"assembly_id\":\"177c56e5435176f4877fbc1b397fa4f0\",\"assembly_url\":\"http://api2.vivian.transloadit.com/assemblies/177c56e5435176f4877fbc1b397fa4f0\",\"bytes_received\":298,\"bytes_expected\":298,\"client_agent\":\"Transloadit Ruby SDK 0.0.1\",\"client_ip\":\"69.180.12.41\",\"client_referer\":null,\"start_date\":\"2011/02/07 04:29:15 GMT\",\"upload_duration\":0.038,\"execution_duration\":0.002,\"fields\":{},\"uploads\":[],\"results\":{}}"
67
+ http_version: "1.1"
@@ -0,0 +1,16 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+ $:.unshift File.expand_path('../../lib', __FILE__)
3
+
4
+ require 'simplecov'
5
+
6
+ SimpleCov.start { add_filter '/test/' }
7
+
8
+ require 'minitest/autorun'
9
+ require 'transloadit'
10
+ require 'vcr'
11
+
12
+ VCR.config do |c|
13
+ c.cassette_library_dir = 'test/fixtures/cassettes'
14
+ c.default_cassette_options = { :record => :new_episodes }
15
+ c.stub_with :webmock
16
+ end
@@ -0,0 +1,97 @@
1
+ require 'test_helper'
2
+
3
+ describe Transloadit do
4
+ before do
5
+ @key = 'a'
6
+ @secret = 'b'
7
+ end
8
+
9
+ it 'must allow initialization' do
10
+ t = Transloadit.new(:key => @key, :secret => @secret)
11
+ t.must_be_kind_of Transloadit
12
+ end
13
+
14
+ it 'must not be initialized with no arguments' do
15
+ lambda { Transloadit.new }.must_raise ArgumentError
16
+ end
17
+
18
+ it 'must require a key' do
19
+ lambda { Transloadit.new(:secret => @secret) }.must_raise ArgumentError
20
+ end
21
+
22
+ it 'must not require a secret' do
23
+ t = Transloadit.new(:key => @key)
24
+ t.must_be_kind_of Transloadit
25
+ end
26
+
27
+ describe 'when initialized' do
28
+ before do
29
+ @transloadit = Transloadit.new(
30
+ :key => @key,
31
+ :secret => @secret
32
+ )
33
+ end
34
+
35
+ it 'must allow access to the key' do
36
+ @transloadit.key.must_equal @key
37
+ end
38
+
39
+ it 'must allow access to the secret' do
40
+ @transloadit.secret.must_equal @secret
41
+ end
42
+
43
+ it 'must create steps' do
44
+ step = @transloadit.step('/image/resize', :width => 320)
45
+
46
+ step.must_be_kind_of Transloadit::Step
47
+ step.robot. must_equal '/image/resize'
48
+ step.options.must_equal :width => 320
49
+ end
50
+
51
+ it 'must create assemblies' do
52
+ step = @transloadit.step('')
53
+ assembly = @transloadit.assembly :steps => step
54
+
55
+ assembly.must_be_kind_of Transloadit::Assembly
56
+ assembly.steps.must_equal step.to_hash
57
+ end
58
+
59
+ it 'must create assemblies with multiple steps' do
60
+ steps = [
61
+ @transloadit.step(''),
62
+ @transloadit.step(''),
63
+ ]
64
+
65
+ assembly = @transloadit.assembly :steps => steps
66
+ assembly.steps.must_equal steps.inject({}) {|h,s| h.merge s }
67
+ end
68
+
69
+ it 'must inspect like a hash' do
70
+ @transloadit.inspect.must_equal @transloadit.to_hash.inspect
71
+ end
72
+
73
+ it 'must produce Transloadit-compatible hash output' do
74
+ @transloadit.to_hash[:key] .must_equal @key
75
+ @transloadit.to_hash[:expires].
76
+ must_match %r{\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}\+00:00}
77
+ end
78
+
79
+ it 'must produce Transloadit-compatible JSON output' do
80
+ @transloadit.to_json.must_equal @transloadit.to_hash.to_json
81
+ end
82
+ end
83
+
84
+ describe 'with no secret' do
85
+ before do
86
+ @transloadit = Transloadit.new(:key => @key)
87
+ end
88
+
89
+ it 'must not include a secret in its hash output' do
90
+ @transloadit.to_hash.keys.wont_include :secret
91
+ end
92
+
93
+ it 'must not include a secret in its JSON output' do
94
+ @transloadit.to_json.must_equal @transloadit.to_hash.to_json
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,87 @@
1
+ require 'test_helper'
2
+
3
+ describe Transloadit::Assembly do
4
+ before do
5
+ @transloadit = Transloadit.new(:key => '')
6
+ end
7
+
8
+ it 'must allow initialization' do
9
+ Transloadit::Assembly.new(@transloadit).
10
+ must_be_kind_of Transloadit::Assembly
11
+ end
12
+
13
+ describe 'when initialized' do
14
+ before do
15
+ @step = @transloadit.step '/video/thumbs'
16
+ @redirect = 'http://foo.bar/'
17
+
18
+ @assembly = Transloadit::Assembly.new @transloadit,
19
+ :steps => @step,
20
+ :redirect_url => @redirect
21
+ end
22
+
23
+ it 'must store a pointer to the transloadit instance' do
24
+ @assembly.transloadit.must_equal @transloadit
25
+ end
26
+
27
+ it 'must remember the options passed' do
28
+ @assembly.options.must_equal(
29
+ :steps => @step,
30
+ :redirect_url => @redirect
31
+ )
32
+ end
33
+
34
+ it 'must wrap its step in a hash' do
35
+ @assembly.steps.must_equal @step.to_hash
36
+ end
37
+
38
+ it 'must not wrap a nil step' do
39
+ @assembly.options[:steps] = nil
40
+ @assembly.steps.must_equal nil
41
+ end
42
+
43
+ it 'must not wrap a hash step' do
44
+ @assembly.options[:steps] = { :foo => 1 }
45
+ @assembly.steps.must_equal :foo => 1
46
+ end
47
+
48
+ it 'must inspect like a hash' do
49
+ @assembly.inspect.must_equal @assembly.to_hash.inspect
50
+ end
51
+
52
+ it 'must produce Transloadit-compatible hash output' do
53
+ @assembly.to_hash.must_equal(
54
+ :auth => @transloadit.to_hash,
55
+ :steps => @assembly.steps,
56
+ :redirect_url => @redirect
57
+ )
58
+ end
59
+
60
+ it 'must produce Transloadit-compatible JSON output' do
61
+ @assembly.to_json.must_equal @assembly.to_hash.to_json
62
+ end
63
+
64
+ it 'must submit files for upload' do
65
+ VCR.use_cassette 'submit_assembly' do
66
+ response = @assembly.submit! open('lib/transloadit/version.rb')
67
+ response.code.must_equal 302
68
+ response.headers[:location].must_match %r{^http://foo.bar/}
69
+ end
70
+ end
71
+ end
72
+
73
+ describe 'with multiple steps' do
74
+ before do
75
+ @encode = @transloadit.step '/video/encode'
76
+ @thumbs = @transloadit.step '/video/thumbs'
77
+
78
+ @assembly = Transloadit::Assembly.new @transloadit,
79
+ :steps => [ @encode, @thumbs ]
80
+ end
81
+
82
+ it 'must wrap its steps into one hash' do
83
+ @assembly.to_hash[:steps].keys.must_include @encode.name
84
+ @assembly.to_hash[:steps].keys.must_include @thumbs.name
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,5 @@
1
+ require 'test_helper'
2
+
3
+ describe Transloadit::Request do
4
+ it 'should be tested'
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'test_helper'
2
+
3
+ describe Transloadit::Response do
4
+ it 'should be tested'
5
+ end
@@ -0,0 +1,103 @@
1
+ require 'test_helper'
2
+
3
+ describe Transloadit::Step do
4
+ it 'must allow initialization' do
5
+ Transloadit::Step.new('/s3/store').must_be_kind_of Transloadit::Step
6
+ end
7
+
8
+ describe 'when initialized' do
9
+ before do
10
+ @robot = '/s3/store'
11
+ @key = 'aws-access-key-id'
12
+ @secret = 'aws-secret-access-key'
13
+ @bucket = 's3-bucket-name'
14
+
15
+ @step = Transloadit::Step.new '/s3/store',
16
+ :key => @key,
17
+ :secret => @secret,
18
+ :bucket => @bucket
19
+ end
20
+
21
+ it 'must generate a name' do
22
+ @step.name.wont_equal nil
23
+ end
24
+
25
+ it 'must generate a unique name' do
26
+ @step.name.wont_equal Transloadit::Step.new('').name
27
+ end
28
+
29
+ it 'must generate a name with 32 hex characters' do
30
+ @step.name.length.must_equal 32
31
+ end
32
+
33
+ it 'must remember the type' do
34
+ @step.robot.must_equal @robot
35
+ end
36
+
37
+ it 'must remember the parameters' do
38
+ @step.options.must_equal(
39
+ :key => @key,
40
+ :secret => @secret,
41
+ :bucket => @bucket
42
+ )
43
+ end
44
+
45
+ it 'must inspect like a hash' do
46
+ @step.inspect.must_equal @step.to_hash[@step.name].inspect
47
+ end
48
+
49
+ it 'must produce Transloadit-compatible hash output' do
50
+ @step.to_hash.must_equal(
51
+ @step.name => {
52
+ :robot => @robot,
53
+ :key => @key,
54
+ :secret => @secret,
55
+ :bucket => @bucket
56
+ }
57
+ )
58
+ end
59
+
60
+ it 'must produce Transloadit-compatible JSON output' do
61
+ @step.to_json.must_equal @step.to_hash.to_json
62
+ end
63
+ end
64
+
65
+ describe 'when using alternative inputs' do
66
+ before do
67
+ @step = Transloadit::Step.new '/image/resize'
68
+ end
69
+
70
+ it 'must allow using the original file as input' do
71
+ @step.use(:original).must_equal ':original'
72
+ @step.options[:use] .must_equal ':original'
73
+ end
74
+
75
+ it 'must allow using another step' do
76
+ input = Transloadit::Step.new '/video/thumbnail'
77
+
78
+ @step.use(input). must_equal [ input.name ]
79
+ @step.options[:use].must_equal [ input.name ]
80
+ end
81
+
82
+ it 'must allow using multiple steps' do
83
+ inputs = [
84
+ Transloadit::Step.new('/video/thumbnail'),
85
+ Transloadit::Step.new('/image/resize')
86
+ ]
87
+
88
+ @step.use(inputs). must_equal inputs.map {|i| i.name }
89
+ @step.options[:use].must_equal inputs.map {|i| i.name }
90
+ end
91
+
92
+ it 'must allow using nothing' do
93
+ @step.use :original
94
+ @step.use(nil).must_equal nil
95
+ @step.options.keys.wont_include(:use)
96
+ end
97
+
98
+ it 'must include the used steps in the hash output' do
99
+ @step.use(:original). must_equal ':original'
100
+ @step.to_hash[@step.name][:use].must_equal ':original'
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,36 @@
1
+ $:.unshift File.expand_path('../lib', __FILE__)
2
+
3
+ require 'transloadit/version'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = 'transloadit'
7
+ gem.version = Transloadit::VERSION
8
+ gem.platform = Gem::Platform::RUBY
9
+
10
+ gem.authors = %w{ Stephen Touset }
11
+ gem.email = %w{ stephen@touset.org }
12
+ gem.homepage = 'http://github.com/stouset/transloadit/'
13
+
14
+ gem.summary = 'Official Ruby gem for Transloadit'
15
+ gem.description = 'The transloadit gem allows you to automate uploading files through the Transloadit REST API'
16
+
17
+ gem.required_rubygems_version = '>= 1.3.6'
18
+ gem.rubyforge_project = 'transloadit'
19
+
20
+ gem.files = `git ls-files`.split("\n")
21
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
+ gem.require_paths = %w{ lib }
23
+
24
+ gem.add_dependency 'rest-client'
25
+ gem.add_dependency 'json'
26
+
27
+ gem.add_development_dependency 'rake'
28
+ gem.add_development_dependency 'minitest' # needed for < 1.9.2
29
+ gem.add_development_dependency 'simplecov'
30
+
31
+ gem.add_development_dependency 'vcr'
32
+ gem.add_development_dependency 'webmock'
33
+
34
+ gem.add_development_dependency 'yard'
35
+ gem.add_development_dependency 'rdiscount' # for YARD rdoc formatting
36
+ end
metadata ADDED
@@ -0,0 +1,180 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: transloadit
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.0
6
+ platform: ruby
7
+ authors:
8
+ - Stephen
9
+ - Touset
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2011-02-09 00:00:00 -05:00
15
+ default_executable:
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: rest-client
19
+ prerelease: false
20
+ requirement: &id001 !ruby/object:Gem::Requirement
21
+ none: false
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: "0"
26
+ type: :runtime
27
+ version_requirements: *id001
28
+ - !ruby/object:Gem::Dependency
29
+ name: json
30
+ prerelease: false
31
+ requirement: &id002 !ruby/object:Gem::Requirement
32
+ none: false
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: "0"
37
+ type: :runtime
38
+ version_requirements: *id002
39
+ - !ruby/object:Gem::Dependency
40
+ name: rake
41
+ prerelease: false
42
+ requirement: &id003 !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: "0"
48
+ type: :development
49
+ version_requirements: *id003
50
+ - !ruby/object:Gem::Dependency
51
+ name: minitest
52
+ prerelease: false
53
+ requirement: &id004 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ type: :development
60
+ version_requirements: *id004
61
+ - !ruby/object:Gem::Dependency
62
+ name: simplecov
63
+ prerelease: false
64
+ requirement: &id005 !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ type: :development
71
+ version_requirements: *id005
72
+ - !ruby/object:Gem::Dependency
73
+ name: vcr
74
+ prerelease: false
75
+ requirement: &id006 !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "0"
81
+ type: :development
82
+ version_requirements: *id006
83
+ - !ruby/object:Gem::Dependency
84
+ name: webmock
85
+ prerelease: false
86
+ requirement: &id007 !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: "0"
92
+ type: :development
93
+ version_requirements: *id007
94
+ - !ruby/object:Gem::Dependency
95
+ name: yard
96
+ prerelease: false
97
+ requirement: &id008 !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: "0"
103
+ type: :development
104
+ version_requirements: *id008
105
+ - !ruby/object:Gem::Dependency
106
+ name: rdiscount
107
+ prerelease: false
108
+ requirement: &id009 !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: "0"
114
+ type: :development
115
+ version_requirements: *id009
116
+ description: The transloadit gem allows you to automate uploading files through the Transloadit REST API
117
+ email:
118
+ - stephen@touset.org
119
+ executables: []
120
+
121
+ extensions: []
122
+
123
+ extra_rdoc_files: []
124
+
125
+ files:
126
+ - .gitignore
127
+ - Gemfile
128
+ - README.md
129
+ - Rakefile
130
+ - lib/transloadit.rb
131
+ - lib/transloadit/assembly.rb
132
+ - lib/transloadit/request.rb
133
+ - lib/transloadit/response.rb
134
+ - lib/transloadit/response/assembly.rb
135
+ - lib/transloadit/step.rb
136
+ - lib/transloadit/version.rb
137
+ - test/fixtures/cassettes/submit_assembly.yml
138
+ - test/test_helper.rb
139
+ - test/unit/test_transloadit.rb
140
+ - test/unit/transloadit/test_assembly.rb
141
+ - test/unit/transloadit/test_request.rb
142
+ - test/unit/transloadit/test_response.rb
143
+ - test/unit/transloadit/test_step.rb
144
+ - transloadit.gemspec
145
+ has_rdoc: true
146
+ homepage: http://github.com/stouset/transloadit/
147
+ licenses: []
148
+
149
+ post_install_message:
150
+ rdoc_options: []
151
+
152
+ require_paths:
153
+ - lib
154
+ required_ruby_version: !ruby/object:Gem::Requirement
155
+ none: false
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: "0"
160
+ required_rubygems_version: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: 1.3.6
166
+ requirements: []
167
+
168
+ rubyforge_project: transloadit
169
+ rubygems_version: 1.5.0
170
+ signing_key:
171
+ specification_version: 3
172
+ summary: Official Ruby gem for Transloadit
173
+ test_files:
174
+ - test/fixtures/cassettes/submit_assembly.yml
175
+ - test/test_helper.rb
176
+ - test/unit/test_transloadit.rb
177
+ - test/unit/transloadit/test_assembly.rb
178
+ - test/unit/transloadit/test_request.rb
179
+ - test/unit/transloadit/test_response.rb
180
+ - test/unit/transloadit/test_step.rb