dragonfly 0.8.6 → 0.9.0

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

Potentially problematic release.


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

Files changed (155) hide show
  1. data/{.specopts → .rspec} +0 -1
  2. data/.yardopts +6 -2
  3. data/Gemfile +14 -13
  4. data/History.md +47 -9
  5. data/README.md +25 -5
  6. data/Rakefile +37 -79
  7. data/VERSION +1 -1
  8. data/dragonfly.gemspec +140 -89
  9. data/extra_docs/Analysers.md +8 -48
  10. data/extra_docs/Configuration.md +40 -25
  11. data/extra_docs/Couch.md +49 -0
  12. data/extra_docs/DataStorage.md +94 -24
  13. data/extra_docs/Encoding.md +6 -35
  14. data/extra_docs/ExampleUseCases.md +113 -0
  15. data/extra_docs/GeneralUsage.md +7 -23
  16. data/extra_docs/Generators.md +15 -49
  17. data/extra_docs/Heroku.md +7 -8
  18. data/extra_docs/ImageMagick.md +126 -0
  19. data/extra_docs/MimeTypes.md +3 -3
  20. data/extra_docs/Models.md +163 -0
  21. data/extra_docs/Mongo.md +1 -4
  22. data/extra_docs/Processing.md +7 -60
  23. data/extra_docs/Rails2.md +3 -1
  24. data/extra_docs/Rails3.md +2 -10
  25. data/extra_docs/ServingRemotely.md +83 -0
  26. data/extra_docs/Sinatra.md +3 -3
  27. data/extra_docs/URLs.md +60 -33
  28. data/features/rails_3.0.5.feature +8 -0
  29. data/features/steps/rails_steps.rb +7 -18
  30. data/features/support/env.rb +10 -37
  31. data/features/support/setup.rb +32 -0
  32. data/fixtures/rails_3.0.5/files/app/models/album.rb +5 -0
  33. data/fixtures/rails_3.0.5/files/app/views/albums/new.html.erb +7 -0
  34. data/fixtures/{files → rails_3.0.5/files}/app/views/albums/show.html.erb +2 -0
  35. data/fixtures/{files → rails_3.0.5/files}/config/initializers/dragonfly.rb +0 -0
  36. data/fixtures/rails_3.0.5/files/features/manage_album_images.feature +38 -0
  37. data/fixtures/rails_3.0.5/files/features/step_definitions/helper_steps.rb +7 -0
  38. data/fixtures/{files → rails_3.0.5/files}/features/step_definitions/image_steps.rb +11 -1
  39. data/fixtures/{files → rails_3.0.5/files}/features/support/paths.rb +2 -0
  40. data/fixtures/{files → rails_3.0.5/files}/features/text_images.feature +0 -0
  41. data/fixtures/{rails_3.0.3 → rails_3.0.5}/template.rb +2 -2
  42. data/irbrc.rb +2 -1
  43. data/lib/dragonfly.rb +7 -0
  44. data/lib/dragonfly/active_model_extensions/attachment.rb +134 -46
  45. data/lib/dragonfly/active_model_extensions/attachment_class_methods.rb +144 -0
  46. data/lib/dragonfly/active_model_extensions/class_methods.rb +62 -9
  47. data/lib/dragonfly/active_model_extensions/instance_methods.rb +2 -2
  48. data/lib/dragonfly/active_model_extensions/validations.rb +10 -6
  49. data/lib/dragonfly/analyser.rb +0 -1
  50. data/lib/dragonfly/analysis/file_command_analyser.rb +1 -1
  51. data/lib/dragonfly/analysis/image_magick_analyser.rb +2 -43
  52. data/lib/dragonfly/app.rb +64 -55
  53. data/lib/dragonfly/config/heroku.rb +1 -1
  54. data/lib/dragonfly/config/image_magick.rb +2 -37
  55. data/lib/dragonfly/config/rails.rb +5 -2
  56. data/lib/dragonfly/configurable.rb +115 -35
  57. data/lib/dragonfly/core_ext/object.rb +1 -1
  58. data/lib/dragonfly/core_ext/string.rb +1 -1
  59. data/lib/dragonfly/data_storage/couch_data_store.rb +84 -0
  60. data/lib/dragonfly/data_storage/file_data_store.rb +43 -18
  61. data/lib/dragonfly/data_storage/mongo_data_store.rb +8 -4
  62. data/lib/dragonfly/data_storage/s3data_store.rb +82 -38
  63. data/lib/dragonfly/encoding/image_magick_encoder.rb +2 -53
  64. data/lib/dragonfly/function_manager.rb +4 -2
  65. data/lib/dragonfly/generation/image_magick_generator.rb +2 -136
  66. data/lib/dragonfly/hash_with_css_style_keys.rb +21 -0
  67. data/lib/dragonfly/image_magick/analyser.rb +51 -0
  68. data/lib/dragonfly/image_magick/config.rb +44 -0
  69. data/lib/dragonfly/{encoding/r_magick_encoder.rb → image_magick/encoder.rb} +10 -14
  70. data/lib/dragonfly/image_magick/generator.rb +145 -0
  71. data/lib/dragonfly/image_magick/processor.rb +104 -0
  72. data/lib/dragonfly/image_magick/utils.rb +72 -0
  73. data/lib/dragonfly/image_magick_utils.rb +2 -79
  74. data/lib/dragonfly/job.rb +152 -90
  75. data/lib/dragonfly/middleware.rb +5 -19
  76. data/lib/dragonfly/processing/image_magick_processor.rb +2 -95
  77. data/lib/dragonfly/rails/images.rb +15 -10
  78. data/lib/dragonfly/response.rb +26 -12
  79. data/lib/dragonfly/serializer.rb +1 -4
  80. data/lib/dragonfly/server.rb +103 -0
  81. data/lib/dragonfly/temp_object.rb +56 -101
  82. data/lib/dragonfly/url_mapper.rb +78 -0
  83. data/spec/dragonfly/active_model_extensions/model_spec.rb +772 -65
  84. data/spec/dragonfly/active_model_extensions/spec_helper.rb +90 -10
  85. data/spec/dragonfly/analyser_spec.rb +1 -1
  86. data/spec/dragonfly/analysis/file_command_analyser_spec.rb +5 -14
  87. data/spec/dragonfly/app_spec.rb +35 -180
  88. data/spec/dragonfly/configurable_spec.rb +259 -18
  89. data/spec/dragonfly/core_ext/string_spec.rb +2 -2
  90. data/spec/dragonfly/core_ext/symbol_spec.rb +1 -1
  91. data/spec/dragonfly/data_storage/couch_data_store_spec.rb +84 -0
  92. data/spec/dragonfly/data_storage/file_data_store_spec.rb +149 -22
  93. data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +21 -2
  94. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +207 -43
  95. data/spec/dragonfly/data_storage/{data_store_spec.rb → shared_data_store_examples.rb} +16 -15
  96. data/spec/dragonfly/function_manager_spec.rb +2 -2
  97. data/spec/dragonfly/{generation/hash_with_css_style_keys_spec.rb → hash_with_css_style_keys_spec.rb} +2 -2
  98. data/spec/dragonfly/{analysis/shared_analyser_spec.rb → image_magick/analyser_spec.rb} +19 -6
  99. data/spec/dragonfly/{encoding/image_magick_encoder_spec.rb → image_magick/encoder_spec.rb} +2 -2
  100. data/spec/dragonfly/image_magick/generator_spec.rb +172 -0
  101. data/spec/dragonfly/{processing/shared_processing_spec.rb → image_magick/processor_spec.rb} +55 -6
  102. data/spec/dragonfly/image_magick/utils_spec.rb +18 -0
  103. data/spec/dragonfly/job_builder_spec.rb +1 -1
  104. data/spec/dragonfly/job_definitions_spec.rb +1 -1
  105. data/spec/dragonfly/job_endpoint_spec.rb +26 -3
  106. data/spec/dragonfly/job_spec.rb +426 -208
  107. data/spec/dragonfly/loggable_spec.rb +2 -2
  108. data/spec/dragonfly/middleware_spec.rb +5 -26
  109. data/spec/dragonfly/routed_endpoint_spec.rb +1 -1
  110. data/spec/dragonfly/serializer_spec.rb +1 -14
  111. data/spec/dragonfly/server_spec.rb +261 -0
  112. data/spec/dragonfly/simple_cache_spec.rb +1 -1
  113. data/spec/dragonfly/temp_object_spec.rb +84 -130
  114. data/spec/dragonfly/url_mapper_spec.rb +130 -0
  115. data/spec/functional/deprecations_spec.rb +51 -0
  116. data/spec/functional/image_magick_app_spec.rb +27 -0
  117. data/spec/functional/model_urls_spec.rb +85 -0
  118. data/spec/functional/remote_on_the_fly_spec.rb +51 -0
  119. data/spec/functional/to_response_spec.rb +31 -0
  120. data/spec/spec_helper.rb +12 -22
  121. data/spec/{argument_matchers.rb → support/argument_matchers.rb} +0 -0
  122. data/spec/{image_matchers.rb → support/image_matchers.rb} +4 -4
  123. data/spec/support/simple_matchers.rb +53 -0
  124. data/yard/handlers/configurable_attr_handler.rb +2 -2
  125. data/yard/templates/default/fulldoc/html/css/common.css +12 -10
  126. data/yard/templates/default/layout/html/layout.erb +6 -0
  127. metadata +267 -308
  128. data/Gemfile.rails.2.3.5 +0 -20
  129. data/features/3.0.3.feature +0 -8
  130. data/features/rails_2.3.5.feature +0 -7
  131. data/fixtures/files/app/models/album.rb +0 -3
  132. data/fixtures/files/app/views/albums/new.html.erb +0 -4
  133. data/fixtures/files/features/manage_album_images.feature +0 -12
  134. data/fixtures/rails_2.3.5/template.rb +0 -10
  135. data/lib/dragonfly/analysis/r_magick_analyser.rb +0 -63
  136. data/lib/dragonfly/config/r_magick.rb +0 -46
  137. data/lib/dragonfly/generation/hash_with_css_style_keys.rb +0 -23
  138. data/lib/dragonfly/generation/r_magick_generator.rb +0 -155
  139. data/lib/dragonfly/processing/r_magick_processor.rb +0 -126
  140. data/lib/dragonfly/r_magick_utils.rb +0 -48
  141. data/lib/dragonfly/simple_endpoint.rb +0 -76
  142. data/spec/dragonfly/active_model_extensions/active_model_setup.rb +0 -97
  143. data/spec/dragonfly/active_model_extensions/active_record_setup.rb +0 -85
  144. data/spec/dragonfly/analysis/image_magick_analyser_spec.rb +0 -15
  145. data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +0 -31
  146. data/spec/dragonfly/config/r_magick_spec.rb +0 -29
  147. data/spec/dragonfly/encoding/r_magick_encoder_spec.rb +0 -41
  148. data/spec/dragonfly/generation/image_magick_generator_spec.rb +0 -12
  149. data/spec/dragonfly/generation/r_magick_generator_spec.rb +0 -28
  150. data/spec/dragonfly/generation/shared_generator_spec.rb +0 -91
  151. data/spec/dragonfly/image_magick_utils_spec.rb +0 -16
  152. data/spec/dragonfly/processing/image_magick_processor_spec.rb +0 -29
  153. data/spec/dragonfly/processing/r_magick_processor_spec.rb +0 -30
  154. data/spec/dragonfly/simple_endpoint_spec.rb +0 -97
  155. data/spec/simple_matchers.rb +0 -44
@@ -1,11 +1,91 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
2
-
3
- begin
4
- require 'active_model'
5
- rescue LoadError => e
6
- # When there's NO active_model
7
- require File.dirname(__FILE__) + '/active_record_setup'
8
- else
9
- # When there IS active model
10
- require File.dirname(__FILE__) + '/active_model_setup'
1
+ require 'spec_helper'
2
+ require 'active_model'
3
+
4
+ # --------------------------------------------------------------- #
5
+ # MODELS
6
+ # --------------------------------------------------------------- #
7
+ class MyModel
8
+
9
+ # Callbacks
10
+ extend ActiveModel::Callbacks
11
+ define_model_callbacks :save, :destroy
12
+
13
+ include ActiveModel::Validations
14
+
15
+ class << self
16
+ def create!(attrs={})
17
+ new(attrs).save!
18
+ end
19
+
20
+ def find(id)
21
+ new(instances[id])
22
+ end
23
+
24
+ def instances
25
+ @instances ||= {}
26
+ end
27
+ end
28
+
29
+ def initialize(attrs={})
30
+ attrs.each do |key, value|
31
+ send("#{key}=", value)
32
+ end
33
+ end
34
+
35
+ attr_accessor :id
36
+
37
+ def to_hash
38
+ self.class::ATTRIBUTES.inject({}) do |hash, attr|
39
+ hash[attr] = send(attr)
40
+ hash
41
+ end
42
+ end
43
+
44
+ def save
45
+ _run_save_callbacks {
46
+ self.id ||= rand(1000)
47
+ self.class.instances[id] = self.to_hash
48
+ }
49
+ end
50
+ def save!
51
+ save
52
+ self
53
+ end
54
+
55
+ def destroy
56
+ _run_destroy_callbacks {}
57
+ end
58
+ end
59
+
60
+ class Item < MyModel
61
+
62
+ ATTRIBUTES = [
63
+ :title,
64
+ :preview_image_uid,
65
+ :preview_image_some_analyser_method,
66
+ :preview_image_size,
67
+ :preview_image_name,
68
+ :preview_image_blah_blah,
69
+ :other_image_uid,
70
+ :yet_another_image_uid,
71
+ :otra_imagen_uid,
72
+ :trailer_video_uid,
73
+ :created_at,
74
+ :updated_at
75
+ ]
76
+ attr_accessor *ATTRIBUTES
77
+ end
78
+
79
+ class Car < MyModel
80
+ ATTRIBUTES = [
81
+ :image_uid,
82
+ :reliant_image_uid,
83
+ :type
84
+ ]
85
+ attr_accessor *ATTRIBUTES
86
+ end
87
+
88
+ class Photo < MyModel
89
+ ATTRIBUTES = [:image_uid]
90
+ attr_accessor *ATTRIBUTES
11
91
  end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe Dragonfly::Analyser do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  png_path = File.dirname(__FILE__) + '/../../../samples/egg.png'
4
4
 
@@ -36,20 +36,11 @@ describe Dragonfly::Analysis::FileCommandAnalyser do
36
36
  @analyser.mime_type(@temp_object)
37
37
  @temp_object.instance_eval{@tempfile}.should be_nil
38
38
  end
39
-
40
- {
41
- :jpg => 'image/jpeg',
42
- :png => 'image/png',
43
- :gif => 'image/gif',
44
- :tif => 'image/tiff'
45
- }.each do |format, mime_type|
46
- it "should work properly (without a broken pipe error) for big files of format #{format}" do
47
- data = Dragonfly::Generation::ImageMagickGenerator.new.plasma(1000, 1000, format).first
48
- temp_object = Dragonfly::TempObject.new(data)
49
- @analyser.mime_type(temp_object).should == mime_type
50
- end
39
+ it "should work properly (without a broken pipe error) for big files of format jpg" do
40
+ data = Dragonfly::ImageMagick::Generator.new.plasma(1000, 1000, :jpg).first
41
+ temp_object = Dragonfly::TempObject.new(data)
42
+ @analyser.mime_type(temp_object).should == "image/jpeg"
51
43
  end
52
-
53
44
  end
54
45
 
55
46
  end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
1
+ require 'spec_helper'
2
2
  require 'rack/mock'
3
3
 
4
4
  def request(app, path)
@@ -69,189 +69,21 @@ describe Dragonfly::App do
69
69
  other_app.mime_type_for(:mark).should == 'second/one'
70
70
  end
71
71
  end
72
-
73
- describe "#resolve_mime_type" do
74
- before(:each) do
75
- @app = test_app
76
- @app.analyser.add :format do |temp_object|
77
- :png
78
- end
79
- @app.analyser.add :mime_type do |temp_object|
80
- 'image/jpeg'
81
- end
82
- @app.encoder.add do |temp_object|
83
- 'ENCODED DATA YO'
84
- end
85
- end
86
-
87
- it "should return the correct mime_type if the temp_object has a format" do
88
- temp_object = Dragonfly::TempObject.new("HIMATE", :format => :tiff, :name => 'test.pdf')
89
- @app.resolve_mime_type(temp_object).should == 'image/tiff'
90
- end
91
-
92
- it "should use the file extension if it has no format" do
93
- temp_object = Dragonfly::TempObject.new("HIMATE", :name => 'test.pdf')
94
- @app.resolve_mime_type(temp_object).should == 'application/pdf'
95
- end
96
-
97
- it "should not use the file extension if it's been switched off (fall back to mime_type analyser)" do
98
- @app.infer_mime_type_from_file_ext = false
99
- temp_object = Dragonfly::TempObject.new("HIMATE", :name => 'test.pdf')
100
- @app.resolve_mime_type(temp_object).should == 'image/jpeg'
101
- end
102
-
103
- it "should fall back to the mime_type analyser if the temp_object has no ext" do
104
- temp_object = Dragonfly::TempObject.new("HIMATE", :name => 'test')
105
- @app.resolve_mime_type(temp_object).should == 'image/jpeg'
106
- end
107
-
108
- describe "when the temp_object has no name" do
109
-
110
- before(:each) do
111
- @temp_object = Dragonfly::TempObject.new("HIMATE")
112
- end
113
-
114
- it "should fall back to the mime_type analyser" do
115
- @app.resolve_mime_type(@temp_object).should == 'image/jpeg'
116
- end
117
-
118
- it "should fall back to the format analyser if the mime_type analyser doesn't exist" do
119
- @app.analyser.functions.delete(:mime_type)
120
- @app.resolve_mime_type(@temp_object).should == 'image/png'
121
- end
122
-
123
- it "should fall back to the app's fallback mime_type if no mime_type/format analyser exists" do
124
- @app.analyser.functions.delete(:mime_type)
125
- @app.analyser.functions.delete(:format)
126
- @app.resolve_mime_type(@temp_object).should == 'application/octet-stream'
127
- end
128
-
129
- end
130
-
131
- end
132
-
133
- end
134
-
135
- describe "without path prefix or DOS protection" do
136
- before(:each) do
137
- @app = test_app
138
- @job = Dragonfly::Job.new(@app).fetch('some_uid')
139
- @app.datastore.stub!(:retrieve).with('some_uid').and_return "Hi there"
140
- @app.configure{|c| c.protect_from_dos_attacks = false }
141
- end
142
- it "should correctly respond with the job data" do
143
- response = request(@app, "/#{@job.serialize}")
144
- response.status.should == 200
145
- response.body.should == "Hi there"
146
- end
147
- it "should generate the correct url" do
148
- @app.url_for(@job).should == "/#{@job.serialize}"
149
- end
150
- end
151
-
152
- describe "url_path_prefix" do
153
- before(:each) do
154
- @app = test_app
155
- @job = Dragonfly::Job.new(@app)
156
- end
157
- it "should add the path prefix to the url if configured" do
158
- @app.url_path_prefix = '/media'
159
- @app.url_for(@job).should =~ %r{^/media/\w+$}
160
- end
161
- it "should add the path prefix to the url if passed in" do
162
- @app.url_for(@job, :path_prefix => '/eggs').should =~ %r{^/eggs/\w+$}
163
- end
164
- it "should favour the passed in one" do
165
- @app.url_path_prefix = '/media'
166
- @app.url_for(@job, :path_prefix => '/bacon').should =~ %r{^/bacon/\w+$}
167
- end
168
72
  end
169
73
 
170
- describe "url_host" do
74
+ describe "remote_url_for" do
171
75
  before(:each) do
172
76
  @app = test_app
173
- @job = Dragonfly::Job.new(@app)
77
+ @app.datastore = Object.new
174
78
  end
175
- it "should add the host to the url if configured" do
176
- @app.url_host = 'http://some.server:4000'
177
- @app.url_for(@job).should =~ %r{^http://some\.server:4000/\w+$}
178
- end
179
- it "should add the host to the url if passed in" do
180
- @app.url_for(@job, :host => 'https://bungle.com').should =~ %r{^https://bungle\.com/\w+$}
181
- end
182
- it "should favour the passed in one" do
183
- @app.url_host = 'http://some.server:4000'
184
- @app.url_for(@job, :host => 'https://smeedy').should =~ %r{^https://smeedy/\w+$}
185
- end
186
- end
187
-
188
- describe "url_suffix" do
189
- before(:each) do
190
- @app = test_app
191
- @job = Dragonfly::Job.new(@app)
192
- end
193
- it "should add the suffix to the url if configured" do
194
- @app.url_suffix = 'hellodudes'
195
- @app.url_for(@job).should =~ /\w+hellodudes$/
196
- end
197
- it "should add the suffix to the url if passed in" do
198
- @app.url_for(@job, :suffix => '/howdy.pardner').should =~ /\w+\/howdy\.pardner$/
199
- end
200
- it "should favour the passed in one" do
201
- @app.url_suffix = 'hellodudes'
202
- @app.url_for(@job, :suffix => '/howdy.pardner').should =~ /\w+\/howdy\.pardner$/
203
- end
204
- it "should accept a proc yielding the job" do
205
- @app.url_suffix = proc{|job| job.uid }
206
- @job.fetch!('some_uid')
207
- @app.url_for(@job).should =~ /\w+some_uid$/
208
- end
209
- end
210
-
211
- describe "url params" do
212
- before(:each) do
213
- @app = test_app
214
- @job = Dragonfly::Job.new(@app)
215
- end
216
- it "should add extra params to the url query string" do
217
- @app.url_for(@job, :suffix => '/suffix', :a => 'thing', :b => 'nuther').should =~ /\w+\/suffix\?a=thing&b=nuther$/
218
- end
219
- end
220
-
221
- describe "Denial of Service protection" do
222
- before(:each) do
223
- @app = test_app
224
- @app.protect_from_dos_attacks = true
225
- @job = Dragonfly::Job.new(@app).fetch('some_uid')
226
- end
227
- it "should generate the correct url" do
228
- @app.url_for(@job).should == "/#{@job.serialize}?s=#{@job.sha}"
229
- end
230
- end
231
-
232
- describe "configuring with saved configurations" do
233
- before(:each) do
234
- @app = test_app
235
- end
236
-
237
- {
238
- :imagemagick => Dragonfly::Config::ImageMagick,
239
- :image_magick => Dragonfly::Config::ImageMagick,
240
- :rmagick => Dragonfly::Config::RMagick,
241
- :r_magick => Dragonfly::Config::RMagick,
242
- :rails => Dragonfly::Config::Rails,
243
- :heroku => Dragonfly::Config::Heroku,
244
- }.each do |key, klass|
245
- it "should map #{key} to #{klass}" do
246
- klass.should_receive(:apply_configuration).with(@app)
247
- @app.configure_with(key)
248
- end
79
+ it "should raise an error if the datastore doesn't provide it" do
80
+ lambda{
81
+ @app.remote_url_for('some_uid')
82
+ }.should raise_error(NotImplementedError)
249
83
  end
250
-
251
- it "should description" do
252
- lambda {
253
- @app.configure_with(:eggs)
254
- }.should raise_error(ArgumentError)
84
+ it "should correctly call it if the datastore provides it" do
85
+ @app.datastore.should_receive(:url_for).with('some_uid', :some => :opts).and_return 'http://egg.head'
86
+ @app.remote_url_for('some_uid', :some => :opts).should == 'http://egg.head'
255
87
  end
256
88
  end
257
89
 
@@ -270,11 +102,34 @@ describe Dragonfly::App do
270
102
  end
271
103
  it "should allow storing with extra stuff" do
272
104
  @app.datastore.should_receive(:store).with(
273
- a_temp_object_with_data("HELLO", :meta => {:egg => :head}),
274
- {:option => :blarney}
105
+ a_temp_object_with_data("HELLO"), :meta => {:egg => :head}, :option => :blarney
275
106
  )
276
107
  @app.store("HELLO", :meta => {:egg => :head}, :option => :blarney)
277
108
  end
278
109
  end
279
110
 
111
+ describe "url_for" do
112
+ before(:each) do
113
+ @app = test_app
114
+ @job = @app.fetch('eggs')
115
+ end
116
+ it "should give the server url by default" do
117
+ @app.url_for(@job).should =~ %r{^/\w+$}
118
+ end
119
+ it "should allow configuring" do
120
+ @app.configure do |c|
121
+ c.define_url do |app, job, opts|
122
+ "doogies"
123
+ end
124
+ end
125
+ @app.url_for(@job).should == 'doogies'
126
+ end
127
+ it "should yield the correct dooberries" do
128
+ @app.define_url do |app, job, opts|
129
+ [app, job, opts]
130
+ end
131
+ @app.url_for(@job, {'chuddies' => 'margate'}).should == [@app, @job, {'chuddies' => 'margate'}]
132
+ end
133
+ end
134
+
280
135
  end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe Dragonfly::Configurable do
4
4
 
@@ -30,6 +30,11 @@ describe Dragonfly::Configurable do
30
30
  @car.colour.should be_nil
31
31
  end
32
32
 
33
+ it "should allow setting to nil" do
34
+ @car.top_speed = nil
35
+ @car.top_speed.should be_nil
36
+ end
37
+
33
38
  it "should allow specifying configurable attrs as strings" do
34
39
  class Bike
35
40
  include Dragonfly::Configurable
@@ -61,12 +66,12 @@ describe Dragonfly::Configurable do
61
66
  end
62
67
 
63
68
  describe "getting configuration" do
64
- it "should return the configuration as a hash" do
65
- @car.configuration.should == {:colour => nil, :top_speed => 216}
69
+ it "should return the configuration when nothing is set" do
70
+ @car.configuration.should == {}
66
71
  end
67
- it "should not allow you to change the configuration via the hash" do
68
- @car.configuration[:top_speed] = 555
69
- @car.top_speed.should == 216
72
+ it "should return the configuration when something is set" do
73
+ @car.top_speed = 10
74
+ @car.configuration.should == {:top_speed => 10}
70
75
  end
71
76
  end
72
77
 
@@ -79,8 +84,8 @@ describe Dragonfly::Configurable do
79
84
  car1.configure{|c| c.colour = 'green'}
80
85
  car2 = Car.new
81
86
  car2.configure{|c| c.colour = 'yellow'}
82
- car1.configuration.should == {:colour => 'green', :top_speed => 216}
83
- car2.configuration.should == {:colour => 'yellow', :top_speed => 216}
87
+ car1.configuration.should == {:colour => 'green'}
88
+ car2.configuration.should == {:colour => 'yellow'}
84
89
  end
85
90
  end
86
91
 
@@ -153,32 +158,50 @@ describe Dragonfly::Configurable do
153
158
 
154
159
  describe "nested configurable objects" do
155
160
 
156
- it "should allow configuring nested configurable objects" do
157
-
161
+ before(:each) do
158
162
  class NestedThing
159
163
  include Dragonfly::Configurable
160
164
  configurable_attr :age, 29
165
+ def some_method(val)
166
+ @some_thing = val
167
+ end
168
+ configuration_method :some_method
169
+ attr_reader :some_thing
161
170
  end
162
171
 
163
172
  class Car
164
173
  def nested_thing
165
174
  @nested_thing ||= NestedThing.new
166
175
  end
176
+ nested_configurable :nested_thing
167
177
  end
168
178
 
169
179
  @car.configure do |c|
170
180
  c.nested_thing.configure do |nt|
171
181
  nt.age = 50
182
+ nt.some_method('yo')
172
183
  end
173
184
  end
185
+ end
174
186
 
187
+ it "should allow configuring nested configurable accessors" do
175
188
  @car.nested_thing.age.should == 50
176
-
177
189
  end
178
190
 
191
+ it "should allow configuring nested configurable normal methods" do
192
+ @car.nested_thing.some_thing.should == 'yo'
193
+ end
194
+
195
+ it "should not allow configuring directly on the config object" do
196
+ expect{
197
+ @car.configure do |c|
198
+ c.some_method('other')
199
+ end
200
+ }.to raise_error(Dragonfly::Configurable::BadConfigAttribute)
201
+ end
179
202
  end
180
203
 
181
- describe "configuring with a configurer" do
204
+ describe "configuring with a saved config" do
182
205
  before(:each) do
183
206
  @cool_configuration = Object.new
184
207
  def @cool_configuration.apply_configuration(car, colour=nil)
@@ -188,13 +211,13 @@ describe Dragonfly::Configurable do
188
211
  end
189
212
  end
190
213
 
191
- it "should allow configuration by a configurer" do
214
+ it "should allow configuration by a saved config" do
192
215
  @car.configure_with(@cool_configuration)
193
216
  @car.colour.should == 'vermelho'
194
217
  @car.top_speed.should == 216
195
218
  end
196
219
 
197
- it "should pass any args through to the configurer" do
220
+ it "should pass any args through to the saved config" do
198
221
  @car.configure_with(@cool_configuration, 'preto')
199
222
  @car.colour.should == 'preto'
200
223
  end
@@ -210,11 +233,229 @@ describe Dragonfly::Configurable do
210
233
  @car.configure_with(@cool_configuration).should == @car
211
234
  end
212
235
 
213
- it "should ask the object which object to configure with if a symbol is given" do
214
- @car.should_receive(:configurer_for).with(:cool).and_return(@cool_configuration)
215
- @car.configure_with(:cool)
216
- @car.colour.should == 'vermelho'
236
+ describe "using a symbol to specify the config" do
237
+
238
+ before(:all) do
239
+ @rally_config = Object.new
240
+ Car.register_configuration(:rally, @rally_config)
241
+ @long_journey_config = Object.new
242
+ Car.register_configuration(:long_journey){ @long_journey_config }
243
+ Car.register_configuration(:some_library){ SomeLibrary }
244
+ end
245
+
246
+ it "should map the symbol to the correct configuration" do
247
+ @rally_config.should_receive(:apply_configuration).with(@car)
248
+ @car.configure_with(:rally)
249
+ end
250
+
251
+ it "should map the symbol to the correct configuration lazily" do
252
+ @long_journey_config.should_receive(:apply_configuration).with(@car)
253
+ @car.configure_with(:long_journey)
254
+ end
255
+
256
+ it "should throw an error if an unknown symbol is passed in" do
257
+ lambda {
258
+ @car.configure_with(:eggs)
259
+ }.should raise_error(ArgumentError)
260
+ end
261
+
262
+ it "should only try to load the library when asked to" do
263
+ lambda{
264
+ @car.configure_with(:some_library)
265
+ }.should raise_error(NameError, /uninitialized constant.*SomeLibrary/)
266
+ end
217
267
  end
268
+
218
269
  end
219
270
 
271
+ describe "falling back to another config" do
272
+ before(:each) do
273
+ @garage = Object.new
274
+ class << @garage
275
+ include Dragonfly::Configurable
276
+ configurable_attr :top_speed, 100
277
+ end
278
+ @car.use_as_fallback_config(@garage)
279
+ end
280
+
281
+ describe "when nothing set" do
282
+ it "should use its default" do
283
+ @car.top_speed.should == 216
284
+ end
285
+ it "shouldn't affect the fallback config object" do
286
+ @garage.top_speed.should == 100
287
+ end
288
+ end
289
+
290
+ describe "if set" do
291
+ before(:each) do
292
+ @car.top_speed = 444
293
+ end
294
+ it "should work normally" do
295
+ @car.top_speed.should == 444
296
+ end
297
+ it "shouldn't affect the fallback config object" do
298
+ @garage.top_speed.should == 100
299
+ end
300
+ end
301
+
302
+ describe "both set" do
303
+ before(:each) do
304
+ @car.top_speed = 444
305
+ @garage.top_speed = 3000
306
+ end
307
+ it "should prefer its own setting" do
308
+ @car.top_speed.should == 444
309
+ end
310
+ it "shouldn't affect the fallback config object" do
311
+ @garage.top_speed.should == 3000
312
+ end
313
+ end
314
+
315
+ describe "the fallback config is set" do
316
+ before(:each) do
317
+ @garage.top_speed = 3000
318
+ end
319
+ it "should use the fallback config" do
320
+ @car.top_speed.should == 3000
321
+ end
322
+ it "shouldn't affect the fallback config object" do
323
+ @garage.top_speed.should == 3000
324
+ end
325
+ end
326
+
327
+ describe "falling back multiple levels" do
328
+ before(:each) do
329
+ @klass = Class.new
330
+ @klass.class_eval do
331
+ include Dragonfly::Configurable
332
+ configurable_attr :veg, 'carrot'
333
+ end
334
+ @a = @klass.new
335
+ @b = @klass.new
336
+ @b.use_as_fallback_config(@a)
337
+ @c = @klass.new
338
+ @c.use_as_fallback_config(@b)
339
+ end
340
+
341
+ it "should be the default if nothing set" do
342
+ @c.veg.should == 'carrot'
343
+ end
344
+
345
+ it "should fall all the way back to the top one if necessary" do
346
+ @a.veg = 'turnip'
347
+ @c.veg.should == 'turnip'
348
+ end
349
+
350
+ it "should prefer the closer one over the further away one" do
351
+ @b.veg = 'tatty'
352
+ @a.veg = 'turnip'
353
+ @c.veg.should == 'tatty'
354
+ end
355
+
356
+ it "should work properly with nils" do
357
+ @a.veg = nil
358
+ @c.veg = 'broc'
359
+ @a.veg.should be_nil
360
+ @b.veg.should be_nil
361
+ @c.veg.should == 'broc'
362
+ end
363
+ end
364
+
365
+ describe "objects with different methods" do
366
+ before(:each) do
367
+ @dad = Object.new
368
+ class << @dad
369
+ include Dragonfly::Configurable
370
+ end
371
+ @kid = Object.new
372
+ class << @kid
373
+ include Dragonfly::Configurable
374
+ configurable_attr :lug, 'default-lug'
375
+ end
376
+ @kid.use_as_fallback_config(@dad)
377
+ end
378
+
379
+ it "should not allow setting on the fallback obj directly" do
380
+ lambda{
381
+ @dad.lug = 'leg'
382
+ }.should raise_error(NoMethodError)
383
+ end
384
+
385
+ it "should not have the fallback obj respond to the method" do
386
+ @dad.should_not respond_to(:lug=)
387
+ end
388
+
389
+ it "should allow configuring through the fallback object even if it doesn't have that method" do
390
+ @dad.configure do |c|
391
+ c.lug = 'leg'
392
+ end
393
+ @kid.lug.should == 'leg'
394
+ end
395
+
396
+ it "should work when a grandchild config is added later" do
397
+ grandkid = Object.new
398
+ class << grandkid
399
+ include Dragonfly::Configurable
400
+ configurable_attr :oogie, 'boogie'
401
+ end
402
+ grandkid.use_as_fallback_config(@kid)
403
+ @dad.configure{|c| c.oogie = 'duggen' }
404
+ grandkid.oogie.should == 'duggen'
405
+ end
406
+
407
+ it "should allow configuring twice through the fallback object" do
408
+ @dad.configure{|c| c.lug = 'leg' }
409
+ @dad.configure{|c| c.lug = 'blug' }
410
+ @kid.lug.should == 'blug'
411
+ end
412
+ end
413
+
414
+ describe "clashing with configurable modules" do
415
+ before(:each) do
416
+ @mod = mod = Module.new
417
+ @mod.module_eval do
418
+ include Dragonfly::Configurable
419
+ configurable_attr :team, 'spurs'
420
+ end
421
+ @class = Class.new
422
+ @class.class_eval do
423
+ include mod
424
+ include Dragonfly::Configurable
425
+ configurable_attr :tree, 'elm'
426
+ end
427
+ end
428
+
429
+ it "should not override the defaults from the module" do
430
+ obj = @class.new
431
+ obj.team.should == 'spurs'
432
+ end
433
+
434
+ it "should still use its own defaults" do
435
+ obj = @class.new
436
+ obj.tree.should == 'elm'
437
+ end
438
+
439
+ describe "when the configurable_attr is specified in a subclass that doesn't include Configurable" do
440
+ before(:each) do
441
+ @subclass = Class.new(@class)
442
+ @subclass.class_eval do
443
+ configurable_attr :car, 'mazda'
444
+ configurable_attr :tree, 'oak'
445
+ end
446
+ @obj = @subclass.new
447
+ end
448
+
449
+ it "should still work with default values" do
450
+ @obj.car.should == 'mazda'
451
+ end
452
+
453
+ it "should override the default from the parent" do
454
+ @obj.tree.should == 'oak'
455
+ end
456
+ end
457
+
458
+ end
459
+
460
+ end
220
461
  end