attachs 0.4.0 → 0.4.1
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.
- checksums.yaml +4 -4
- data/README.md +35 -3
- data/lib/attachs/attachment.rb +6 -0
- data/lib/attachs/processors/base.rb +25 -0
- data/lib/attachs/processors/thumbnail.rb +69 -0
- data/lib/attachs/storages/base.rb +4 -8
- data/lib/attachs/storages/local.rb +11 -12
- data/lib/attachs/storages/s3.rb +14 -13
- data/lib/attachs/version.rb +1 -1
- data/lib/attachs.rb +6 -4
- data/lib/tasks/attachs.rake +2 -2
- data/test/dummy/log/test.log +7308 -0
- data/test/dummy/public/big/180x150.gif +0 -0
- data/test/dummy/public/medium/180x150.gif +0 -0
- data/test/dummy/public/original/180x150.gif +0 -0
- data/test/dummy/public/original/file.txt +1 -0
- data/test/dummy/public/resized.gif +0 -0
- data/test/dummy/public/small/180x150.gif +0 -0
- data/test/dummy/public/storage/image/5461/big/11/180x150.gif +0 -0
- data/test/dummy/public/storage/image/5461/big/9/180x150.gif +0 -0
- data/test/dummy/public/storage/image/5461/medium/11/180x150.gif +0 -0
- data/test/dummy/public/storage/image/5461/medium/9/180x150.gif +0 -0
- data/test/dummy/public/storage/image/5461/original/11/180x150.gif +0 -0
- data/test/dummy/public/storage/image/5461/original/9/180x150.gif +0 -0
- data/test/dummy/public/storage/image/5461/small/11/180x150.gif +0 -0
- data/test/dummy/public/storage/image/5461/small/9/180x150.gif +0 -0
- data/test/dummy/public/storage/text/11/original/11/file.txt +1 -0
- data/test/dummy/public/storage/text/11/original/9/file.txt +1 -0
- data/test/local_storage_test.rb +15 -15
- data/test/processor_test.rb +46 -0
- data/test/s3_storage_tes.rb +18 -22
- data/test/tasks_test.rb +3 -11
- metadata +38 -5
- data/lib/attachs/tools/magick.rb +0 -52
- data/test/magick_tool_test.rb +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 393185c42c0aec2c323f8d958fa832825ab2b931
|
4
|
+
data.tar.gz: 3d7edbd5e15fbd5ee1eba21bbf9563f345d94fb1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c2d7d87ff89da949369dad068fde6a325fc386eb64f84d839a7f5e09f2fd35fbec582491e905bca766e5979422cef1e67a43c073f907a19889892ad5400e444
|
7
|
+
data.tar.gz: 3696bfd7933332c93cf6747fb1b6600f3e7e1b1a2072be2f625279e1e2a289a9bd0dd523ea0d8785d28483fa5d15b335a54647d016d87210135da8ed9b4fc810
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[](http://badge.fury.io/rb/attachs) [](https://codeclimate.com/github/museways/attachs) [](https://travis-ci.org/museways/attachs)
|
1
|
+
[](http://badge.fury.io/rb/attachs) [](https://codeclimate.com/github/museways/attachs) [](https://travis-ci.org/museways/attachs) [](https://gemnasium.com/museways/attachs)
|
2
2
|
|
3
3
|
# Attachs
|
4
4
|
|
@@ -33,6 +33,7 @@ Attachs.configure do |config|
|
|
33
33
|
config.global_styles = []
|
34
34
|
config.global_convert_options= ''
|
35
35
|
config.convert_options = {}
|
36
|
+
config.default_processors = [:thumbnail]
|
36
37
|
config.default_storage = :local
|
37
38
|
config.default_path = '/:timestamp-:filename'
|
38
39
|
config.base_url = ''
|
@@ -224,6 +225,37 @@ Attachs.configure do |config|
|
|
224
225
|
end
|
225
226
|
```
|
226
227
|
|
228
|
+
## Processors
|
229
|
+
|
230
|
+
To create a custom processor:
|
231
|
+
```ruby
|
232
|
+
class Attachs::Processors::CustomThumbnail
|
233
|
+
|
234
|
+
def initialize(attachment, source)
|
235
|
+
# Custom initialization
|
236
|
+
end
|
237
|
+
|
238
|
+
def process(style, destination)
|
239
|
+
# Custom logic
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
```
|
244
|
+
|
245
|
+
To change the processors in the model:
|
246
|
+
```ruby
|
247
|
+
class User < ActiveRecord::Base
|
248
|
+
has_attached_file :avatar, processors: [:custom_thumbnail]
|
249
|
+
end
|
250
|
+
```
|
251
|
+
|
252
|
+
To change the default processors:
|
253
|
+
```ruby
|
254
|
+
Attachs.configure do |config|
|
255
|
+
config.default_processors = [:custom_thumbnail]
|
256
|
+
end
|
257
|
+
```
|
258
|
+
|
227
259
|
## CDN
|
228
260
|
|
229
261
|
To configure a cdn:
|
@@ -237,12 +269,12 @@ end
|
|
237
269
|
|
238
270
|
To refresh all the styles of some attachment:
|
239
271
|
```
|
240
|
-
bundle exec rake attachs:refresh:all
|
272
|
+
bundle exec rake attachs:refresh:all class=user attachment=avatar
|
241
273
|
```
|
242
274
|
|
243
275
|
To refresh missing styles of some attachment:
|
244
276
|
```
|
245
|
-
bundle exec rake attachs:refresh:missing
|
277
|
+
bundle exec rake attachs:refresh:missing class=user attachment=avatar
|
246
278
|
```
|
247
279
|
|
248
280
|
## Credits
|
data/lib/attachs/attachment.rb
CHANGED
@@ -38,6 +38,12 @@ module Attachs
|
|
38
38
|
@private ||= options[:private] == true
|
39
39
|
end
|
40
40
|
|
41
|
+
def processors
|
42
|
+
@processors ||= (options[:processors] || Attachs.config.default_processors).map do |processor|
|
43
|
+
"Attachs::Processors::#{processor.to_s.classify}".constantize
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
41
47
|
def public?
|
42
48
|
!private?
|
43
49
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Attachs
|
2
|
+
module Processors
|
3
|
+
class Base
|
4
|
+
|
5
|
+
def initialize(attachment, source)
|
6
|
+
@attachment = attachment
|
7
|
+
@source = source
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
attr_reader :attachment, :source
|
13
|
+
|
14
|
+
def run(cmd)
|
15
|
+
stdout, stderr, status = Open3.capture3(cmd)
|
16
|
+
if status.success?
|
17
|
+
stdout.strip
|
18
|
+
else
|
19
|
+
false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Attachs
|
2
|
+
module Processors
|
3
|
+
class Thumbnail < Base
|
4
|
+
|
5
|
+
def initialize(attachment, source)
|
6
|
+
super
|
7
|
+
@width, @height = dimensions(source)
|
8
|
+
end
|
9
|
+
|
10
|
+
def process(style, destination)
|
11
|
+
new_width, new_height, strategy, options = geometry(style)
|
12
|
+
resize source, width, height, new_width, new_height, strategy, options, destination
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
attr_reader :width, :height
|
18
|
+
|
19
|
+
def geometry(style)
|
20
|
+
geometry = Attachs.config.styles[style]
|
21
|
+
width, height = geometry.scan(/[^x]+/).map(&:to_i)
|
22
|
+
case geometry[/!|#/]
|
23
|
+
when '#'
|
24
|
+
strategy = 'cover'
|
25
|
+
when '!'
|
26
|
+
strategy = 'force'
|
27
|
+
else
|
28
|
+
strategy = 'contain'
|
29
|
+
end
|
30
|
+
options = Attachs.config.convert_options[style]
|
31
|
+
[width, height, strategy, options]
|
32
|
+
end
|
33
|
+
|
34
|
+
def resize(source, width, height, new_width, new_height, strategy, custom_options, destination)
|
35
|
+
case strategy
|
36
|
+
when 'cover'
|
37
|
+
ratio = [new_width.to_f/width, new_height.to_f/height].max
|
38
|
+
options = "-resize #{(ratio*width).ceil}x#{(ratio*height).ceil} -gravity center -crop #{new_width}x#{new_height}+0+0"
|
39
|
+
when 'force'
|
40
|
+
options = "-resize #{new_width}x#{new_height}\!"
|
41
|
+
when 'contain'
|
42
|
+
options = "-resize #{new_width}x#{new_height}"
|
43
|
+
end
|
44
|
+
if global_options = Attachs.config.global_convert_options
|
45
|
+
options << " #{global_options}"
|
46
|
+
end
|
47
|
+
if custom_options
|
48
|
+
options << " #{custom_options}"
|
49
|
+
end
|
50
|
+
convert source, options, destination
|
51
|
+
end
|
52
|
+
|
53
|
+
def dimensions(source)
|
54
|
+
if output = identify(source, '-format %wx%h')
|
55
|
+
output.split('x').map(&:to_i)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def convert(source, options, destination)
|
60
|
+
run "convert '#{source}' #{options} '#{destination}'"
|
61
|
+
end
|
62
|
+
|
63
|
+
def identify(source, options)
|
64
|
+
run "identify #{options} '#{source}'"
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -10,12 +10,8 @@ module Attachs
|
|
10
10
|
|
11
11
|
attr_reader :attachment
|
12
12
|
|
13
|
-
def resize(*args)
|
14
|
-
Attachs::Tools::Magick.resize(*args)
|
15
|
-
end
|
16
|
-
|
17
13
|
def template
|
18
|
-
@template
|
14
|
+
@template ||= begin
|
19
15
|
if attachment.exists?
|
20
16
|
(attachment.options[:path] || Attachs.config.default_path).dup
|
21
17
|
else
|
@@ -52,13 +48,13 @@ module Attachs
|
|
52
48
|
when :type
|
53
49
|
attachment.content_type.split('/').first.parameterize
|
54
50
|
when :timestamp
|
55
|
-
|
51
|
+
attachment.updated_at.to_i
|
56
52
|
when :class
|
57
53
|
attachment.record.class.name.parameterize
|
58
54
|
when :id
|
59
55
|
attachment.record.id
|
60
|
-
when :
|
61
|
-
attachment.
|
56
|
+
when :attribute
|
57
|
+
attachment.attribute.to_s.parameterize
|
62
58
|
end.to_s
|
63
59
|
end
|
64
60
|
end
|
@@ -4,7 +4,7 @@ module Attachs
|
|
4
4
|
|
5
5
|
def url(style=:original)
|
6
6
|
if attachment.url?
|
7
|
-
base_url.join(path(style)).
|
7
|
+
"#{base_url.join(path(style))}?#{attachment.updated_at.to_i}"
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -24,13 +24,16 @@ module Attachs
|
|
24
24
|
|
25
25
|
def process_styles(force=false)
|
26
26
|
if attachment.image?
|
27
|
-
attachment.
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
attachment.processors.each do |klass|
|
28
|
+
processor = klass.new(attachment, realpath)
|
29
|
+
attachment.styles.each do |style|
|
30
|
+
if force == true
|
31
|
+
delete realpath(style)
|
32
|
+
end
|
33
|
+
unless File.exist? realpath(style)
|
34
|
+
FileUtils.mkdir_p realpath(style).dirname
|
35
|
+
processor.process style, realpath(style)
|
36
|
+
end
|
34
37
|
end
|
35
38
|
end
|
36
39
|
end
|
@@ -51,10 +54,6 @@ module Attachs
|
|
51
54
|
|
52
55
|
protected
|
53
56
|
|
54
|
-
def move(origin, destination)
|
55
|
-
FileUtils.mv base_path.join(origin), base_path.join(destination)
|
56
|
-
end
|
57
|
-
|
58
57
|
def delete(realpath)
|
59
58
|
if File.exist? realpath
|
60
59
|
File.delete realpath
|
data/lib/attachs/storages/s3.rb
CHANGED
@@ -7,7 +7,7 @@ module Attachs
|
|
7
7
|
options = args.extract_options!
|
8
8
|
style = (args[0] || :original)
|
9
9
|
if Attachs.config.base_url.present?
|
10
|
-
Pathname.new(Attachs.config.base_url
|
10
|
+
Pathname.new(Attachs.config.base_url).join(path(style)).to_s
|
11
11
|
else
|
12
12
|
if options[:ssl].present?
|
13
13
|
secure = options[:ssl]
|
@@ -17,6 +17,8 @@ module Attachs
|
|
17
17
|
secure = Attachs.config.s3[:ssl]
|
18
18
|
end
|
19
19
|
object(style).public_url(secure: secure).to_s
|
20
|
+
end.tap do |url|
|
21
|
+
url << "?#{attachment.updated_at.to_i}"
|
20
22
|
end
|
21
23
|
end
|
22
24
|
end
|
@@ -38,14 +40,17 @@ module Attachs
|
|
38
40
|
end
|
39
41
|
cache[path] = download
|
40
42
|
end
|
41
|
-
attachment.
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
43
|
+
attachment.processors.each do |klass|
|
44
|
+
processor = klass.new(attachment, cache[path].path)
|
45
|
+
attachment.styles.each do |style|
|
46
|
+
if force == true
|
47
|
+
object(style).delete
|
48
|
+
end
|
49
|
+
unless object(style).exists?
|
50
|
+
tmp = Tempfile.new('s3')
|
51
|
+
processor.process style, tmp.path
|
52
|
+
stream tmp, path(style)
|
53
|
+
end
|
49
54
|
end
|
50
55
|
end
|
51
56
|
end
|
@@ -66,10 +71,6 @@ module Attachs
|
|
66
71
|
|
67
72
|
protected
|
68
73
|
|
69
|
-
def move(origin, destination)
|
70
|
-
bucket.objects[origin].move_to(destination)
|
71
|
-
end
|
72
|
-
|
73
74
|
def cache
|
74
75
|
@cache ||= {}
|
75
76
|
end
|
data/lib/attachs/version.rb
CHANGED
data/lib/attachs.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'open3'
|
2
2
|
require 'attachs/attachment'
|
3
|
-
require 'attachs/
|
3
|
+
require 'attachs/processors/base'
|
4
|
+
require 'attachs/processors/thumbnail'
|
4
5
|
require 'attachs/storages/base'
|
5
6
|
require 'attachs/storages/local'
|
6
7
|
require 'attachs/storages/s3'
|
@@ -26,15 +27,16 @@ module Attachs
|
|
26
27
|
def config
|
27
28
|
@config ||= begin
|
28
29
|
ActiveSupport::OrderedOptions.new.tap do |config|
|
30
|
+
config.s3 = { ssl: false }
|
31
|
+
config.base_url = ''
|
29
32
|
config.styles = {}
|
30
33
|
config.interpolations = {}
|
34
|
+
config.convert_options = {}
|
31
35
|
config.global_styles = []
|
32
36
|
config.global_convert_options= ''
|
33
|
-
config.convert_options = {}
|
34
37
|
config.default_storage = :local
|
38
|
+
config.default_processors = [:thumbnail]
|
35
39
|
config.default_path = '/:timestamp-:filename'
|
36
|
-
config.base_url = ''
|
37
|
-
config.s3 = { ssl: false }
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
data/lib/tasks/attachs.rake
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module Attachs
|
2
2
|
module Task
|
3
3
|
def self.process(force)
|
4
|
-
model = ENV['CLASS'].classify.constantize
|
5
|
-
attachment = ENV['ATTACHMENT'].to_sym
|
4
|
+
model = (ENV['class'] || ENV['CLASS']).classify.constantize
|
5
|
+
attachment = (ENV['attachment'] || ENV['ATTACHMENT']).to_sym
|
6
6
|
model.find_each do |record|
|
7
7
|
model.attachments.each do |attr, options|
|
8
8
|
if attr == attachment
|