imagery 0.0.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,109 @@
1
+ require File.expand_path("helper", File.dirname(__FILE__))
2
+
3
+ test "autloads" do
4
+ e = nil
5
+
6
+ begin
7
+ Imagery::S3
8
+ rescue Exception => ex
9
+ e = ex
10
+ end
11
+
12
+ assert e.nil?
13
+ end
14
+
15
+ class Imagery
16
+ include S3
17
+
18
+ s3_bucket "cdn.site.com"
19
+ end
20
+
21
+ test "changes url to an S3 hosted one" do
22
+ i = Imagery.new(:avatar)
23
+
24
+ expect = "http://s3.amazonaws.com/cdn.site.com/missing/avatar/original.jpg"
25
+ assert_equal expect, i.url
26
+ end
27
+
28
+ test "allows an s3_host override" do
29
+ begin
30
+ Imagery.s3_host "https://foo.com"
31
+
32
+ i = Imagery.new(:avatar)
33
+
34
+ expect = "https://foo.com/cdn.site.com/missing/avatar/original.jpg"
35
+ assert_equal expect, i.url
36
+ ensure
37
+ Imagery.s3_host "http://s3.amazonaws.com"
38
+ end
39
+ end
40
+
41
+ test "allows a distribution domain for cloudfront hosted buckets" do
42
+ begin
43
+ Imagery.s3_distribution_domain "https://cdn.site.com"
44
+
45
+ i = Imagery.new(:avatar)
46
+ expect = "https://cdn.site.com/missing/avatar/original.jpg"
47
+ assert_equal expect, i.url
48
+
49
+ i = Imagery.new(:avatar, "1001")
50
+ expect = "https://cdn.site.com/avatar/1001/original.jpg"
51
+ assert_equal expect, i.url
52
+
53
+ ensure
54
+ Imagery.instance_variable_set(:@s3_distribution_domain, nil)
55
+ end
56
+ end
57
+
58
+ # persisting in sandboxed Gateway
59
+ scope do
60
+ setup do
61
+ Imagery.s3_bucket "buck"
62
+
63
+ im = Imagery.new(:avatar, "1001", small: ["100x100"], medium: ["200x200"])
64
+ io = File.open(fixture("r8.jpg"), "rb")
65
+
66
+ [im, io]
67
+ end
68
+
69
+ test "saves all sizes to S3" do |im, io|
70
+ im.save(io)
71
+
72
+ cmds = Imagery::S3::Gateway.commands
73
+
74
+ assert_equal [:store, "avatar/1001/original.jpg", "buck"], cmds.shift
75
+ assert_equal [:store, "avatar/1001/small.jpg", "buck"], cmds.shift
76
+ assert_equal [:store, "avatar/1001/medium.jpg", "buck"], cmds.shift
77
+
78
+ assert cmds.empty?
79
+ end
80
+
81
+ test "doesn't delete when passing same key" do |im, io|
82
+ im.save(io, "1001")
83
+
84
+ cmds = Imagery::S3::Gateway.commands
85
+
86
+ assert_equal [:store, "avatar/1001/original.jpg", "buck"], cmds.shift
87
+ assert_equal [:store, "avatar/1001/small.jpg", "buck"], cmds.shift
88
+ assert_equal [:store, "avatar/1001/medium.jpg", "buck"], cmds.shift
89
+
90
+ assert cmds.empty?
91
+ end
92
+
93
+ test "deletes when passing a different key" do |im, io|
94
+ im.save(io, "1002")
95
+
96
+ cmds = Imagery::S3::Gateway.commands
97
+
98
+ assert_equal [:delete, "avatar/1001/original.jpg", "buck"], cmds.shift
99
+ assert_equal [:delete, "avatar/1001/small.jpg", "buck"], cmds.shift
100
+ assert_equal [:delete, "avatar/1001/medium.jpg", "buck"], cmds.shift
101
+
102
+
103
+ assert_equal [:store, "avatar/1002/original.jpg", "buck"], cmds.shift
104
+ assert_equal [:store, "avatar/1002/small.jpg", "buck"], cmds.shift
105
+ assert_equal [:store, "avatar/1002/medium.jpg", "buck"], cmds.shift
106
+
107
+ assert cmds.empty?
108
+ end
109
+ end
metadata CHANGED
@@ -1,12 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: imagery
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 0
8
- - 6
9
- version: 0.0.6
4
+ prerelease:
5
+ version: 0.2.0
10
6
  platform: ruby
11
7
  authors:
12
8
  - Cyril David
@@ -14,96 +10,38 @@ autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
12
 
17
- date: 2010-07-06 00:00:00 +08:00
13
+ date: 2011-06-23 00:00:00 +08:00
18
14
  default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: escape
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
- none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- segments:
29
- - 0
30
- version: "0"
31
- type: :runtime
32
- version_requirements: *id001
33
- - !ruby/object:Gem::Dependency
34
- name: contest
35
- prerelease: false
36
- requirement: &id002 !ruby/object:Gem::Requirement
37
- none: false
38
- requirements:
39
- - - ">="
40
- - !ruby/object:Gem::Version
41
- segments:
42
- - 0
43
- version: "0"
44
- type: :development
45
- version_requirements: *id002
46
- - !ruby/object:Gem::Dependency
47
- name: aws-s3
48
- prerelease: false
49
- requirement: &id003 !ruby/object:Gem::Requirement
50
- none: false
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- segments:
55
- - 0
56
- version: "0"
57
- type: :development
58
- version_requirements: *id003
59
- - !ruby/object:Gem::Dependency
60
- name: mocha
61
- prerelease: false
62
- requirement: &id004 !ruby/object:Gem::Requirement
63
- none: false
64
- requirements:
65
- - - ">="
66
- - !ruby/object:Gem::Version
67
- segments:
68
- - 0
69
- version: "0"
70
- type: :development
71
- version_requirements: *id004
72
- description: Uses ImageMagick directly underneath. Nuff said.
73
- email: cyx.ucron@gmail.com
15
+ dependencies: []
16
+
17
+ description: Provide a clean and light interface around GraphicsMagick.
18
+ email:
19
+ - me@cyrildavid.com
74
20
  executables: []
75
21
 
76
22
  extensions: []
77
23
 
78
- extra_rdoc_files:
79
- - LICENSE
80
- - README.markdown
24
+ extra_rdoc_files: []
25
+
81
26
  files:
82
- - .document
83
- - .gitignore
84
27
  - LICENSE
85
28
  - README.markdown
86
- - Rakefile
87
- - VERSION
88
- - imagery.gemspec
89
- - lib/imagery.rb
90
29
  - lib/imagery/faking.rb
91
- - lib/imagery/missing.rb
92
- - lib/imagery/model.rb
93
30
  - lib/imagery/s3.rb
94
31
  - lib/imagery/test.rb
95
- - test/fixtures/lake.jpg
32
+ - lib/imagery.rb
33
+ - imagery.gemspec
34
+ - test/faking.rb
96
35
  - test/helper.rb
97
- - test/test_imagery.rb
98
- - test/test_missing.rb
99
- - test/test_with_s3.rb
36
+ - test/imagery.rb
37
+ - test/s3.rb
100
38
  has_rdoc: true
101
- homepage: http://github.com/sinefunc/imagery
39
+ homepage: http://github.com/cyx/imagery
102
40
  licenses: []
103
41
 
104
42
  post_install_message:
105
- rdoc_options:
106
- - --charset=UTF-8
43
+ rdoc_options: []
44
+
107
45
  require_paths:
108
46
  - lib
109
47
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -111,26 +49,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
111
49
  requirements:
112
50
  - - ">="
113
51
  - !ruby/object:Gem::Version
114
- segments:
115
- - 0
116
52
  version: "0"
117
53
  required_rubygems_version: !ruby/object:Gem::Requirement
118
54
  none: false
119
55
  requirements:
120
56
  - - ">="
121
57
  - !ruby/object:Gem::Version
122
- segments:
123
- - 0
124
58
  version: "0"
125
59
  requirements: []
126
60
 
127
61
  rubyforge_project:
128
- rubygems_version: 1.3.7
62
+ rubygems_version: 1.5.2
129
63
  signing_key:
130
64
  specification_version: 3
131
- summary: Image resizing without all the bloat
132
- test_files:
133
- - test/helper.rb
134
- - test/test_imagery.rb
135
- - test/test_missing.rb
136
- - test/test_with_s3.rb
65
+ summary: POROS + GraphicsMagick.
66
+ test_files: []
67
+
data/.document DELETED
@@ -1,5 +0,0 @@
1
- README.rdoc
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- LICENSE
data/.gitignore DELETED
@@ -1,24 +0,0 @@
1
- ## MAC OS
2
- .DS_Store
3
-
4
- ## TEXTMATE
5
- *.tmproj
6
- tmtags
7
-
8
- ## EMACS
9
- *~
10
- \#*
11
- .\#*
12
-
13
- ## VIM
14
- *.swp
15
-
16
- ## PROJECT::GENERAL
17
- coverage
18
- rdoc
19
- pkg
20
-
21
- ## PROJECT::SPECIFIC
22
- /.rvmrc
23
- /.yardoc
24
- /doc
data/Rakefile DELETED
@@ -1,56 +0,0 @@
1
- require 'rubygems'
2
- require 'rake'
3
-
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = "imagery"
8
- gem.summary = %Q{Image resizing without all the bloat}
9
- gem.description = %Q{Uses ImageMagick directly underneath. Nuff said.}
10
- gem.email = "cyx.ucron@gmail.com"
11
- gem.homepage = "http://github.com/sinefunc/imagery"
12
- gem.authors = ["Cyril David"]
13
- gem.add_dependency "escape", ">= 0"
14
- gem.add_development_dependency "contest", ">= 0"
15
- gem.add_development_dependency "aws-s3", ">= 0"
16
- gem.add_development_dependency "mocha", ">= 0"
17
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
- end
19
- Jeweler::GemcutterTasks.new
20
- rescue LoadError
21
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
22
- end
23
-
24
- require 'rake/testtask'
25
- Rake::TestTask.new(:test) do |test|
26
- test.libs << 'lib' << 'test'
27
- test.pattern = 'test/**/test_*.rb'
28
- test.verbose = true
29
- end
30
-
31
- begin
32
- require 'rcov/rcovtask'
33
- Rcov::RcovTask.new do |test|
34
- test.libs << 'test'
35
- test.pattern = 'test/**/test_*.rb'
36
- test.verbose = true
37
- end
38
- rescue LoadError
39
- task :rcov do
40
- abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
41
- end
42
- end
43
-
44
- task :test => :check_dependencies
45
-
46
- task :default => :test
47
-
48
- require 'rake/rdoctask'
49
- Rake::RDocTask.new do |rdoc|
50
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
51
-
52
- rdoc.rdoc_dir = 'rdoc'
53
- rdoc.title = "imagery #{version}"
54
- rdoc.rdoc_files.include('README*')
55
- rdoc.rdoc_files.include('lib/**/*.rb')
56
- end
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.0.6
@@ -1,30 +0,0 @@
1
- module Imagery
2
- module Missing
3
- # Allows you to set the current filename of your photo.
4
- # Much of Imagery::Missing is hinged on this.
5
- #
6
- # @example
7
- #
8
- # Photo = Class.new(Struct.new(:id))
9
- # i = Imagery::Model.new(Photo.new(1001))
10
- # i.extend Imagery::Missing
11
- # i.url == "/photo/1001/original.png"
12
- # # => true
13
- #
14
- # i.existing = "Filename"
15
- # i.url == "/missing/photo/original.png"
16
- # # => true
17
- #
18
- # @see Imagery::Missing#url
19
- #
20
- attr_accessor :existing
21
-
22
- def url(size = self.default_size)
23
- if existing.to_s.empty?
24
- return ['', 'missing', namespace, filename(size)].join('/')
25
- else
26
- super
27
- end
28
- end
29
- end
30
- end
@@ -1,217 +0,0 @@
1
- module Imagery
2
- class Model
3
- UnknownSize = Class.new(StandardError)
4
- UndefinedRoot = Class.new(StandardError)
5
-
6
- @@directory = 'public/system'
7
- @@default = { :original => ["1920x1200>"] }
8
-
9
- # This is typically the database ID, you may also use something
10
- # like a GUID for it, the sky's the limit.
11
- attr :key
12
-
13
- # Used as a grouping scheme, if you name this as `photos` for example,
14
- # you will have public/system/photos as the path.
15
- attr :namespace
16
-
17
- # Returns a single key => value pair hash, defaulting to @@default.
18
- attr :default
19
-
20
- # Returns the directory used which defaults to public/system.
21
- attr :directory
22
-
23
- # Defaulting to :original, the value used here will be the default
24
- # size used when calling Imagery::Model#url and Imagery::Model#file.
25
- attr_accessor :default_size
26
-
27
- # Allows you to define the root of your application, all other paths
28
- # are determined relative to this.
29
- attr_writer :root
30
-
31
- # Allows you to define the different sizes you want as a hash of
32
- # :style => [geometry] pairs.
33
- attr_writer :sizes
34
-
35
- # @param [#id] model any ruby object
36
- # @param [#to_s] key typically the database ID of a model. But you may also
37
- # use anything here just as long as its unique across the
38
- # namespace.
39
- # @param [#to_s] namespace used as a grouping mechanism for your images.
40
- def initialize(model, key = model.id, namespace = namespace_for(model.class))
41
- @key = key.to_s
42
- @namespace = namespace.to_s
43
- @default = @@default
44
- @directory = @@directory
45
- @sizes = {}
46
- @default_size = :original
47
- end
48
-
49
- # Returns all the sizes defined including the default size.
50
- #
51
- # @example
52
- # Photo = Class.new(Struct.new(:id))
53
- # i = Imagery::Model.new(Photo.new(1001))
54
- # i.sizes == { :original => ["1920x1280"] }
55
- # # => true
56
- #
57
- # i.sizes = { :thumb => ["48x48"] }
58
- # i.sizes == { :thumb => ["48x48"], :original => ["1920x1280"] }
59
- # # => true
60
- #
61
- # @return [Hash] size => [dimension] pairs.
62
- def sizes
63
- @sizes.merge(default)
64
- end
65
-
66
- # Gives the absolute file for a specified size.
67
- #
68
- # @example
69
- #
70
- # Photo = Class.new(Struct.new(:id))
71
- # i = Imagery.new(Photo.new(1001))
72
- # i.root = '/tmp'
73
- # i.file(:original) == '/tmp/public/system/photo/1001/original.png
74
- # # => true
75
- #
76
- # i.file(:thumb)
77
- # # raise Imagery::Model::UnknownSize
78
- #
79
- # i.sizes = { :thumb => ["100x100"] }
80
- # i.file(:thumb) == '/tmp/public/system/photo/1001/thumb.png
81
- # # => true
82
- #
83
- # @param [Symbol] size the size specific filename.
84
- # @raise [UnknownSize] if the size is not found in
85
- # Imagery::Model#sizes.
86
- # @return [String] the absolute path of the size specific filename e.g.
87
- # /u/apps/reddit/current/public/system/photo/1/thumb.png
88
- # where photo is the namespace and 1 is the key.
89
- def file(size = self.default_size)
90
- raise UnknownSize, "#{ size } is not defined" unless sizes.has_key?(size)
91
-
92
- root_path(directory, namespace, key, filename(size))
93
- end
94
-
95
- # The Web module is basically here to let plugins override
96
- # the url as they see fit.
97
- #
98
- # @example
99
- # module FunkyUrls
100
- # def url(size = default_size)
101
- # super.gsub('/system', '/funky')
102
- # end
103
- # end
104
- #
105
- # class Imagery::Model
106
- # include FunkyUrls
107
- # end
108
- module Web
109
- # Gives the absolute URI path for use in a web context.
110
- #
111
- # Photo = Class.new(Struct.new(:id))
112
- # i = Imagery.new(Photo.new(1001))
113
- # i.url(:original) == '/system/photo/1001/original.png
114
- # # => true
115
- #
116
- # i.file(:thumb)
117
- # # raise Imagery::Model::UnknownSize
118
- #
119
- # i.sizes = { :thumb => ["100x100"] }
120
- # i.file(:thumb) == '/system/photo/1001/thumb.png
121
- # # => true
122
- #
123
- # @param [Symbol] size the size specific url.
124
- # @raise [UnknownSize] if the size is not found in
125
- # Imagery::Model#sizes.
126
- # @return [String] the absolute URI path of the size specific url e.g.
127
- # /system/photo/1/thumb.png
128
- # where photo is the namespace and 1 is the key.
129
- def url(size = self.default_size)
130
- file(size).split('public').last
131
- end
132
- end
133
- include Web
134
-
135
- # This module is basically here so that plugins like Imagery::S3
136
- # can override #save and #delete and call super.
137
- module Persistence
138
- # Writes the data in `io` and resizes them according to the different
139
- # geometry strings.
140
- #
141
- # @example
142
- #
143
- # Photo = Class.new(Struct.new(:id))
144
- # i = Imagery.new(Photo.new(1001))
145
- # i.root = '/tmp'
146
- # i.size = { :thumb => ["48x48"] }
147
- # i.save(File.open('/path/to/file.jpg'))
148
- #
149
- # File.exist?("/tmp/public/system/photo/1001/thumb.png")
150
- # # => true
151
- #
152
- # File.exist?("/tmp/public/system/photo/1001/original.png")
153
- # # => true
154
- #
155
- # @param [#read] io any object responding to read. Typically
156
- # a Rack filehandle is passed here from a
157
- # controller in rails or a Sinatra handler.
158
- # You may also use File.open to provide a proper
159
- # IO handle.
160
- # @return [true] returns when all other file operations are done.
161
- def save(io)
162
- FileUtils.mkdir_p(File.dirname(tmp))
163
- File.open(tmp, "wb") { |target| target.write(io.read) }
164
- sizes.keys.each { |size| convert(size) }
165
- FileUtils.rm(tmp)
166
-
167
- return true
168
- end
169
-
170
- # Deletes all of the files related to this Imagery::Model instance.
171
- # @return [true] when successfully deleted.
172
- def delete
173
- FileUtils.rm_rf File.dirname(file)
174
- return true
175
- end
176
- end
177
- include Persistence
178
-
179
- private
180
- def tmp
181
- root_path(directory, namespace, key, 'tmp')
182
- end
183
-
184
- def namespace_for(klass)
185
- klass.name.split('::').last.downcase
186
- end
187
-
188
- def filename(size)
189
- "%s.png" % size
190
- end
191
-
192
- def convert(size, geometry = self.sizes[size][0], extent = self.sizes[size][1])
193
- `#{ cmd size }`
194
- end
195
-
196
- def cmd(size, geometry = self.sizes[size][0], extent = self.sizes[size][1])
197
- cmd = [].tap do |cmd|
198
- cmd.push 'convert', tmp
199
- cmd.push '-thumbnail', geometry
200
- cmd.push '-gravity', 'center'
201
- cmd.push '-extent', extent if extent
202
- cmd.push file(size)
203
- end
204
-
205
- Escape.shell_command(cmd)
206
- end
207
-
208
- def root(root = defined?(ROOT_DIR) && ROOT_DIR)
209
- @root ||= root if root
210
- @root || raise(UndefinedRoot, "You must define Imagery::Model#root or have a ROOT_DIR constant present")
211
- end
212
-
213
- def root_path(*args)
214
- File.join(root, *args)
215
- end
216
- end
217
- end