dragonfly 0.1.6 → 0.2.1
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.
- data/.yardopts +4 -0
- data/{README.markdown → README.md} +12 -24
- data/Rakefile +6 -6
- data/VERSION +1 -1
- data/config.rb +1 -3
- data/docs.watchr +1 -1
- data/dragonfly-rails.gemspec +2 -5
- data/dragonfly.gemspec +32 -12
- data/extra_docs/ActiveRecord.md +195 -0
- data/extra_docs/Analysers.md +63 -0
- data/extra_docs/DataStorage.md +33 -0
- data/extra_docs/Encoding.md +58 -0
- data/extra_docs/GettingStarted.md +114 -0
- data/extra_docs/Processing.md +58 -0
- data/extra_docs/Shortcuts.md +118 -0
- data/extra_docs/UsingWithRails.md +104 -0
- data/features/{dragonfly.feature → images.feature} +14 -4
- data/features/no_processing.feature +20 -0
- data/features/steps/dragonfly_steps.rb +29 -8
- data/features/support/env.rb +20 -8
- data/generators/dragonfly_app/USAGE +0 -1
- data/generators/dragonfly_app/dragonfly_app_generator.rb +1 -13
- data/generators/dragonfly_app/templates/metal_file.erb +1 -1
- data/lib/dragonfly/active_record_extensions.rb +1 -0
- data/lib/dragonfly/active_record_extensions/attachment.rb +52 -6
- data/lib/dragonfly/active_record_extensions/validations.rb +26 -6
- data/lib/dragonfly/analysis/base.rb +6 -3
- data/lib/dragonfly/analysis/r_magick_analyser.rb +0 -6
- data/lib/dragonfly/app.rb +53 -35
- data/lib/dragonfly/configurable.rb +1 -1
- data/lib/dragonfly/data_storage/file_data_store.rb +8 -8
- data/lib/dragonfly/delegatable.rb +14 -0
- data/lib/dragonfly/delegator.rb +50 -0
- data/lib/dragonfly/encoding/base.rb +7 -7
- data/lib/dragonfly/encoding/r_magick_encoder.rb +3 -0
- data/lib/dragonfly/encoding/transparent_encoder.rb +1 -1
- data/lib/dragonfly/extended_temp_object.rb +13 -7
- data/lib/dragonfly/parameters.rb +17 -11
- data/lib/dragonfly/processing/base.rb +9 -0
- data/lib/dragonfly/processing/r_magick_processor.rb +15 -1
- data/lib/dragonfly/r_magick_configuration.rb +12 -8
- data/lib/dragonfly/rails/images.rb +1 -1
- data/lib/dragonfly/temp_object.rb +14 -2
- data/lib/dragonfly/url_handler.rb +5 -6
- data/samples/sample.docx +0 -0
- data/spec/dragonfly/active_record_extensions/model_spec.rb +175 -84
- data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +0 -8
- data/spec/dragonfly/app_spec.rb +3 -3
- data/spec/dragonfly/configurable_spec.rb +1 -1
- data/spec/dragonfly/data_storage/file_data_store_spec.rb +55 -40
- data/spec/dragonfly/delegatable_spec.rb +32 -0
- data/spec/dragonfly/delegator_spec.rb +133 -0
- data/spec/dragonfly/encoding/r_magick_encoder_spec.rb +28 -0
- data/spec/dragonfly/extended_temp_object_spec.rb +5 -5
- data/spec/dragonfly/parameters_spec.rb +22 -32
- data/spec/dragonfly/processing/rmagick_processor_spec.rb +1 -2
- data/spec/dragonfly/temp_object_spec.rb +51 -0
- data/spec/dragonfly/url_handler_spec.rb +10 -15
- data/yard/handlers/configurable_attr_handler.rb +38 -0
- data/yard/setup.rb +9 -0
- data/yard/templates/default/fulldoc/html/css/common.css +27 -0
- data/yard/templates/default/module/html/configuration_summary.erb +31 -0
- data/yard/templates/default/module/setup.rb +17 -0
- metadata +31 -12
- data/features/support/image_helpers.rb +0 -9
- data/generators/dragonfly_app/templates/custom_processing.erb +0 -13
- data/lib/dragonfly/analysis/analyser.rb +0 -45
- data/lib/dragonfly/processing/processor.rb +0 -14
- data/spec/dragonfly/analysis/analyser_spec.rb +0 -85
@@ -3,7 +3,7 @@ require 'rmagick'
|
|
3
3
|
module Dragonfly
|
4
4
|
module Processing
|
5
5
|
|
6
|
-
|
6
|
+
class RMagickProcessor < Base
|
7
7
|
|
8
8
|
GRAVITY_MAPPINGS = {
|
9
9
|
'nw' => Magick::NorthWestGravity,
|
@@ -34,6 +34,20 @@ module Dragonfly
|
|
34
34
|
image.crop(gravity, x, y, width, height).to_blob
|
35
35
|
end
|
36
36
|
|
37
|
+
def generate(width, height)
|
38
|
+
image = Magick::Image.new(width, height)
|
39
|
+
num_points = 7
|
40
|
+
args = []
|
41
|
+
num_points.times do
|
42
|
+
args << rand(width)
|
43
|
+
args << rand(height)
|
44
|
+
args << "rgb(#{rand(256)},#{rand(256)},#{rand(256)})"
|
45
|
+
end
|
46
|
+
image = image.sparse_color(Magick::ShepardsColorInterpolate, *args)
|
47
|
+
image.format = 'png'
|
48
|
+
image.to_blob
|
49
|
+
end
|
50
|
+
|
37
51
|
def resize(temp_object, opts={})
|
38
52
|
rmagick_image(temp_object).change_geometry!(opts[:geometry]) do |cols, rows, img|
|
39
53
|
img.resize!(cols, rows)
|
@@ -1,16 +1,20 @@
|
|
1
1
|
module Dragonfly
|
2
|
+
|
3
|
+
# RMagickConfiguration is a saved configuration for Dragonfly apps, which does the following:
|
4
|
+
# - registers an rmagick analyser
|
5
|
+
# - registers an rmagick processor
|
6
|
+
# - registers an rmagick encoder
|
7
|
+
# - adds parameter shortcuts like '280x140!', etc.
|
8
|
+
# Look at the source code for apply_configuration to see exactly how it configures the app.
|
2
9
|
module RMagickConfiguration
|
3
10
|
|
4
11
|
def self.apply_configuration(app)
|
5
12
|
app.configure do |c|
|
6
|
-
c.
|
7
|
-
|
8
|
-
|
9
|
-
c.
|
10
|
-
|
11
|
-
end
|
12
|
-
c.encoder = Encoding::RMagickEncoder.new
|
13
|
-
c.parameters do |p|
|
13
|
+
c.register_analyser(Analysis::FileCommandAnalyser)
|
14
|
+
c.register_analyser(Analysis::RMagickAnalyser)
|
15
|
+
c.register_processor(Processing::RMagickProcessor)
|
16
|
+
c.register_encoder(Encoding::RMagickEncoder)
|
17
|
+
c.parameters.configure do |p|
|
14
18
|
p.default_format = :jpg
|
15
19
|
# Standard resizing like '30x40!', etc.
|
16
20
|
p.add_shortcut(Symbol) do |format|
|
@@ -20,8 +20,10 @@ module Dragonfly
|
|
20
20
|
attr_accessor :name
|
21
21
|
|
22
22
|
def modify_self!(obj)
|
23
|
-
|
24
|
-
|
23
|
+
unless obj == self
|
24
|
+
reset!
|
25
|
+
initialize_from_object!(obj)
|
26
|
+
end
|
25
27
|
self
|
26
28
|
end
|
27
29
|
|
@@ -79,6 +81,15 @@ module Dragonfly
|
|
79
81
|
end
|
80
82
|
end
|
81
83
|
|
84
|
+
def to_file(path)
|
85
|
+
if initialized_data
|
86
|
+
File.open(path, 'w'){|f| f.write(initialized_data) }
|
87
|
+
else
|
88
|
+
FileUtils.cp(self.path, path)
|
89
|
+
end
|
90
|
+
File.new(path)
|
91
|
+
end
|
92
|
+
|
82
93
|
protected
|
83
94
|
|
84
95
|
attr_accessor :initialized_data, :initialized_tempfile, :initialized_file
|
@@ -103,6 +114,7 @@ module Dragonfly
|
|
103
114
|
@initialized_tempfile = obj
|
104
115
|
when File
|
105
116
|
@initialized_file = obj
|
117
|
+
self.name = File.basename(obj.path)
|
106
118
|
else
|
107
119
|
raise ArgumentError, "#{self.class.name} must be initialized with a String, a File or a Tempfile"
|
108
120
|
end
|
@@ -52,12 +52,12 @@ module Dragonfly
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def parameters_to_url(parameters)
|
55
|
-
parameters.validate!
|
56
55
|
query_string = [:processing_method, :processing_options, :encoding].map do |attribute|
|
57
56
|
build_query(MAPPINGS[attribute] => parameters[attribute]) unless parameters[attribute].blank?
|
58
57
|
end.compact.join('&')
|
59
58
|
sha_string = "&#{MAPPINGS[:sha]}=#{sha_from_parameters(parameters)}" if protect_from_dos_attacks?
|
60
|
-
|
59
|
+
ext = ".#{parameters.format}" if parameters.format
|
60
|
+
url = "#{path_prefix}/#{escape_except_for_slashes(parameters.uid)}#{ext}?#{query_string}#{sha_string}"
|
61
61
|
url.sub!(/\?$/,'')
|
62
62
|
url
|
63
63
|
end
|
@@ -82,7 +82,8 @@ module Dragonfly
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def extract_format(path, query)
|
85
|
-
path.sub(/^\//,'').split('.')
|
85
|
+
bits = path.sub(/^\//,'').split('.')
|
86
|
+
bits.last if bits.length > 1
|
86
87
|
end
|
87
88
|
|
88
89
|
def extract_encoding(path, query)
|
@@ -140,9 +141,7 @@ module Dragonfly
|
|
140
141
|
end
|
141
142
|
|
142
143
|
def validate_format!(path)
|
143
|
-
|
144
|
-
raise UnknownUrl, "path '#{path}' not found"
|
145
|
-
end
|
144
|
+
raise UnknownUrl, "path '#{path}' not found" unless path =~ %r(^#{path_prefix}/[^.]+)
|
146
145
|
end
|
147
146
|
|
148
147
|
end
|
data/samples/sample.docx
ADDED
Binary file
|
@@ -93,9 +93,6 @@ describe Item do
|
|
93
93
|
it "should return nil for the url" do
|
94
94
|
@item.preview_image.url.should be_nil
|
95
95
|
end
|
96
|
-
it "should return the size" do
|
97
|
-
@item.preview_image.size.should == 10
|
98
|
-
end
|
99
96
|
it "should return the temp_object" do
|
100
97
|
temp_object = @item.preview_image.temp_object
|
101
98
|
temp_object.should be_a(Dragonfly::ExtendedTempObject)
|
@@ -135,39 +132,35 @@ describe Item do
|
|
135
132
|
@item.preview_image.url(:arg).should == 'some.url'
|
136
133
|
end
|
137
134
|
|
138
|
-
describe "when
|
135
|
+
describe "when accessed by a new model object" do
|
139
136
|
before(:each) do
|
140
|
-
@item.
|
137
|
+
@item = Item.find(@item.id)
|
141
138
|
end
|
142
139
|
it "should destroy the data on destroy" do
|
143
140
|
@app.datastore.should_receive(:destroy).with(@item.preview_image_uid)
|
144
141
|
@item.destroy
|
145
142
|
end
|
146
|
-
it "should return the size" do
|
147
|
-
@item.preview_image.size.should == 10
|
148
|
-
end
|
149
143
|
it "should return the temp_object" do
|
150
|
-
temp_object =
|
151
|
-
temp_object.should
|
152
|
-
temp_object.data.should == 'DATASTRING'
|
144
|
+
@app.should_receive(:fetch).with('some_uid').and_return(temp_object = mock('extended temp_object'))
|
145
|
+
@item.preview_image.temp_object.should == temp_object
|
153
146
|
end
|
154
147
|
end
|
155
148
|
|
156
149
|
describe "when something new is assigned" do
|
157
150
|
before(:each) do
|
158
|
-
@item.preview_image = "
|
151
|
+
@item.preview_image = "ANEWDATASTRING"
|
159
152
|
end
|
160
153
|
it "should set the uid to pending" do
|
161
154
|
@item.preview_image_uid.should be_a(Dragonfly::ActiveRecordExtensions::PendingUID)
|
162
155
|
end
|
163
156
|
it "should destroy the old data when saved" do
|
164
|
-
@app.datastore.should_receive(:store).with(a_temp_object_with_data("
|
157
|
+
@app.datastore.should_receive(:store).with(a_temp_object_with_data("ANEWDATASTRING")).once.and_return('some_uid')
|
165
158
|
|
166
159
|
@app.datastore.should_receive(:destroy).with('some_uid')
|
167
160
|
@item.save!
|
168
161
|
end
|
169
162
|
it "should store the new data when saved" do
|
170
|
-
@app.datastore.should_receive(:store).with(a_temp_object_with_data("
|
163
|
+
@app.datastore.should_receive(:store).with(a_temp_object_with_data("ANEWDATASTRING"))
|
171
164
|
@item.save!
|
172
165
|
end
|
173
166
|
it "should destroy the old data on destroy" do
|
@@ -175,12 +168,12 @@ describe Item do
|
|
175
168
|
@item.destroy
|
176
169
|
end
|
177
170
|
it "should return the new size" do
|
178
|
-
@item.preview_image.size.should ==
|
171
|
+
@item.preview_image.size.should == 14
|
179
172
|
end
|
180
173
|
it "should return the new temp_object" do
|
181
174
|
temp_object = @item.preview_image.temp_object
|
182
175
|
temp_object.should be_a(Dragonfly::ExtendedTempObject)
|
183
|
-
temp_object.data.should == '
|
176
|
+
temp_object.data.should == 'ANEWDATASTRING'
|
184
177
|
end
|
185
178
|
end
|
186
179
|
|
@@ -216,9 +209,8 @@ describe Item do
|
|
216
209
|
end
|
217
210
|
|
218
211
|
end
|
219
|
-
|
220
212
|
end
|
221
|
-
end
|
213
|
+
end
|
222
214
|
|
223
215
|
describe "validations" do
|
224
216
|
|
@@ -265,26 +257,33 @@ describe Item do
|
|
265
257
|
|
266
258
|
end
|
267
259
|
|
268
|
-
describe "
|
260
|
+
describe "validates_property" do
|
269
261
|
|
270
262
|
before(:each) do
|
271
263
|
@item = Item.new(:preview_image => "1234567890")
|
272
264
|
end
|
273
265
|
|
274
266
|
before(:all) do
|
275
|
-
custom_analyser =
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
267
|
+
custom_analyser = Class.new(Dragonfly::Analysis::Base)
|
268
|
+
custom_analyser.class_eval do
|
269
|
+
def mime_type(temp_object)
|
270
|
+
case temp_object.data
|
271
|
+
when "WRONG TYPE" then 'wrong/type'
|
272
|
+
when "OTHER TYPE" then nil
|
273
|
+
else 'how/special'
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def number_of_Gs(temp_object)
|
278
|
+
temp_object.data.count('G')
|
281
279
|
end
|
282
280
|
end
|
283
|
-
@app.
|
281
|
+
@app.register_analyser(custom_analyser)
|
284
282
|
|
285
283
|
Item.class_eval do
|
286
|
-
|
287
|
-
|
284
|
+
validates_property :mime_type, :of => :preview_image, :in => ['how/special', 'how/crazy'], :if => :its_friday
|
285
|
+
validates_property :mime_type, :of => [:other_image, :yet_another_image], :as => 'how/special'
|
286
|
+
validates_property :number_of_Gs, :of => :preview_image, :in => (0..2)
|
288
287
|
|
289
288
|
image_accessor :preview_image
|
290
289
|
image_accessor :other_image
|
@@ -297,21 +296,27 @@ describe Item do
|
|
297
296
|
end
|
298
297
|
end
|
299
298
|
|
300
|
-
it "should be valid if nil, if not validated on presence (even with
|
299
|
+
it "should be valid if nil, if not validated on presence (even with validates_property)" do
|
301
300
|
@item.other_image = nil
|
302
301
|
@item.should be_valid
|
303
302
|
end
|
304
303
|
|
305
|
-
it "should be invalid if the
|
304
|
+
it "should be invalid if the property is nil" do
|
306
305
|
@item.preview_image = "OTHER TYPE"
|
307
306
|
@item.should_not be_valid
|
308
|
-
@item.errors.on(:preview_image).should == "
|
307
|
+
@item.errors.on(:preview_image).should == "mime type is incorrect. It needs to be one of 'how/special', 'how/crazy', but was ''"
|
309
308
|
end
|
310
309
|
|
311
|
-
it "should be invalid if the
|
310
|
+
it "should be invalid if the property is wrong" do
|
312
311
|
@item.preview_image = "WRONG TYPE"
|
313
312
|
@item.should_not be_valid
|
314
|
-
@item.errors.on(:preview_image).should == "
|
313
|
+
@item.errors.on(:preview_image).should == "mime type is incorrect. It needs to be one of 'how/special', 'how/crazy', but was 'wrong/type'"
|
314
|
+
end
|
315
|
+
|
316
|
+
it "should work for a range" do
|
317
|
+
@item.preview_image = "GOOGLE GUM"
|
318
|
+
@item.should_not be_valid
|
319
|
+
@item.errors.on(:preview_image).should == "number of gs is incorrect. It needs to be between 0 and 2, but was '3'"
|
315
320
|
end
|
316
321
|
|
317
322
|
it "should validate individually" do
|
@@ -319,7 +324,7 @@ describe Item do
|
|
319
324
|
@item.yet_another_image = "WRONG TYPE"
|
320
325
|
@item.should_not be_valid
|
321
326
|
@item.errors.on(:other_image).should be_nil
|
322
|
-
@item.errors.on(:yet_another_image).should == "
|
327
|
+
@item.errors.on(:yet_another_image).should == "mime type is incorrect. It needs to be 'how/special', but was 'wrong/type'"
|
323
328
|
end
|
324
329
|
|
325
330
|
it "should include standard extra options like 'if' on mime type validation" do
|
@@ -331,24 +336,44 @@ describe Item do
|
|
331
336
|
it "should require either :as or :in as an argument" do
|
332
337
|
lambda{
|
333
338
|
Item.class_eval do
|
334
|
-
|
339
|
+
validates_property :mime_type, :of => :preview_image
|
340
|
+
end
|
341
|
+
}.should raise_error(ArgumentError)
|
342
|
+
end
|
343
|
+
|
344
|
+
it "should require :of as an argument" do
|
345
|
+
lambda{
|
346
|
+
Item.class_eval do
|
347
|
+
validates_property :mime_type, :as => 'hi/there'
|
335
348
|
end
|
336
349
|
}.should raise_error(ArgumentError)
|
337
350
|
end
|
338
351
|
|
339
352
|
end
|
340
353
|
|
354
|
+
describe "validates_mime_type_of" do
|
355
|
+
it "should provide validates_mime_type as a convenience wrapper for validates_property" do
|
356
|
+
Item.should_receive(:validates_property).with(:mime_type, :of => :preview_image, :in => ['how/special', 'how/crazy'], :if => :its_friday)
|
357
|
+
Item.class_eval do
|
358
|
+
validates_mime_type_of :preview_image, :in => ['how/special', 'how/crazy'], :if => :its_friday
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
341
363
|
end
|
342
364
|
|
343
|
-
describe "
|
344
|
-
|
365
|
+
describe "extra properties" do
|
366
|
+
|
345
367
|
before(:each) do
|
346
368
|
@app = Dragonfly::App[:images]
|
347
|
-
custom_analyser =
|
348
|
-
|
349
|
-
|
369
|
+
custom_analyser = Class.new(Dragonfly::Analysis::Base)
|
370
|
+
custom_analyser.class_eval do
|
371
|
+
def some_analyser_method(temp_object)
|
372
|
+
"abc" + temp_object.data[0..0]
|
373
|
+
end
|
374
|
+
def number_of_As(temp_object); temp_object.data.count('A'); end
|
350
375
|
end
|
351
|
-
@app.
|
376
|
+
@app.register_analyser(custom_analyser)
|
352
377
|
ActiveRecord::Base.register_dragonfly_app(:image, @app)
|
353
378
|
Item.class_eval do
|
354
379
|
image_accessor :preview_image
|
@@ -356,59 +381,125 @@ describe Item do
|
|
356
381
|
@item = Item.new
|
357
382
|
end
|
358
383
|
|
359
|
-
|
360
|
-
@item.preview_image_some_analyser_method.should be_nil
|
361
|
-
end
|
384
|
+
describe "magic attributes" do
|
362
385
|
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
end
|
386
|
+
it "should default the magic attribute as nil" do
|
387
|
+
@item.preview_image_some_analyser_method.should be_nil
|
388
|
+
end
|
367
389
|
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
end
|
390
|
+
it "should set the magic attribute when assigned" do
|
391
|
+
@item.preview_image = '123'
|
392
|
+
@item.preview_image_some_analyser_method.should == 'abc1'
|
393
|
+
end
|
373
394
|
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
395
|
+
it "should not set non-magic attributes with the same prefix when assigned" do
|
396
|
+
@item.preview_image_blah_blah = 'wassup'
|
397
|
+
@item.preview_image = '123'
|
398
|
+
@item.preview_image_blah_blah.should == 'wassup'
|
399
|
+
end
|
379
400
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
401
|
+
it "should update the magic attribute when something else is assigned" do
|
402
|
+
@item.preview_image = '123'
|
403
|
+
@item.preview_image = '456'
|
404
|
+
@item.preview_image_some_analyser_method.should == 'abc4'
|
405
|
+
end
|
385
406
|
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
end
|
407
|
+
it "should reset the magic attribute when set to nil" do
|
408
|
+
@item.preview_image = '123'
|
409
|
+
@item.preview_image = nil
|
410
|
+
@item.preview_image_some_analyser_method.should be_nil
|
411
|
+
end
|
392
412
|
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
413
|
+
it "should not reset non-magic attributes with the same prefix when set to nil" do
|
414
|
+
@item.preview_image_blah_blah = 'wassup'
|
415
|
+
@item.preview_image = '123'
|
416
|
+
@item.preview_image = nil
|
417
|
+
@item.preview_image_blah_blah.should == 'wassup'
|
418
|
+
end
|
397
419
|
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
420
|
+
it "should work for size too" do
|
421
|
+
@item.preview_image = '123'
|
422
|
+
@item.preview_image_size.should == 3
|
423
|
+
end
|
424
|
+
|
425
|
+
it "should store the original file extension if it exists" do
|
426
|
+
data = 'jasdlkf sadjl'
|
427
|
+
data.stub!(:original_filename).and_return('hello.png')
|
428
|
+
@item.preview_image = data
|
429
|
+
@item.preview_image_ext.should == 'png'
|
430
|
+
end
|
404
431
|
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
432
|
+
it "should store the original file name if it exists" do
|
433
|
+
data = 'jasdlkf sadjl'
|
434
|
+
data.stub!(:original_filename).and_return('hello.png')
|
435
|
+
@item.preview_image = data
|
436
|
+
@item.preview_image_name.should == 'hello.png'
|
437
|
+
end
|
410
438
|
end
|
439
|
+
|
440
|
+
|
441
|
+
describe "delegating methods to the temp_object" do
|
442
|
+
before(:each) do
|
443
|
+
@item.preview_image = "DATASTRING"
|
444
|
+
end
|
445
|
+
it "should have properties from the analyser" do
|
446
|
+
@item.preview_image.number_of_As.should == 2
|
447
|
+
end
|
448
|
+
it "should report that it responds to analyser methods" do
|
449
|
+
@item.preview_image.respond_to?(:number_of_As).should be_true
|
450
|
+
end
|
451
|
+
it "should include analyser methods in methods" do
|
452
|
+
@item.preview_image.methods.include?('number_of_As').should be_true
|
453
|
+
end
|
454
|
+
it "should include analyser methods in public_methods" do
|
455
|
+
@item.preview_image.public_methods.include?('number_of_As').should be_true
|
456
|
+
end
|
457
|
+
it "should update when something new is assigned" do
|
458
|
+
@item.preview_image = 'ANEWDATASTRING'
|
459
|
+
@item.preview_image.number_of_As.should == 3
|
460
|
+
end
|
461
|
+
|
462
|
+
describe "from a new model object" do
|
463
|
+
before(:each) do
|
464
|
+
@app.datastore.stub!(:store).and_return('my_uid')
|
465
|
+
item = Item.create!(:preview_image => 'DATASTRING')
|
466
|
+
@item = Item.find(item.id)
|
467
|
+
@temp_object = @app.create_object('DATASTRING')
|
468
|
+
@temp_object.name = 'jonny.briggs'
|
469
|
+
end
|
470
|
+
it "should load the temp_object then delegate the method" do
|
471
|
+
@app.should_receive(:fetch).with('my_uid').and_return(@temp_object)
|
472
|
+
@item.preview_image.number_of_As.should == 2
|
473
|
+
end
|
474
|
+
it "should use the magic attribute if there is one, and not load the temp_object" do
|
475
|
+
@app.should_not_receive(:fetch)
|
476
|
+
@item.should_receive(:preview_image_some_analyser_method).and_return('result yo')
|
477
|
+
@item.preview_image.some_analyser_method.should == 'result yo'
|
478
|
+
end
|
479
|
+
|
480
|
+
%w(size name ext).each do |attr|
|
481
|
+
it "should use the magic attribute for #{attr} if there is one, and not load the temp_object" do
|
482
|
+
@app.should_not_receive(:fetch)
|
483
|
+
@item.should_receive("preview_image_#{attr}".to_sym).and_return('result yo')
|
484
|
+
@item.preview_image.send(attr).should == 'result yo'
|
485
|
+
end
|
486
|
+
it "should load the temp_object then delegate '#{attr}' if there is no magic attribute for it" do
|
487
|
+
Item.should_receive(:column_names).and_return(['preview_image_uid']) # no magic attributes
|
488
|
+
|
489
|
+
@app.should_receive(:fetch).with('my_uid').and_return(@temp_object)
|
490
|
+
@item.preview_image.send(attr).should == @temp_object.send(attr)
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
end
|
411
495
|
|
496
|
+
it "should not raise an error if a non-existent method is called" do
|
497
|
+
# Just checking method missing works ok
|
498
|
+
lambda{
|
499
|
+
@item.preview_image.eggbert
|
500
|
+
}.should raise_error(NoMethodError)
|
501
|
+
end
|
502
|
+
end
|
412
503
|
end
|
413
504
|
|
414
505
|
end
|