imagery 0.0.1 → 0.0.2
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/.gitignore +2 -0
- data/README.markdown +231 -0
- data/VERSION +1 -1
- data/imagery.gemspec +70 -0
- data/lib/imagery.rb +5 -7
- data/lib/imagery/faking.rb +7 -0
- data/lib/imagery/model.rb +130 -15
- data/lib/imagery/s3.rb +68 -2
- data/lib/imagery/test.rb +17 -0
- data/test/test_imagery.rb +3 -3
- metadata +7 -5
- data/README.rdoc +0 -17
data/.gitignore
CHANGED
data/README.markdown
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
Imagery
|
2
|
+
=======
|
3
|
+
|
4
|
+
(See documentation at [http://labs.sinefunc.com/imagery/doc](http://labs.sinefunc.com/imagery/doc))
|
5
|
+
|
6
|
+
## Image manipulation should be simple. It should be customizable. It should allow for flexibility. Imagery attempts to solve these.
|
7
|
+
|
8
|
+
### Imagery favors:
|
9
|
+
|
10
|
+
1. Simplicity and explicitness over magic DSLs.
|
11
|
+
2. OOP principles such as inheritance and composition.
|
12
|
+
3. Flexibility and extensibility.
|
13
|
+
4. Not being tied to any form of ORM.
|
14
|
+
|
15
|
+
1. Simplicity and Explicitness
|
16
|
+
------------------------------
|
17
|
+
To get started using Imagery you only need ImageMagick, ruby and Imagery of
|
18
|
+
course.
|
19
|
+
|
20
|
+
# on debian based systems
|
21
|
+
sudo apt-get install imagemagick
|
22
|
+
# or maybe using macports
|
23
|
+
sudo port install ImageMagick
|
24
|
+
[sudo] gem install imagery
|
25
|
+
|
26
|
+
Then you may proceed using it.
|
27
|
+
|
28
|
+
require 'rubygems'
|
29
|
+
require 'imagery'
|
30
|
+
|
31
|
+
Photo = Class.new(Struct.new(:id))
|
32
|
+
|
33
|
+
i = Imagery.new(Photo.new(1001))
|
34
|
+
i.root = '/some/path/here'
|
35
|
+
i.sizes = { :thumb => ["48x48^", "48x48"], :large => ["480x320"] }
|
36
|
+
i.save(File.open('/some/path/to/image.jpg'))
|
37
|
+
|
38
|
+
File.exist?('/some/path/here/public/system/photo/1001/thumb.png')
|
39
|
+
# => true
|
40
|
+
|
41
|
+
File.exist?('/some/path/here/public/system/photo/1001/large.png')
|
42
|
+
# => true
|
43
|
+
|
44
|
+
File.exist?('/some/path/here/public/system/photo/1001/original.png')
|
45
|
+
# => true
|
46
|
+
|
47
|
+
# the defaut is to use the .id and the name of the class passed,
|
48
|
+
# but you can specify a different scheme.
|
49
|
+
|
50
|
+
i = Imagery.new(Photo.new(1001), `uuidgen`.strip, "photos")
|
51
|
+
i.root = '/some/path/here'
|
52
|
+
i.file == '/some/path/here/public/system/photos/1c2030a6-6bfa-11df-8997-67a71f1f84c7/original.png'
|
53
|
+
# => true
|
54
|
+
|
55
|
+
2. OOP Principles (that we already know)
|
56
|
+
----------------------------------------
|
57
|
+
|
58
|
+
### Ohm example (See [http://ohm.keyvalue.org](http://ohm.keyvalue.org))
|
59
|
+
|
60
|
+
# Imagery will use ROOT_DIR if its available
|
61
|
+
ROOT_DIR = "/u/apps/site/current"
|
62
|
+
|
63
|
+
class User < Ohm::Model
|
64
|
+
include Ohm::Callbacks
|
65
|
+
|
66
|
+
after :save, :write_avatar
|
67
|
+
|
68
|
+
def avatar=(fp)
|
69
|
+
@avatar_fp = fp
|
70
|
+
end
|
71
|
+
|
72
|
+
def avatar
|
73
|
+
@avatar ||=
|
74
|
+
Imagery.new(self).tap do |i|
|
75
|
+
i.sizes = { :thumb => ["48x48^", "48x48"], :medium => ["120x120"] }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
protected
|
80
|
+
def write_avatar
|
81
|
+
avatar.save(@avatar_fp[:tempfile]) if @avatar_fp
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Since we're using composition, we can customize the dimensions on an
|
86
|
+
# instance level.
|
87
|
+
class Collage < Ohm::Model
|
88
|
+
attribute :width
|
89
|
+
attribute :height
|
90
|
+
|
91
|
+
def photo
|
92
|
+
@photo ||=
|
93
|
+
Imagery.new(self).tap do |i|
|
94
|
+
i.sizes = { :thumb => ["%sx%s" % [width, height]] }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# For cases where we want to use S3 for some and normal filesystem for others
|
100
|
+
class S3Photo < Imagery::Model
|
101
|
+
include Imagery::S3
|
102
|
+
self.s3_bucket = 'my-bucket'
|
103
|
+
end
|
104
|
+
|
105
|
+
# then maybe some other files are using cloudfront
|
106
|
+
class CloudfrontPhoto < Imagery::Model
|
107
|
+
include Imagery::S3
|
108
|
+
self.s3_bucket = 'my-bucket'
|
109
|
+
self.s3_distribution_domain = 'assets.site.com'
|
110
|
+
end
|
111
|
+
|
112
|
+
3. Flexibility and Extensibility
|
113
|
+
--------------------------------
|
114
|
+
### Existing plugins: Faking and S3
|
115
|
+
|
116
|
+
#### Imagery::S3
|
117
|
+
|
118
|
+
As was shown in some examples above you can easily do S3 integration.
|
119
|
+
The access credentials are assumed to be stored in
|
120
|
+
|
121
|
+
ENV["AMAZON_ACCESS_KEY_ID"]
|
122
|
+
ENV["AMAZON_SECRET_ACCESS_KEY"]
|
123
|
+
|
124
|
+
you can do this by setting it on your .bash_profile / .bashrc or just
|
125
|
+
manually setting them somewhere in your appication
|
126
|
+
|
127
|
+
ENV["AMAZON_ACCESS_KEY_ID"] = '_access_key_id_'
|
128
|
+
ENV["AMAZON_SECRET_ACCESS_KEY"] = '_secret_access_key_'
|
129
|
+
|
130
|
+
Now you can just start using it:
|
131
|
+
|
132
|
+
Photo = Class.new(Struct.new(:id))
|
133
|
+
|
134
|
+
class Imagery::Model
|
135
|
+
include Imagery::S3
|
136
|
+
self.s3_bucket = 'my-bucket'
|
137
|
+
end
|
138
|
+
|
139
|
+
i = Imagery.new(Photo.new(1001))
|
140
|
+
i.root = '/tmp'
|
141
|
+
i.save(File.open('/some/path/to/image.jpg'))
|
142
|
+
|
143
|
+
#### Imagery::Faking
|
144
|
+
|
145
|
+
When doing testing, you definitely don't want to run image
|
146
|
+
resizing everytime. Enter Faking.
|
147
|
+
|
148
|
+
# in your test_helper / spec_helper
|
149
|
+
Imagery::Model.send :include, Imagery::Faking
|
150
|
+
Imagery::Model.mode = :fake
|
151
|
+
|
152
|
+
# but what if we want to run it for real on a case to case basis?
|
153
|
+
# sure we can!
|
154
|
+
Imagery::Model.real {
|
155
|
+
# do some imagery testing here
|
156
|
+
}
|
157
|
+
|
158
|
+
#### Imagery::Test
|
159
|
+
|
160
|
+
There is a module you can include in your test context to automate the pattern
|
161
|
+
of testing / faking on an opt-in basis.
|
162
|
+
|
163
|
+
# in your test_helper / spec_helper
|
164
|
+
class Test::Unit::TestCase
|
165
|
+
include Imagery::Test
|
166
|
+
end
|
167
|
+
|
168
|
+
# now when you do some testing... (User assumes the user example above)
|
169
|
+
imagery do |is_real|
|
170
|
+
user = User.new(:avatar => { tempfile: File.open('avatar.jpg') })
|
171
|
+
user.save
|
172
|
+
|
173
|
+
if is_real
|
174
|
+
assert File.exist?(user.avatar.file)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
Running your test suite:
|
179
|
+
|
180
|
+
REAL_IMAGERY=true rake test
|
181
|
+
|
182
|
+
It's off by default though, so you don't have to do anything to make sure
|
183
|
+
Imagery doesn't run.
|
184
|
+
|
185
|
+
### Extending Imagery
|
186
|
+
By making use of standard Ruby idioms, we can easily do lots with it.
|
187
|
+
Exensibility is addressed via Ruby modules for example:
|
188
|
+
|
189
|
+
module Imagery
|
190
|
+
module MogileStore
|
191
|
+
def self.included(base)
|
192
|
+
class << base
|
193
|
+
attr_accessor :mogile_config
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def save(io)
|
198
|
+
if super
|
199
|
+
# do some mogie FS stuff here
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def delete
|
204
|
+
super
|
205
|
+
# remove the mogile stuff here
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# Now just include the module however, whenever you want
|
211
|
+
module Imagery
|
212
|
+
class Model
|
213
|
+
include Imagery::MogileStore
|
214
|
+
self.mogile_config = { :foo => :bar }
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
|
219
|
+
### Note on Patches/Pull Requests
|
220
|
+
|
221
|
+
* Fork the project.
|
222
|
+
* Make your feature addition or bug fix.
|
223
|
+
* Add tests for it. This is important so I don't break it in a
|
224
|
+
future version unintentionally.
|
225
|
+
* Commit, do not mess with rakefile, version, or history.
|
226
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
227
|
+
* Send me a pull request. Bonus points for topic branches.
|
228
|
+
|
229
|
+
### Copyright
|
230
|
+
|
231
|
+
Copyright (c) 2010 Cyril David. See LICENSE for details.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
data/imagery.gemspec
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{imagery}
|
8
|
+
s.version = "0.0.2"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Cyril David"]
|
12
|
+
s.date = %q{2010-05-31}
|
13
|
+
s.description = %q{Uses ImageMagick directly underneath. Nuff said.}
|
14
|
+
s.email = %q{cyx.ucron@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.markdown"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.markdown",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"imagery.gemspec",
|
27
|
+
"lib/imagery.rb",
|
28
|
+
"lib/imagery/faking.rb",
|
29
|
+
"lib/imagery/model.rb",
|
30
|
+
"lib/imagery/s3.rb",
|
31
|
+
"lib/imagery/test.rb",
|
32
|
+
"test/fixtures/lake.jpg",
|
33
|
+
"test/helper.rb",
|
34
|
+
"test/test_imagery.rb",
|
35
|
+
"test/test_with_s3.rb"
|
36
|
+
]
|
37
|
+
s.homepage = %q{http://github.com/sinefunc/imagery}
|
38
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
39
|
+
s.require_paths = ["lib"]
|
40
|
+
s.rubygems_version = %q{1.3.6}
|
41
|
+
s.summary = %q{Image resizing without all the bloat}
|
42
|
+
s.test_files = [
|
43
|
+
"test/helper.rb",
|
44
|
+
"test/test_imagery.rb",
|
45
|
+
"test/test_with_s3.rb"
|
46
|
+
]
|
47
|
+
|
48
|
+
if s.respond_to? :specification_version then
|
49
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
50
|
+
s.specification_version = 3
|
51
|
+
|
52
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
53
|
+
s.add_runtime_dependency(%q<escape>, [">= 0"])
|
54
|
+
s.add_development_dependency(%q<contest>, [">= 0"])
|
55
|
+
s.add_development_dependency(%q<aws-s3>, [">= 0"])
|
56
|
+
s.add_development_dependency(%q<mocha>, [">= 0"])
|
57
|
+
else
|
58
|
+
s.add_dependency(%q<escape>, [">= 0"])
|
59
|
+
s.add_dependency(%q<contest>, [">= 0"])
|
60
|
+
s.add_dependency(%q<aws-s3>, [">= 0"])
|
61
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
62
|
+
end
|
63
|
+
else
|
64
|
+
s.add_dependency(%q<escape>, [">= 0"])
|
65
|
+
s.add_dependency(%q<contest>, [">= 0"])
|
66
|
+
s.add_dependency(%q<aws-s3>, [">= 0"])
|
67
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
data/lib/imagery.rb
CHANGED
@@ -2,19 +2,17 @@ require 'escape'
|
|
2
2
|
require 'fileutils'
|
3
3
|
|
4
4
|
module Imagery
|
5
|
-
VERSION = "0.0.
|
5
|
+
VERSION = "0.0.2"
|
6
6
|
|
7
7
|
autoload :Model, "imagery/model"
|
8
8
|
autoload :Faking, "imagery/faking"
|
9
9
|
autoload :S3, "imagery/s3"
|
10
|
-
|
10
|
+
autoload :Test, "imagery/test"
|
11
|
+
|
12
|
+
# Syntactic sugar for Imagery::Model::new
|
13
|
+
# @see Imagery::Model#initialize for details
|
11
14
|
def new(*args, &blk)
|
12
15
|
Model.new(*args, &blk)
|
13
16
|
end
|
14
17
|
module_function :new
|
15
|
-
|
16
|
-
def faked(&blk)
|
17
|
-
Model.faked(&blk)
|
18
|
-
end
|
19
|
-
module_function :faked
|
20
18
|
end
|
data/lib/imagery/faking.rb
CHANGED
data/lib/imagery/model.rb
CHANGED
@@ -1,41 +1,146 @@
|
|
1
1
|
module Imagery
|
2
2
|
class Model
|
3
3
|
UnknownSize = Class.new(StandardError)
|
4
|
+
|
5
|
+
@@directory = 'public/system'
|
6
|
+
@@default = { :original => ["1920x1200>"] }
|
4
7
|
|
8
|
+
# This is typically the database ID, you may also use something
|
9
|
+
# like a GUID for it, the sky's the limit.
|
5
10
|
attr :key
|
11
|
+
|
12
|
+
# Used as a grouping scheme, if you name this as `photos` for example,
|
13
|
+
# you will have public/system/photos as the path.
|
6
14
|
attr :namespace
|
15
|
+
|
16
|
+
# Returns a single key => value pair hash, defaulting to @@default.
|
7
17
|
attr :default
|
18
|
+
|
19
|
+
# Returns the directory used which defaults to public/system.
|
8
20
|
attr :directory
|
21
|
+
|
22
|
+
# Defaulting to :original, the value used here will be the default
|
23
|
+
# size used when calling Imagery::Model#url and Imagery::Model#file.
|
24
|
+
attr_accessor :default_size
|
9
25
|
|
10
|
-
|
26
|
+
# Allows you to define the root of your application, all other paths
|
27
|
+
# are determined relative to this.
|
28
|
+
attr_writer :root
|
29
|
+
|
30
|
+
# Allows you to define the different sizes you want as a hash of
|
31
|
+
# :style => [geometry] pairs.
|
32
|
+
attr_writer :sizes
|
11
33
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
34
|
+
# @param [#id] model any ruby object
|
35
|
+
# @param [#to_s] key typically the database ID of a model. But you may also
|
36
|
+
# use anything here just as long as its unique across the
|
37
|
+
# namespace.
|
38
|
+
# @param [String] namespace used as a grouping mechanism for your images.
|
39
|
+
def initialize(model, key = model.id, namespace = namespace_for(model.class))
|
40
|
+
@key = key.to_s
|
41
|
+
@namespace = namespace
|
42
|
+
@default = @@default
|
43
|
+
@directory = @@directory
|
44
|
+
@sizes = {}
|
45
|
+
@default_size = :original
|
18
46
|
end
|
19
47
|
|
48
|
+
# Returns all the sizes defined including the default size.
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# Photo = Class.new(Struct.new(:id))
|
52
|
+
# i = Imagery::Model.new(Photo.new(1001))
|
53
|
+
# i.sizes == { :original => ["1920x1280"] }
|
54
|
+
# # => true
|
55
|
+
#
|
56
|
+
# i.sizes = { :thumb => ["48x48"] }
|
57
|
+
# i.sizes == { :thumb => ["48x48"], :original => ["1920x1280"] }
|
58
|
+
# # => true
|
59
|
+
#
|
60
|
+
# @return [Hash] size => [dimension] pairs.
|
20
61
|
def sizes
|
21
|
-
@sizes.merge(
|
62
|
+
@sizes.merge(default)
|
22
63
|
end
|
23
64
|
|
24
|
-
|
65
|
+
# Gives the absolute file for a specified size.
|
66
|
+
#
|
67
|
+
# @example
|
68
|
+
#
|
69
|
+
# Photo = Class.new(Struct.new(:id))
|
70
|
+
# i = Imagery.new(Photo.new(1001))
|
71
|
+
# i.root = '/tmp'
|
72
|
+
# i.file(:original) == '/tmp/public/system/photo/1001/original.png
|
73
|
+
# # => true
|
74
|
+
#
|
75
|
+
# i.file(:thumb)
|
76
|
+
# # raise Imagery::Model::UnknownSize
|
77
|
+
#
|
78
|
+
# i.sizes = { :thumb => ["100x100"] }
|
79
|
+
# i.file(:thumb) == '/tmp/public/system/photo/1001/thumb.png
|
80
|
+
# # => true
|
81
|
+
#
|
82
|
+
# @param [Symbol] size the size specific filename.
|
83
|
+
# @raise [UnknownSize] if the size is not found in
|
84
|
+
# Imagery::Model#sizes.
|
85
|
+
# @return [String] the absolute path of the size specific filename e.g.
|
86
|
+
# /u/apps/reddit/current/public/system/photo/1/thumb.png
|
87
|
+
# where photo is the namespace and 1 is the key.
|
88
|
+
def file(size = self.default_size)
|
25
89
|
raise UnknownSize, "#{ size } is not defined" unless sizes.has_key?(size)
|
26
90
|
|
27
91
|
root_path(directory, namespace, key, filename(size))
|
28
92
|
end
|
29
93
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
94
|
+
# Gives the absolute URI path for use in a web context.
|
95
|
+
#
|
96
|
+
# Photo = Class.new(Struct.new(:id))
|
97
|
+
# i = Imagery.new(Photo.new(1001))
|
98
|
+
# i.url(:original) == '/system/photo/1001/original.png
|
99
|
+
# # => true
|
100
|
+
#
|
101
|
+
# i.file(:thumb)
|
102
|
+
# # raise Imagery::Model::UnknownSize
|
103
|
+
#
|
104
|
+
# i.sizes = { :thumb => ["100x100"] }
|
105
|
+
# i.file(:thumb) == '/system/photo/1001/thumb.png
|
106
|
+
# # => true
|
107
|
+
#
|
108
|
+
# @param [Symbol] size the size specific url.
|
109
|
+
# @raise [UnknownSize] if the size is not found in
|
110
|
+
# Imagery::Model#sizes.
|
111
|
+
# @return [String] the absolute URI path of the size specific url e.g.
|
112
|
+
# /system/photo/1/thumb.png
|
113
|
+
# where photo is the namespace and 1 is the key.
|
114
|
+
def url(size = self.default_size)
|
35
115
|
file(size).split('public').last
|
36
116
|
end
|
37
117
|
|
118
|
+
# This module is basically here so that plugins like Imagery::S3
|
119
|
+
# can override #save and #delete and call super.
|
38
120
|
module Persistence
|
121
|
+
# Writes the data in `io` and resizes them according to the different
|
122
|
+
# geometry strings.
|
123
|
+
#
|
124
|
+
# @example
|
125
|
+
#
|
126
|
+
# Photo = Class.new(Struct.new(:id))
|
127
|
+
# i = Imagery.new(Photo.new(1001))
|
128
|
+
# i.root = '/tmp'
|
129
|
+
# i.size = { :thumb => ["48x48"] }
|
130
|
+
# i.save(File.open('/path/to/file.jpg'))
|
131
|
+
#
|
132
|
+
# File.exist?("/tmp/public/system/photo/1001/thumb.png")
|
133
|
+
# # => true
|
134
|
+
#
|
135
|
+
# File.exist?("/tmp/public/system/photo/1001/original.png")
|
136
|
+
# # => true
|
137
|
+
#
|
138
|
+
# @param [#read] io any object responding to read. Typically
|
139
|
+
# a Rack filehandle is passed here from a
|
140
|
+
# controller in rails or a Sinatra handler.
|
141
|
+
# You may also use File.open to provide a proper
|
142
|
+
# IO handle.
|
143
|
+
# @return [true] returns when all other file operations are done.
|
39
144
|
def save(io)
|
40
145
|
FileUtils.mkdir_p(File.dirname(tmp))
|
41
146
|
File.open(tmp, "wb") { |target| target.write(io.read) }
|
@@ -44,7 +149,9 @@ module Imagery
|
|
44
149
|
|
45
150
|
return true
|
46
151
|
end
|
47
|
-
|
152
|
+
|
153
|
+
# Deletes all of the files related to this Imagery::Model instance.
|
154
|
+
# @return [true] when successfully deleted.
|
48
155
|
def delete
|
49
156
|
FileUtils.rm_rf File.dirname(file)
|
50
157
|
return true
|
@@ -53,6 +160,14 @@ module Imagery
|
|
53
160
|
include Persistence
|
54
161
|
|
55
162
|
private
|
163
|
+
def tmp
|
164
|
+
root_path(directory, namespace, key, 'tmp')
|
165
|
+
end
|
166
|
+
|
167
|
+
def namespace_for(klass)
|
168
|
+
klass.name.split('::').last.downcase
|
169
|
+
end
|
170
|
+
|
56
171
|
def filename(size)
|
57
172
|
"%s.png" % size
|
58
173
|
end
|
data/lib/imagery/s3.rb
CHANGED
@@ -9,8 +9,45 @@ module Imagery
|
|
9
9
|
end
|
10
10
|
|
11
11
|
S3_HOST = "http://s3.amazonaws.com"
|
12
|
-
|
13
|
-
|
12
|
+
|
13
|
+
# Returns a url publicly accessible. If a distribution domain is set,
|
14
|
+
# then the url will be based on that.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
#
|
18
|
+
# class Imagery::Model
|
19
|
+
# include Imagery::S3
|
20
|
+
#
|
21
|
+
# self.s3_bucket = 'bucket-name'
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# Photo = Class.new(Struct.new(:id))
|
25
|
+
# i = Imagery.new(Photo.new(1001))
|
26
|
+
#
|
27
|
+
# i.url == 'http://s3.amazonaws.com/bucket-name/photo/1001/original.png'
|
28
|
+
# # => true
|
29
|
+
#
|
30
|
+
# Imagery::Model.s3_distribution_domain = 'assets.site.com'
|
31
|
+
# i.url == 'http://assets.site.com/photo/1001/original.png'
|
32
|
+
# # => true
|
33
|
+
#
|
34
|
+
# # You may also subclass this of course since it's just a ruby object
|
35
|
+
# # and configure them differently as needed.
|
36
|
+
#
|
37
|
+
# class CloudFront < Imagery::Model
|
38
|
+
# include Imagery::S3
|
39
|
+
# self.s3_bucket = 'cloudfront'
|
40
|
+
# self.s3_distribution_domain = 'assets.site.com'
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# class RegularS3 < Imagery::Model
|
44
|
+
# include Imagery::S3
|
45
|
+
# self.s3_bucket = 'cloudfront'
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# @param [Symbol] size the preferred size you want for the url.
|
49
|
+
# @return [String] the size specific url.
|
50
|
+
def url(size = self.default_size)
|
14
51
|
if domain = self.class.s3_distribution_domain
|
15
52
|
[domain, namespace, key, filename(size)].join('/')
|
16
53
|
else
|
@@ -18,6 +55,8 @@ module Imagery
|
|
18
55
|
end
|
19
56
|
end
|
20
57
|
|
58
|
+
# In addition to saving the files and resizing them locally, uploads all
|
59
|
+
# the different sizes to amazon S3.
|
21
60
|
def save(io)
|
22
61
|
if super
|
23
62
|
s3_object_keys.each do |key, size|
|
@@ -31,6 +70,8 @@ module Imagery
|
|
31
70
|
end
|
32
71
|
end
|
33
72
|
|
73
|
+
# Deletes all the files related to this Imagery instance and also
|
74
|
+
# all the S3 keys.
|
34
75
|
def delete
|
35
76
|
super
|
36
77
|
s3_object_keys.each do |key, size|
|
@@ -46,11 +87,36 @@ module Imagery
|
|
46
87
|
end
|
47
88
|
|
48
89
|
module Gateway
|
90
|
+
# A wrapper for AWS::S3::S3Object.store. Basically auto-connects
|
91
|
+
# using the environment vars.
|
92
|
+
#
|
93
|
+
# @example
|
94
|
+
#
|
95
|
+
# AWS::S3::Base.connected?
|
96
|
+
# # => false
|
97
|
+
#
|
98
|
+
# Imagery::S3::Gateway.store(
|
99
|
+
# 'avatar', File.open('avatar.jpg'), 'bucket'
|
100
|
+
# )
|
101
|
+
# AWS::S3::Base.connected?
|
102
|
+
# # => true
|
103
|
+
#
|
49
104
|
def store(*args)
|
50
105
|
execute(:store, *args)
|
51
106
|
end
|
52
107
|
module_function :store
|
53
108
|
|
109
|
+
# A wrapper for AWS::S3::S3Object.delete. Basically auto-connects
|
110
|
+
# using the environment vars.
|
111
|
+
#
|
112
|
+
# @example
|
113
|
+
#
|
114
|
+
# AWS::S3::Base.connected?
|
115
|
+
# # => false
|
116
|
+
#
|
117
|
+
# Imagery::S3::Gateway.delete('avatar', 'bucket')
|
118
|
+
# AWS::S3::Base.connected?
|
119
|
+
# # => true
|
54
120
|
def delete(*args)
|
55
121
|
execute(:delete, *args)
|
56
122
|
end
|
data/lib/imagery/test.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Imagery
|
2
|
+
module Test
|
3
|
+
def self.included(base)
|
4
|
+
Imagery::Model.send :include, Imagery::Faking
|
5
|
+
Imagery::Model.mode = :fake
|
6
|
+
end
|
7
|
+
|
8
|
+
protected
|
9
|
+
def imagery
|
10
|
+
if ENV["REAL_IMAGERY"]
|
11
|
+
Imagery::Model.real { yield true }
|
12
|
+
else
|
13
|
+
Imagery::Model.faked { yield false }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/test/test_imagery.rb
CHANGED
@@ -19,14 +19,14 @@ class TestImagery < Test::Unit::TestCase
|
|
19
19
|
test "root_path when no ROOT_DIR" do
|
20
20
|
imagery = Imagery.new(Photo.new(1001))
|
21
21
|
imagery.root = '/'
|
22
|
-
assert_equal "/public/system/photo/1001/tmp", imagery.tmp
|
22
|
+
assert_equal "/public/system/photo/1001/tmp", imagery.send(:tmp)
|
23
23
|
end
|
24
24
|
|
25
25
|
test "root_path when ROOT_DIR defined on imagery" do
|
26
26
|
Imagery::ROOT_DIR = '/root/dir'
|
27
27
|
|
28
28
|
imagery = Imagery.new(Photo.new(1001))
|
29
|
-
assert_equal "/root/dir/public/system/photo/1001/tmp", imagery.tmp
|
29
|
+
assert_equal "/root/dir/public/system/photo/1001/tmp", imagery.send(:tmp)
|
30
30
|
|
31
31
|
Imagery.send :remove_const, :ROOT_DIR
|
32
32
|
end
|
@@ -35,7 +35,7 @@ class TestImagery < Test::Unit::TestCase
|
|
35
35
|
Object::ROOT_DIR = '/root/dir'
|
36
36
|
|
37
37
|
imagery = Imagery.new(Photo.new(1001))
|
38
|
-
assert_equal "/root/dir/public/system/photo/1001/tmp", imagery.tmp
|
38
|
+
assert_equal "/root/dir/public/system/photo/1001/tmp", imagery.send(:tmp)
|
39
39
|
|
40
40
|
Object.send :remove_const, :ROOT_DIR
|
41
41
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Cyril David
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-05-
|
17
|
+
date: 2010-05-31 00:00:00 +08:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -73,18 +73,20 @@ extensions: []
|
|
73
73
|
|
74
74
|
extra_rdoc_files:
|
75
75
|
- LICENSE
|
76
|
-
- README.
|
76
|
+
- README.markdown
|
77
77
|
files:
|
78
78
|
- .document
|
79
79
|
- .gitignore
|
80
80
|
- LICENSE
|
81
|
-
- README.
|
81
|
+
- README.markdown
|
82
82
|
- Rakefile
|
83
83
|
- VERSION
|
84
|
+
- imagery.gemspec
|
84
85
|
- lib/imagery.rb
|
85
86
|
- lib/imagery/faking.rb
|
86
87
|
- lib/imagery/model.rb
|
87
88
|
- lib/imagery/s3.rb
|
89
|
+
- lib/imagery/test.rb
|
88
90
|
- test/fixtures/lake.jpg
|
89
91
|
- test/helper.rb
|
90
92
|
- test/test_imagery.rb
|
data/README.rdoc
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
= imagery
|
2
|
-
|
3
|
-
Description goes here.
|
4
|
-
|
5
|
-
== Note on Patches/Pull Requests
|
6
|
-
|
7
|
-
* Fork the project.
|
8
|
-
* Make your feature addition or bug fix.
|
9
|
-
* Add tests for it. This is important so I don't break it in a
|
10
|
-
future version unintentionally.
|
11
|
-
* Commit, do not mess with rakefile, version, or history.
|
12
|
-
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
13
|
-
* Send me a pull request. Bonus points for topic branches.
|
14
|
-
|
15
|
-
== Copyright
|
16
|
-
|
17
|
-
Copyright (c) 2010 Cyril David. See LICENSE for details.
|