oahu-dragonfly 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. data/.rspec +1 -0
  2. data/.yardopts +24 -0
  3. data/Gemfile +30 -0
  4. data/History.md +323 -0
  5. data/LICENSE +20 -0
  6. data/README.md +88 -0
  7. data/Rakefile +50 -0
  8. data/VERSION +1 -0
  9. data/config.ru +14 -0
  10. data/docs.watchr +1 -0
  11. data/dragonfly.gemspec +297 -0
  12. data/extra_docs/Analysers.md +66 -0
  13. data/extra_docs/Caching.md +23 -0
  14. data/extra_docs/Configuration.md +124 -0
  15. data/extra_docs/Couch.md +49 -0
  16. data/extra_docs/DataStorage.md +153 -0
  17. data/extra_docs/Encoding.md +67 -0
  18. data/extra_docs/GeneralUsage.md +121 -0
  19. data/extra_docs/Generators.md +60 -0
  20. data/extra_docs/Heroku.md +50 -0
  21. data/extra_docs/ImageMagick.md +125 -0
  22. data/extra_docs/Index.md +33 -0
  23. data/extra_docs/MimeTypes.md +40 -0
  24. data/extra_docs/Models.md +272 -0
  25. data/extra_docs/Mongo.md +45 -0
  26. data/extra_docs/Processing.md +77 -0
  27. data/extra_docs/Rack.md +52 -0
  28. data/extra_docs/Rails2.md +57 -0
  29. data/extra_docs/Rails3.md +62 -0
  30. data/extra_docs/Sinatra.md +25 -0
  31. data/extra_docs/URLs.md +169 -0
  32. data/features/images.feature +47 -0
  33. data/features/no_processing.feature +14 -0
  34. data/features/rails_3.0.5.feature +8 -0
  35. data/features/steps/common_steps.rb +8 -0
  36. data/features/steps/dragonfly_steps.rb +66 -0
  37. data/features/steps/rails_steps.rb +28 -0
  38. data/features/support/env.rb +13 -0
  39. data/features/support/setup.rb +32 -0
  40. data/fixtures/rails_3.0.5/files/app/models/album.rb +7 -0
  41. data/fixtures/rails_3.0.5/files/app/views/albums/new.html.erb +7 -0
  42. data/fixtures/rails_3.0.5/files/app/views/albums/show.html.erb +6 -0
  43. data/fixtures/rails_3.0.5/files/config/initializers/dragonfly.rb +4 -0
  44. data/fixtures/rails_3.0.5/files/features/manage_album_images.feature +38 -0
  45. data/fixtures/rails_3.0.5/files/features/step_definitions/helper_steps.rb +7 -0
  46. data/fixtures/rails_3.0.5/files/features/step_definitions/image_steps.rb +25 -0
  47. data/fixtures/rails_3.0.5/files/features/support/paths.rb +17 -0
  48. data/fixtures/rails_3.0.5/files/features/text_images.feature +7 -0
  49. data/fixtures/rails_3.0.5/template.rb +20 -0
  50. data/irbrc.rb +18 -0
  51. data/lib/dragonfly.rb +55 -0
  52. data/lib/dragonfly/active_model_extensions.rb +13 -0
  53. data/lib/dragonfly/active_model_extensions/attachment.rb +250 -0
  54. data/lib/dragonfly/active_model_extensions/attachment_class_methods.rb +148 -0
  55. data/lib/dragonfly/active_model_extensions/class_methods.rb +95 -0
  56. data/lib/dragonfly/active_model_extensions/instance_methods.rb +28 -0
  57. data/lib/dragonfly/active_model_extensions/validations.rb +41 -0
  58. data/lib/dragonfly/analyser.rb +58 -0
  59. data/lib/dragonfly/analysis/file_command_analyser.rb +32 -0
  60. data/lib/dragonfly/analysis/image_magick_analyser.rb +6 -0
  61. data/lib/dragonfly/app.rb +172 -0
  62. data/lib/dragonfly/config/heroku.rb +19 -0
  63. data/lib/dragonfly/config/image_magick.rb +6 -0
  64. data/lib/dragonfly/config/rails.rb +20 -0
  65. data/lib/dragonfly/configurable.rb +207 -0
  66. data/lib/dragonfly/core_ext/array.rb +7 -0
  67. data/lib/dragonfly/core_ext/hash.rb +7 -0
  68. data/lib/dragonfly/core_ext/object.rb +12 -0
  69. data/lib/dragonfly/core_ext/string.rb +9 -0
  70. data/lib/dragonfly/core_ext/symbol.rb +9 -0
  71. data/lib/dragonfly/data_storage.rb +9 -0
  72. data/lib/dragonfly/data_storage/couch_data_store.rb +64 -0
  73. data/lib/dragonfly/data_storage/file_data_store.rb +141 -0
  74. data/lib/dragonfly/data_storage/mongo_data_store.rb +86 -0
  75. data/lib/dragonfly/data_storage/s3data_store.rb +145 -0
  76. data/lib/dragonfly/encoder.rb +13 -0
  77. data/lib/dragonfly/encoding/image_magick_encoder.rb +6 -0
  78. data/lib/dragonfly/function_manager.rb +71 -0
  79. data/lib/dragonfly/generation/image_magick_generator.rb +6 -0
  80. data/lib/dragonfly/generator.rb +9 -0
  81. data/lib/dragonfly/hash_with_css_style_keys.rb +21 -0
  82. data/lib/dragonfly/image_magick/analyser.rb +51 -0
  83. data/lib/dragonfly/image_magick/config.rb +41 -0
  84. data/lib/dragonfly/image_magick/encoder.rb +57 -0
  85. data/lib/dragonfly/image_magick/generator.rb +145 -0
  86. data/lib/dragonfly/image_magick/processor.rb +99 -0
  87. data/lib/dragonfly/image_magick/utils.rb +72 -0
  88. data/lib/dragonfly/image_magick_utils.rb +4 -0
  89. data/lib/dragonfly/job.rb +451 -0
  90. data/lib/dragonfly/job_builder.rb +39 -0
  91. data/lib/dragonfly/job_definitions.rb +26 -0
  92. data/lib/dragonfly/job_endpoint.rb +15 -0
  93. data/lib/dragonfly/loggable.rb +28 -0
  94. data/lib/dragonfly/middleware.rb +20 -0
  95. data/lib/dragonfly/processing/image_magick_processor.rb +6 -0
  96. data/lib/dragonfly/processor.rb +9 -0
  97. data/lib/dragonfly/rails/images.rb +27 -0
  98. data/lib/dragonfly/response.rb +97 -0
  99. data/lib/dragonfly/routed_endpoint.rb +40 -0
  100. data/lib/dragonfly/serializer.rb +32 -0
  101. data/lib/dragonfly/server.rb +113 -0
  102. data/lib/dragonfly/simple_cache.rb +23 -0
  103. data/lib/dragonfly/temp_object.rb +175 -0
  104. data/lib/dragonfly/url_mapper.rb +78 -0
  105. data/samples/beach.png +0 -0
  106. data/samples/egg.png +0 -0
  107. data/samples/round.gif +0 -0
  108. data/samples/sample.docx +0 -0
  109. data/samples/taj.jpg +0 -0
  110. data/spec/dragonfly/active_model_extensions/model_spec.rb +1426 -0
  111. data/spec/dragonfly/active_model_extensions/spec_helper.rb +91 -0
  112. data/spec/dragonfly/analyser_spec.rb +123 -0
  113. data/spec/dragonfly/analysis/file_command_analyser_spec.rb +48 -0
  114. data/spec/dragonfly/app_spec.rb +135 -0
  115. data/spec/dragonfly/configurable_spec.rb +461 -0
  116. data/spec/dragonfly/core_ext/array_spec.rb +19 -0
  117. data/spec/dragonfly/core_ext/hash_spec.rb +19 -0
  118. data/spec/dragonfly/core_ext/string_spec.rb +17 -0
  119. data/spec/dragonfly/core_ext/symbol_spec.rb +17 -0
  120. data/spec/dragonfly/data_storage/couch_data_store_spec.rb +76 -0
  121. data/spec/dragonfly/data_storage/file_data_store_spec.rb +296 -0
  122. data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +57 -0
  123. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +258 -0
  124. data/spec/dragonfly/data_storage/shared_data_store_examples.rb +77 -0
  125. data/spec/dragonfly/function_manager_spec.rb +154 -0
  126. data/spec/dragonfly/hash_with_css_style_keys_spec.rb +24 -0
  127. data/spec/dragonfly/image_magick/analyser_spec.rb +64 -0
  128. data/spec/dragonfly/image_magick/encoder_spec.rb +41 -0
  129. data/spec/dragonfly/image_magick/generator_spec.rb +172 -0
  130. data/spec/dragonfly/image_magick/processor_spec.rb +233 -0
  131. data/spec/dragonfly/image_magick/utils_spec.rb +18 -0
  132. data/spec/dragonfly/job_builder_spec.rb +37 -0
  133. data/spec/dragonfly/job_definitions_spec.rb +35 -0
  134. data/spec/dragonfly/job_endpoint_spec.rb +173 -0
  135. data/spec/dragonfly/job_spec.rb +1046 -0
  136. data/spec/dragonfly/loggable_spec.rb +80 -0
  137. data/spec/dragonfly/middleware_spec.rb +47 -0
  138. data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
  139. data/spec/dragonfly/serializer_spec.rb +61 -0
  140. data/spec/dragonfly/server_spec.rb +278 -0
  141. data/spec/dragonfly/simple_cache_spec.rb +27 -0
  142. data/spec/dragonfly/temp_object_spec.rb +306 -0
  143. data/spec/dragonfly/url_mapper_spec.rb +126 -0
  144. data/spec/functional/deprecations_spec.rb +51 -0
  145. data/spec/functional/image_magick_app_spec.rb +27 -0
  146. data/spec/functional/model_urls_spec.rb +85 -0
  147. data/spec/functional/remote_on_the_fly_spec.rb +51 -0
  148. data/spec/functional/to_response_spec.rb +31 -0
  149. data/spec/spec_helper.rb +51 -0
  150. data/spec/support/argument_matchers.rb +19 -0
  151. data/spec/support/image_matchers.rb +47 -0
  152. data/spec/support/simple_matchers.rb +53 -0
  153. data/yard/handlers/configurable_attr_handler.rb +38 -0
  154. data/yard/setup.rb +15 -0
  155. data/yard/templates/default/fulldoc/html/css/common.css +107 -0
  156. data/yard/templates/default/layout/html/layout.erb +89 -0
  157. data/yard/templates/default/module/html/configuration_summary.erb +31 -0
  158. data/yard/templates/default/module/setup.rb +17 -0
  159. metadata +544 -0
@@ -0,0 +1,72 @@
1
+ require 'tempfile'
2
+
3
+ module Dragonfly
4
+ module ImageMagick
5
+ module Utils
6
+
7
+ # Exceptions
8
+ class ShellCommandFailed < RuntimeError; end
9
+
10
+ include Loggable
11
+ include Configurable
12
+ configurable_attr :convert_command, "convert"
13
+ configurable_attr :identify_command, "identify"
14
+ configurable_attr :log_commands, false
15
+
16
+ private
17
+
18
+ def convert(temp_object=nil, args='', format=nil)
19
+ tempfile = new_tempfile(format)
20
+ run "#{convert_command} #{args} #{temp_object.path if temp_object} #{tempfile.path}"
21
+ tempfile
22
+ end
23
+
24
+ def identify(temp_object)
25
+ # example of details string:
26
+ # myimage.png PNG 200x100 200x100+0+0 8-bit DirectClass 31.2kb
27
+ details = raw_identify(temp_object)
28
+ filename, format, geometry, geometry_2, depth, image_class, size = details.split(' ')
29
+ width, height = geometry.split('x')
30
+ {
31
+ :filename => filename,
32
+ :format => format.downcase.to_sym,
33
+ :width => width.to_i,
34
+ :height => height.to_i,
35
+ :depth => depth.to_i,
36
+ :image_class => image_class
37
+ }
38
+ end
39
+
40
+ def raw_identify(temp_object, args='')
41
+ run "#{identify_command} #{args} #{temp_object.path}"
42
+ end
43
+
44
+ def new_tempfile(ext=nil)
45
+ tempfile = ext ? Tempfile.new(['dragonfly', ".#{ext}"]) : Tempfile.new('dragonfly')
46
+ tempfile.binmode
47
+ tempfile.close
48
+ tempfile
49
+ end
50
+
51
+ def run(command)
52
+ log.debug("Running command: #{command}") if log_commands
53
+ begin
54
+ result = `#{command}`
55
+ rescue Errno::ENOENT
56
+ raise_shell_command_failed(command)
57
+ end
58
+ if $?.exitstatus == 1
59
+ throw :unable_to_handle
60
+ elsif !$?.success?
61
+ raise_shell_command_failed(command)
62
+ end
63
+ result
64
+ end
65
+
66
+ def raise_shell_command_failed(command)
67
+ raise ShellCommandFailed, "Command failed (#{command}) with exit status #{$?.exitstatus}"
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,4 @@
1
+ module Dragonfly
2
+ puts "WARNING: Dragonfly::ImageMagickUtils is DEPRECATED and will soon be removed. Please use Dragonfly::ImageMagick::Utils instead."
3
+ ImageMagickUtils = ImageMagick::Utils
4
+ end
@@ -0,0 +1,451 @@
1
+ require 'forwardable'
2
+ require 'digest/sha1'
3
+ require 'base64'
4
+ require 'open-uri'
5
+ require 'pathname'
6
+
7
+ module Dragonfly
8
+ class Job
9
+
10
+ # Exceptions
11
+ class AppDoesNotMatch < StandardError; end
12
+ class JobAlreadyApplied < StandardError; end
13
+ class NothingToProcess < StandardError; end
14
+ class NothingToEncode < StandardError; end
15
+ class NothingToAnalyse < StandardError; end
16
+ class InvalidArray < StandardError; end
17
+ class NoSHAGiven < StandardError; end
18
+ class IncorrectSHA < StandardError; end
19
+
20
+ extend Forwardable
21
+ def_delegators :result,
22
+ :data, :file, :tempfile, :path, :to_file, :size
23
+ def_delegator :app, :server
24
+
25
+ class Step
26
+
27
+ class << self
28
+ # Dragonfly::Job::Fetch -> 'Fetch'
29
+ def basename
30
+ @basename ||= name.split('::').last
31
+ end
32
+ # Dragonfly::Job::Fetch -> :fetch
33
+ def step_name
34
+ @step_name ||= basename.gsub(/[A-Z]/){ "_#{$&.downcase}" }.sub('_','').to_sym
35
+ end
36
+ # Dragonfly::Job::Fetch -> :f
37
+ def abbreviation
38
+ @abbreviation ||= basename.scan(/[A-Z]/).join.downcase.to_sym
39
+ end
40
+ end
41
+
42
+ def initialize(job, *args)
43
+ @job, @args = job, args
44
+ init
45
+ end
46
+
47
+ def init # To be overridden
48
+ end
49
+
50
+ attr_reader :job, :args
51
+
52
+ def inspect
53
+ "#{self.class.step_name}(#{args.map{|a| a.inspect }.join(', ')})"
54
+ end
55
+
56
+ end
57
+
58
+ class Fetch < Step
59
+ def uid
60
+ args.first
61
+ end
62
+ def apply
63
+ content, meta = job.app.datastore.retrieve(uid)
64
+ job.update(content, meta)
65
+ end
66
+ end
67
+
68
+ class Process < Step
69
+ def name
70
+ args.first
71
+ end
72
+ def arguments
73
+ args[1..-1]
74
+ end
75
+ def apply
76
+ raise NothingToProcess, "Can't process because temp object has not been initialized. Need to fetch first?" unless job.temp_object
77
+ content, meta = job.app.processor.process(job.temp_object, name, *arguments)
78
+ job.update(content, meta)
79
+ end
80
+ end
81
+
82
+ class Encode < Step
83
+ def init
84
+ job.meta[:format] = format
85
+ end
86
+ def format
87
+ args.first
88
+ end
89
+ def arguments
90
+ args[1..-1]
91
+ end
92
+ def apply
93
+ raise NothingToEncode, "Can't encode because temp object has not been initialized. Need to fetch first?" unless job.temp_object
94
+ content, meta = job.app.encoder.encode(job.temp_object, format, *arguments)
95
+ job.update(content, meta)
96
+ job.meta[:format] = format
97
+ end
98
+ end
99
+
100
+ class Generate < Step
101
+ def apply
102
+ content, meta = job.app.generator.generate(*args)
103
+ job.update(content, meta)
104
+ end
105
+ end
106
+
107
+ class FetchFile < Step
108
+ def init
109
+ job.name = File.basename(path)
110
+ end
111
+ def path
112
+ File.expand_path(args.first)
113
+ end
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
133
+ end
134
+ end
135
+
136
+ STEPS = [
137
+ Fetch,
138
+ Process,
139
+ Encode,
140
+ Generate,
141
+ FetchFile,
142
+ FetchUrl
143
+ ]
144
+
145
+ # Class methods
146
+ class << self
147
+
148
+ def from_a(steps_array, app)
149
+ unless steps_array.is_a?(Array) &&
150
+ steps_array.all?{|s| s.is_a?(Array) && step_abbreviations[s.first] }
151
+ raise InvalidArray, "can't define a job from #{steps_array.inspect}"
152
+ end
153
+ job = app.new_job
154
+ steps_array.each do |step_array|
155
+ step_class = step_abbreviations[step_array.shift]
156
+ job.steps << step_class.new(job, *step_array)
157
+ end
158
+ job
159
+ end
160
+
161
+ def deserialize(string, app)
162
+ from_a(Serializer.marshal_decode(string), app)
163
+ end
164
+
165
+ def step_abbreviations
166
+ @step_abbreviations ||= STEPS.inject({}){|hash, step_class| hash[step_class.abbreviation] = step_class; hash }
167
+ end
168
+
169
+ def step_names
170
+ @step_names ||= STEPS.map{|step_class| step_class.step_name }
171
+ end
172
+
173
+ end
174
+
175
+ ####### Instance methods #######
176
+
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={})
200
+ @app = app
201
+ @steps = []
202
+ @next_step_index = 0
203
+ @meta = {}
204
+ update(content, meta)
205
+ end
206
+
207
+ # Used by 'dup' and 'clone'
208
+ def initialize_copy(other)
209
+ self.steps = other.steps.map do |step|
210
+ step.class.new(self, *step.args)
211
+ end
212
+ end
213
+
214
+ attr_accessor :temp_object
215
+ attr_reader :app, :steps
216
+
217
+ # define fetch(), fetch!(), process(), etc.
218
+ STEPS.each do |step_class|
219
+ class_eval %(
220
+ def #{step_class.step_name}(*args)
221
+ new_job = self.dup
222
+ new_job.steps << #{step_class}.new(new_job, *args)
223
+ new_job
224
+ end
225
+
226
+ def #{step_class.step_name}!(*args)
227
+ steps << #{step_class}.new(self, *args)
228
+ self
229
+ end
230
+ )
231
+ end
232
+
233
+ def analyse(method, *args)
234
+ unless result
235
+ raise NothingToAnalyse, "Can't analyse because temp object has not been initialized. Need to fetch first?"
236
+ end
237
+ analyser.analyse(result, method, *args)
238
+ end
239
+
240
+ # Applying, etc.
241
+
242
+ def apply
243
+ pending_steps.each{|step| step.apply }
244
+ self.next_step_index = steps.length
245
+ self
246
+ end
247
+
248
+ def applied?
249
+ next_step_index == steps.length
250
+ end
251
+
252
+ def result
253
+ apply
254
+ temp_object
255
+ end
256
+
257
+ def applied_steps
258
+ steps[0...next_step_index]
259
+ end
260
+
261
+ def pending_steps
262
+ steps[next_step_index..-1]
263
+ end
264
+
265
+ def to_a
266
+ steps.map{|step|
267
+ [step.class.abbreviation, *step.args]
268
+ }
269
+ end
270
+
271
+ # Serializing, etc.
272
+
273
+ def to_unique_s
274
+ to_a.to_dragonfly_unique_s
275
+ end
276
+
277
+ def serialize
278
+ Serializer.marshal_encode(to_a)
279
+ end
280
+
281
+ def unique_signature
282
+ Digest::SHA1.hexdigest(to_unique_s)
283
+ end
284
+
285
+ def sha
286
+ Digest::SHA1.hexdigest("#{to_unique_s}#{app.secret}")[0...8]
287
+ end
288
+
289
+ def validate_sha!(sha)
290
+ case sha
291
+ when nil
292
+ raise NoSHAGiven
293
+ when self.sha
294
+ self
295
+ else
296
+ raise IncorrectSHA, sha
297
+ end
298
+ end
299
+
300
+ # URLs, etc.
301
+
302
+ def url(opts={})
303
+ app.url_for(self, attributes_for_url.merge(opts)) unless steps.empty?
304
+ end
305
+
306
+ def b64_data
307
+ "data:#{mime_type};base64,#{Base64.encode64(data)}"
308
+ end
309
+
310
+ # to_stuff...
311
+
312
+ def to_app
313
+ JobEndpoint.new(self)
314
+ end
315
+
316
+ def to_response(env={"REQUEST_METHOD" => "GET"})
317
+ to_app.call(env)
318
+ end
319
+
320
+ def to_path
321
+ "/#{serialize}"
322
+ end
323
+
324
+ def to_fetched_job(uid)
325
+ new_job = self.class.new(app, temp_object, meta)
326
+ new_job.fetch!(uid)
327
+ new_job.next_step_index = 1
328
+ new_job
329
+ end
330
+
331
+ # Step inspection
332
+
333
+ def fetch_step
334
+ last_step_of_type(Fetch)
335
+ end
336
+
337
+ def uid
338
+ step = fetch_step
339
+ step.uid if step
340
+ end
341
+
342
+ def uid_basename
343
+ File.basename(uid, '.*') if uid
344
+ end
345
+
346
+ def uid_extname
347
+ File.extname(uid) if uid
348
+ end
349
+
350
+ def generate_step
351
+ last_step_of_type(Generate)
352
+ end
353
+
354
+ def fetch_file_step
355
+ last_step_of_type(FetchFile)
356
+ end
357
+
358
+ def fetch_url_step
359
+ last_step_of_type(FetchUrl)
360
+ end
361
+
362
+ def process_steps
363
+ steps.select{|s| s.is_a?(Process) }
364
+ end
365
+
366
+ def encode_step
367
+ last_step_of_type(Encode)
368
+ end
369
+
370
+ def encoded_format
371
+ step = encode_step
372
+ step.format if step
373
+ end
374
+
375
+ def encoded_extname
376
+ format = encoded_format
377
+ ".#{format}" if format
378
+ end
379
+
380
+ # Misc
381
+
382
+ def store(opts={})
383
+ app.store(result, opts.merge(:meta => meta))
384
+ end
385
+
386
+ def inspect
387
+ to_s.sub(/>$/, " app=#{app}, steps=#{steps.inspect}, temp_object=#{temp_object.inspect}, steps applied:#{applied_steps.length}/#{steps.length} >")
388
+ end
389
+
390
+ # Name and stuff
391
+
392
+ attr_reader :meta
393
+
394
+ def meta=(hash)
395
+ raise ArgumentError, "meta must be a hash, you tried setting it as #{hash.inspect}" unless hash.is_a?(Hash)
396
+ @meta = hash
397
+ end
398
+
399
+ def name
400
+ meta[:name]
401
+ end
402
+
403
+ def name=(name)
404
+ meta[:name] = name
405
+ end
406
+
407
+ def basename
408
+ meta[:basename] || (File.basename(name, '.*') if name)
409
+ end
410
+
411
+ def ext
412
+ meta[:ext] || (File.extname(name)[/\.(.*)/, 1] if name)
413
+ end
414
+
415
+ def attributes_for_url
416
+ attrs = meta.reject{|k, v| !server.params_in_url.include?(k.to_s) }
417
+ attrs[:basename] ||= basename if server.params_in_url.include?('basename')
418
+ attrs[:ext] ||= ext if server.params_in_url.include?('ext')
419
+ attrs[:format] = (attrs[:format] || format_from_meta).to_s if server.params_in_url.include?('format')
420
+ attrs.delete_if{|k, v| v.blank? }
421
+ attrs
422
+ end
423
+
424
+ def update(content, meta)
425
+ if meta
426
+ meta.merge!(meta.delete(:meta)) if meta[:meta] # legacy data etc. may have nested meta hash - deprecate gracefully here
427
+ self.meta.merge!(meta)
428
+ end
429
+ if content
430
+ self.temp_object = TempObject.new(content)
431
+ self.name = temp_object.original_filename if name.nil? && temp_object.original_filename
432
+ end
433
+ end
434
+
435
+ protected
436
+
437
+ attr_writer :steps
438
+ attr_accessor :next_step_index
439
+
440
+ private
441
+
442
+ def format_from_meta
443
+ meta[:format] || (ext.to_sym if ext && app.trust_file_extensions)
444
+ end
445
+
446
+ def last_step_of_type(type)
447
+ steps.select{|s| s.is_a?(type) }.last
448
+ end
449
+
450
+ end
451
+ end