fog-dragonfly 0.8.1

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

Potentially problematic release.


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

Files changed (155) hide show
  1. data/.specopts +2 -0
  2. data/.yardopts +23 -0
  3. data/Gemfile +23 -0
  4. data/Gemfile.rails.2.3.5 +14 -0
  5. data/History.md +266 -0
  6. data/LICENSE +20 -0
  7. data/README.md +88 -0
  8. data/Rakefile +92 -0
  9. data/VERSION +1 -0
  10. data/config.ru +13 -0
  11. data/docs.watchr +1 -0
  12. data/dragonfly.gemspec +293 -0
  13. data/extra_docs/Analysers.md +108 -0
  14. data/extra_docs/Caching.md +23 -0
  15. data/extra_docs/Configuration.md +138 -0
  16. data/extra_docs/DataStorage.md +136 -0
  17. data/extra_docs/Encoding.md +96 -0
  18. data/extra_docs/GeneralUsage.md +121 -0
  19. data/extra_docs/Generators.md +102 -0
  20. data/extra_docs/Heroku.md +50 -0
  21. data/extra_docs/Index.md +36 -0
  22. data/extra_docs/MimeTypes.md +40 -0
  23. data/extra_docs/Models.md +266 -0
  24. data/extra_docs/Mongo.md +45 -0
  25. data/extra_docs/Processing.md +130 -0
  26. data/extra_docs/Rack.md +52 -0
  27. data/extra_docs/Rails2.md +55 -0
  28. data/extra_docs/Rails3.md +62 -0
  29. data/extra_docs/Sinatra.md +25 -0
  30. data/extra_docs/URLs.md +169 -0
  31. data/features/3.0.3.feature +8 -0
  32. data/features/images.feature +47 -0
  33. data/features/no_processing.feature +14 -0
  34. data/features/rails_2.3.5.feature +7 -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 +39 -0
  38. data/features/support/env.rb +40 -0
  39. data/fixtures/files/app/models/album.rb +3 -0
  40. data/fixtures/files/app/views/albums/new.html.erb +4 -0
  41. data/fixtures/files/app/views/albums/show.html.erb +4 -0
  42. data/fixtures/files/config/initializers/dragonfly.rb +4 -0
  43. data/fixtures/files/features/manage_album_images.feature +12 -0
  44. data/fixtures/files/features/step_definitions/image_steps.rb +15 -0
  45. data/fixtures/files/features/support/paths.rb +15 -0
  46. data/fixtures/files/features/text_images.feature +7 -0
  47. data/fixtures/rails_2.3.5/template.rb +10 -0
  48. data/fixtures/rails_3.0.3/template.rb +20 -0
  49. data/irbrc.rb +17 -0
  50. data/lib/dragonfly.rb +45 -0
  51. data/lib/dragonfly/active_model_extensions.rb +13 -0
  52. data/lib/dragonfly/active_model_extensions/attachment.rb +169 -0
  53. data/lib/dragonfly/active_model_extensions/class_methods.rb +45 -0
  54. data/lib/dragonfly/active_model_extensions/instance_methods.rb +28 -0
  55. data/lib/dragonfly/active_model_extensions/validations.rb +37 -0
  56. data/lib/dragonfly/analyser.rb +59 -0
  57. data/lib/dragonfly/analysis/file_command_analyser.rb +32 -0
  58. data/lib/dragonfly/analysis/image_magick_analyser.rb +47 -0
  59. data/lib/dragonfly/analysis/r_magick_analyser.rb +63 -0
  60. data/lib/dragonfly/app.rb +182 -0
  61. data/lib/dragonfly/config/heroku.rb +19 -0
  62. data/lib/dragonfly/config/image_magick.rb +41 -0
  63. data/lib/dragonfly/config/r_magick.rb +46 -0
  64. data/lib/dragonfly/config/rails.rb +17 -0
  65. data/lib/dragonfly/configurable.rb +119 -0
  66. data/lib/dragonfly/core_ext/object.rb +8 -0
  67. data/lib/dragonfly/core_ext/string.rb +9 -0
  68. data/lib/dragonfly/core_ext/symbol.rb +9 -0
  69. data/lib/dragonfly/data_storage.rb +9 -0
  70. data/lib/dragonfly/data_storage/file_data_store.rb +114 -0
  71. data/lib/dragonfly/data_storage/mongo_data_store.rb +82 -0
  72. data/lib/dragonfly/data_storage/s3data_store.rb +115 -0
  73. data/lib/dragonfly/encoder.rb +13 -0
  74. data/lib/dragonfly/encoding/image_magick_encoder.rb +57 -0
  75. data/lib/dragonfly/encoding/r_magick_encoder.rb +61 -0
  76. data/lib/dragonfly/function_manager.rb +69 -0
  77. data/lib/dragonfly/generation/hash_with_css_style_keys.rb +23 -0
  78. data/lib/dragonfly/generation/image_magick_generator.rb +140 -0
  79. data/lib/dragonfly/generation/r_magick_generator.rb +155 -0
  80. data/lib/dragonfly/generator.rb +9 -0
  81. data/lib/dragonfly/image_magick_utils.rb +81 -0
  82. data/lib/dragonfly/job.rb +371 -0
  83. data/lib/dragonfly/job_builder.rb +39 -0
  84. data/lib/dragonfly/job_definitions.rb +26 -0
  85. data/lib/dragonfly/job_endpoint.rb +15 -0
  86. data/lib/dragonfly/loggable.rb +28 -0
  87. data/lib/dragonfly/middleware.rb +34 -0
  88. data/lib/dragonfly/processing/image_magick_processor.rb +99 -0
  89. data/lib/dragonfly/processing/r_magick_processor.rb +126 -0
  90. data/lib/dragonfly/processor.rb +9 -0
  91. data/lib/dragonfly/r_magick_utils.rb +48 -0
  92. data/lib/dragonfly/rails/images.rb +22 -0
  93. data/lib/dragonfly/response.rb +82 -0
  94. data/lib/dragonfly/routed_endpoint.rb +40 -0
  95. data/lib/dragonfly/serializer.rb +32 -0
  96. data/lib/dragonfly/simple_cache.rb +23 -0
  97. data/lib/dragonfly/simple_endpoint.rb +63 -0
  98. data/lib/dragonfly/temp_object.rb +220 -0
  99. data/samples/beach.png +0 -0
  100. data/samples/egg.png +0 -0
  101. data/samples/round.gif +0 -0
  102. data/samples/sample.docx +0 -0
  103. data/samples/taj.jpg +0 -0
  104. data/spec/argument_matchers.rb +19 -0
  105. data/spec/dragonfly/active_model_extensions/active_model_setup.rb +97 -0
  106. data/spec/dragonfly/active_model_extensions/active_record_setup.rb +85 -0
  107. data/spec/dragonfly/active_model_extensions/model_spec.rb +723 -0
  108. data/spec/dragonfly/active_model_extensions/spec_helper.rb +11 -0
  109. data/spec/dragonfly/analyser_spec.rb +123 -0
  110. data/spec/dragonfly/analysis/file_command_analyser_spec.rb +57 -0
  111. data/spec/dragonfly/analysis/image_magick_analyser_spec.rb +15 -0
  112. data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +27 -0
  113. data/spec/dragonfly/analysis/shared_analyser_spec.rb +51 -0
  114. data/spec/dragonfly/app_spec.rb +280 -0
  115. data/spec/dragonfly/config/r_magick_spec.rb +25 -0
  116. data/spec/dragonfly/configurable_spec.rb +220 -0
  117. data/spec/dragonfly/core_ext/string_spec.rb +17 -0
  118. data/spec/dragonfly/core_ext/symbol_spec.rb +17 -0
  119. data/spec/dragonfly/data_storage/data_store_spec.rb +76 -0
  120. data/spec/dragonfly/data_storage/file_data_store_spec.rb +169 -0
  121. data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +38 -0
  122. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +94 -0
  123. data/spec/dragonfly/deprecation_spec.rb +20 -0
  124. data/spec/dragonfly/encoding/image_magick_encoder_spec.rb +41 -0
  125. data/spec/dragonfly/encoding/r_magick_encoder_spec.rb +37 -0
  126. data/spec/dragonfly/function_manager_spec.rb +154 -0
  127. data/spec/dragonfly/generation/hash_with_css_style_keys_spec.rb +24 -0
  128. data/spec/dragonfly/generation/image_magick_generator_spec.rb +12 -0
  129. data/spec/dragonfly/generation/r_magick_generator_spec.rb +24 -0
  130. data/spec/dragonfly/generation/shared_generator_spec.rb +91 -0
  131. data/spec/dragonfly/image_magick_utils_spec.rb +16 -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 +120 -0
  135. data/spec/dragonfly/job_spec.rb +773 -0
  136. data/spec/dragonfly/loggable_spec.rb +80 -0
  137. data/spec/dragonfly/middleware_spec.rb +68 -0
  138. data/spec/dragonfly/processing/image_magick_processor_spec.rb +29 -0
  139. data/spec/dragonfly/processing/r_magick_processor_spec.rb +26 -0
  140. data/spec/dragonfly/processing/shared_processing_spec.rb +215 -0
  141. data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
  142. data/spec/dragonfly/serializer_spec.rb +61 -0
  143. data/spec/dragonfly/simple_cache_spec.rb +27 -0
  144. data/spec/dragonfly/simple_endpoint_spec.rb +89 -0
  145. data/spec/dragonfly/temp_object_spec.rb +352 -0
  146. data/spec/image_matchers.rb +47 -0
  147. data/spec/simple_matchers.rb +44 -0
  148. data/spec/spec_helper.rb +58 -0
  149. data/yard/handlers/configurable_attr_handler.rb +38 -0
  150. data/yard/setup.rb +15 -0
  151. data/yard/templates/default/fulldoc/html/css/common.css +107 -0
  152. data/yard/templates/default/layout/html/layout.erb +87 -0
  153. data/yard/templates/default/module/html/configuration_summary.erb +31 -0
  154. data/yard/templates/default/module/setup.rb +17 -0
  155. metadata +550 -0
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,19 @@
1
+ def string_matching(regexp)
2
+ Spec::Mocks::ArgumentMatchers::RegexpMatcher.new(regexp)
3
+ end
4
+
5
+ class TempObjectArgumentMatcher
6
+ def initialize(data, opts)
7
+ @data = data
8
+ @opts = opts
9
+ end
10
+ def ==(actual)
11
+ actual.is_a?(Dragonfly::TempObject) &&
12
+ actual.data == @data &&
13
+ @opts.all?{|k,v| actual.send(k) == v }
14
+ end
15
+ end
16
+
17
+ def a_temp_object_with_data(data, opts={})
18
+ TempObjectArgumentMatcher.new(data, opts)
19
+ end
@@ -0,0 +1,97 @@
1
+ # --------------------------------------------------------------- #
2
+ # MODELS
3
+ # --------------------------------------------------------------- #
4
+ class MyModel
5
+
6
+ # Callbacks
7
+ extend ActiveModel::Callbacks
8
+ define_model_callbacks :save, :destroy
9
+
10
+ include ActiveModel::Validations
11
+
12
+ class << self
13
+ def create!(attrs={})
14
+ new(attrs).save!
15
+ end
16
+
17
+ def find(id)
18
+ new(instances[id])
19
+ end
20
+
21
+ def instances
22
+ @instances ||= {}
23
+ end
24
+ end
25
+
26
+ def initialize(attrs={})
27
+ attrs.each do |key, value|
28
+ send("#{key}=", value)
29
+ end
30
+ end
31
+
32
+ attr_accessor :id
33
+
34
+ def to_hash
35
+ self.class::ATTRIBUTES.inject({}) do |hash, attr|
36
+ hash[attr] = send(attr)
37
+ hash
38
+ end
39
+ end
40
+
41
+ def save
42
+ _run_save_callbacks {
43
+ self.id ||= rand(1000)
44
+ self.class.instances[id] = self.to_hash
45
+ }
46
+ end
47
+ def save!
48
+ save
49
+ self
50
+ end
51
+
52
+ def destroy
53
+ _run_destroy_callbacks {}
54
+ end
55
+ end
56
+
57
+ class Item < MyModel
58
+
59
+ ATTRIBUTES = [
60
+ :title,
61
+ :preview_image_uid,
62
+ :preview_image_some_analyser_method,
63
+ :preview_image_size,
64
+ :preview_image_name,
65
+ :preview_image_ext,
66
+ :preview_image_blah_blah,
67
+ :other_image_uid,
68
+ :yet_another_image_uid,
69
+ :otra_imagen_uid,
70
+ :trailer_video_uid,
71
+ :created_at,
72
+ :updated_at
73
+ ]
74
+ attr_accessor *ATTRIBUTES
75
+ end
76
+
77
+ class Car < MyModel
78
+ ATTRIBUTES = [
79
+ :image_uid,
80
+ :reliant_image_uid,
81
+ :type
82
+ ]
83
+ attr_accessor *ATTRIBUTES
84
+ end
85
+
86
+ class Photo < MyModel
87
+ ATTRIBUTES = [:image_uid]
88
+ attr_accessor *ATTRIBUTES
89
+ end
90
+
91
+
92
+ # --------------------------------------------------------------- #
93
+ # HELPER METHODS
94
+ # --------------------------------------------------------------- #
95
+ def model_class
96
+ MyModel
97
+ end
@@ -0,0 +1,85 @@
1
+ # Seems to blow up on Rails 3 without this - only need temporarily
2
+ begin
3
+ require 'active_support/all'
4
+ rescue LoadError => e
5
+ puts "Couldn't load activesupport: #{e}"
6
+ end
7
+
8
+ require 'active_record'
9
+
10
+ # --------------------------------------------------------------- #
11
+ # MIGRATION
12
+ # --------------------------------------------------------------- #
13
+ class MigrationForTest < ActiveRecord::Migration
14
+
15
+ def self.up
16
+ create_table :items, :force => true do |t|
17
+ t.string :title
18
+ t.string :preview_image_uid
19
+ t.string :preview_image_some_analyser_method
20
+ t.integer :preview_image_size
21
+ t.string :preview_image_name
22
+ t.string :preview_image_ext
23
+ t.string :preview_image_blah_blah
24
+ t.string :other_image_uid
25
+ t.string :yet_another_image_uid
26
+ t.string :otra_imagen_uid
27
+ t.string :trailer_video_uid
28
+ t.timestamps
29
+ end
30
+
31
+ create_table :cars do |t|
32
+ t.string :image_uid
33
+ t.string :reliant_image_uid
34
+ t.string :type
35
+ end
36
+
37
+ create_table :photos do |t|
38
+ t.string :image_uid
39
+ end
40
+
41
+ end
42
+
43
+ def self.down
44
+ drop_table :items
45
+ end
46
+
47
+ end
48
+
49
+
50
+ # --------------------------------------------------------------- #
51
+ # MODELS
52
+ # --------------------------------------------------------------- #
53
+ class Item < ActiveRecord::Base
54
+ end
55
+ class Car < ActiveRecord::Base
56
+ end
57
+ class Photo < ActiveRecord::Base
58
+ end
59
+
60
+
61
+ # --------------------------------------------------------------- #
62
+ # SPEC CONFIG
63
+ # --------------------------------------------------------------- #
64
+ DB_FILE = File.expand_path(File.dirname(__FILE__)+'/db.sqlite3')
65
+
66
+ Spec::Runner.configure do |config|
67
+
68
+ config.before(:all) do
69
+ FileUtils.rm_f(DB_FILE)
70
+ ActiveRecord::Base.establish_connection(
71
+ :adapter => "sqlite3",
72
+ :database => DB_FILE
73
+ )
74
+ MigrationForTest.verbose = false
75
+ MigrationForTest.up
76
+ end
77
+
78
+ end
79
+
80
+ # --------------------------------------------------------------- #
81
+ # HELPER METHODS
82
+ # --------------------------------------------------------------- #
83
+ def model_class
84
+ ActiveRecord::Base
85
+ end
@@ -0,0 +1,723 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Item do
4
+
5
+ # See extra setup in models / initializer files
6
+
7
+ describe "defining accessors" do
8
+
9
+ let(:app1){ Dragonfly[:images] }
10
+ let(:app2){ Dragonfly[:videos] }
11
+
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
18
+ end
19
+ Item.dragonfly_apps_for_attributes.should == {:preview_image => app1, :trailer_video => app2}
20
+ end
21
+
22
+ it "should work for included modules (e.g. Mongoid::Document)" do
23
+ mongoid_document = Module.new
24
+ app1.define_macro_on_include(mongoid_document, :dog_accessor)
25
+ model_class = Class.new do
26
+ def self.before_save(*args); end
27
+ def self.before_destroy(*args); end
28
+ include mongoid_document
29
+ dog_accessor :doogie
30
+ end
31
+ model_class.dragonfly_apps_for_attributes.should == {:doogie => app1}
32
+ end
33
+
34
+ end
35
+
36
+ describe "correctly defined" do
37
+
38
+ before(:each) do
39
+ @app = Dragonfly[:images]
40
+ @app.define_macro(model_class, :image_accessor)
41
+ Item.class_eval do
42
+ image_accessor :preview_image
43
+ end
44
+ @item = Item.new
45
+ end
46
+
47
+ it "should provide a reader" do
48
+ @item.should respond_to(:preview_image)
49
+ end
50
+
51
+ it "should provide a writer" do
52
+ @item.should respond_to(:preview_image=)
53
+ end
54
+
55
+ describe "when there has been nothing assigned" do
56
+ it "the reader should return nil" do
57
+ @item.preview_image.should be_nil
58
+ end
59
+ it "the uid should be nil" do
60
+ @item.preview_image_uid.should be_nil
61
+ end
62
+ it "should not try to store anything on save" do
63
+ @app.datastore.should_not_receive(:store)
64
+ @item.save!
65
+ end
66
+ it "should not try to destroy anything on save" do
67
+ @app.datastore.should_not_receive(:destroy)
68
+ @item.save!
69
+ end
70
+ it "should not try to destroy anything on destroy" do
71
+ @app.datastore.should_not_receive(:destroy)
72
+ @item.destroy
73
+ end
74
+ end
75
+
76
+ describe "when the uid is set manually" do
77
+ before(:each) do
78
+ @item.preview_image_uid = 'some_known_uid'
79
+ end
80
+ it "should not try to retrieve any data" do
81
+ @app.datastore.should_not_receive(:retrieve)
82
+ @item.save!
83
+ end
84
+ it "should not try to destroy any data" do
85
+ @app.datastore.should_not_receive(:destroy)
86
+ @item.save!
87
+ end
88
+ it "should not try to store any data" do
89
+ @app.datastore.should_not_receive(:store)
90
+ @item.save!
91
+ end
92
+ end
93
+
94
+ describe "when there has been some thing assigned but not saved" do
95
+ before(:each) do
96
+ @item.preview_image = "DATASTRING"
97
+ end
98
+ it "the reader should return an attachment" do
99
+ @item.preview_image.should be_a(Dragonfly::ActiveModelExtensions::Attachment)
100
+ end
101
+ it "the uid should be nil" do
102
+ @item.preview_image_uid.should be_nil
103
+ end
104
+ it "should store the image when saved" do
105
+ @app.datastore.should_receive(:store).with(a_temp_object_with_data("DATASTRING"), {})
106
+ @item.save!
107
+ end
108
+ it "should not try to destroy anything on destroy" do
109
+ @app.datastore.should_not_receive(:destroy)
110
+ @item.destroy
111
+ end
112
+ it "should return nil for the url" do
113
+ @item.preview_image.url.should be_nil
114
+ end
115
+ describe "when the uid is set manually" do
116
+ before(:each) do
117
+ @item.preview_image_uid = 'some_known_uid'
118
+ end
119
+ it "should not try to retrieve any data" do
120
+ @app.datastore.should_not_receive(:retrieve)
121
+ @item.save!
122
+ end
123
+ it "should not try to destroy any data" do
124
+ @app.datastore.should_not_receive(:destroy)
125
+ @item.save!
126
+ end
127
+ it "should not try to store any data" do
128
+ @app.datastore.should_not_receive(:store)
129
+ @item.save!
130
+ end
131
+ end
132
+
133
+ end
134
+
135
+ describe "when something has been assigned and saved" do
136
+
137
+ before(:each) do
138
+ @item.preview_image = "DATASTRING"
139
+ @app.datastore.should_receive(:store).with(a_temp_object_with_data("DATASTRING"), {}).once.and_return('some_uid')
140
+ @item.save!
141
+ end
142
+
143
+ it "should have the correct uid" do
144
+ @item.preview_image_uid.should == 'some_uid'
145
+ end
146
+ it "should not try to store anything if saved again" do
147
+ @app.datastore.should_not_receive(:store)
148
+ @item.save!
149
+ end
150
+
151
+ it "should not try to destroy anything if saved again" do
152
+ @app.datastore.should_not_receive(:destroy)
153
+ @item.save!
154
+ end
155
+
156
+ it "should destroy the data on destroy" do
157
+ @app.datastore.should_receive(:destroy).with('some_uid')
158
+ @item.destroy
159
+ end
160
+
161
+ 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'
164
+ end
165
+
166
+ it "should destroy the old data when the uid is set manually" do
167
+ @app.datastore.should_receive(:destroy).with('some_uid')
168
+ @item.preview_image_uid = 'some_known_uid'
169
+ @item.save!
170
+ end
171
+
172
+ describe "when accessed by a new model object" do
173
+ before(:each) do
174
+ @item = Item.find(@item.id)
175
+ end
176
+ it "should destroy the data on destroy" do
177
+ @app.datastore.should_receive(:destroy).with(@item.preview_image_uid)
178
+ @item.destroy
179
+ end
180
+ end
181
+
182
+ describe "when something new is assigned" do
183
+ before(:each) do
184
+ @item.preview_image = "ANEWDATASTRING"
185
+ @app.datastore.stub!(:store).and_return('some_uid')
186
+ end
187
+ it "should set the uid to nil" do
188
+ @item.preview_image_uid.should be_nil
189
+ end
190
+ it "should destroy the old data when saved" do
191
+ @app.datastore.should_receive(:destroy).with('some_uid')
192
+ @item.save!
193
+ end
194
+ it "should not try to destroy the old data if saved again" do
195
+ @app.datastore.should_receive(:destroy).with('some_uid')
196
+ @item.save!
197
+ @app.datastore.should_not_receive(:destroy).with('some_uid')
198
+ @item.save!
199
+ end
200
+ it "should destroy the old data when saved, even if yet another thing is assigned" do
201
+ @item.preview_image = "YET ANOTHER DATA STRING"
202
+ @app.datastore.should_receive(:destroy).with('some_uid')
203
+ @item.save!
204
+ end
205
+ it "should store the new data when saved" do
206
+ @app.datastore.should_receive(:store).with(a_temp_object_with_data("ANEWDATASTRING"), {})
207
+ @item.save!
208
+ end
209
+ it "should destroy the old data on destroy" do
210
+ @app.datastore.should_receive(:destroy).with('some_uid')
211
+ @item.destroy
212
+ end
213
+ it "should destroy the old data on destroy, even if yet another thing is assigned" do
214
+ @item.preview_image = "YET ANOTHER DATA STRING"
215
+ @app.datastore.should_receive(:destroy).with('some_uid')
216
+ @item.destroy
217
+ end
218
+ it "should destroy the old data when the uid has been set manually" do
219
+ @app.datastore.should_receive(:destroy).with('some_uid')
220
+ @item.preview_image_uid = 'some_known_uid'
221
+ @item.save!
222
+ end
223
+ it "should return the new size" do
224
+ @item.preview_image.size.should == 14
225
+ end
226
+ it "should return the new data" do
227
+ @item.preview_image.data.should == 'ANEWDATASTRING'
228
+ end
229
+ end
230
+
231
+ describe "when it is set to nil" do
232
+ before(:each) do
233
+ @item.preview_image = nil
234
+ end
235
+ it "should set the uid to nil" do
236
+ @item.preview_image_uid.should be_nil
237
+ end
238
+ it "should return the attribute as nil" do
239
+ @item.preview_image.should be_nil
240
+ end
241
+ it "should destroy the data on save" do
242
+ @app.datastore.should_receive(:destroy).with('some_uid')
243
+ @item.save!
244
+ @item.preview_image.should be_nil
245
+ end
246
+ it "should destroy the old data on destroy" do
247
+ @app.datastore.should_receive(:destroy).with('some_uid')
248
+ @item.destroy
249
+ end
250
+ end
251
+
252
+ describe "when the data can't be found" do
253
+ it "should log a warning if the data wasn't found on destroy" do
254
+ @app.datastore.should_receive(:destroy).with('some_uid').and_raise(Dragonfly::DataStorage::DataNotFound)
255
+ @app.log.should_receive(:warn)
256
+ @item.destroy
257
+ end
258
+ end
259
+
260
+ end
261
+
262
+ describe "other types of assignment" do
263
+ before(:each) do
264
+ @app.generator.add :egg do
265
+ "Gungedin"
266
+ end
267
+ @app.processor.add :doogie do |temp_object|
268
+ temp_object.data.upcase
269
+ end
270
+ end
271
+
272
+ describe "assigning with a job" do
273
+ before(:each) do
274
+ @job = @app.generate(:egg)
275
+ @item.preview_image = @job
276
+ end
277
+
278
+ it "should work" do
279
+ @item.preview_image.data.should == 'Gungedin'
280
+ end
281
+
282
+ it "should not be affected by subsequent changes to the job" do
283
+ @job.process!(:doogie)
284
+ @item.preview_image.data.should == 'Gungedin'
285
+ end
286
+ end
287
+
288
+ describe "assigning with another attachment" do
289
+ before(:each) do
290
+ Item.class_eval do
291
+ image_accessor :other_image
292
+ end
293
+ end
294
+ it "should work like assigning the job" do
295
+ @item.preview_image = 'eggheads'
296
+ @item.other_image = @item.preview_image
297
+ @item.preview_image = 'dogchin'
298
+ @item.other_image.data.should == 'eggheads'
299
+ end
300
+ end
301
+
302
+ describe "assigning by means of a bang method" do
303
+ before(:each) do
304
+ @app.processor.add :double do |temp_object|
305
+ temp_object.data * 2
306
+ end
307
+ @app.encoder.add do |temp_object, format|
308
+ temp_object.data.downcase + format.to_s
309
+ end
310
+ @item.preview_image = "HELLO"
311
+ end
312
+ it "should modify as if being assigned again" do
313
+ @item.preview_image.process!(:double)
314
+ @item.preview_image.data.should == 'HELLOHELLO'
315
+ end
316
+ it "should update the magic attributes" do
317
+ @item.preview_image.process!(:double)
318
+ @item.preview_image_size.should == 10
319
+ end
320
+ it "should work for encode" do
321
+ @item.preview_image.encode!(:egg)
322
+ @item.preview_image.data.should == 'helloegg'
323
+ end
324
+ it "should work repeatedly" do
325
+ @item.preview_image.process!(:double).encode!(:egg)
326
+ @item.preview_image.data.should == 'hellohelloegg'
327
+ @item.preview_image_size.should == 13
328
+ end
329
+ end
330
+ end
331
+
332
+ end
333
+
334
+ describe "validations" do
335
+
336
+ before(:all) do
337
+ @app = Dragonfly[:images]
338
+ @app.define_macro(model_class, :image_accessor)
339
+ end
340
+
341
+ describe "validates_presence_of" do
342
+
343
+ before(:all) do
344
+ Item.class_eval do
345
+ image_accessor :preview_image
346
+ validates_presence_of :preview_image
347
+ end
348
+ end
349
+
350
+ it "should be valid if set" do
351
+ Item.new(:preview_image => "1234567890").should be_valid
352
+ end
353
+
354
+ it "should be invalid if not set" do
355
+ Item.new.should_not be_valid
356
+ end
357
+
358
+ end
359
+
360
+ describe "validates_size_of" do
361
+
362
+ before(:all) do
363
+ Item.class_eval do
364
+ image_accessor :preview_image
365
+ validates_size_of :preview_image, :within => (6..10)
366
+ end
367
+ end
368
+
369
+ it "should be valid if ok" do
370
+ Item.new(:preview_image => "1234567890").should be_valid
371
+ end
372
+
373
+ it "should be invalid if too small" do
374
+ Item.new(:preview_image => "12345").should_not be_valid
375
+ end
376
+
377
+ end
378
+
379
+ describe "validates_property" do
380
+
381
+ before(:each) do
382
+ @item = Item.new(:preview_image => "1234567890")
383
+ end
384
+
385
+ before(:all) do
386
+ custom_analyser = Class.new do
387
+ def mime_type(temp_object)
388
+ case temp_object.data
389
+ when "WRONG TYPE" then 'wrong/type'
390
+ when "OTHER TYPE" then nil
391
+ else 'how/special'
392
+ end
393
+ end
394
+
395
+ def number_of_Gs(temp_object)
396
+ temp_object.data.count('G')
397
+ end
398
+ end
399
+ @app.analyser.register(custom_analyser)
400
+
401
+ Item.class_eval do
402
+ validates_property :mime_type, :of => :preview_image, :in => ['how/special', 'how/crazy'], :if => :its_friday
403
+ validates_property :mime_type, :of => [:other_image, :yet_another_image], :as => 'how/special'
404
+ validates_property :number_of_Gs, :of => :preview_image, :in => (0..2)
405
+ validates_property :mime_type, :of => :otra_imagen, :in => ['que/pasa', 'illo/tio'], :message => "tipo de contenido incorrecto. Que chungo tio"
406
+
407
+ image_accessor :preview_image
408
+ image_accessor :other_image
409
+ image_accessor :yet_another_image
410
+ image_accessor :otra_imagen
411
+
412
+ def its_friday
413
+ true
414
+ end
415
+
416
+ end
417
+ end
418
+
419
+ it "should be valid if nil, if not validated on presence (even with validates_property)" do
420
+ @item.other_image = nil
421
+ @item.should be_valid
422
+ end
423
+
424
+ it "should be invalid if the property is nil" do
425
+ @item.preview_image = "OTHER TYPE"
426
+ @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 ''")
428
+ end
429
+
430
+ it "should be invalid if the property is wrong" do
431
+ @item.preview_image = "WRONG TYPE"
432
+ @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'")
434
+ end
435
+
436
+ it "should work for a range" do
437
+ @item.preview_image = "GOOGLE GUM"
438
+ @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'")
440
+ end
441
+
442
+ it "should validate individually" do
443
+ @item.other_image = "1234567"
444
+ @item.yet_another_image = "WRONG TYPE"
445
+ @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'")
448
+ end
449
+
450
+ it "should include standard extra options like 'if' on mime type validation" do
451
+ @item.should_receive(:its_friday).and_return(false)
452
+ @item.preview_image = "WRONG TYPE"
453
+ @item.should be_valid
454
+ end
455
+
456
+ it "should require either :as or :in as an argument" do
457
+ lambda{
458
+ Item.class_eval do
459
+ validates_property :mime_type, :of => :preview_image
460
+ end
461
+ }.should raise_error(ArgumentError)
462
+ end
463
+
464
+ it "should require :of as an argument" do
465
+ lambda{
466
+ Item.class_eval do
467
+ validates_property :mime_type, :as => 'hi/there'
468
+ end
469
+ }.should raise_error(ArgumentError)
470
+ end
471
+
472
+ it "should allow for custom messages" do
473
+ @item.otra_imagen = "WRONG TYPE"
474
+ @item.should_not be_valid
475
+ @item.errors[:otra_imagen].should match_ar_error("tipo de contenido incorrecto. Que chungo tio")
476
+ end
477
+
478
+ end
479
+
480
+ end
481
+
482
+ describe "extra properties" do
483
+
484
+ before(:each) do
485
+ @app = Dragonfly[:images]
486
+ custom_analyser = Class.new do
487
+ def some_analyser_method(temp_object)
488
+ "abc" + temp_object.data[0..0]
489
+ end
490
+ def number_of_As(temp_object); temp_object.data.count('A'); end
491
+ end
492
+ @app.analyser.register(custom_analyser)
493
+ @app.define_macro(model_class, :image_accessor)
494
+ Item.class_eval do
495
+ image_accessor :preview_image
496
+ end
497
+ @item = Item.new
498
+ end
499
+
500
+ describe "magic attributes" do
501
+
502
+ it "should default the magic attribute as nil" do
503
+ @item.preview_image_some_analyser_method.should be_nil
504
+ end
505
+
506
+ it "should set the magic attribute when assigned" do
507
+ @item.preview_image = '123'
508
+ @item.preview_image_some_analyser_method.should == 'abc1'
509
+ end
510
+
511
+ it "should not set non-magic attributes with the same prefix when assigned" do
512
+ @item.preview_image_blah_blah = 'wassup'
513
+ @item.preview_image = '123'
514
+ @item.preview_image_blah_blah.should == 'wassup'
515
+ end
516
+
517
+ it "should update the magic attribute when something else is assigned" do
518
+ @item.preview_image = '123'
519
+ @item.preview_image = '456'
520
+ @item.preview_image_some_analyser_method.should == 'abc4'
521
+ end
522
+
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
+ it "should not reset non-magic attributes with the same prefix when set to nil" do
530
+ @item.preview_image_blah_blah = 'wassup'
531
+ @item.preview_image = '123'
532
+ @item.preview_image = nil
533
+ @item.preview_image_blah_blah.should == 'wassup'
534
+ end
535
+
536
+ it "should work for size too" do
537
+ @item.preview_image = '123'
538
+ @item.preview_image_size.should == 3
539
+ end
540
+
541
+ it "should store the original file extension if it exists" do
542
+ data = 'jasdlkf sadjl'
543
+ data.stub!(:original_filename).and_return('hello.png')
544
+ @item.preview_image = data
545
+ @item.preview_image_ext.should == 'png'
546
+ end
547
+
548
+ it "should store the original file name if it exists" do
549
+ data = 'jasdlkf sadjl'
550
+ data.stub!(:original_filename).and_return('hello.png')
551
+ @item.preview_image = data
552
+ @item.preview_image_name.should == 'hello.png'
553
+ end
554
+ end
555
+
556
+
557
+ describe "delegating methods to the job" do
558
+ before(:each) do
559
+ @item.preview_image = "DATASTRING"
560
+ end
561
+ it "should have properties from the analyser" do
562
+ @item.preview_image.number_of_As.should == 2
563
+ end
564
+ it "should report that it responds to analyser methods" do
565
+ @item.preview_image.respond_to?(:number_of_As).should be_true
566
+ end
567
+ it "should include analyser methods in methods" do
568
+ @item.preview_image.methods.include?('number_of_As'.to_method_name).should be_true
569
+ end
570
+ it "should include analyser methods in public_methods" do
571
+ @item.preview_image.public_methods.include?('number_of_As'.to_method_name).should be_true
572
+ end
573
+
574
+ it "should update when something new is assigned" do
575
+ @item.preview_image = 'ANEWDATASTRING'
576
+ @item.preview_image.number_of_As.should == 3
577
+ end
578
+
579
+ describe "from a new model object" do
580
+ before(:each) do
581
+ @app.datastore.stub!(:store).and_return('my_uid')
582
+ item = Item.create!(:preview_image => 'DATASTRING')
583
+ @item = Item.find(item.id)
584
+ end
585
+ it "should load the content then delegate the method" do
586
+ @app.datastore.should_receive(:retrieve).with('my_uid').and_return(['DATASTRING', {}])
587
+ @item.preview_image.number_of_As.should == 2
588
+ end
589
+ it "should use the magic attribute if there is one, and not load the content" do
590
+ @app.datastore.should_not_receive(:retrieve)
591
+ @item.should_receive(:preview_image_some_analyser_method).and_return('result yo')
592
+ @item.preview_image.some_analyser_method.should == 'result yo'
593
+ end
594
+
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
601
+
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
607
+ end
608
+
609
+ end
610
+
611
+ it "should not raise an error if a non-existent method is called" do
612
+ # Just checking method missing works ok
613
+ lambda{
614
+ @item.preview_image.eggbert
615
+ }.should raise_error(NoMethodError)
616
+ end
617
+ end
618
+
619
+ describe "setting things on the attachment" do
620
+
621
+ before(:each) do
622
+ @item = Item.new
623
+ end
624
+
625
+ describe "name" do
626
+ before(:each) do
627
+ @item.preview_image = "Hello"
628
+ @item.preview_image.name = 'hello.there'
629
+ end
630
+ it "should allow for setting the name" do
631
+ @item.preview_image.name.should == 'hello.there'
632
+ end
633
+ it "should update the magic attribute" do
634
+ @item.preview_image_name.should == 'hello.there'
635
+ end
636
+ it "should return the name" do
637
+ (@item.preview_image.name = 'no.silly').should == 'no.silly'
638
+ end
639
+ end
640
+
641
+ describe "meta" do
642
+ before(:each) do
643
+ @item.preview_image = "Hello all"
644
+ @item.preview_image.meta = {:slime => 'balls'}
645
+ end
646
+ it "should allow for setting the meta" do
647
+ @item.preview_image.meta.should == {:slime => 'balls'}
648
+ end
649
+ it "should allow for updating the meta" do
650
+ @item.preview_image.meta[:numb] = 'nuts'
651
+ @item.preview_image.meta.should == {:slime => 'balls', :numb => 'nuts'}
652
+ end
653
+ it "should return the meta" do
654
+ (@item.preview_image.meta = {:doogs => 'boogs'}).should == {:doogs => 'boogs'}
655
+ end
656
+ it "should save it correctly" do
657
+ @item.save!
658
+ item = Item.find(@item.id)
659
+ item.preview_image.meta.should include_hash(:slime => 'balls')
660
+ end
661
+ it "should store meta info about the model" do
662
+ @item.save!
663
+ meta = {:model_class => 'Item', :model_attachment => :preview_image, :slime => 'balls'}
664
+ @app.fetch(@item.preview_image_uid).meta.should == meta
665
+ end
666
+ end
667
+
668
+ end
669
+
670
+ end
671
+
672
+ describe "inheritance" do
673
+
674
+ 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)
679
+ Car.class_eval do
680
+ image_accessor :image
681
+ end
682
+ Photo.class_eval do
683
+ egg_accessor :image
684
+ end
685
+
686
+ @base_class = Car
687
+ class ReliantRobin < Car; image_accessor :reliant_image; end
688
+ @subclass = ReliantRobin
689
+ class ReliantRobinWithModule < Car
690
+ include Module.new
691
+ image_accessor :reliant_image
692
+ end
693
+ @subclass_with_module = ReliantRobinWithModule
694
+ @unrelated_class = Photo
695
+ end
696
+
697
+ it "should allow assigning base class accessors" do
698
+ @base_class.create! :image => 'blah'
699
+ end
700
+ it "should not allow assigning subclass accessors in the base class" do
701
+ @base_class.new.should_not respond_to(:reliant_image=)
702
+ end
703
+ it "should allow assigning base class accessors in the subclass" do
704
+ @subclass.create! :image => 'blah'
705
+ end
706
+ it "should allow assigning subclass accessors in the subclass" do
707
+ @subclass.create! :reliant_image => 'blah'
708
+ end
709
+ it "should allow assigning base class accessors in the subclass, even if it has mixins" do
710
+ @subclass_with_module.create! :image => 'blah'
711
+ end
712
+ it "should allow assigning subclass accessors in the subclass, even if it has mixins" do
713
+ @subclass_with_module.create! :reliant_image => 'blah'
714
+ 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}
720
+ end
721
+ end
722
+
723
+ end