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
@@ -0,0 +1,78 @@
1
+ module Dragonfly
2
+ class UrlMapper
3
+
4
+ # Exceptions
5
+ class BadUrlFormat < StandardError; end
6
+
7
+ class Segment < Struct.new(:param, :seperator, :pattern)
8
+
9
+ def regexp_string
10
+ @regexp_string ||= "(#{Regexp.escape(seperator)}#{pattern}+?)?"
11
+ end
12
+ #
13
+ # def regexp
14
+ # @regexp ||= Regexp.new(regexp_string)
15
+ # end
16
+
17
+ end
18
+
19
+ def initialize(url_format, patterns={})
20
+ @url_format = url_format
21
+ raise BadUrlFormat, "bad url format #{url_format}" if url_format[/[\w_]:[\w_]/]
22
+ init_segments(patterns)
23
+ init_url_regexp
24
+ end
25
+
26
+ attr_reader :url_format, :url_regexp, :segments
27
+
28
+ def params_for(path, query=nil)
29
+ if path and md = path.match(url_regexp)
30
+ params = Rack::Utils.parse_query(query)
31
+ params_in_url.each_with_index do |var, i|
32
+ value = md[i+1][1..-1] if md[i+1]
33
+ params[var] = value
34
+ end
35
+ params
36
+ end
37
+ end
38
+
39
+ def params_in_url
40
+ @params_in_url ||= url_format.scan(/\:[\w_]+/).map{|f| f.tr(':','') }
41
+ end
42
+
43
+ def url_for(params)
44
+ params = params.dup
45
+ url = url_format.dup
46
+ segments.each do |seg|
47
+ value = params[seg.param]
48
+ value ? url.sub!(/:[\w_]+/, value.to_s) : url.sub!(/.:[\w_]+/, '')
49
+ params.delete(seg.param)
50
+ end
51
+ url << "?#{Rack::Utils.build_query(params)}" if params.any?
52
+ url
53
+ end
54
+
55
+ private
56
+
57
+ def init_segments(patterns)
58
+ @segments = []
59
+ url_format.scan(/([^\w_]):([\w_]+)/).each do |seperator, param|
60
+ segments << Segment.new(
61
+ param,
62
+ seperator,
63
+ patterns[param.to_sym] || '[^\/\-\.]'
64
+ )
65
+ end
66
+ end
67
+
68
+ def init_url_regexp
69
+ i = -1
70
+ regexp_string = url_format.gsub(/[^\w_]:[\w_]+/) do
71
+ i += 1
72
+ segments[i].regexp_string
73
+ end
74
+ @url_regexp = Regexp.new('^' + regexp_string + '$')
75
+ end
76
+
77
+ end
78
+ end
@@ -1,22 +1,52 @@
1
- require File.dirname(__FILE__) + '/spec_helper'
1
+ require 'dragonfly/active_model_extensions/spec_helper'
2
2
 
3
3
  describe Item do
4
4
 
5
+ def set_up_item_class(app=test_app)
6
+ app.define_macro(MyModel, :image_accessor)
7
+ Item.class_eval do
8
+ image_accessor :preview_image
9
+ end
10
+ end
11
+
5
12
  # See extra setup in models / initializer files
6
13
 
7
14
  describe "defining accessors" do
8
15
 
9
- let(:app1){ Dragonfly[:images] }
10
- let(:app2){ Dragonfly[:videos] }
16
+ let(:app1){ Dragonfly[:img] }
17
+ let(:app2){ Dragonfly[:vid] }
11
18
 
12
- it "should return the mapping of apps to attributes" do
13
- app1.define_macro(model_class, :image_accessor)
14
- app2.define_macro(model_class, :video_accessor)
15
- Item.class_eval do
16
- image_accessor :preview_image
17
- video_accessor :trailer_video
19
+ describe "attachment classes" do
20
+ before(:each) do
21
+ app1.define_macro(MyModel, :image_accessor)
22
+ app2.define_macro(MyModel, :video_accessor)
23
+ Item.class_eval do
24
+ image_accessor :preview_image
25
+ video_accessor :trailer_video
26
+ end
27
+ @classes = Item.dragonfly_attachment_classes
28
+ @class1, @class2 = @classes
29
+ end
30
+
31
+ it "should return the attachment classes" do
32
+ @class1.superclass.should == Dragonfly::ActiveModelExtensions::Attachment
33
+ @class2.superclass.should == Dragonfly::ActiveModelExtensions::Attachment
34
+ end
35
+
36
+ it "should associate the correct app with each class" do
37
+ @class1.app.should == app1
38
+ @class2.app.should == app2
39
+ end
40
+
41
+ it "should associate the correct attribute with each class" do
42
+ @class1.attribute.should == :preview_image
43
+ @class2.attribute.should == :trailer_video
44
+ end
45
+
46
+ it "should associate the correct model class with each class" do
47
+ @class1.model_class.should == Item
48
+ @class2.model_class.should == Item
18
49
  end
19
- Item.dragonfly_apps_for_attributes.should == {:preview_image => app1, :trailer_video => app2}
20
50
  end
21
51
 
22
52
  it "should work for included modules (e.g. Mongoid::Document)" do
@@ -28,7 +58,9 @@ describe Item do
28
58
  include mongoid_document
29
59
  dog_accessor :doogie
30
60
  end
31
- model_class.dragonfly_apps_for_attributes.should == {:doogie => app1}
61
+ klass = model_class.dragonfly_attachment_classes.first
62
+ klass.app.should == app1
63
+ klass.attribute.should == :doogie
32
64
  end
33
65
 
34
66
  end
@@ -36,8 +68,8 @@ describe Item do
36
68
  describe "correctly defined" do
37
69
 
38
70
  before(:each) do
39
- @app = Dragonfly[:images]
40
- @app.define_macro(model_class, :image_accessor)
71
+ @app = test_app
72
+ @app.define_macro(MyModel, :image_accessor)
41
73
  Item.class_eval do
42
74
  image_accessor :preview_image
43
75
  end
@@ -102,7 +134,7 @@ describe Item do
102
134
  @item.preview_image_uid.should be_nil
103
135
  end
104
136
  it "should store the image when saved" do
105
- @app.datastore.should_receive(:store).with(a_temp_object_with_data("DATASTRING"), {})
137
+ @app.datastore.should_receive(:store).with(a_temp_object_with_data("DATASTRING"), hash_including)
106
138
  @item.save!
107
139
  end
108
140
  it "should not try to destroy anything on destroy" do
@@ -136,7 +168,7 @@ describe Item do
136
168
 
137
169
  before(:each) do
138
170
  @item.preview_image = "DATASTRING"
139
- @app.datastore.should_receive(:store).with(a_temp_object_with_data("DATASTRING"), {}).once.and_return('some_uid')
171
+ @app.datastore.should_receive(:store).with(a_temp_object_with_data("DATASTRING"), hash_including).once.and_return('some_uid')
140
172
  @item.save!
141
173
  end
142
174
 
@@ -159,8 +191,7 @@ describe Item do
159
191
  end
160
192
 
161
193
  it "should return the url for the data" do
162
- @app.should_receive(:url_for).with(an_instance_of(Dragonfly::Job), {}).and_return('some.url')
163
- @item.preview_image.url.should == 'some.url'
194
+ @item.preview_image.url.should =~ %r<^/\w+$>
164
195
  end
165
196
 
166
197
  it "should destroy the old data when the uid is set manually" do
@@ -203,7 +234,7 @@ describe Item do
203
234
  @item.save!
204
235
  end
205
236
  it "should store the new data when saved" do
206
- @app.datastore.should_receive(:store).with(a_temp_object_with_data("ANEWDATASTRING"), {})
237
+ @app.datastore.should_receive(:store).with(a_temp_object_with_data("ANEWDATASTRING"), hash_including)
207
238
  @item.save!
208
239
  end
209
240
  it "should destroy the old data on destroy" do
@@ -329,13 +360,25 @@ describe Item do
329
360
  end
330
361
  end
331
362
 
363
+ describe "remote_url" do
364
+ it "should give the remote url if the uid is set" do
365
+ @item.preview_image_uid = 'some/uid'
366
+ @app.should_receive(:remote_url_for).with('some/uid', :some => 'param').and_return('http://egg.nog')
367
+ @item.preview_image.remote_url(:some => 'param').should == 'http://egg.nog'
368
+ end
369
+ it "should return nil if the content is not yet saved" do
370
+ @item.preview_image = "hello"
371
+ @item.preview_image.remote_url(:some => 'param').should be_nil
372
+ end
373
+ end
374
+
332
375
  end
333
376
 
334
377
  describe "validations" do
335
378
 
336
379
  before(:all) do
337
- @app = Dragonfly[:images]
338
- @app.define_macro(model_class, :image_accessor)
380
+ @app = test_app
381
+ @app.define_macro(MyModel, :image_accessor)
339
382
  end
340
383
 
341
384
  describe "validates_presence_of" do
@@ -424,27 +467,27 @@ describe Item do
424
467
  it "should be invalid if the property is nil" do
425
468
  @item.preview_image = "OTHER TYPE"
426
469
  @item.should_not be_valid
427
- @item.errors[:preview_image].should match_ar_error("mime type is incorrect. It needs to be one of 'how/special', 'how/crazy', but was ''")
470
+ @item.errors[:preview_image].should == ["mime type is incorrect. It needs to be one of 'how/special', 'how/crazy', but was 'application/octet-stream'"]
428
471
  end
429
472
 
430
473
  it "should be invalid if the property is wrong" do
431
474
  @item.preview_image = "WRONG TYPE"
432
475
  @item.should_not be_valid
433
- @item.errors[:preview_image].should match_ar_error("mime type is incorrect. It needs to be one of 'how/special', 'how/crazy', but was 'wrong/type'")
476
+ @item.errors[:preview_image].should == ["mime type is incorrect. It needs to be one of 'how/special', 'how/crazy', but was 'wrong/type'"]
434
477
  end
435
478
 
436
479
  it "should work for a range" do
437
480
  @item.preview_image = "GOOGLE GUM"
438
481
  @item.should_not be_valid
439
- @item.errors[:preview_image].should match_ar_error("number of gs is incorrect. It needs to be between 0 and 2, but was '3'")
482
+ @item.errors[:preview_image].should == ["number of gs is incorrect. It needs to be between 0 and 2, but was '3'"]
440
483
  end
441
484
 
442
485
  it "should validate individually" do
443
486
  @item.other_image = "1234567"
444
487
  @item.yet_another_image = "WRONG TYPE"
445
488
  @item.should_not be_valid
446
- @item.errors[:other_image].should match_ar_error(nil)
447
- @item.errors[:yet_another_image].should match_ar_error("mime type is incorrect. It needs to be 'how/special', but was 'wrong/type'")
489
+ @item.errors[:other_image].should == []
490
+ @item.errors[:yet_another_image].should == ["mime type is incorrect. It needs to be 'how/special', but was 'wrong/type'"]
448
491
  end
449
492
 
450
493
  it "should include standard extra options like 'if' on mime type validation" do
@@ -472,7 +515,19 @@ describe Item do
472
515
  it "should allow for custom messages" do
473
516
  @item.otra_imagen = "WRONG TYPE"
474
517
  @item.should_not be_valid
475
- @item.errors[:otra_imagen].should match_ar_error("tipo de contenido incorrecto. Que chungo tio")
518
+ @item.errors[:otra_imagen].should == ["tipo de contenido incorrecto. Que chungo tio"]
519
+ end
520
+
521
+ it "should allow for custom messages including access to the property name and expected/allowed values" do
522
+ @item.should_receive(:its_friday).and_return(false) # hack to get rid of other validation
523
+ Item.class_eval do
524
+ validates_property :mime_type, :of => :preview_image, :as => 'one/thing',
525
+ :message => proc{|actual, model| "Unlucky #{model.title}! Was #{actual}" }
526
+ end
527
+ @item.title = 'scubby'
528
+ @item.preview_image = "WRONG TYPE"
529
+ @item.should_not be_valid
530
+ @item.errors[:preview_image].should == ["Unlucky scubby! Was wrong/type"]
476
531
  end
477
532
 
478
533
  end
@@ -482,7 +537,7 @@ describe Item do
482
537
  describe "extra properties" do
483
538
 
484
539
  before(:each) do
485
- @app = Dragonfly[:images]
540
+ @app = test_app
486
541
  custom_analyser = Class.new do
487
542
  def some_analyser_method(temp_object)
488
543
  "abc" + temp_object.data[0..0]
@@ -490,7 +545,7 @@ describe Item do
490
545
  def number_of_As(temp_object); temp_object.data.count('A'); end
491
546
  end
492
547
  @app.analyser.register(custom_analyser)
493
- @app.define_macro(model_class, :image_accessor)
548
+ @app.define_macro(MyModel, :image_accessor)
494
549
  Item.class_eval do
495
550
  image_accessor :preview_image
496
551
  end
@@ -520,12 +575,6 @@ describe Item do
520
575
  @item.preview_image_some_analyser_method.should == 'abc4'
521
576
  end
522
577
 
523
- it "should reset the magic attribute when set to nil" do
524
- @item.preview_image = '123'
525
- @item.preview_image = nil
526
- @item.preview_image_some_analyser_method.should be_nil
527
- end
528
-
529
578
  it "should not reset non-magic attributes with the same prefix when set to nil" do
530
579
  @item.preview_image_blah_blah = 'wassup'
531
580
  @item.preview_image = '123'
@@ -538,21 +587,53 @@ describe Item do
538
587
  @item.preview_image_size.should == 3
539
588
  end
540
589
 
541
- it "should store the original file extension if it exists" do
590
+ it "should store the original file name if it exists" do
542
591
  data = 'jasdlkf sadjl'
543
592
  data.stub!(:original_filename).and_return('hello.png')
544
593
  @item.preview_image = data
545
- @item.preview_image_ext.should == 'png'
594
+ @item.preview_image_name.should == 'hello.png'
546
595
  end
547
596
 
548
- it "should store the original file name if it exists" do
597
+ end
598
+
599
+ describe "meta from magic attributes" do
600
+
601
+ it "should set the meta for the magic attribute when assigned" do
602
+ @item.preview_image = '123'
603
+ @item.preview_image.meta[:some_analyser_method].should == 'abc1'
604
+ end
605
+
606
+ it "should not set meta for non-magic attributes with the same prefix when assigned" do
607
+ @item.preview_image = '123'
608
+ @item.preview_image.meta[:blah_blah].should be_nil
609
+ end
610
+
611
+ it "should update the meta for the magic attribute when something else is assigned" do
612
+ @item.preview_image = '123'
613
+ @item.preview_image = '456'
614
+ @item.preview_image.meta[:some_analyser_method].should == 'abc4'
615
+ end
616
+
617
+ it "should include the meta for size too" do
618
+ @item.preview_image = '123'
619
+ @item.preview_image.meta[:size].should == 3
620
+ end
621
+
622
+ it "should store the meta for the original file name if it exists" do
549
623
  data = 'jasdlkf sadjl'
550
624
  data.stub!(:original_filename).and_return('hello.png')
551
625
  @item.preview_image = data
552
- @item.preview_image_name.should == 'hello.png'
626
+ @item.preview_image.meta[:name].should == 'hello.png'
627
+ end
628
+
629
+ it "should still have the meta after reload" do
630
+ @item.preview_image = '123'
631
+ @item.save!
632
+ item = Item.find(@item.id)
633
+ item.preview_image.meta[:some_analyser_method].should == 'abc1'
553
634
  end
554
- end
555
635
 
636
+ end
556
637
 
557
638
  describe "delegating methods to the job" do
558
639
  before(:each) do
@@ -588,22 +669,20 @@ describe Item do
588
669
  end
589
670
  it "should use the magic attribute if there is one, and not load the content" do
590
671
  @app.datastore.should_not_receive(:retrieve)
591
- @item.should_receive(:preview_image_some_analyser_method).and_return('result yo')
672
+ @item.should_receive(:preview_image_some_analyser_method).at_least(:once).and_return('result yo')
592
673
  @item.preview_image.some_analyser_method.should == 'result yo'
593
674
  end
594
675
 
595
- %w(size name ext).each do |attr|
596
- it "should use the magic attribute for #{attr} if there is one, and not load the content" do
597
- @app.datastore.should_not_receive(:retrieve)
598
- @item.should_receive("preview_image_#{attr}".to_sym).and_return('result yo')
599
- @item.preview_image.send(attr).should == 'result yo'
600
- end
676
+ it "should use the magic attribute for size if there is one, and not the job object" do
677
+ @item.preview_image.send(:job).should_not_receive(:size)
678
+ @item.should_receive("preview_image_size").and_return(17)
679
+ @item.preview_image.size.should == 17
680
+ end
601
681
 
602
- it "should load the content then delegate '#{attr}' if there is no magic attribute for it" do
603
- @item.should_receive(:public_methods).and_return(['preview_image_uid']) # no magic attributes
604
- @app.datastore.should_receive(:retrieve).with('my_uid').and_return(['DATASTRING', {}])
605
- @item.preview_image.send(attr).should == @item.preview_image.send(:job).send(attr)
606
- end
682
+ it "should delegate 'size' to the job object if there is no magic attribute for it" do
683
+ @item.other_image = 'blahdata'
684
+ @item.other_image.send(:job).should_receive(:size).and_return 54
685
+ @item.other_image.size.should == 54
607
686
  end
608
687
 
609
688
  end
@@ -615,6 +694,19 @@ describe Item do
615
694
  }.should raise_error(NoMethodError)
616
695
  end
617
696
  end
697
+
698
+ describe "job shortcuts" do
699
+ before(:each) do
700
+ @app.job :bacon do
701
+ process :breakfast
702
+ end
703
+ @item = Item.new :preview_image => 'gurg'
704
+ end
705
+ it "should add job shortcuts for that app" do
706
+ job = @item.preview_image.bacon
707
+ job.steps.first.should be_a(Dragonfly::Job::Process)
708
+ end
709
+ end
618
710
 
619
711
  describe "setting things on the attachment" do
620
712
 
@@ -636,6 +728,9 @@ describe Item do
636
728
  it "should return the name" do
637
729
  (@item.preview_image.name = 'no.silly').should == 'no.silly'
638
730
  end
731
+ it "should update the ext too" do
732
+ @item.preview_image.ext.should == 'there'
733
+ end
639
734
  end
640
735
 
641
736
  describe "meta" do
@@ -656,12 +751,12 @@ describe Item do
656
751
  it "should save it correctly" do
657
752
  @item.save!
658
753
  item = Item.find(@item.id)
659
- item.preview_image.meta.should include_hash(:slime => 'balls')
754
+ item.preview_image.apply.meta.should include_hash(:slime => 'balls')
660
755
  end
661
- it "should store meta info about the model" do
756
+ it "should include meta info about the model" do
662
757
  @item.save!
663
- meta = {:model_class => 'Item', :model_attachment => :preview_image, :slime => 'balls'}
664
- @app.fetch(@item.preview_image_uid).meta.should == meta
758
+ item = Item.find(@item.id)
759
+ item.preview_image.meta.should include_hash(:model_class => 'Item', :model_attachment => :preview_image)
665
760
  end
666
761
  end
667
762
 
@@ -672,10 +767,10 @@ describe Item do
672
767
  describe "inheritance" do
673
768
 
674
769
  before(:all) do
675
- @app = Dragonfly[:images]
676
- @app2 = Dragonfly[:egg]
677
- @app.define_macro(model_class, :image_accessor)
678
- @app2.define_macro(model_class, :egg_accessor)
770
+ @app = test_app
771
+ @app2 = test_app
772
+ @app.define_macro(MyModel, :image_accessor)
773
+ @app2.define_macro(MyModel, :egg_accessor)
679
774
  Car.class_eval do
680
775
  image_accessor :image
681
776
  end
@@ -712,12 +807,624 @@ describe Item do
712
807
  it "should allow assigning subclass accessors in the subclass, even if it has mixins" do
713
808
  @subclass_with_module.create! :reliant_image => 'blah'
714
809
  end
715
- it "return the correct apps for each accessors, even when names clash" do
716
- @base_class.dragonfly_apps_for_attributes.should == {:image => @app}
717
- @subclass.dragonfly_apps_for_attributes.should == {:image => @app, :reliant_image => @app}
718
- @subclass_with_module.dragonfly_apps_for_attributes.should == {:image => @app, :reliant_image => @app}
719
- @unrelated_class.dragonfly_apps_for_attributes.should == {:image => @app2}
810
+ it "should return the correct attachment classes for the base class" do
811
+ @base_class.dragonfly_attachment_classes.should match_attachment_classes([[Car, :image, @app]])
812
+ end
813
+ it "should return the correct attachment classes for the subclass" do
814
+ @subclass.dragonfly_attachment_classes.should match_attachment_classes([[ReliantRobin, :image, @app], [ReliantRobin, :reliant_image, @app]])
815
+ end
816
+ it "should return the correct attachment classes for the subclass with module" do
817
+ @subclass_with_module.dragonfly_attachment_classes.should match_attachment_classes([[ReliantRobinWithModule, :image, @app], [ReliantRobinWithModule, :reliant_image, @app]])
818
+ end
819
+ it "should return the correct attachment classes for a class from a different hierarchy" do
820
+ @unrelated_class.dragonfly_attachment_classes.should match_attachment_classes([[Photo, :image, @app2]])
821
+ end
822
+ end
823
+
824
+ describe "setting the url" do
825
+ before(:each) do
826
+ set_up_item_class
827
+ @item = Item.new
828
+ stub_request(:get, "http://some.url/yo.png").to_return(:body => "aaaaayo")
829
+ end
830
+
831
+ it "should allow setting the url" do
832
+ @item.preview_image_url = 'http://some.url/yo.png'
833
+ @item.preview_image.data.should == 'aaaaayo'
834
+ end
835
+ it "should return nil always for the reader" do
836
+ @item.preview_image_url = 'http://some.url/yo.png'
837
+ @item.preview_image_url.should be_nil
838
+ end
839
+ it "should have set the name" do
840
+ @item.preview_image_url = 'http://some.url/yo.png'
841
+ @item.preview_image_name.should == 'yo.png'
842
+ @item.preview_image.meta[:name].should == 'yo.png'
843
+ end
844
+ [nil, ""].each do |value|
845
+ it "should do nothing if set with #{value.inspect}" do
846
+ @item.preview_image_url = value
847
+ @item.preview_image.should be_nil
848
+ end
849
+ end
850
+ end
851
+
852
+ describe "removing the accessor with e.g. a form" do
853
+ before(:each) do
854
+ set_up_item_class
855
+ @item = Item.new
856
+ @item.preview_image = "something"
857
+ end
858
+
859
+ [
860
+ 1,
861
+ "1",
862
+ true,
863
+ "true",
864
+ "blahblah"
865
+ ].each do |value|
866
+ it "should remove the accessor if passed #{value.inspect}" do
867
+ @item.remove_preview_image = value
868
+ @item.preview_image.should be_nil
869
+ end
870
+
871
+ it "should return true when called if set with #{value.inspect}" do
872
+ @item.remove_preview_image = value
873
+ @item.remove_preview_image.should be_true
874
+ end
875
+ end
876
+
877
+ [
878
+ 0,
879
+ "0",
880
+ false,
881
+ "false",
882
+ "",
883
+ nil
884
+ ].each do |value|
885
+ it "should not remove the accessor if passed #{value.inspect}" do
886
+ @item.remove_preview_image = value
887
+ @item.preview_image.should_not be_nil
888
+ end
889
+
890
+ it "should return false when called if set with #{value.inspect}" do
891
+ @item.remove_preview_image = value
892
+ @item.remove_preview_image.should be_false
893
+ end
894
+ end
895
+
896
+ it "should return false by default for the getter" do
897
+ @item.remove_preview_image.should be_false
898
+ end
899
+
900
+ end
901
+
902
+ describe "callbacks" do
903
+
904
+ describe "after_assign" do
905
+
906
+ before(:each) do
907
+ @app = test_app
908
+ @app.define_macro(MyModel, :image_accessor)
909
+ end
910
+
911
+ describe "as a block" do
912
+
913
+ def set_after_assign(*args, &block)
914
+ Item.class_eval do
915
+ image_accessor :preview_image do
916
+ after_assign(*args, &block)
917
+ end
918
+ end
919
+ end
920
+
921
+ it "should call it after assign" do
922
+ x = nil
923
+ set_after_assign{ x = 3 }
924
+ Item.new.preview_image = "hello"
925
+ x.should == 3
926
+ end
927
+
928
+ it "should not call it after unassign" do
929
+ x = nil
930
+ set_after_assign{ x = 3 }
931
+ Item.new.preview_image = nil
932
+ x.should be_nil
933
+ end
934
+
935
+ it "should yield the attachment" do
936
+ x = nil
937
+ set_after_assign{|a| x = a.data }
938
+ Item.new.preview_image = "discussion"
939
+ x.should == "discussion"
940
+ end
941
+
942
+ it "should evaluate in the model context" do
943
+ x = nil
944
+ set_after_assign{ x = title.upcase }
945
+ item = Item.new
946
+ item.title = "big"
947
+ item.preview_image = "jobs"
948
+ x.should == "BIG"
949
+ end
950
+
951
+ it "should allow passing a symbol for calling a model method" do
952
+ set_after_assign :set_title
953
+ item = Item.new
954
+ def item.set_title; self.title = 'duggen'; end
955
+ item.preview_image = "jobs"
956
+ item.title.should == "duggen"
957
+ end
958
+
959
+ it "should allow passing multiple symbols" do
960
+ set_after_assign :set_title, :upcase_title
961
+ item = Item.new
962
+ def item.set_title; self.title = 'doobie'; end
963
+ def item.upcase_title; self.title.upcase!; end
964
+ item.preview_image = "jobs"
965
+ item.title.should == "DOOBIE"
966
+ end
967
+
968
+ it "should not re-trigger callbacks (causing an infinite loop)" do
969
+ set_after_assign{|a| self.preview_image = 'dogman' }
970
+ item = Item.new
971
+ item.preview_image = "hello"
972
+ end
973
+
974
+ end
975
+
976
+ end
977
+
978
+ describe "after_unassign" do
979
+ before(:each) do
980
+ @app = test_app
981
+ @app.define_macro(MyModel, :image_accessor)
982
+ Item.class_eval do
983
+ image_accessor :preview_image do
984
+ after_unassign{ self.title = 'unassigned' }
985
+ end
986
+ end
987
+ @item = Item.new :title => 'yo'
988
+ end
989
+
990
+ it "should not call it after assign" do
991
+ @item.preview_image = 'suggs'
992
+ @item.title.should == 'yo'
993
+ end
994
+
995
+ it "should call it after unassign" do
996
+ @item.preview_image = nil
997
+ @item.title.should == 'unassigned'
998
+ end
999
+ end
1000
+
1001
+ describe "copy_to" do
1002
+ before(:each) do
1003
+ @app = test_app
1004
+ @app.define_macro(MyModel, :image_accessor)
1005
+ @app.processor.add(:append) do |temp_object, string|
1006
+ temp_object.data + string
1007
+ end
1008
+ Item.class_eval do
1009
+ image_accessor :preview_image do
1010
+ copy_to(:other_image){|a| a.process(:append, title) }
1011
+ copy_to(:yet_another_image)
1012
+ end
1013
+ image_accessor :other_image
1014
+ image_accessor :yet_another_image
1015
+ end
1016
+ @item = Item.new :title => 'yo'
1017
+ end
1018
+
1019
+ it "should copy to the other image when assigned" do
1020
+ @item.preview_image = 'hello bear'
1021
+ @item.other_image.data.should == 'hello bearyo'
1022
+ end
1023
+
1024
+ it "should remove the other image when unassigned" do
1025
+ @item.preview_image = 'hello bear'
1026
+ @item.preview_image = nil
1027
+ @item.other_image.should be_nil
1028
+ end
1029
+
1030
+ it "should allow simply copying over without args" do
1031
+ @item.preview_image = 'hello bear'
1032
+ @item.yet_another_image.data.should == 'hello bear'
1033
+ end
1034
+
1035
+ end
1036
+
1037
+ end
1038
+
1039
+ describe "storage_opts" do
1040
+
1041
+ def set_storage_opts(*args, &block)
1042
+ Item.class_eval do
1043
+ image_accessor :preview_image do
1044
+ storage_opts(*args, &block)
1045
+ end
1046
+ end
1047
+ end
1048
+
1049
+ before(:each) do
1050
+ @app = test_app
1051
+ @app.define_macro(MyModel, :image_accessor)
1052
+ end
1053
+
1054
+ it "should send the specified options to the datastore on store" do
1055
+ set_storage_opts :egg => 'head'
1056
+ item = Item.new :preview_image => 'hello'
1057
+ @app.datastore.should_receive(:store).with(anything, hash_including(:egg => 'head'))
1058
+ item.save!
1059
+ end
1060
+
1061
+ it "should allow putting in a proc" do
1062
+ set_storage_opts{ {:egg => 'numb'} }
1063
+ item = Item.new :preview_image => 'hello'
1064
+ @app.datastore.should_receive(:store).with(anything, hash_including(:egg => 'numb'))
1065
+ item.save!
1066
+ end
1067
+
1068
+ it "should yield the attachment and exec in model context" do
1069
+ set_storage_opts{|a| {:egg => (a.data + title)} }
1070
+ item = Item.new :title => 'lump', :preview_image => 'hello'
1071
+ @app.datastore.should_receive(:store).with(anything, hash_including(:egg => 'hellolump'))
1072
+ item.save!
1073
+ end
1074
+
1075
+ it "should allow giving it a method symbol" do
1076
+ set_storage_opts :special_ops
1077
+ item = Item.new :preview_image => 'hello'
1078
+ def item.special_ops; {:a => 1}; end
1079
+ @app.datastore.should_receive(:store).with(anything, hash_including(:a => 1))
1080
+ item.save!
1081
+ end
1082
+
1083
+ it "should allow setting more than once" do
1084
+ Item.class_eval do
1085
+ image_accessor :preview_image do
1086
+ storage_opts{{ :a => title, :b => 'dumple' }}
1087
+ storage_opts{{ :b => title.upcase, :c => 'digby' }}
1088
+ end
1089
+ end
1090
+ item = Item.new :title => 'lump', :preview_image => 'hello'
1091
+ @app.datastore.should_receive(:store).with(anything, hash_including(
1092
+ :a => 'lump', :b => 'LUMP', :c => 'digby'
1093
+ ))
1094
+ item.save!
720
1095
  end
721
1096
  end
722
1097
 
723
- end
1098
+ describe "storage_path, etc." do
1099
+
1100
+ def set_storage_path(path=nil, &block)
1101
+ Item.class_eval do
1102
+ image_accessor :preview_image do
1103
+ storage_path(path, &block)
1104
+ end
1105
+ def monkey
1106
+ "mr/#{title}/monkey"
1107
+ end
1108
+ end
1109
+ end
1110
+
1111
+ before(:each) do
1112
+ @app = test_app
1113
+ @app.define_macro(MyModel, :image_accessor)
1114
+ end
1115
+
1116
+ it "should allow setting as a string" do
1117
+ set_storage_path 'always/the/same'
1118
+ item = Item.new :preview_image => 'bilbo'
1119
+ @app.datastore.should_receive(:store).with(anything, hash_including(
1120
+ :path => 'always/the/same'
1121
+ ))
1122
+ item.save!
1123
+ end
1124
+
1125
+ it "should allow setting as a symbol" do
1126
+ set_storage_path :monkey
1127
+ item = Item.new :title => 'billy'
1128
+ item.preview_image = 'bilbo'
1129
+ @app.datastore.should_receive(:store).with(anything, hash_including(
1130
+ :path => 'mr/billy/monkey'
1131
+ ))
1132
+ item.save!
1133
+ end
1134
+
1135
+ it "should allow setting as a block" do
1136
+ set_storage_path{|a| "#{a.data}/megs/#{title}" }
1137
+ item = Item.new :title => 'billy'
1138
+ item.preview_image = 'bilbo'
1139
+ @app.datastore.should_receive(:store).with(anything, hash_including(
1140
+ :path => 'bilbo/megs/billy'
1141
+ ))
1142
+ item.save!
1143
+ end
1144
+
1145
+ it "should work for other storage_xxx declarations" do
1146
+ Item.class_eval do
1147
+ image_accessor :preview_image do
1148
+ storage_eggs 23
1149
+ end
1150
+ end
1151
+ item = Item.new :preview_image => 'bilbo'
1152
+ @app.datastore.should_receive(:store).with(anything, hash_including(
1153
+ :eggs => 23
1154
+ ))
1155
+ item.save!
1156
+ end
1157
+ end
1158
+
1159
+ describe "unknown config method" do
1160
+ it "should raise an error" do
1161
+ lambda{
1162
+ Item.class_eval do
1163
+ image_accessor :preview_image do
1164
+ what :now?
1165
+ end
1166
+ end
1167
+ }.should raise_error(NoMethodError)
1168
+ end
1169
+ end
1170
+
1171
+ describe "changed?" do
1172
+ before(:each) do
1173
+ set_up_item_class
1174
+ @item = Item.new
1175
+ end
1176
+
1177
+ it "should be changed when assigned" do
1178
+ @item.preview_image = 'ggg'
1179
+ @item.preview_image.should be_changed
1180
+ end
1181
+
1182
+ it "should not be changed when saved" do
1183
+ @item.preview_image = 'ggg'
1184
+ @item.save!
1185
+ @item.preview_image.should_not be_changed
1186
+ end
1187
+
1188
+ it "should not be changed when reloaded" do
1189
+ @item.preview_image = 'ggg'
1190
+ @item.save!
1191
+ item = Item.find(@item.id)
1192
+ item.preview_image.should_not be_changed
1193
+ end
1194
+ end
1195
+
1196
+ describe "retain and pending" do
1197
+ before(:each) do
1198
+ set_up_item_class(@app=test_app)
1199
+ @app.analyser.add :some_analyser_method do |temp_object|
1200
+ temp_object.data.upcase
1201
+ end
1202
+ @item = Item.new
1203
+ end
1204
+
1205
+ it "should return nil if there are no changes" do
1206
+ @item.retained_preview_image.should be_nil
1207
+ end
1208
+
1209
+ it "should return nil if assigned but not saved" do
1210
+ @item.preview_image = 'hello'
1211
+ @item.retained_preview_image.should be_nil
1212
+ end
1213
+
1214
+ it "should return nil if assigned and saved" do
1215
+ @item.preview_image = 'hello'
1216
+ @item.save!
1217
+ @item.retained_preview_image.should be_nil
1218
+ end
1219
+
1220
+ it "should return the saved stuff if assigned and retained" do
1221
+ @item.preview_image = 'hello'
1222
+ @item.preview_image.name = 'dog.biscuit'
1223
+ @app.datastore.should_receive(:store).with(a_temp_object_with_data('hello'), anything).and_return('new/uid')
1224
+ @item.preview_image.retain!
1225
+ Dragonfly::Serializer.marshal_decode(@item.retained_preview_image).should == {
1226
+ :uid => 'new/uid',
1227
+ :some_analyser_method => 'HELLO',
1228
+ :size => 5,
1229
+ :name => 'dog.biscuit'
1230
+ }
1231
+ end
1232
+
1233
+ it "should return nil if assigned, retained and saved" do
1234
+ @item.preview_image = 'hello'
1235
+ @item.preview_image.retain!
1236
+ @item.save!
1237
+ @item.retained_preview_image.should be_nil
1238
+ end
1239
+
1240
+ it "should return nil if assigned, saved and retained" do
1241
+ @item.preview_image = 'hello'
1242
+ @item.save!
1243
+ @item.preview_image.retain!
1244
+ @item.retained_preview_image.should be_nil
1245
+ end
1246
+
1247
+ it "should return nil if no changes have been made" do
1248
+ @item.preview_image = 'hello'
1249
+ @item.save!
1250
+ item = Item.find(@item.id)
1251
+ item.preview_image.retain!
1252
+ item.retained_preview_image.should be_nil
1253
+ end
1254
+ end
1255
+
1256
+ describe "assigning from a pending state" do
1257
+ before(:each) do
1258
+ set_up_item_class(@app=test_app)
1259
+ @app.analyser.add :some_analyser_method do |temp_object|
1260
+ temp_object.data.upcase
1261
+ end
1262
+ @pending_string = Dragonfly::Serializer.marshal_encode(
1263
+ :uid => 'new/uid',
1264
+ :some_analyser_method => 'HELLO',
1265
+ :size => 5,
1266
+ :name => 'dog.biscuit'
1267
+ )
1268
+ @item = Item.new
1269
+ end
1270
+
1271
+ it "should update the attributes" do
1272
+ @item.retained_preview_image = @pending_string
1273
+ @item.preview_image_uid.should == 'new/uid'
1274
+ @item.preview_image_some_analyser_method.should == 'HELLO'
1275
+ @item.preview_image_size.should == 5
1276
+ @item.preview_image_name.should == 'dog.biscuit'
1277
+ end
1278
+
1279
+ it "should update the attachment meta" do
1280
+ @item.retained_preview_image = @pending_string
1281
+ @item.preview_image.meta[:some_analyser_method].should == 'HELLO'
1282
+ @item.preview_image.meta[:size].should == 5
1283
+ @item.preview_image.meta[:name].should == 'dog.biscuit'
1284
+ end
1285
+
1286
+ it "should be a normal fetch job" do
1287
+ @item.retained_preview_image = @pending_string
1288
+ @app.datastore.should_receive(:retrieve).with('new/uid').and_return(Dragonfly::TempObject.new('retrieved yo'))
1289
+ @item.preview_image.data.should == 'retrieved yo'
1290
+ end
1291
+
1292
+ it "should give the correct url" do
1293
+ @item.retained_preview_image = @pending_string
1294
+ @item.preview_image.url.should =~ %r{^/\w+/dog.biscuit$}
1295
+ end
1296
+
1297
+ it "should raise an error if the pending string contains a non-magic attr method" do
1298
+ pending_string = Dragonfly::Serializer.marshal_encode(
1299
+ :uid => 'new/uid',
1300
+ :some_analyser_method => 'HELLO',
1301
+ :size => 5,
1302
+ :name => 'dog.biscuit',
1303
+ :something => 'else'
1304
+ )
1305
+ item = @item
1306
+ lambda{
1307
+ item.retained_preview_image = pending_string
1308
+ }.should raise_error(Dragonfly::ActiveModelExtensions::Attachment::BadAssignmentKey)
1309
+ end
1310
+
1311
+ [nil, "", "asdfsad"].each do |value|
1312
+ it "should do nothing if assigned with #{value}" do
1313
+ @item.retained_preview_image = value
1314
+ @item.preview_image_uid.should be_nil
1315
+ end
1316
+ end
1317
+
1318
+ it "should return the pending string again" do
1319
+ @item.retained_preview_image = @pending_string
1320
+ Dragonfly::Serializer.marshal_decode(@item.retained_preview_image).should ==
1321
+ Dragonfly::Serializer.marshal_decode(@pending_string)
1322
+ end
1323
+
1324
+ it "should destroy the old one on save" do
1325
+ @item.preview_image = 'oldone'
1326
+ @app.datastore.should_receive(:store).with(a_temp_object_with_data('oldone'), anything).and_return('old/uid')
1327
+ @item.save!
1328
+ item = Item.find(@item.id)
1329
+ item.retained_preview_image = @pending_string
1330
+ @app.datastore.should_receive(:destroy).with('old/uid')
1331
+ item.save!
1332
+ end
1333
+
1334
+ describe "combinations of assignment" do
1335
+ it "should destroy the previously retained one if something new is then assigned" do
1336
+ @item.retained_preview_image = @pending_string
1337
+ @app.datastore.should_receive(:destroy).with('new/uid')
1338
+ @item.preview_image = 'yet another new thing'
1339
+ end
1340
+
1341
+ it "should destroy the previously retained one if something new is already assigned" do
1342
+ @item.preview_image = 'yet another new thing'
1343
+ @app.datastore.should_receive(:destroy).with('new/uid')
1344
+ @item.retained_preview_image = @pending_string
1345
+ end
1346
+
1347
+ it "should destroy the previously retained one if nil is then assigned" do
1348
+ @item.retained_preview_image = @pending_string
1349
+ @app.datastore.should_receive(:destroy).with('new/uid')
1350
+ @item.preview_image = nil
1351
+ end
1352
+
1353
+ it "should destroy the previously retained one if nil is already assigned" do
1354
+ @item.preview_image = nil
1355
+ @app.datastore.should_receive(:destroy).with('new/uid')
1356
+ @item.retained_preview_image = @pending_string
1357
+ end
1358
+
1359
+ describe "automatically retaining (hack to test for existence of hidden form field)" do
1360
+ it "should automatically retain if set as an empty string then changed" do
1361
+ @item.retained_preview_image = ""
1362
+ @item.dragonfly_attachments[:preview_image].should_receive(:retain!)
1363
+ @item.preview_image = "hello"
1364
+ end
1365
+
1366
+ it "should automatically retain if changed then set as an empty string" do
1367
+ @item.preview_image = "hello"
1368
+ @item.preview_image.should_receive(:retain!)
1369
+ @item.retained_preview_image = ""
1370
+ end
1371
+
1372
+ it "should retain if retained_string then accessor is assigned" do
1373
+ @item.retained_preview_image = @pending_string
1374
+ @item.preview_image.should_receive(:retain!)
1375
+ @item.preview_image = 'yet another new thing'
1376
+ end
1377
+
1378
+ it "should retain if accessor then retained_string is assigned" do
1379
+ @item.preview_image = 'yet another new thing'
1380
+ @item.preview_image.should_receive(:retain!)
1381
+ @item.retained_preview_image = @pending_string
1382
+ end
1383
+ end
1384
+ end
1385
+
1386
+ end
1387
+
1388
+ describe "format and mime type" do
1389
+ before(:each) do
1390
+ @app = test_app
1391
+ @app.analyser.add :mime_type do |temp_object|
1392
+ 'some/type'
1393
+ end
1394
+ set_up_item_class(@app)
1395
+ @item = Item.new
1396
+ @content = "doggo"
1397
+ @content.stub!(:original_filename).and_return('egg.png')
1398
+ end
1399
+ it "should trust the file extension with format if configured to" do
1400
+ @item.preview_image = @content
1401
+ @item.preview_image.format.should == :png
1402
+ end
1403
+ it "should trust the file extension with mime_type if configured to" do
1404
+ @item.preview_image = @content
1405
+ @item.preview_image.mime_type.should == 'image/png'
1406
+ end
1407
+ it "should not trust the file extension with format if configured not to" do
1408
+ @app.trust_file_extensions = false
1409
+ @item.preview_image = @content
1410
+ @item.preview_image.format.should == nil
1411
+ end
1412
+ it "should not trust the file extension with mime_type if configured not to" do
1413
+ @app.trust_file_extensions = false
1414
+ @item.preview_image = @content
1415
+ @item.preview_image.mime_type.should == 'some/type'
1416
+ end
1417
+ end
1418
+
1419
+ describe "inspect" do
1420
+ before(:each) do
1421
+ set_up_item_class
1422
+ @item = Item.new :preview_image => 'blug'
1423
+ @item.save!
1424
+ end
1425
+ it "should be awesome" do
1426
+ @item.preview_image.inspect.should =~ %r{^<Dragonfly Attachment uid="[^"]+".*>$}
1427
+ end
1428
+ end
1429
+
1430
+ end