imagery 0.0.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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