upload_juicer 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +0 -0
- data/LICENSE +20 -0
- data/README.md +155 -0
- data/app/controllers/upload_juicer/uploads_controller.rb +8 -0
- data/app/helpers/uploads_helper.rb +43 -0
- data/app/models/upload_juicer/upload.rb +30 -0
- data/config/routes.rb +5 -0
- data/lib/generators/upload_juicer/templates/initializer.rb +1 -0
- data/lib/generators/upload_juicer/templates/migration.rb +20 -0
- data/lib/generators/upload_juicer/upload_juicer_generator.rb +40 -0
- data/lib/upload_juicer/engine.rb +7 -0
- data/lib/upload_juicer/extensions/string.rb +8 -0
- data/lib/upload_juicer/railtie.rb +16 -0
- data/lib/upload_juicer.rb +29 -0
- metadata +101 -0
data/CHANGELOG.md
ADDED
File without changes
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Juicer LLC
|
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.md
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
# Welcome!
|
2
|
+
|
3
|
+
This is a rather simple gem for working the the [Juicer
|
4
|
+
API](http://www.uploadjuicer.com) for resizing images. It's currently pretty
|
5
|
+
rough around the edges (no tests! ack!) but it works. :)
|
6
|
+
|
7
|
+
# The basics
|
8
|
+
|
9
|
+
## Submitting jobs
|
10
|
+
|
11
|
+
The Job class provides two class-level methods for you to interact with the
|
12
|
+
API. First, the `submit` method takes an API key, a source URL, and a array
|
13
|
+
of output hashes. This is POSTed to the API as JSON and a hash is returned to
|
14
|
+
you with the results of the API call. You'll get back a job id, the source URL
|
15
|
+
and the outputs you defined, and an indication of the status ("queued" or
|
16
|
+
"failed").
|
17
|
+
|
18
|
+
Here's an example request to create a job:
|
19
|
+
|
20
|
+
UploadJuicer::Job.submit("your api key",
|
21
|
+
"http://farm3.static.flickr.com/2084/2222523486_5e1894e314.jpg",
|
22
|
+
[{"size" => "100x100>"}])
|
23
|
+
|
24
|
+
=> {"id" => "a string", "outputs" => [{"size" => "100x100>"}], "status" => "queued"}
|
25
|
+
|
26
|
+
You can specify your own destination URLs as S3 locations:
|
27
|
+
|
28
|
+
UploadJuicer::Job.submit("your api key",
|
29
|
+
"http://farm3.static.flickr.com/2084/2222523486_5e1894e314.jpg",
|
30
|
+
[{"size" => "100x100>", "url" => "s3://mybucket/path/to/destfile.jpg"}])
|
31
|
+
|
32
|
+
=> {"id" => "a string", "outputs" => [{"size" => "100x100>", "url" => "s3://mybucket/path/to/destfile.jpg"}], "status" => "queued"}
|
33
|
+
|
34
|
+
When you specify output URLs, those URLs show up in the hash returned when
|
35
|
+
queuing the job. For this to work, you'll need to grant access to Juicer to
|
36
|
+
write to your bucket. You can find Juicer's S3 ID in the documentation at the
|
37
|
+
Juicer site.
|
38
|
+
|
39
|
+
Though size is the only required key in the outputs hashes, you can add other
|
40
|
+
keys (e.g., a label, or your own ids) to the hashes and they will be passed
|
41
|
+
back to you. This could be useful if you aren't specifying output URLs and you
|
42
|
+
want to associate some data with the URLs you'll get back.
|
43
|
+
|
44
|
+
## Querying jobs
|
45
|
+
|
46
|
+
You can use the id that was returned to you as the second argument (after your
|
47
|
+
API key) to the `info` method. The return hash would look exactly like the
|
48
|
+
hash you got back from `submit`, but hopefully the status will now be
|
49
|
+
"finished" rather than "queued" (or "failed").
|
50
|
+
|
51
|
+
# Using Juicer with Rails 3
|
52
|
+
|
53
|
+
The intended usage is to have your users upload files directly to S3 via
|
54
|
+
swfupload, create an UploadJuicer::Upload record via ajax once the upload is
|
55
|
+
complete, and then associate that UploadJuicer::Upload record and call the
|
56
|
+
Juicer API when the record your using is working with (e.g., a Project or a
|
57
|
+
Contact) is created or updated.
|
58
|
+
|
59
|
+
A Rails Engine and a generator is included with this gem to make it easy to
|
60
|
+
integrate Juicer with your Rails application. The engine provides an
|
61
|
+
UploadJuicer::Upload model, an UploadJuicer::Uploads controller, and a helper
|
62
|
+
to use in your app. The generator creates a migration, creates a configuration
|
63
|
+
file, and copies swfupload in place for you to use in your forms.
|
64
|
+
|
65
|
+
To use the generator, either specify your API key that you got from the Juicer
|
66
|
+
site with the --api-key option, or you specify that your API key will be
|
67
|
+
loaded in your Heroku environment (if you are using Juicer as a Heroku add-on)
|
68
|
+
with the --heroku option. After running the generator you'll need to run the
|
69
|
+
migration and edit the config/upload\_juicer.yml file to add your S3
|
70
|
+
credentials and specify which bucket you want to use for your uploads.
|
71
|
+
|
72
|
+
For swfupload to be able to upload to your bucket, you'll need to upload a
|
73
|
+
crossdomain.xml to the top-level of your bucket. A sample crossdomain.xml file
|
74
|
+
is placed in your public directory by the generator.
|
75
|
+
|
76
|
+
## Example
|
77
|
+
|
78
|
+
Once you are all set up, here's an example of how you'd use the gem in a Rails
|
79
|
+
view and model:
|
80
|
+
|
81
|
+
### app/views/people/new.html.erb
|
82
|
+
|
83
|
+
<%= form_for @person do |p| %>
|
84
|
+
<%= p.hidden_field :image_key, :id => :image_key %>
|
85
|
+
<%= p.hidden_field :image_id, :id => :image_id %>
|
86
|
+
|
87
|
+
<p>
|
88
|
+
<%= p.label :name %>
|
89
|
+
<%= p.text_field :name %>
|
90
|
+
</p>
|
91
|
+
|
92
|
+
<div id="file_container"></div>
|
93
|
+
<p id="upload_placeholder" class="uploadify"></p>
|
94
|
+
|
95
|
+
<p><%= p.submit %></p>
|
96
|
+
<% end %>
|
97
|
+
|
98
|
+
<% content_for :head do %>
|
99
|
+
<%= stylesheet_link_tag('swfupload.css') %>
|
100
|
+
<% end %>
|
101
|
+
|
102
|
+
<% content_for :foot do %>
|
103
|
+
<%= javascript_include_tag('swfupload.js', 'uploader.js') %>
|
104
|
+
<script type="text/javascript">
|
105
|
+
$('#upload_placeholder').uploadify(<%= swfupload_params %>);
|
106
|
+
</script>
|
107
|
+
<% end %>
|
108
|
+
|
109
|
+
This view just has two fields, the name and the file that is being uploaded.
|
110
|
+
the reference javascripts are copied into your public directory by the
|
111
|
+
generator. Once the file is selected, the upload begins (and the form is
|
112
|
+
disabled). Once the file is finished uploading, an ajax request is made to the
|
113
|
+
UploadJuicer::Uploads controller to create an UploadJuicer::Upload record, the
|
114
|
+
form is enabled, and the image\_key and image\_id fields are populated with
|
115
|
+
the JSON response from the UploadJuicer::Uploads controller with info about
|
116
|
+
the UploadJuicer::Upload model that was just created. This info is used when
|
117
|
+
the form is submitted to associated the UploadJuicer::Upload with the Person.
|
118
|
+
The Uploads helper provides the `swfupload_params` method, which does all the
|
119
|
+
request signing, etc. that S3 requires.
|
120
|
+
|
121
|
+
### app/models/person.rb
|
122
|
+
|
123
|
+
class Person < ActiveRecord::Base
|
124
|
+
has_one :image, :class_name => 'UploadJuicer::Upload', :as => :uploadable
|
125
|
+
|
126
|
+
after_save :process_image
|
127
|
+
|
128
|
+
attr_accessor :image_key, :image_id
|
129
|
+
|
130
|
+
def process_image
|
131
|
+
return if @image_key.blank? || @image_id.blank?
|
132
|
+
if self.image = UploadJuicer::Upload.first(:conditions => { :key => @image_key, :id => @image_id, :uploadable_id => nil })
|
133
|
+
image.juice_upload(:avatar => { :size => '40x40>' }, :thumb => { :size => '100x100>' })
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
This model simply associates the UploadJuicer::Upload that was created via the
|
139
|
+
AJAX call, then calls the `juice_upload` method with a hash of labels and size
|
140
|
+
info to pass on to the Juicer API. The UploadJuicer::Upload model creates
|
141
|
+
partitioned paths for the files in your S3 bucket like so:
|
142
|
+
|
143
|
+
Original: http://s3.amazonaws.com/your_bucket/34j/e8r/9fu/file_name.jpg
|
144
|
+
Avatar: http://s3.amazonaws.com/your_bucket/34j/e8r/9fu/avatar/file_name.jpg
|
145
|
+
Thumb: http://s3.amazonaws.com/your_bucket/34j/e8r/9fu/thumb/file_name.jpg
|
146
|
+
|
147
|
+
### app/views/person/show.html.erb
|
148
|
+
|
149
|
+
<h1><%= @person.name %></h1>
|
150
|
+
<p>Avatar: <%= image_tag(@person.image.url(:avatar)) %></p>
|
151
|
+
<p>Thumb: <%= image_tag(@person.image.url(:thumb)) %></p>
|
152
|
+
<p>Full image: <%= image_tag(@person.image.url) %></p>
|
153
|
+
|
154
|
+
This view shows how to get the publicly-readable S3 URLs from the
|
155
|
+
UploadJuicer::Upload record associated with the Person.
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module UploadsHelper
|
2
|
+
def s3_post_params(options = {})
|
3
|
+
acl = options[:acl] || 'public-read'
|
4
|
+
expiration = options[:expiration] || 6.hours.from_now.utc.strftime('%Y-%m-%dT%H:%M:%S.000Z')
|
5
|
+
max_filesize = options[:max_filesize] || 2.gigabyte
|
6
|
+
|
7
|
+
policy = Base64.encode64(
|
8
|
+
{ 'expiration' => expiration,
|
9
|
+
'conditions' => [
|
10
|
+
{'bucket' => UploadJuicer::Config.s3['bucket']},
|
11
|
+
['starts-with', '$key', s3_key],
|
12
|
+
{'acl' => acl},
|
13
|
+
{'success_action_status' => '201'},
|
14
|
+
['starts-with', '$Filename', ''],
|
15
|
+
['content-length-range', 0, max_filesize]
|
16
|
+
]
|
17
|
+
}.to_json)
|
18
|
+
|
19
|
+
signature = Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'), UploadJuicer::Config.s3['secret_access_key'], policy)).gsub("\n", "")
|
20
|
+
|
21
|
+
{
|
22
|
+
"key" => "#{s3_key}/${filename}",
|
23
|
+
"AWSAccessKeyId" => "#{UploadJuicer::Config.s3['access_key_id']}",
|
24
|
+
"acl" => "#{acl}",
|
25
|
+
"policy" => "#{policy}",
|
26
|
+
"signature" => "#{signature}",
|
27
|
+
"success_action_status" => "201"
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def s3_key
|
32
|
+
@s3_key ||= SecureRandom.hex(8).scan(/..../).join('/')
|
33
|
+
end
|
34
|
+
|
35
|
+
def s3_upload_url
|
36
|
+
@s3_upload_url ||= "http://#{UploadJuicer::Config.s3['bucket']}.s3.amazonaws.com/"
|
37
|
+
end
|
38
|
+
|
39
|
+
def swfupload_params
|
40
|
+
{ :upload_url => s3_upload_url, :post_params => s3_post_params }.to_json.html_safe
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'upload_juicer'
|
2
|
+
|
3
|
+
class UploadJuicer::Upload < ActiveRecord::Base
|
4
|
+
set_table_name 'upload_juicer_uploads'
|
5
|
+
|
6
|
+
belongs_to :uploadable, :polymorphic => :true
|
7
|
+
|
8
|
+
def url(style = nil)
|
9
|
+
"http://#{UploadJuicer::Config.s3['bucket']}.s3.amazonaws.com/#{s3_path(style)}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def s3_url(style = nil)
|
13
|
+
"s3://#{UploadJuicer::Config.s3['bucket']}/#{s3_path(style)}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def s3_path(style = nil)
|
17
|
+
style = style.to_s
|
18
|
+
style << '/' unless style.blank? || style.ends_with?('/')
|
19
|
+
"#{key}/#{style}#{file_name}"
|
20
|
+
end
|
21
|
+
|
22
|
+
# The outputs var goes from this:
|
23
|
+
# { :avatar => { :size => '40x40>' } }
|
24
|
+
# to this:
|
25
|
+
# [ { :label => 'avatar', :size => '40x40>', :url => s3_url('avatar') } ]
|
26
|
+
def juice_upload(outputs)
|
27
|
+
output_array = outputs.collect {|style, opts| { :label => style.to_s, :url => s3_url(style) }.merge(opts) }
|
28
|
+
UploadJuicer::Job.submit(UploadJuicer::Config.api_key, s3_url, output_array)
|
29
|
+
end
|
30
|
+
end
|
data/config/routes.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
UploadJuicer::Config.api_key = <%= api_key_fetcher %>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class CreateUploadTables < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :upload_juicer_uploads do |t|
|
4
|
+
t.string :file_name
|
5
|
+
t.string :key
|
6
|
+
t.integer :size
|
7
|
+
t.integer :uploadable_id
|
8
|
+
t.string :uploadable_type
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
|
13
|
+
add_index :upload_juicer_uploads, :key
|
14
|
+
add_index :upload_juicer_uploads, [:uploadable_id, :uploadable_type]
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.down
|
18
|
+
drop_table :upload_juicer_uploads
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class UploadJuicerGenerator < Rails::Generators::Base
|
2
|
+
include Rails::Generators::Migration
|
3
|
+
|
4
|
+
desc <<-EOD
|
5
|
+
This generator creates a configuration and migration to use the API at
|
6
|
+
http://uploadjuicer.com in your Rails application. If you signed up for
|
7
|
+
Juicer via Heroku, use the --heroku option to have the API key loaded
|
8
|
+
from your Heroku environment. Otherwise, use the --api_key option to
|
9
|
+
supply the API key you received after signing up at the Juicer site.
|
10
|
+
|
11
|
+
EOD
|
12
|
+
|
13
|
+
class_option :api_key, :type => :string, :desc => "Your Juicer API key"
|
14
|
+
class_option :heroku, :type => :boolean, :desc => "Use the Heroku addon to provide your Juicer API key"
|
15
|
+
|
16
|
+
def self.source_root
|
17
|
+
@source_root ||= File.join(File.dirname(__FILE__), 'templates')
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.next_migration_number(dirname)
|
21
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
22
|
+
end
|
23
|
+
|
24
|
+
def doit
|
25
|
+
if !options[:api_key] && !options[:heroku] && !File.exists?(File.join('config', 'upload_juicer.yml'))
|
26
|
+
puts "Please use --api-key or --heroku or create config/upload_juicer.yml"
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
migration_template 'migration.rb', File.join('db', 'migrate', 'create_upload_tables.rb')
|
30
|
+
template 'config.yml', File.join('config', 'upload_juicer.yml')
|
31
|
+
directory 'public'
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def api_key_fetcher
|
37
|
+
options[:api_key] ? options[:api_key] : "<%= ENV['JUICER_API_KEY'] %>"
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module UploadJuicer
|
2
|
+
def self.rails_init
|
3
|
+
YAML::load(ERB.new(File.read(Rails.root.join('config', 'upload_juicer.yml'))).result)[Rails.env].each { |k, v| UploadJuicer::Config.send("#{k}=", v) } rescue nil
|
4
|
+
end
|
5
|
+
|
6
|
+
if defined?(::Rails::Railtie)
|
7
|
+
class Railtie < ::Rails::Railtie
|
8
|
+
config.after_initialize do |app|
|
9
|
+
UploadJuicer.rails_init
|
10
|
+
end
|
11
|
+
end
|
12
|
+
else
|
13
|
+
rails_init
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'rest_client'
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
module UploadJuicer
|
6
|
+
API_URL = 'http://app.uploadjuicer.com/jobs'
|
7
|
+
VERSION = '0.9.1'
|
8
|
+
|
9
|
+
Config = OpenStruct.new
|
10
|
+
|
11
|
+
class Job
|
12
|
+
def self.submit(api_key, url, outputs)
|
13
|
+
JSON.parse(RestClient.post("#{UploadJuicer::API_URL}?token=#{api_key}&gem=#{UploadJuicer::VERSION}",
|
14
|
+
{ :url => url, :outputs => outputs }.to_json, { :content_type => :json, :accept => :json }))
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.info(api_key, id)
|
18
|
+
JSON.parse(RestClient.get("#{UploadJuicer::API_URL}/#{id}?token=#{api_key}&gem=#{UploadJuicer::VERSION}",
|
19
|
+
{ :content_type => :json, :accept => :json }))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
if defined?(Rails)
|
26
|
+
require 'upload_juicer/extensions/string'
|
27
|
+
require 'upload_juicer/railtie'
|
28
|
+
require 'upload_juicer/engine'
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: upload_juicer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 9
|
8
|
+
- 1
|
9
|
+
version: 0.9.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Benjamin Curtis
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-07-20 00:00:00 -07:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rest-client
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: json
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
segments:
|
40
|
+
- 0
|
41
|
+
version: "0"
|
42
|
+
type: :runtime
|
43
|
+
version_requirements: *id002
|
44
|
+
description:
|
45
|
+
email:
|
46
|
+
- ben@uploadjuicer.com
|
47
|
+
executables: []
|
48
|
+
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files: []
|
52
|
+
|
53
|
+
files:
|
54
|
+
- lib/generators/upload_juicer/templates/initializer.rb
|
55
|
+
- lib/generators/upload_juicer/templates/migration.rb
|
56
|
+
- lib/generators/upload_juicer/upload_juicer_generator.rb
|
57
|
+
- lib/upload_juicer/engine.rb
|
58
|
+
- lib/upload_juicer/extensions/string.rb
|
59
|
+
- lib/upload_juicer/railtie.rb
|
60
|
+
- lib/upload_juicer.rb
|
61
|
+
- app/controllers/upload_juicer/uploads_controller.rb
|
62
|
+
- app/helpers/uploads_helper.rb
|
63
|
+
- app/models/upload_juicer/upload.rb
|
64
|
+
- config/routes.rb
|
65
|
+
- LICENSE
|
66
|
+
- CHANGELOG.md
|
67
|
+
- README.md
|
68
|
+
has_rdoc: true
|
69
|
+
homepage: http://www.uploadjuicer.com
|
70
|
+
licenses: []
|
71
|
+
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
segments:
|
82
|
+
- 0
|
83
|
+
version: "0"
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
segments:
|
89
|
+
- 1
|
90
|
+
- 3
|
91
|
+
- 6
|
92
|
+
version: 1.3.6
|
93
|
+
requirements: []
|
94
|
+
|
95
|
+
rubyforge_project:
|
96
|
+
rubygems_version: 1.3.6
|
97
|
+
signing_key:
|
98
|
+
specification_version: 3
|
99
|
+
summary: UploadJuicer juices up your images!
|
100
|
+
test_files: []
|
101
|
+
|