attached 0.1.8 → 0.1.9
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/lib/attached.rb +30 -0
- data/lib/attached/attachment.rb +14 -5
- data/lib/attached/processor.rb +23 -39
- data/lib/attached/processor/audio.rb +72 -0
- data/lib/attached/processor/base.rb +48 -0
- data/lib/attached/processor/error.rb +6 -0
- data/lib/attached/processor/image.rb +92 -0
- data/lib/attached/storage.rb +8 -4
- data/lib/attached/storage/aws.rb +4 -4
- data/lib/attached/storage/error.rb +6 -0
- data/lib/attached/version.rb +1 -1
- data/lib/tasks/attached.rake +3 -3
- metadata +8 -4
- data/lib/attached/image.rb +0 -88
data/lib/attached.rb
CHANGED
@@ -65,6 +65,13 @@ module Attached
|
|
65
65
|
attachment_for(name).file?
|
66
66
|
end
|
67
67
|
|
68
|
+
validates_each(name) do |record, attr, value|
|
69
|
+
attachment = record.attachment_for(name)
|
70
|
+
attachment.errors.each do |error|
|
71
|
+
record.errors.add(name, error)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
68
75
|
after_validation do
|
69
76
|
|
70
77
|
self.errors[:"#{name}_size"].each do |message|
|
@@ -128,6 +135,29 @@ module Attached
|
|
128
135
|
end
|
129
136
|
|
130
137
|
|
138
|
+
# Validates an attached extension in a specified set.
|
139
|
+
#
|
140
|
+
# Options:
|
141
|
+
#
|
142
|
+
# * :in - allowed values for attached
|
143
|
+
#
|
144
|
+
# Usage:
|
145
|
+
#
|
146
|
+
# validates_attached_extension :avatar, :in => %w(png jpg)
|
147
|
+
# validates_attached_extension :avatar, :in => [:png, :jpg]
|
148
|
+
# validates_attached_extension :avatar, :in => %w(png jpg), :message => "extension must be :in"
|
149
|
+
# validates_attached_extension :avatar, :in => %w(png jpg), :message => "extension must be :in"
|
150
|
+
|
151
|
+
def validates_attached_extension(name, options = {})
|
152
|
+
|
153
|
+
message = options[:message]
|
154
|
+
message ||= "extension must be specified"
|
155
|
+
|
156
|
+
range = options[:in].map { |element| /element/ }
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
|
131
161
|
# Validates that an attachment is included.
|
132
162
|
#
|
133
163
|
# Options:
|
data/lib/attached/attachment.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
require 'guid'
|
2
2
|
|
3
3
|
require 'attached/storage'
|
4
|
+
require 'attached/storage/error'
|
5
|
+
|
4
6
|
require 'attached/processor'
|
5
|
-
require 'attached/
|
7
|
+
require 'attached/processor/error'
|
6
8
|
|
7
9
|
module Attached
|
8
10
|
|
@@ -13,6 +15,7 @@ module Attached
|
|
13
15
|
attr_reader :name
|
14
16
|
attr_reader :instance
|
15
17
|
attr_reader :queue
|
18
|
+
attr_reader :errors
|
16
19
|
attr_reader :path
|
17
20
|
attr_reader :styles
|
18
21
|
attr_reader :default
|
@@ -66,6 +69,7 @@ module Attached
|
|
66
69
|
@instance = instance
|
67
70
|
|
68
71
|
@queue = {}
|
72
|
+
@errors = []
|
69
73
|
|
70
74
|
@path = options[:path]
|
71
75
|
@styles = options[:styles]
|
@@ -267,13 +271,18 @@ module Attached
|
|
267
271
|
|
268
272
|
def process
|
269
273
|
self.queue[self.default] = self.file
|
274
|
+
|
275
|
+
begin
|
270
276
|
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
277
|
+
self.processors.each do |processor|
|
278
|
+
processor = Attached::Processor.processor(processor)
|
279
|
+
self.styles.each do |style, options|
|
280
|
+
self.queue[style] = processor.process(self.queue[style] || self.file, options, self)
|
275
281
|
end
|
276
282
|
end
|
283
|
+
|
284
|
+
rescue Attached::Processor::Error => error
|
285
|
+
self.errors << error.message
|
277
286
|
end
|
278
287
|
end
|
279
288
|
|
data/lib/attached/processor.rb
CHANGED
@@ -1,48 +1,32 @@
|
|
1
|
-
|
1
|
+
require 'attached/processor/base'
|
2
|
+
require 'attached/processor/audio'
|
3
|
+
require 'attached/processor/image'
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
attr_accessor :file
|
7
|
-
attr_accessor :options
|
8
|
-
attr_accessor :attachment
|
5
|
+
module Attached
|
6
|
+
module Processor
|
9
7
|
|
10
8
|
|
11
|
-
# Create
|
9
|
+
# Create a storage object given a medium and credentials.
|
12
10
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
# * file - The file to be processed.
|
16
|
-
# * options - The options to be applied to the processing.
|
17
|
-
# * attachment - The attachment the processor is being run for.
|
18
|
-
|
19
|
-
def self.process(file, options = {}, attachment = nil)
|
20
|
-
new(file, options, attachment).process
|
21
|
-
end
|
22
|
-
|
23
|
-
|
24
|
-
# Create a processor.
|
11
|
+
# Usage:
|
25
12
|
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
def process
|
42
|
-
raise NotImplementedError.new
|
13
|
+
# Attached::Processor.processor(:audio)
|
14
|
+
# Attached::Processor.processor(:image)
|
15
|
+
# Attached::Processor.processor(Attached::Processor::Video)
|
16
|
+
|
17
|
+
def self.processor(processor)
|
18
|
+
|
19
|
+
return processor if processor.is_a? Attached::Processor::Base
|
20
|
+
|
21
|
+
case processor
|
22
|
+
when :audio then return Attached::Processor::Audio
|
23
|
+
when :image then return Attached::Processor::Image
|
24
|
+
end
|
25
|
+
|
26
|
+
raise "undefined processor '#{processor}'"
|
27
|
+
|
43
28
|
end
|
44
29
|
|
45
30
|
|
46
31
|
end
|
47
|
-
|
48
|
-
end
|
32
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'attached/processor/base'
|
2
|
+
require 'attached/processor/error'
|
3
|
+
|
4
|
+
module Attached
|
5
|
+
module Processor
|
6
|
+
class Audio < Base
|
7
|
+
|
8
|
+
|
9
|
+
attr_reader :path
|
10
|
+
attr_reader :extension
|
11
|
+
attr_reader :preset
|
12
|
+
|
13
|
+
|
14
|
+
# Create a processor.
|
15
|
+
#
|
16
|
+
# Parameters:
|
17
|
+
#
|
18
|
+
# * file - The file to be processed.
|
19
|
+
# * options - The options to be applied to the processing.
|
20
|
+
# * attachment - The attachment the processor is being run for.
|
21
|
+
|
22
|
+
def initialize(file, options = {}, attachment = nil)
|
23
|
+
super
|
24
|
+
|
25
|
+
@path = self.file.path
|
26
|
+
|
27
|
+
@preset = options[:preset]
|
28
|
+
@extension = options[:extension]
|
29
|
+
|
30
|
+
@extension ||= File.extname(self.file.path)
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# Helper function for calling processors.
|
35
|
+
#
|
36
|
+
# Usage:
|
37
|
+
#
|
38
|
+
# self.process
|
39
|
+
|
40
|
+
def process
|
41
|
+
|
42
|
+
result = Tempfile.new(["", self.extension])
|
43
|
+
result.binmode
|
44
|
+
|
45
|
+
begin
|
46
|
+
|
47
|
+
parameters = []
|
48
|
+
|
49
|
+
parameters << "--preset #{self.preset}" if self.preset
|
50
|
+
|
51
|
+
parameters << self.path
|
52
|
+
parameters << result.path
|
53
|
+
|
54
|
+
parameters = parameters.join(" ").squeeze(" ")
|
55
|
+
|
56
|
+
`lame #{parameters}`
|
57
|
+
|
58
|
+
rescue Errno::ENOENT
|
59
|
+
raise "command 'lame' not found: ensure LAME is installed"
|
60
|
+
end
|
61
|
+
|
62
|
+
unless $?.exitstatus == 0
|
63
|
+
raise Attached::Processor::Error, "attachment file must be an audio file"
|
64
|
+
end
|
65
|
+
|
66
|
+
return result
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Attached
|
2
|
+
module Processor
|
3
|
+
class Base
|
4
|
+
|
5
|
+
|
6
|
+
attr_accessor :file
|
7
|
+
attr_accessor :options
|
8
|
+
attr_accessor :attachment
|
9
|
+
|
10
|
+
|
11
|
+
# Create and run a processor.
|
12
|
+
#
|
13
|
+
# Parameters:
|
14
|
+
#
|
15
|
+
# * file - The file to be processed.
|
16
|
+
# * options - The options to be applied to the processing.
|
17
|
+
# * attachment - The attachment the processor is being run for.
|
18
|
+
|
19
|
+
def self.process(file, options = {}, attachment = nil)
|
20
|
+
new(file, options, attachment).process
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
# Create a processor.
|
25
|
+
#
|
26
|
+
# Parameters:
|
27
|
+
#
|
28
|
+
# * file - The file to be processed.
|
29
|
+
# * options - The options to be applied to the processing.
|
30
|
+
# * attachment - The attachment the processor is being run for.
|
31
|
+
|
32
|
+
def initialize(file, options = {}, attachment = nil)
|
33
|
+
@file = file
|
34
|
+
@options = options
|
35
|
+
@attachment = attachment
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
# Run the processor.
|
40
|
+
|
41
|
+
def process
|
42
|
+
raise NotImplementedError.new
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'attached/processor/base'
|
2
|
+
require 'attached/processor/error'
|
3
|
+
|
4
|
+
module Attached
|
5
|
+
module Processor
|
6
|
+
class Image < Base
|
7
|
+
|
8
|
+
|
9
|
+
attr_reader :path
|
10
|
+
attr_reader :extension
|
11
|
+
|
12
|
+
attr_reader :width
|
13
|
+
attr_reader :height
|
14
|
+
attr_reader :operation
|
15
|
+
|
16
|
+
|
17
|
+
# Create a processor.
|
18
|
+
#
|
19
|
+
# Parameters:
|
20
|
+
#
|
21
|
+
# * file - The file to be processed.
|
22
|
+
# * options - The options to be applied to the processing.
|
23
|
+
# * attachment - The attachment the processor is being run for.
|
24
|
+
|
25
|
+
def initialize(file, options = {}, attachment = nil)
|
26
|
+
super
|
27
|
+
|
28
|
+
@path = self.file.path
|
29
|
+
|
30
|
+
@size = options[:size]
|
31
|
+
@extension = options[:extension]
|
32
|
+
|
33
|
+
@width, @height, @operation = @size.match(/(\d*)x?(\d*)(.*)/)[1..3] if @size
|
34
|
+
|
35
|
+
@width ||= options[:width]
|
36
|
+
@height ||= options[:height]
|
37
|
+
@operation ||= options[:operation]
|
38
|
+
|
39
|
+
@extension ||= File.extname(self.file.path)
|
40
|
+
|
41
|
+
@width = Integer(self.width) if self.width
|
42
|
+
@height = Integer(self.height) if self.height
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
# Helper function for calling processors.
|
47
|
+
#
|
48
|
+
# Usage:
|
49
|
+
#
|
50
|
+
# self.process
|
51
|
+
|
52
|
+
def process
|
53
|
+
|
54
|
+
result = Tempfile.new(["", self.extension])
|
55
|
+
result.binmode
|
56
|
+
|
57
|
+
begin
|
58
|
+
|
59
|
+
parameters = []
|
60
|
+
|
61
|
+
parameters << self.path
|
62
|
+
|
63
|
+
if width and height
|
64
|
+
case operation
|
65
|
+
when '#' then parameters << "-resize #{width}x#{height}^ -gravity center -extent #{width}x#{height}"
|
66
|
+
when '<' then parameters << "-resize #{width}x#{height}\\<"
|
67
|
+
when '>' then parameters << "-resize #{width}x#{height}\\>"
|
68
|
+
else parameters << "-resize #{width}x#{height}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
parameters << result.path
|
73
|
+
|
74
|
+
parameters = parameters.join(" ").squeeze(" ")
|
75
|
+
|
76
|
+
`convert #{parameters}`
|
77
|
+
|
78
|
+
rescue Errno::ENOENT
|
79
|
+
raise "command 'convert' not found: ensure ImageMagick is installed"
|
80
|
+
end
|
81
|
+
|
82
|
+
unless $?.exitstatus == 0
|
83
|
+
raise Attached::Processor::Error, "attachment file must be an image file"
|
84
|
+
end
|
85
|
+
|
86
|
+
return result
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/attached/storage.rb
CHANGED
@@ -1,23 +1,27 @@
|
|
1
|
+
require 'attached/storage/base'
|
1
2
|
require 'attached/storage/aws'
|
2
3
|
|
3
4
|
module Attached
|
4
5
|
module Storage
|
5
6
|
|
7
|
+
|
6
8
|
# Create a storage object given a medium and credentials.
|
7
9
|
#
|
8
10
|
# Usage:
|
9
11
|
#
|
10
|
-
# Attached::Storage.
|
11
|
-
# Attached::Storage.
|
12
|
+
# Attached::Storage.storage()
|
13
|
+
# Attached::Storage.storage(:aws)
|
14
|
+
# Attached::Storage.storage(:aws, credentials)
|
12
15
|
|
13
16
|
def self.storage(medium = :aws, credentials = nil)
|
14
17
|
|
15
18
|
case medium
|
16
|
-
|
17
|
-
|
19
|
+
when :aws then return Attached::Storage::AWS.new credentials
|
20
|
+
else raise "undefined storage medium '#{medium}'"
|
18
21
|
end
|
19
22
|
|
20
23
|
end
|
21
24
|
|
25
|
+
|
22
26
|
end
|
23
27
|
end
|
data/lib/attached/storage/aws.rb
CHANGED
@@ -3,7 +3,7 @@ require 'attached/storage/base'
|
|
3
3
|
begin
|
4
4
|
require 'aws/s3'
|
5
5
|
rescue LoadError
|
6
|
-
raise "
|
6
|
+
raise "installation of 'aws/s3' is required before using 'aws' for storage"
|
7
7
|
end
|
8
8
|
|
9
9
|
|
@@ -57,8 +57,8 @@ module Attached
|
|
57
57
|
connect()
|
58
58
|
begin
|
59
59
|
::AWS::S3::S3Object.store(path, file, bucket, :access => access)
|
60
|
-
rescue AWS::S3::NoSuchBucket => e
|
61
|
-
|
60
|
+
rescue ::AWS::S3::NoSuchBucket => e
|
61
|
+
::AWS::S3::Bucket.create(bucket)
|
62
62
|
retry
|
63
63
|
end
|
64
64
|
end
|
@@ -74,7 +74,7 @@ module Attached
|
|
74
74
|
connect()
|
75
75
|
begin
|
76
76
|
::AWS::S3::S3Object.delete(path, bucket)
|
77
|
-
rescue AWS::S3::NoSuchBucket => e
|
77
|
+
rescue ::AWS::S3::NoSuchBucket => e
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
data/lib/attached/version.rb
CHANGED
data/lib/tasks/attached.rake
CHANGED
@@ -3,10 +3,10 @@ namespace :attached do
|
|
3
3
|
desc "Process a given 'model' and 'attachment'."
|
4
4
|
task :process, :model, :attachment, :needs => :environment do |t, args|
|
5
5
|
|
6
|
-
model = args[:model] or raise "
|
7
|
-
attachment = args[:attachment] or raise "
|
6
|
+
model = args[:model] or raise "must specify model"
|
7
|
+
attachment = args[:attachment] or raise "must specify attachment"
|
8
8
|
|
9
|
-
klass = model.camelize.constantize or raise "
|
9
|
+
klass = model.camelize.constantize or raise "invalid model '#{model}'"
|
10
10
|
|
11
11
|
klass.all.each do |instance|
|
12
12
|
instance.send(attachment).reprocess!
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 9
|
9
|
+
version: 0.1.9
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Kevin Sylvestre
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-12-
|
17
|
+
date: 2010-12-23 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -54,11 +54,15 @@ extra_rdoc_files: []
|
|
54
54
|
|
55
55
|
files:
|
56
56
|
- lib/attached/attachment.rb
|
57
|
-
- lib/attached/
|
57
|
+
- lib/attached/processor/audio.rb
|
58
|
+
- lib/attached/processor/base.rb
|
59
|
+
- lib/attached/processor/error.rb
|
60
|
+
- lib/attached/processor/image.rb
|
58
61
|
- lib/attached/processor.rb
|
59
62
|
- lib/attached/railtie.rb
|
60
63
|
- lib/attached/storage/aws.rb
|
61
64
|
- lib/attached/storage/base.rb
|
65
|
+
- lib/attached/storage/error.rb
|
62
66
|
- lib/attached/storage.rb
|
63
67
|
- lib/attached/version.rb
|
64
68
|
- lib/attached.rb
|
data/lib/attached/image.rb
DELETED
@@ -1,88 +0,0 @@
|
|
1
|
-
require 'attached/processor'
|
2
|
-
|
3
|
-
module Attached
|
4
|
-
|
5
|
-
class Image < Processor
|
6
|
-
|
7
|
-
|
8
|
-
attr_reader :path
|
9
|
-
attr_reader :extension
|
10
|
-
|
11
|
-
attr_reader :width
|
12
|
-
attr_reader :height
|
13
|
-
attr_reader :operation
|
14
|
-
|
15
|
-
# Create a processor.
|
16
|
-
#
|
17
|
-
# Parameters:
|
18
|
-
#
|
19
|
-
# * file - The file to be processed.
|
20
|
-
# * options - The options to be applied to the processing.
|
21
|
-
# * attachment - The attachment the processor is being run for.
|
22
|
-
|
23
|
-
def initialize(file, options = {}, attachment = nil)
|
24
|
-
super
|
25
|
-
|
26
|
-
@path = self.file.path
|
27
|
-
|
28
|
-
@size = options[:size]
|
29
|
-
@extension = options[:extension]
|
30
|
-
|
31
|
-
@width, @height, @operation = @size.match(/(\d*)x?(\d*)(.*)/)[1..3] if @size
|
32
|
-
|
33
|
-
@width ||= options[:width]
|
34
|
-
@height ||= options[:height]
|
35
|
-
@operation ||= options[:operation]
|
36
|
-
|
37
|
-
@extension ||= File.extname(self.file.path)
|
38
|
-
|
39
|
-
@width = Integer(self.width)
|
40
|
-
@height = Integer(self.height)
|
41
|
-
|
42
|
-
raise "Image processor requires specification of 'width' or 'size'" unless self.width
|
43
|
-
raise "Image processor requires specification of 'height' or 'size'" unless self.height
|
44
|
-
end
|
45
|
-
|
46
|
-
|
47
|
-
# Helper function for calling processors.
|
48
|
-
#
|
49
|
-
# Usage:
|
50
|
-
#
|
51
|
-
# self.process
|
52
|
-
|
53
|
-
def process
|
54
|
-
result = Tempfile.new(["", self.extension])
|
55
|
-
result.binmode
|
56
|
-
|
57
|
-
begin
|
58
|
-
parameters = []
|
59
|
-
|
60
|
-
parameters << self.path
|
61
|
-
|
62
|
-
case operation
|
63
|
-
when '#' then parameters << "-resize #{width}x#{height}^ -gravity center -extent #{width}x#{height}"
|
64
|
-
when '<' then parameters << "-resize #{width}x#{height}\\<"
|
65
|
-
when '>' then parameters << "-resize #{width}x#{height}\\>"
|
66
|
-
else parameters << "-resize #{width}x#{height}"
|
67
|
-
end
|
68
|
-
|
69
|
-
parameters << result.path
|
70
|
-
|
71
|
-
parameters = parameters.join(" ").squeeze(" ")
|
72
|
-
|
73
|
-
`convert #{parameters}`
|
74
|
-
|
75
|
-
raise "Command 'convert' failed. Ensure upload file is an image and options are correct." unless $?.exitstatus == 0
|
76
|
-
|
77
|
-
rescue Errno::ENOENT
|
78
|
-
|
79
|
-
raise "Command 'convert' not found. Ensure 'Image Magick' is installed."
|
80
|
-
|
81
|
-
end
|
82
|
-
|
83
|
-
return result
|
84
|
-
end
|
85
|
-
|
86
|
-
|
87
|
-
end
|
88
|
-
end
|