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.
Files changed (77) hide show
  1. data/.gitignore +2 -0
  2. data/DESCRIPTION.txt +3 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +18 -0
  5. data/Rakefile +64 -0
  6. data/VERSION +1 -0
  7. data/bulldog.gemspec +157 -0
  8. data/lib/bulldog.rb +95 -0
  9. data/lib/bulldog/attachment.rb +49 -0
  10. data/lib/bulldog/attachment/base.rb +167 -0
  11. data/lib/bulldog/attachment/has_dimensions.rb +94 -0
  12. data/lib/bulldog/attachment/image.rb +63 -0
  13. data/lib/bulldog/attachment/maybe.rb +229 -0
  14. data/lib/bulldog/attachment/none.rb +37 -0
  15. data/lib/bulldog/attachment/pdf.rb +63 -0
  16. data/lib/bulldog/attachment/unknown.rb +11 -0
  17. data/lib/bulldog/attachment/video.rb +143 -0
  18. data/lib/bulldog/error.rb +5 -0
  19. data/lib/bulldog/has_attachment.rb +214 -0
  20. data/lib/bulldog/interpolation.rb +73 -0
  21. data/lib/bulldog/missing_file.rb +12 -0
  22. data/lib/bulldog/processor.rb +5 -0
  23. data/lib/bulldog/processor/argument_tree.rb +116 -0
  24. data/lib/bulldog/processor/base.rb +124 -0
  25. data/lib/bulldog/processor/ffmpeg.rb +172 -0
  26. data/lib/bulldog/processor/image_magick.rb +134 -0
  27. data/lib/bulldog/processor/one_shot.rb +19 -0
  28. data/lib/bulldog/reflection.rb +234 -0
  29. data/lib/bulldog/saved_file.rb +19 -0
  30. data/lib/bulldog/stream.rb +186 -0
  31. data/lib/bulldog/style.rb +38 -0
  32. data/lib/bulldog/style_set.rb +101 -0
  33. data/lib/bulldog/tempfile.rb +28 -0
  34. data/lib/bulldog/util.rb +92 -0
  35. data/lib/bulldog/validations.rb +68 -0
  36. data/lib/bulldog/vector2.rb +18 -0
  37. data/rails/init.rb +9 -0
  38. data/script/console +8 -0
  39. data/spec/data/empty.txt +0 -0
  40. data/spec/data/test.jpg +0 -0
  41. data/spec/data/test.mov +0 -0
  42. data/spec/data/test.pdf +0 -0
  43. data/spec/data/test.png +0 -0
  44. data/spec/data/test2.jpg +0 -0
  45. data/spec/helpers/image_creation.rb +8 -0
  46. data/spec/helpers/temporary_directory.rb +25 -0
  47. data/spec/helpers/temporary_models.rb +76 -0
  48. data/spec/helpers/temporary_values.rb +102 -0
  49. data/spec/helpers/test_upload_files.rb +108 -0
  50. data/spec/helpers/time_travel.rb +20 -0
  51. data/spec/integration/data/test.jpg +0 -0
  52. data/spec/integration/lifecycle_hooks_spec.rb +213 -0
  53. data/spec/integration/processing_image_attachments.rb +72 -0
  54. data/spec/integration/processing_video_attachments_spec.rb +82 -0
  55. data/spec/integration/saving_an_attachment_spec.rb +31 -0
  56. data/spec/matchers/file_operations.rb +159 -0
  57. data/spec/spec_helper.rb +76 -0
  58. data/spec/unit/attachment/base_spec.rb +311 -0
  59. data/spec/unit/attachment/image_spec.rb +128 -0
  60. data/spec/unit/attachment/maybe_spec.rb +126 -0
  61. data/spec/unit/attachment/pdf_spec.rb +137 -0
  62. data/spec/unit/attachment/video_spec.rb +176 -0
  63. data/spec/unit/attachment_spec.rb +61 -0
  64. data/spec/unit/has_attachment_spec.rb +700 -0
  65. data/spec/unit/interpolation_spec.rb +108 -0
  66. data/spec/unit/processor/argument_tree_spec.rb +159 -0
  67. data/spec/unit/processor/ffmpeg_spec.rb +467 -0
  68. data/spec/unit/processor/image_magick_spec.rb +260 -0
  69. data/spec/unit/processor/one_shot_spec.rb +70 -0
  70. data/spec/unit/reflection_spec.rb +338 -0
  71. data/spec/unit/stream_spec.rb +234 -0
  72. data/spec/unit/style_set_spec.rb +44 -0
  73. data/spec/unit/style_spec.rb +51 -0
  74. data/spec/unit/validations_spec.rb +491 -0
  75. data/spec/unit/vector2_spec.rb +27 -0
  76. data/tasks/bulldog_tasks.rake +4 -0
  77. metadata +193 -0
@@ -0,0 +1,2 @@
1
+ /pkg
2
+ /tmp
@@ -0,0 +1,3 @@
1
+ = Bulldog
2
+
3
+ Flexible file attachments for active record.
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.
@@ -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.
@@ -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
@@ -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
+
@@ -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