bulldog 0.0.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.
- data/.gitignore +2 -0
- data/DESCRIPTION.txt +3 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +64 -0
- data/VERSION +1 -0
- data/bulldog.gemspec +157 -0
- data/lib/bulldog.rb +95 -0
- data/lib/bulldog/attachment.rb +49 -0
- data/lib/bulldog/attachment/base.rb +167 -0
- data/lib/bulldog/attachment/has_dimensions.rb +94 -0
- data/lib/bulldog/attachment/image.rb +63 -0
- data/lib/bulldog/attachment/maybe.rb +229 -0
- data/lib/bulldog/attachment/none.rb +37 -0
- data/lib/bulldog/attachment/pdf.rb +63 -0
- data/lib/bulldog/attachment/unknown.rb +11 -0
- data/lib/bulldog/attachment/video.rb +143 -0
- data/lib/bulldog/error.rb +5 -0
- data/lib/bulldog/has_attachment.rb +214 -0
- data/lib/bulldog/interpolation.rb +73 -0
- data/lib/bulldog/missing_file.rb +12 -0
- data/lib/bulldog/processor.rb +5 -0
- data/lib/bulldog/processor/argument_tree.rb +116 -0
- data/lib/bulldog/processor/base.rb +124 -0
- data/lib/bulldog/processor/ffmpeg.rb +172 -0
- data/lib/bulldog/processor/image_magick.rb +134 -0
- data/lib/bulldog/processor/one_shot.rb +19 -0
- data/lib/bulldog/reflection.rb +234 -0
- data/lib/bulldog/saved_file.rb +19 -0
- data/lib/bulldog/stream.rb +186 -0
- data/lib/bulldog/style.rb +38 -0
- data/lib/bulldog/style_set.rb +101 -0
- data/lib/bulldog/tempfile.rb +28 -0
- data/lib/bulldog/util.rb +92 -0
- data/lib/bulldog/validations.rb +68 -0
- data/lib/bulldog/vector2.rb +18 -0
- data/rails/init.rb +9 -0
- data/script/console +8 -0
- data/spec/data/empty.txt +0 -0
- data/spec/data/test.jpg +0 -0
- data/spec/data/test.mov +0 -0
- data/spec/data/test.pdf +0 -0
- data/spec/data/test.png +0 -0
- data/spec/data/test2.jpg +0 -0
- data/spec/helpers/image_creation.rb +8 -0
- data/spec/helpers/temporary_directory.rb +25 -0
- data/spec/helpers/temporary_models.rb +76 -0
- data/spec/helpers/temporary_values.rb +102 -0
- data/spec/helpers/test_upload_files.rb +108 -0
- data/spec/helpers/time_travel.rb +20 -0
- data/spec/integration/data/test.jpg +0 -0
- data/spec/integration/lifecycle_hooks_spec.rb +213 -0
- data/spec/integration/processing_image_attachments.rb +72 -0
- data/spec/integration/processing_video_attachments_spec.rb +82 -0
- data/spec/integration/saving_an_attachment_spec.rb +31 -0
- data/spec/matchers/file_operations.rb +159 -0
- data/spec/spec_helper.rb +76 -0
- data/spec/unit/attachment/base_spec.rb +311 -0
- data/spec/unit/attachment/image_spec.rb +128 -0
- data/spec/unit/attachment/maybe_spec.rb +126 -0
- data/spec/unit/attachment/pdf_spec.rb +137 -0
- data/spec/unit/attachment/video_spec.rb +176 -0
- data/spec/unit/attachment_spec.rb +61 -0
- data/spec/unit/has_attachment_spec.rb +700 -0
- data/spec/unit/interpolation_spec.rb +108 -0
- data/spec/unit/processor/argument_tree_spec.rb +159 -0
- data/spec/unit/processor/ffmpeg_spec.rb +467 -0
- data/spec/unit/processor/image_magick_spec.rb +260 -0
- data/spec/unit/processor/one_shot_spec.rb +70 -0
- data/spec/unit/reflection_spec.rb +338 -0
- data/spec/unit/stream_spec.rb +234 -0
- data/spec/unit/style_set_spec.rb +44 -0
- data/spec/unit/style_spec.rb +51 -0
- data/spec/unit/validations_spec.rb +491 -0
- data/spec/unit/vector2_spec.rb +27 -0
- data/tasks/bulldog_tasks.rake +4 -0
- metadata +193 -0
data/.gitignore
ADDED
data/DESCRIPTION.txt
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 George Ogata
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
= Bulldog
|
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
|
13
|
+
bump version in a commit by itself I can ignore when I pull)
|
14
|
+
* Send me a pull request. Bonus points for topic branches.
|
15
|
+
|
16
|
+
== Copyright
|
17
|
+
|
18
|
+
Copyright (c) 2009 George Ogata. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
PLUGIN_ROOT = File.dirname(__FILE__)
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'jeweler'
|
9
|
+
Jeweler::Tasks.new do |gem|
|
10
|
+
gem.name = "bulldog"
|
11
|
+
gem.summary = "A heavy-duty paperclip. File attachments for ActiveRecord."
|
12
|
+
gem.description = File.read("#{PLUGIN_ROOT}/DESCRIPTION.txt")
|
13
|
+
gem.email = "george.ogata@gmail.com"
|
14
|
+
gem.homepage = "http://github.com/oggy/bulldog"
|
15
|
+
gem.authors = ["George Ogata"]
|
16
|
+
gem.add_development_dependency "rspec"
|
17
|
+
gem.add_development_dependency "rspec_outlines"
|
18
|
+
gem.add_development_dependency "mocha"
|
19
|
+
end
|
20
|
+
rescue LoadError
|
21
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
22
|
+
end
|
23
|
+
|
24
|
+
require 'rake/rdoctask'
|
25
|
+
Rake::RDocTask.new do |rdoc|
|
26
|
+
if File.exist?('VERSION')
|
27
|
+
version = File.read('VERSION')
|
28
|
+
else
|
29
|
+
version = ""
|
30
|
+
end
|
31
|
+
|
32
|
+
rdoc.rdoc_dir = 'rdoc'
|
33
|
+
rdoc.title = "Bulldog #{version}"
|
34
|
+
rdoc.rdoc_files.include('README*')
|
35
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "Run all specs."
|
39
|
+
task :spec => ['check_dependencies', 'spec:unit', 'spec:integration']
|
40
|
+
|
41
|
+
namespace :spec do
|
42
|
+
Spec::Rake::SpecTask.new(:unit) do |t|
|
43
|
+
t.pattern = 'spec/unit/**/*_spec.rb'
|
44
|
+
t.libs << 'lib' << 'spec'
|
45
|
+
t.spec_opts = ['--options', "\"#{PLUGIN_ROOT}/spec/spec.opts\""]
|
46
|
+
end
|
47
|
+
|
48
|
+
Spec::Rake::SpecTask.new(:integration) do |t|
|
49
|
+
t.pattern = 'spec/integration/**/*_spec.rb'
|
50
|
+
t.libs << 'lib' << 'spec'
|
51
|
+
t.spec_opts = ['--options', "\"#{PLUGIN_ROOT}/spec/spec.opts\""]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
desc "Run all specs in spec directory with RCov"
|
56
|
+
Spec::Rake::SpecTask.new(:rcov) do |t|
|
57
|
+
t.spec_opts = ['--options', "\"#{PLUGIN_ROOT}/spec/spec.opts\""]
|
58
|
+
t.rcov = true
|
59
|
+
t.rcov_opts = lambda do
|
60
|
+
IO.readlines(File.dirname(__FILE__) + "/spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
task :default => :spec
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/bulldog.gemspec
ADDED
@@ -0,0 +1,157 @@
|
|
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{bulldog}
|
8
|
+
s.version = "0.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["George Ogata"]
|
12
|
+
s.date = %q{2009-11-15}
|
13
|
+
s.description = %q{= Bulldog
|
14
|
+
|
15
|
+
Flexible file attachments for active record.
|
16
|
+
}
|
17
|
+
s.email = %q{george.ogata@gmail.com}
|
18
|
+
s.extra_rdoc_files = [
|
19
|
+
"LICENSE",
|
20
|
+
"README.rdoc"
|
21
|
+
]
|
22
|
+
s.files = [
|
23
|
+
".gitignore",
|
24
|
+
"DESCRIPTION.txt",
|
25
|
+
"LICENSE",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"bulldog.gemspec",
|
30
|
+
"lib/bulldog.rb",
|
31
|
+
"lib/bulldog/attachment.rb",
|
32
|
+
"lib/bulldog/attachment/base.rb",
|
33
|
+
"lib/bulldog/attachment/has_dimensions.rb",
|
34
|
+
"lib/bulldog/attachment/image.rb",
|
35
|
+
"lib/bulldog/attachment/maybe.rb",
|
36
|
+
"lib/bulldog/attachment/none.rb",
|
37
|
+
"lib/bulldog/attachment/pdf.rb",
|
38
|
+
"lib/bulldog/attachment/unknown.rb",
|
39
|
+
"lib/bulldog/attachment/video.rb",
|
40
|
+
"lib/bulldog/error.rb",
|
41
|
+
"lib/bulldog/has_attachment.rb",
|
42
|
+
"lib/bulldog/interpolation.rb",
|
43
|
+
"lib/bulldog/missing_file.rb",
|
44
|
+
"lib/bulldog/processor.rb",
|
45
|
+
"lib/bulldog/processor/argument_tree.rb",
|
46
|
+
"lib/bulldog/processor/base.rb",
|
47
|
+
"lib/bulldog/processor/ffmpeg.rb",
|
48
|
+
"lib/bulldog/processor/image_magick.rb",
|
49
|
+
"lib/bulldog/processor/one_shot.rb",
|
50
|
+
"lib/bulldog/reflection.rb",
|
51
|
+
"lib/bulldog/saved_file.rb",
|
52
|
+
"lib/bulldog/stream.rb",
|
53
|
+
"lib/bulldog/style.rb",
|
54
|
+
"lib/bulldog/style_set.rb",
|
55
|
+
"lib/bulldog/tempfile.rb",
|
56
|
+
"lib/bulldog/util.rb",
|
57
|
+
"lib/bulldog/validations.rb",
|
58
|
+
"lib/bulldog/vector2.rb",
|
59
|
+
"rails/init.rb",
|
60
|
+
"script/console",
|
61
|
+
"spec/data/empty.txt",
|
62
|
+
"spec/data/test.jpg",
|
63
|
+
"spec/data/test.mov",
|
64
|
+
"spec/data/test.pdf",
|
65
|
+
"spec/data/test.png",
|
66
|
+
"spec/data/test2.jpg",
|
67
|
+
"spec/helpers/image_creation.rb",
|
68
|
+
"spec/helpers/temporary_directory.rb",
|
69
|
+
"spec/helpers/temporary_models.rb",
|
70
|
+
"spec/helpers/temporary_values.rb",
|
71
|
+
"spec/helpers/test_upload_files.rb",
|
72
|
+
"spec/helpers/time_travel.rb",
|
73
|
+
"spec/integration/data/test.jpg",
|
74
|
+
"spec/integration/lifecycle_hooks_spec.rb",
|
75
|
+
"spec/integration/processing_image_attachments.rb",
|
76
|
+
"spec/integration/processing_video_attachments_spec.rb",
|
77
|
+
"spec/integration/saving_an_attachment_spec.rb",
|
78
|
+
"spec/matchers/file_operations.rb",
|
79
|
+
"spec/spec_helper.rb",
|
80
|
+
"spec/unit/attachment/base_spec.rb",
|
81
|
+
"spec/unit/attachment/image_spec.rb",
|
82
|
+
"spec/unit/attachment/maybe_spec.rb",
|
83
|
+
"spec/unit/attachment/pdf_spec.rb",
|
84
|
+
"spec/unit/attachment/video_spec.rb",
|
85
|
+
"spec/unit/attachment_spec.rb",
|
86
|
+
"spec/unit/has_attachment_spec.rb",
|
87
|
+
"spec/unit/interpolation_spec.rb",
|
88
|
+
"spec/unit/processor/argument_tree_spec.rb",
|
89
|
+
"spec/unit/processor/ffmpeg_spec.rb",
|
90
|
+
"spec/unit/processor/image_magick_spec.rb",
|
91
|
+
"spec/unit/processor/one_shot_spec.rb",
|
92
|
+
"spec/unit/reflection_spec.rb",
|
93
|
+
"spec/unit/stream_spec.rb",
|
94
|
+
"spec/unit/style_set_spec.rb",
|
95
|
+
"spec/unit/style_spec.rb",
|
96
|
+
"spec/unit/validations_spec.rb",
|
97
|
+
"spec/unit/vector2_spec.rb",
|
98
|
+
"tasks/bulldog_tasks.rake"
|
99
|
+
]
|
100
|
+
s.homepage = %q{http://github.com/oggy/bulldog}
|
101
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
102
|
+
s.require_paths = ["lib"]
|
103
|
+
s.rubygems_version = %q{1.3.5}
|
104
|
+
s.summary = %q{A heavy-duty paperclip. File attachments for ActiveRecord.}
|
105
|
+
s.test_files = [
|
106
|
+
"spec/helpers/image_creation.rb",
|
107
|
+
"spec/helpers/temporary_directory.rb",
|
108
|
+
"spec/helpers/temporary_models.rb",
|
109
|
+
"spec/helpers/temporary_values.rb",
|
110
|
+
"spec/helpers/test_upload_files.rb",
|
111
|
+
"spec/helpers/time_travel.rb",
|
112
|
+
"spec/integration/lifecycle_hooks_spec.rb",
|
113
|
+
"spec/integration/processing_image_attachments.rb",
|
114
|
+
"spec/integration/processing_video_attachments_spec.rb",
|
115
|
+
"spec/integration/saving_an_attachment_spec.rb",
|
116
|
+
"spec/matchers/file_operations.rb",
|
117
|
+
"spec/spec_helper.rb",
|
118
|
+
"spec/unit/attachment/base_spec.rb",
|
119
|
+
"spec/unit/attachment/image_spec.rb",
|
120
|
+
"spec/unit/attachment/maybe_spec.rb",
|
121
|
+
"spec/unit/attachment/pdf_spec.rb",
|
122
|
+
"spec/unit/attachment/video_spec.rb",
|
123
|
+
"spec/unit/attachment_spec.rb",
|
124
|
+
"spec/unit/has_attachment_spec.rb",
|
125
|
+
"spec/unit/interpolation_spec.rb",
|
126
|
+
"spec/unit/processor/argument_tree_spec.rb",
|
127
|
+
"spec/unit/processor/ffmpeg_spec.rb",
|
128
|
+
"spec/unit/processor/image_magick_spec.rb",
|
129
|
+
"spec/unit/processor/one_shot_spec.rb",
|
130
|
+
"spec/unit/reflection_spec.rb",
|
131
|
+
"spec/unit/stream_spec.rb",
|
132
|
+
"spec/unit/style_set_spec.rb",
|
133
|
+
"spec/unit/style_spec.rb",
|
134
|
+
"spec/unit/validations_spec.rb",
|
135
|
+
"spec/unit/vector2_spec.rb"
|
136
|
+
]
|
137
|
+
|
138
|
+
if s.respond_to? :specification_version then
|
139
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
140
|
+
s.specification_version = 3
|
141
|
+
|
142
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
143
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
144
|
+
s.add_development_dependency(%q<rspec_outlines>, [">= 0"])
|
145
|
+
s.add_development_dependency(%q<mocha>, [">= 0"])
|
146
|
+
else
|
147
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
148
|
+
s.add_dependency(%q<rspec_outlines>, [">= 0"])
|
149
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
150
|
+
end
|
151
|
+
else
|
152
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
153
|
+
s.add_dependency(%q<rspec_outlines>, [">= 0"])
|
154
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
data/lib/bulldog.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'bulldog/util'
|
2
|
+
module Bulldog
|
3
|
+
extend Util
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'bulldog/error'
|
7
|
+
require 'bulldog/has_attachment'
|
8
|
+
require 'bulldog/validations'
|
9
|
+
require 'bulldog/reflection'
|
10
|
+
require 'bulldog/attachment'
|
11
|
+
require 'bulldog/style'
|
12
|
+
require 'bulldog/style_set'
|
13
|
+
require 'bulldog/interpolation'
|
14
|
+
require 'bulldog/saved_file'
|
15
|
+
require 'bulldog/missing_file'
|
16
|
+
require 'bulldog/processor'
|
17
|
+
require 'bulldog/tempfile'
|
18
|
+
require 'bulldog/stream'
|
19
|
+
require 'bulldog/vector2'
|
20
|
+
|
21
|
+
module Bulldog
|
22
|
+
class << self
|
23
|
+
#
|
24
|
+
# Logger object to log to. Set to nil to omit logging.
|
25
|
+
#
|
26
|
+
attr_accessor :logger
|
27
|
+
|
28
|
+
#
|
29
|
+
# The default path template to use. See the #path configuration
|
30
|
+
# option for #has_attachment.
|
31
|
+
#
|
32
|
+
attr_accessor :default_path_template
|
33
|
+
|
34
|
+
#
|
35
|
+
# The default url template to use. See the #url configuration
|
36
|
+
# option for #has_attachment.
|
37
|
+
#
|
38
|
+
attr_accessor :default_url_template
|
39
|
+
|
40
|
+
#
|
41
|
+
# Define an interpolation token.
|
42
|
+
#
|
43
|
+
# If :<token> appears in a path or URL template, the block will be
|
44
|
+
# called to get the value to substitute in. The block will be
|
45
|
+
# called with 3 arguments: the record, the attachment name, and
|
46
|
+
# the style.
|
47
|
+
#
|
48
|
+
# Example:
|
49
|
+
#
|
50
|
+
# Bulldog.to_interpolate :datestamp do |record, name, style|
|
51
|
+
# Date.today.strftime("%Y%m%d")
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
def to_interpolate(token, &block)
|
55
|
+
Interpolation.to_interpolate(token, &block)
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Register a custom type detector.
|
60
|
+
#
|
61
|
+
# When instantiating an attachment, Bulldog will use the
|
62
|
+
# configured type detector to work out which type of attachment to
|
63
|
+
# use. This method registers a custom type detector which may be
|
64
|
+
# selected in your attachment configuration by just using the
|
65
|
+
# name.
|
66
|
+
#
|
67
|
+
# The given block is passed the record, the attribute name, and
|
68
|
+
# the value as a Bulldog::Stream. The block should return a
|
69
|
+
# symbol representing the attachment type.
|
70
|
+
#
|
71
|
+
# Example:
|
72
|
+
#
|
73
|
+
# Bulldog.to_detect_type_by :file_extension do |record, name, stream|
|
74
|
+
# case File.extname(stream.file_name).sub(/\A\./)
|
75
|
+
# when 'jpg', 'png', 'gif', 'tiff'
|
76
|
+
# :image
|
77
|
+
# when 'mpg', 'avi', 'ogv'
|
78
|
+
# :video
|
79
|
+
# when 'pdf'
|
80
|
+
# :pdf
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
def to_detect_type_by(name, &block)
|
85
|
+
Reflection.to_detect_type_by(name, &block)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
self.logger = nil
|
90
|
+
self.default_path_template = nil
|
91
|
+
self.default_url_template = "/assets/:class/:id.:style.:extension"
|
92
|
+
end
|
93
|
+
|
94
|
+
ActiveRecord::Base.send :include, Bulldog::HasAttachment
|
95
|
+
ActiveRecord::Base.send :include, Bulldog::Validations
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Bulldog
|
2
|
+
module Attachment
|
3
|
+
def self.types_to_classes #:nodoc:
|
4
|
+
@types_to_classes ||= {}
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'bulldog/attachment/maybe'
|
10
|
+
require 'bulldog/attachment/has_dimensions'
|
11
|
+
require 'bulldog/attachment/base'
|
12
|
+
require 'bulldog/attachment/none'
|
13
|
+
require 'bulldog/attachment/image'
|
14
|
+
require 'bulldog/attachment/video'
|
15
|
+
require 'bulldog/attachment/pdf'
|
16
|
+
require 'bulldog/attachment/unknown'
|
17
|
+
|
18
|
+
module Bulldog
|
19
|
+
module Attachment
|
20
|
+
#
|
21
|
+
# Return a new attachment of the specified type.
|
22
|
+
#
|
23
|
+
# If +type+ is nil, then the returned attachment will be None if
|
24
|
+
# the stream is nil, or Unknown otherwise.
|
25
|
+
#
|
26
|
+
def self.of_type(type, record, name, stream)
|
27
|
+
if type.nil?
|
28
|
+
klass = stream ? Unknown : None
|
29
|
+
else
|
30
|
+
klass = class_from_type(type)
|
31
|
+
end
|
32
|
+
klass.new(record, name, stream)
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Return a None attachment for the given record and name.
|
37
|
+
#
|
38
|
+
def self.none(record, name)
|
39
|
+
None.new(record, name, nil)
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Return the class corresponding to the given type.
|
44
|
+
#
|
45
|
+
def self.class_from_type(type)
|
46
|
+
types_to_classes[type]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module Bulldog
|
2
|
+
module Attachment
|
3
|
+
class Base < Maybe
|
4
|
+
#
|
5
|
+
# Return an instance of the record if the stream is valid, nil
|
6
|
+
# otherwise.
|
7
|
+
#
|
8
|
+
def self.try(record, name, stream)
|
9
|
+
attachment = new(record, name, stream)
|
10
|
+
attachment.send(:examine) ? attachment : nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(record, name, stream)
|
14
|
+
@record = record
|
15
|
+
@name = name
|
16
|
+
@stream = stream
|
17
|
+
@value = stream && stream.target
|
18
|
+
@examination_result = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Run the processors for the named event.
|
23
|
+
#
|
24
|
+
def process(event_name, *args)
|
25
|
+
reflection.events[event_name].each do |event|
|
26
|
+
if (types = event.attachment_types)
|
27
|
+
next unless types.include?(type)
|
28
|
+
end
|
29
|
+
processor_type = event.processor_type || default_processor_type
|
30
|
+
processor_class = Processor.const_get(processor_type.to_s.camelize)
|
31
|
+
processor = processor_class.new(self, styles_for_event(event), stream.path)
|
32
|
+
processor.process(*args, &event.callback)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Return the path on the file system where the given style's
|
38
|
+
# image is to be stored.
|
39
|
+
#
|
40
|
+
def path(style_name = reflection.default_style)
|
41
|
+
interpolate_path(style_name)
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Return the URL where the given style's image is to be found.
|
46
|
+
#
|
47
|
+
def url(style_name = reflection.default_style)
|
48
|
+
interpolate_url(style_name)
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# Return the size of the attached file.
|
53
|
+
#
|
54
|
+
def file_size
|
55
|
+
stream.size
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Return the original file name of the attached file.
|
60
|
+
#
|
61
|
+
def file_name
|
62
|
+
@file_name ||= stream.file_name
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# Return the content type of the data.
|
67
|
+
#
|
68
|
+
def content_type
|
69
|
+
@content_type ||= stream.content_type
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# Called when the attachment is saved.
|
74
|
+
#
|
75
|
+
def save
|
76
|
+
return if saved?
|
77
|
+
self.saved = true
|
78
|
+
original_path = interpolate_path(:original)
|
79
|
+
stream.write_to(original_path)
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# Called when the attachment is destroyed, or just before
|
84
|
+
# another attachment is saved in its place.
|
85
|
+
#
|
86
|
+
def destroy
|
87
|
+
delete_files_and_empty_parent_directories
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
# Set any attributes that the attachment is configured to store.
|
92
|
+
#
|
93
|
+
storable_attribute :file_name
|
94
|
+
storable_attribute :file_size
|
95
|
+
storable_attribute :content_type
|
96
|
+
|
97
|
+
#
|
98
|
+
# Ensure the file examination has been run, and return the
|
99
|
+
# result.
|
100
|
+
#
|
101
|
+
def examine
|
102
|
+
if @examination_result.nil?
|
103
|
+
@examination_result = run_examination
|
104
|
+
else
|
105
|
+
@examination_result
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
protected # ---------------------------------------------------
|
110
|
+
|
111
|
+
#
|
112
|
+
# Return the default processor class to use for this attachment.
|
113
|
+
#
|
114
|
+
def default_processor_type
|
115
|
+
:base
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
# Examine the stream.
|
120
|
+
#
|
121
|
+
# Return true if the stream looks like a valid instance of this
|
122
|
+
# attachment type, false otherwise.
|
123
|
+
#
|
124
|
+
def run_examination
|
125
|
+
true
|
126
|
+
end
|
127
|
+
|
128
|
+
private # -------------------------------------------------------
|
129
|
+
|
130
|
+
def styles_for_event(event)
|
131
|
+
if event.styles
|
132
|
+
styles = reflection.styles.slice(*event.styles)
|
133
|
+
else
|
134
|
+
styles = reflection.styles
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
#
|
139
|
+
# Remove the files for this attachment, along with any parent
|
140
|
+
# directories.
|
141
|
+
#
|
142
|
+
def delete_files_and_empty_parent_directories
|
143
|
+
style_names = reflection.styles.map{|style| style.name} << :original
|
144
|
+
# If the attachment was set to nil, we need the original value
|
145
|
+
# to work out what to delete.
|
146
|
+
if column_name = reflection.column_name_for_stored_attribute(:file_name)
|
147
|
+
interpolation_params = {:basename => record.send("#{column_name}_was")}
|
148
|
+
else
|
149
|
+
interpolation_params = {}
|
150
|
+
end
|
151
|
+
style_names.each do |style_name|
|
152
|
+
path = interpolate_path(style_name, interpolation_params) or
|
153
|
+
next
|
154
|
+
FileUtils.rm_f(path)
|
155
|
+
begin
|
156
|
+
loop do
|
157
|
+
path = File.dirname(path)
|
158
|
+
FileUtils.rmdir(path)
|
159
|
+
end
|
160
|
+
rescue Errno::EEXIST, Errno::ENOTEMPTY, Errno::ENOENT, Errno::EINVAL, Errno::ENOTDIR
|
161
|
+
# Can't delete any further.
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|