dragonfly 0.8.6 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of dragonfly might be problematic. Click here for more details.

Files changed (155) hide show
  1. data/{.specopts → .rspec} +0 -1
  2. data/.yardopts +6 -2
  3. data/Gemfile +14 -13
  4. data/History.md +47 -9
  5. data/README.md +25 -5
  6. data/Rakefile +37 -79
  7. data/VERSION +1 -1
  8. data/dragonfly.gemspec +140 -89
  9. data/extra_docs/Analysers.md +8 -48
  10. data/extra_docs/Configuration.md +40 -25
  11. data/extra_docs/Couch.md +49 -0
  12. data/extra_docs/DataStorage.md +94 -24
  13. data/extra_docs/Encoding.md +6 -35
  14. data/extra_docs/ExampleUseCases.md +113 -0
  15. data/extra_docs/GeneralUsage.md +7 -23
  16. data/extra_docs/Generators.md +15 -49
  17. data/extra_docs/Heroku.md +7 -8
  18. data/extra_docs/ImageMagick.md +126 -0
  19. data/extra_docs/MimeTypes.md +3 -3
  20. data/extra_docs/Models.md +163 -0
  21. data/extra_docs/Mongo.md +1 -4
  22. data/extra_docs/Processing.md +7 -60
  23. data/extra_docs/Rails2.md +3 -1
  24. data/extra_docs/Rails3.md +2 -10
  25. data/extra_docs/ServingRemotely.md +83 -0
  26. data/extra_docs/Sinatra.md +3 -3
  27. data/extra_docs/URLs.md +60 -33
  28. data/features/rails_3.0.5.feature +8 -0
  29. data/features/steps/rails_steps.rb +7 -18
  30. data/features/support/env.rb +10 -37
  31. data/features/support/setup.rb +32 -0
  32. data/fixtures/rails_3.0.5/files/app/models/album.rb +5 -0
  33. data/fixtures/rails_3.0.5/files/app/views/albums/new.html.erb +7 -0
  34. data/fixtures/{files → rails_3.0.5/files}/app/views/albums/show.html.erb +2 -0
  35. data/fixtures/{files → rails_3.0.5/files}/config/initializers/dragonfly.rb +0 -0
  36. data/fixtures/rails_3.0.5/files/features/manage_album_images.feature +38 -0
  37. data/fixtures/rails_3.0.5/files/features/step_definitions/helper_steps.rb +7 -0
  38. data/fixtures/{files → rails_3.0.5/files}/features/step_definitions/image_steps.rb +11 -1
  39. data/fixtures/{files → rails_3.0.5/files}/features/support/paths.rb +2 -0
  40. data/fixtures/{files → rails_3.0.5/files}/features/text_images.feature +0 -0
  41. data/fixtures/{rails_3.0.3 → rails_3.0.5}/template.rb +2 -2
  42. data/irbrc.rb +2 -1
  43. data/lib/dragonfly.rb +7 -0
  44. data/lib/dragonfly/active_model_extensions/attachment.rb +134 -46
  45. data/lib/dragonfly/active_model_extensions/attachment_class_methods.rb +144 -0
  46. data/lib/dragonfly/active_model_extensions/class_methods.rb +62 -9
  47. data/lib/dragonfly/active_model_extensions/instance_methods.rb +2 -2
  48. data/lib/dragonfly/active_model_extensions/validations.rb +10 -6
  49. data/lib/dragonfly/analyser.rb +0 -1
  50. data/lib/dragonfly/analysis/file_command_analyser.rb +1 -1
  51. data/lib/dragonfly/analysis/image_magick_analyser.rb +2 -43
  52. data/lib/dragonfly/app.rb +64 -55
  53. data/lib/dragonfly/config/heroku.rb +1 -1
  54. data/lib/dragonfly/config/image_magick.rb +2 -37
  55. data/lib/dragonfly/config/rails.rb +5 -2
  56. data/lib/dragonfly/configurable.rb +115 -35
  57. data/lib/dragonfly/core_ext/object.rb +1 -1
  58. data/lib/dragonfly/core_ext/string.rb +1 -1
  59. data/lib/dragonfly/data_storage/couch_data_store.rb +84 -0
  60. data/lib/dragonfly/data_storage/file_data_store.rb +43 -18
  61. data/lib/dragonfly/data_storage/mongo_data_store.rb +8 -4
  62. data/lib/dragonfly/data_storage/s3data_store.rb +82 -38
  63. data/lib/dragonfly/encoding/image_magick_encoder.rb +2 -53
  64. data/lib/dragonfly/function_manager.rb +4 -2
  65. data/lib/dragonfly/generation/image_magick_generator.rb +2 -136
  66. data/lib/dragonfly/hash_with_css_style_keys.rb +21 -0
  67. data/lib/dragonfly/image_magick/analyser.rb +51 -0
  68. data/lib/dragonfly/image_magick/config.rb +44 -0
  69. data/lib/dragonfly/{encoding/r_magick_encoder.rb → image_magick/encoder.rb} +10 -14
  70. data/lib/dragonfly/image_magick/generator.rb +145 -0
  71. data/lib/dragonfly/image_magick/processor.rb +104 -0
  72. data/lib/dragonfly/image_magick/utils.rb +72 -0
  73. data/lib/dragonfly/image_magick_utils.rb +2 -79
  74. data/lib/dragonfly/job.rb +152 -90
  75. data/lib/dragonfly/middleware.rb +5 -19
  76. data/lib/dragonfly/processing/image_magick_processor.rb +2 -95
  77. data/lib/dragonfly/rails/images.rb +15 -10
  78. data/lib/dragonfly/response.rb +26 -12
  79. data/lib/dragonfly/serializer.rb +1 -4
  80. data/lib/dragonfly/server.rb +103 -0
  81. data/lib/dragonfly/temp_object.rb +56 -101
  82. data/lib/dragonfly/url_mapper.rb +78 -0
  83. data/spec/dragonfly/active_model_extensions/model_spec.rb +772 -65
  84. data/spec/dragonfly/active_model_extensions/spec_helper.rb +90 -10
  85. data/spec/dragonfly/analyser_spec.rb +1 -1
  86. data/spec/dragonfly/analysis/file_command_analyser_spec.rb +5 -14
  87. data/spec/dragonfly/app_spec.rb +35 -180
  88. data/spec/dragonfly/configurable_spec.rb +259 -18
  89. data/spec/dragonfly/core_ext/string_spec.rb +2 -2
  90. data/spec/dragonfly/core_ext/symbol_spec.rb +1 -1
  91. data/spec/dragonfly/data_storage/couch_data_store_spec.rb +84 -0
  92. data/spec/dragonfly/data_storage/file_data_store_spec.rb +149 -22
  93. data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +21 -2
  94. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +207 -43
  95. data/spec/dragonfly/data_storage/{data_store_spec.rb → shared_data_store_examples.rb} +16 -15
  96. data/spec/dragonfly/function_manager_spec.rb +2 -2
  97. data/spec/dragonfly/{generation/hash_with_css_style_keys_spec.rb → hash_with_css_style_keys_spec.rb} +2 -2
  98. data/spec/dragonfly/{analysis/shared_analyser_spec.rb → image_magick/analyser_spec.rb} +19 -6
  99. data/spec/dragonfly/{encoding/image_magick_encoder_spec.rb → image_magick/encoder_spec.rb} +2 -2
  100. data/spec/dragonfly/image_magick/generator_spec.rb +172 -0
  101. data/spec/dragonfly/{processing/shared_processing_spec.rb → image_magick/processor_spec.rb} +55 -6
  102. data/spec/dragonfly/image_magick/utils_spec.rb +18 -0
  103. data/spec/dragonfly/job_builder_spec.rb +1 -1
  104. data/spec/dragonfly/job_definitions_spec.rb +1 -1
  105. data/spec/dragonfly/job_endpoint_spec.rb +26 -3
  106. data/spec/dragonfly/job_spec.rb +426 -208
  107. data/spec/dragonfly/loggable_spec.rb +2 -2
  108. data/spec/dragonfly/middleware_spec.rb +5 -26
  109. data/spec/dragonfly/routed_endpoint_spec.rb +1 -1
  110. data/spec/dragonfly/serializer_spec.rb +1 -14
  111. data/spec/dragonfly/server_spec.rb +261 -0
  112. data/spec/dragonfly/simple_cache_spec.rb +1 -1
  113. data/spec/dragonfly/temp_object_spec.rb +84 -130
  114. data/spec/dragonfly/url_mapper_spec.rb +130 -0
  115. data/spec/functional/deprecations_spec.rb +51 -0
  116. data/spec/functional/image_magick_app_spec.rb +27 -0
  117. data/spec/functional/model_urls_spec.rb +85 -0
  118. data/spec/functional/remote_on_the_fly_spec.rb +51 -0
  119. data/spec/functional/to_response_spec.rb +31 -0
  120. data/spec/spec_helper.rb +12 -22
  121. data/spec/{argument_matchers.rb → support/argument_matchers.rb} +0 -0
  122. data/spec/{image_matchers.rb → support/image_matchers.rb} +4 -4
  123. data/spec/support/simple_matchers.rb +53 -0
  124. data/yard/handlers/configurable_attr_handler.rb +2 -2
  125. data/yard/templates/default/fulldoc/html/css/common.css +12 -10
  126. data/yard/templates/default/layout/html/layout.erb +6 -0
  127. metadata +267 -308
  128. data/Gemfile.rails.2.3.5 +0 -20
  129. data/features/3.0.3.feature +0 -8
  130. data/features/rails_2.3.5.feature +0 -7
  131. data/fixtures/files/app/models/album.rb +0 -3
  132. data/fixtures/files/app/views/albums/new.html.erb +0 -4
  133. data/fixtures/files/features/manage_album_images.feature +0 -12
  134. data/fixtures/rails_2.3.5/template.rb +0 -10
  135. data/lib/dragonfly/analysis/r_magick_analyser.rb +0 -63
  136. data/lib/dragonfly/config/r_magick.rb +0 -46
  137. data/lib/dragonfly/generation/hash_with_css_style_keys.rb +0 -23
  138. data/lib/dragonfly/generation/r_magick_generator.rb +0 -155
  139. data/lib/dragonfly/processing/r_magick_processor.rb +0 -126
  140. data/lib/dragonfly/r_magick_utils.rb +0 -48
  141. data/lib/dragonfly/simple_endpoint.rb +0 -76
  142. data/spec/dragonfly/active_model_extensions/active_model_setup.rb +0 -97
  143. data/spec/dragonfly/active_model_extensions/active_record_setup.rb +0 -85
  144. data/spec/dragonfly/analysis/image_magick_analyser_spec.rb +0 -15
  145. data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +0 -31
  146. data/spec/dragonfly/config/r_magick_spec.rb +0 -29
  147. data/spec/dragonfly/encoding/r_magick_encoder_spec.rb +0 -41
  148. data/spec/dragonfly/generation/image_magick_generator_spec.rb +0 -12
  149. data/spec/dragonfly/generation/r_magick_generator_spec.rb +0 -28
  150. data/spec/dragonfly/generation/shared_generator_spec.rb +0 -91
  151. data/spec/dragonfly/image_magick_utils_spec.rb +0 -16
  152. data/spec/dragonfly/processing/image_magick_processor_spec.rb +0 -29
  153. data/spec/dragonfly/processing/r_magick_processor_spec.rb +0 -30
  154. data/spec/dragonfly/simple_endpoint_spec.rb +0 -97
  155. data/spec/simple_matchers.rb +0 -44
@@ -1,81 +1,4 @@
1
- require 'tempfile'
2
-
3
1
  module Dragonfly
4
- module ImageMagickUtils
5
-
6
- # Exceptions
7
- class ShellCommandFailed < RuntimeError; end
8
-
9
- class << self
10
- include Configurable
11
- configurable_attr :convert_command, "convert"
12
- configurable_attr :identify_command, "identify"
13
- configurable_attr :log_commands, false
14
- end
15
-
16
- include Loggable
17
-
18
- private
19
-
20
- def convert(temp_object, args='', format=nil)
21
- tempfile = new_tempfile(format)
22
- run "#{convert_command} #{args} #{temp_object.path} #{tempfile.path}"
23
- tempfile
24
- end
25
-
26
- def identify(temp_object)
27
- # example of details string:
28
- # myimage.png PNG 200x100 200x100+0+0 8-bit DirectClass 31.2kb
29
- details = raw_identify(temp_object)
30
- filename, format, geometry, geometry_2, depth, image_class, size = details.split(' ')
31
- width, height = geometry.split('x')
32
- {
33
- :filename => filename,
34
- :format => format.downcase.to_sym,
35
- :width => width.to_i,
36
- :height => height.to_i,
37
- :depth => depth.to_i,
38
- :image_class => image_class
39
- }
40
- end
41
-
42
- def raw_identify(temp_object, args='')
43
- run "#{identify_command} #{args} #{temp_object.path}"
44
- end
45
-
46
- def new_tempfile(ext=nil)
47
- tempfile = ext ? Tempfile.new(['dragonfly', ".#{ext}"]) : Tempfile.new('dragonfly')
48
- tempfile.binmode
49
- tempfile.close
50
- tempfile
51
- end
52
-
53
- def convert_command
54
- ImageMagickUtils.convert_command
55
- end
56
-
57
- def identify_command
58
- ImageMagickUtils.identify_command
59
- end
60
-
61
- def run(command)
62
- log.debug("Running command: #{command}") if ImageMagickUtils.log_commands
63
- begin
64
- result = `#{command}`
65
- rescue Errno::ENOENT
66
- raise_shell_command_failed(command)
67
- end
68
- if $?.exitstatus == 1
69
- throw :unable_to_handle
70
- elsif !$?.success?
71
- raise_shell_command_failed(command)
72
- end
73
- result
74
- end
75
-
76
- def raise_shell_command_failed(command)
77
- raise ShellCommandFailed, "Command failed (#{command}) with exit status #{$?.exitstatus}"
78
- end
79
-
80
- end
2
+ puts "WARNING: Dragonfly::ImageMagickUtils is DEPRECATED and will soon be removed. Please use Dragonfly::ImageMagick::Utils instead."
3
+ ImageMagickUtils = ImageMagick::Utils
81
4
  end
@@ -1,6 +1,8 @@
1
1
  require 'forwardable'
2
2
  require 'digest/sha1'
3
3
  require 'base64'
4
+ require 'open-uri'
5
+ require 'pathname'
4
6
 
5
7
  module Dragonfly
6
8
  class Job
@@ -16,7 +18,9 @@ module Dragonfly
16
18
  class IncorrectSHA < StandardError; end
17
19
 
18
20
  extend Forwardable
19
- def_delegators :result, :data, :file, :tempfile, :path, :to_file, :size, :ext, :name, :name=, :basename, :meta, :meta=, :format, :_format
21
+ def_delegators :result,
22
+ :data, :file, :tempfile, :path, :to_file, :size
23
+ def_delegator :app, :server
20
24
 
21
25
  class Step
22
26
 
@@ -35,30 +39,29 @@ module Dragonfly
35
39
  end
36
40
  end
37
41
 
38
- def initialize(*args)
39
- @args = args
42
+ def initialize(job, *args)
43
+ @job, @args = job, args
44
+ init
40
45
  end
41
46
 
42
- attr_reader :args
43
-
44
- def update_temp_object(job, content, extra)
45
- temp_object = TempObject.new(content, job.temp_object.attributes)
46
- temp_object.extract_attributes_from(extra) if extra
47
- job.temp_object = temp_object
47
+ def init # To be overridden
48
48
  end
49
49
 
50
+ attr_reader :job, :args
51
+
50
52
  def inspect
51
53
  "#{self.class.step_name}(#{args.map{|a| a.inspect }.join(', ')})"
52
54
  end
55
+
53
56
  end
54
57
 
55
58
  class Fetch < Step
56
59
  def uid
57
60
  args.first
58
61
  end
59
- def apply(job)
60
- content, extra = job.app.datastore.retrieve(uid)
61
- job.temp_object = TempObject.new(content, extra)
62
+ def apply
63
+ content, meta = job.app.datastore.retrieve(uid)
64
+ job.update(content, meta)
62
65
  end
63
66
  end
64
67
 
@@ -69,41 +72,64 @@ module Dragonfly
69
72
  def arguments
70
73
  args[1..-1]
71
74
  end
72
- def apply(job)
75
+ def apply
73
76
  raise NothingToProcess, "Can't process because temp object has not been initialized. Need to fetch first?" unless job.temp_object
74
- content, extra = job.app.processor.process(job.temp_object, name, *arguments)
75
- update_temp_object(job, content, extra)
77
+ content, meta = job.app.processor.process(job.temp_object, name, *arguments)
78
+ job.update(content, meta)
76
79
  end
77
80
  end
78
81
 
79
82
  class Encode < Step
83
+ def init
84
+ job.meta[:format] = format
85
+ end
80
86
  def format
81
87
  args.first
82
88
  end
83
89
  def arguments
84
90
  args[1..-1]
85
91
  end
86
- def apply(job)
92
+ def apply
87
93
  raise NothingToEncode, "Can't encode because temp object has not been initialized. Need to fetch first?" unless job.temp_object
88
- content, extra = job.app.encoder.encode(job.temp_object, format, *arguments)
89
- update_temp_object(job, content, extra)
90
- job.temp_object.format = format
94
+ content, meta = job.app.encoder.encode(job.temp_object, format, *arguments)
95
+ job.update(content, meta)
96
+ job.meta[:format] = format
91
97
  end
92
98
  end
93
99
 
94
100
  class Generate < Step
95
- def apply(job)
96
- content, extra = job.app.generator.generate(*args)
97
- job.temp_object = TempObject.new(content, extra)
101
+ def apply
102
+ content, meta = job.app.generator.generate(*args)
103
+ job.update(content, meta)
98
104
  end
99
105
  end
100
106
 
101
107
  class FetchFile < Step
108
+ def init
109
+ job.name = File.basename(path)
110
+ end
102
111
  def path
103
112
  File.expand_path(args.first)
104
113
  end
105
- def apply(job)
106
- job.temp_object = TempObject.new(File.new(path))
114
+ def apply
115
+ job.temp_object = TempObject.new(Pathname.new(path))
116
+ end
117
+ end
118
+
119
+ class FetchUrl < Step
120
+ def init
121
+ job.name = File.basename(path) if path[/[^\/]$/]
122
+ end
123
+ def url
124
+ @url ||= (args.first[%r<^\w+://>] ? args.first : "http://#{args.first}")
125
+ end
126
+ def path
127
+ @path ||= URI.parse(url).path
128
+ end
129
+ def apply
130
+ open(url) do |f|
131
+ job.temp_object = TempObject.new(f.read)
132
+ end
107
133
  end
108
134
  end
109
135
 
@@ -112,7 +138,8 @@ module Dragonfly
112
138
  Process,
113
139
  Encode,
114
140
  Generate,
115
- FetchFile
141
+ FetchFile,
142
+ FetchUrl
116
143
  ]
117
144
 
118
145
  # Class methods
@@ -126,18 +153,11 @@ module Dragonfly
126
153
  job = app.new_job
127
154
  steps_array.each do |step_array|
128
155
  step_class = step_abbreviations[step_array.shift]
129
- job.steps << step_class.new(*step_array)
156
+ job.steps << step_class.new(job, *step_array)
130
157
  end
131
158
  job
132
159
  end
133
160
 
134
- def from_path(path, app)
135
- path = path.dup
136
- path.sub!(app.url_path_prefix, '') if app.url_path_prefix
137
- path.sub!('/', '')
138
- deserialize(path, app)
139
- end
140
-
141
161
  def deserialize(string, app)
142
162
  from_a(Serializer.marshal_decode(string), app)
143
163
  end
@@ -152,22 +172,43 @@ module Dragonfly
152
172
 
153
173
  end
154
174
 
155
- # Instance methods
175
+ ####### Instance methods #######
156
176
 
157
- def initialize(app, temp_object=nil)
177
+ # This is needed because we need a way of overriding
178
+ # the methods added to Job objects by the analyser and by
179
+ # the job shortcuts like 'thumb', etc.
180
+ # If we had traits/classboxes in ruby maybe this wouldn't be needed
181
+ # Think of it as like a normal instance method but with a css-like !important after it
182
+ module OverrideInstanceMethods
183
+
184
+ def format
185
+ apply
186
+ format_from_meta || analyse(:format)
187
+ end
188
+
189
+ def mime_type
190
+ app.mime_type_for(format) || analyse(:mime_type) || app.fallback_mime_type
191
+ end
192
+
193
+ def to_s
194
+ super.sub(/#<Class:\w+>/, 'Extended Dragonfly::Job')
195
+ end
196
+
197
+ end
198
+
199
+ def initialize(app, content=nil, meta={})
158
200
  @app = app
159
- self.extend app.analyser.analysis_methods
160
- self.extend app.job_definitions
161
201
  @steps = []
162
202
  @next_step_index = 0
163
- @temp_object = temp_object
203
+ @meta = {}
204
+ update(content, meta)
164
205
  end
165
206
 
166
207
  # Used by 'dup' and 'clone'
167
208
  def initialize_copy(other)
168
- self.steps = other.steps.dup
169
- self.extend app.analyser.analysis_methods
170
- self.extend app.job_definitions
209
+ self.steps = other.steps.map do |step|
210
+ step.class.new(self, *step.args)
211
+ end
171
212
  end
172
213
 
173
214
  attr_accessor :temp_object
@@ -178,12 +219,12 @@ module Dragonfly
178
219
  class_eval %(
179
220
  def #{step_class.step_name}(*args)
180
221
  new_job = self.dup
181
- new_job.steps << #{step_class}.new(*args)
222
+ new_job.steps << #{step_class}.new(new_job, *args)
182
223
  new_job
183
224
  end
184
225
 
185
226
  def #{step_class.step_name}!(*args)
186
- steps << #{step_class}.new(*args)
227
+ steps << #{step_class}.new(self, *args)
187
228
  self
188
229
  end
189
230
  )
@@ -193,35 +234,21 @@ module Dragonfly
193
234
  unless result
194
235
  raise NothingToAnalyse, "Can't analyse because temp object has not been initialized. Need to fetch first?"
195
236
  end
196
- # Hacky - wish there was a nicer way to do this without extending with yet another module
197
- if method == :format
198
- _format || analyser.analyse(result, method, *args)
199
- else
200
- analyser.analyse(result, method, *args)
201
- end
202
- end
203
-
204
- def +(other_job)
205
- unless app == other_job.app
206
- raise AppDoesNotMatch, "Cannot add jobs belonging to different apps (#{app} is not #{other_job.app})"
207
- end
208
- unless other_job.applied_steps.empty?
209
- raise JobAlreadyApplied, "Cannot add jobs when the second one has already been applied (#{other_job})"
210
- end
211
- new_job = self.class.new(app, temp_object)
212
- new_job.steps = steps + other_job.steps
213
- new_job.next_step_index = next_step_index
214
- new_job
237
+ analyser.analyse(result, method, *args)
215
238
  end
216
239
 
217
240
  # Applying, etc.
218
241
 
219
242
  def apply
220
- pending_steps.each{|step| step.apply(self) }
243
+ pending_steps.each{|step| step.apply }
221
244
  self.next_step_index = steps.length
222
245
  self
223
246
  end
224
247
 
248
+ def applied?
249
+ next_step_index == steps.length
250
+ end
251
+
225
252
  def result
226
253
  apply
227
254
  temp_object
@@ -273,11 +300,11 @@ module Dragonfly
273
300
  # URLs, etc.
274
301
 
275
302
  def url(opts={})
276
- app.url_for(self, opts) unless steps.empty?
303
+ app.url_for(self, attributes_for_url.merge(opts)) unless steps.empty?
277
304
  end
278
305
 
279
306
  def b64_data
280
- "data:#{resolve_mime_type};base64,#{Base64.encode64(data)}"
307
+ "data:#{mime_type};base64,#{Base64.encode64(data)}"
281
308
  end
282
309
 
283
310
  # to_stuff...
@@ -286,7 +313,7 @@ module Dragonfly
286
313
  JobEndpoint.new(self)
287
314
  end
288
315
 
289
- def to_response(env={})
316
+ def to_response(env={"REQUEST_METHOD" => "GET"})
290
317
  to_app.call(env)
291
318
  end
292
319
 
@@ -295,7 +322,7 @@ module Dragonfly
295
322
  end
296
323
 
297
324
  def to_fetched_job(uid)
298
- new_job = self.class.new(app, temp_object)
325
+ new_job = self.class.new(app, temp_object, meta)
299
326
  new_job.fetch!(uid)
300
327
  new_job.next_step_index = 1
301
328
  new_job
@@ -303,21 +330,13 @@ module Dragonfly
303
330
 
304
331
  # Step inspection
305
332
 
306
- def fetch_step
307
- last_step_of_type(Fetch)
308
- end
309
-
310
333
  def uid
311
334
  step = fetch_step
312
335
  step.uid if step
313
336
  end
314
337
 
315
- def uid_basename
316
- File.basename(uid, '.*') if uid
317
- end
318
-
319
- def uid_extname
320
- File.extname(uid) if uid
338
+ def fetch_step
339
+ last_step_of_type(Fetch)
321
340
  end
322
341
 
323
342
  def generate_step
@@ -328,6 +347,10 @@ module Dragonfly
328
347
  last_step_of_type(FetchFile)
329
348
  end
330
349
 
350
+ def fetch_url_step
351
+ last_step_of_type(FetchUrl)
352
+ end
353
+
331
354
  def process_steps
332
355
  steps.select{|s| s.is_a?(Process) }
333
356
  end
@@ -336,30 +359,65 @@ module Dragonfly
336
359
  last_step_of_type(Encode)
337
360
  end
338
361
 
339
- def encoded_format
340
- step = encode_step
341
- step.format if step
342
- end
343
-
344
- def encoded_extname
345
- format = encoded_format
346
- ".#{format}" if format
362
+ def step_types
363
+ steps.map{|s| s.class.step_name }
347
364
  end
348
365
 
349
366
  # Misc
350
367
 
351
368
  def store(opts={})
352
- app.store(result, opts)
353
- end
354
-
355
- def resolve_mime_type
356
- app.resolve_mime_type(result)
369
+ app.store(result, opts.merge(:meta => meta))
357
370
  end
358
371
 
359
372
  def inspect
360
373
  to_s.sub(/>$/, " app=#{app}, steps=#{steps.inspect}, temp_object=#{temp_object.inspect}, steps applied:#{applied_steps.length}/#{steps.length} >")
361
374
  end
362
375
 
376
+ # Name and stuff
377
+
378
+ attr_reader :meta
379
+
380
+ def meta=(hash)
381
+ raise ArgumentError, "meta must be a hash, you tried setting it as #{hash.inspect}" unless hash.is_a?(Hash)
382
+ @meta = hash
383
+ end
384
+
385
+ def name
386
+ meta[:name]
387
+ end
388
+
389
+ def name=(name)
390
+ meta[:name] = name
391
+ end
392
+
393
+ def basename
394
+ meta[:basename] || (File.basename(name, '.*') if name)
395
+ end
396
+
397
+ def ext
398
+ meta[:ext] || (File.extname(name)[/\.(.*)/, 1] if name)
399
+ end
400
+
401
+ def attributes_for_url
402
+ attrs = meta.reject{|k, v| !server.params_in_url.include?(k.to_s) }
403
+ attrs[:basename] ||= basename if server.params_in_url.include?('basename')
404
+ attrs[:ext] ||= ext if server.params_in_url.include?('ext')
405
+ attrs[:format] = (attrs[:format] || format_from_meta).to_s if server.params_in_url.include?('format')
406
+ attrs.delete_if{|k, v| v.blank? }
407
+ attrs
408
+ end
409
+
410
+ def update(content, meta)
411
+ if meta
412
+ meta.merge!(meta.delete(:meta)) if meta[:meta] # legacy data etc. may have nested meta hash - deprecate gracefully here
413
+ self.meta.merge!(meta)
414
+ end
415
+ if content
416
+ self.temp_object = TempObject.new(content)
417
+ self.name = temp_object.original_filename if name.nil? && temp_object.original_filename
418
+ end
419
+ end
420
+
363
421
  protected
364
422
 
365
423
  attr_writer :steps
@@ -367,6 +425,10 @@ module Dragonfly
367
425
 
368
426
  private
369
427
 
428
+ def format_from_meta
429
+ meta[:format] || (ext.to_sym if ext && app.trust_file_extensions)
430
+ end
431
+
370
432
  def last_step_of_type(type)
371
433
  steps.select{|s| s.is_a?(type) }.last
372
434
  end