oahu-dragonfly 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. data/.rspec +1 -0
  2. data/.yardopts +24 -0
  3. data/Gemfile +30 -0
  4. data/History.md +323 -0
  5. data/LICENSE +20 -0
  6. data/README.md +88 -0
  7. data/Rakefile +50 -0
  8. data/VERSION +1 -0
  9. data/config.ru +14 -0
  10. data/docs.watchr +1 -0
  11. data/dragonfly.gemspec +297 -0
  12. data/extra_docs/Analysers.md +66 -0
  13. data/extra_docs/Caching.md +23 -0
  14. data/extra_docs/Configuration.md +124 -0
  15. data/extra_docs/Couch.md +49 -0
  16. data/extra_docs/DataStorage.md +153 -0
  17. data/extra_docs/Encoding.md +67 -0
  18. data/extra_docs/GeneralUsage.md +121 -0
  19. data/extra_docs/Generators.md +60 -0
  20. data/extra_docs/Heroku.md +50 -0
  21. data/extra_docs/ImageMagick.md +125 -0
  22. data/extra_docs/Index.md +33 -0
  23. data/extra_docs/MimeTypes.md +40 -0
  24. data/extra_docs/Models.md +272 -0
  25. data/extra_docs/Mongo.md +45 -0
  26. data/extra_docs/Processing.md +77 -0
  27. data/extra_docs/Rack.md +52 -0
  28. data/extra_docs/Rails2.md +57 -0
  29. data/extra_docs/Rails3.md +62 -0
  30. data/extra_docs/Sinatra.md +25 -0
  31. data/extra_docs/URLs.md +169 -0
  32. data/features/images.feature +47 -0
  33. data/features/no_processing.feature +14 -0
  34. data/features/rails_3.0.5.feature +8 -0
  35. data/features/steps/common_steps.rb +8 -0
  36. data/features/steps/dragonfly_steps.rb +66 -0
  37. data/features/steps/rails_steps.rb +28 -0
  38. data/features/support/env.rb +13 -0
  39. data/features/support/setup.rb +32 -0
  40. data/fixtures/rails_3.0.5/files/app/models/album.rb +7 -0
  41. data/fixtures/rails_3.0.5/files/app/views/albums/new.html.erb +7 -0
  42. data/fixtures/rails_3.0.5/files/app/views/albums/show.html.erb +6 -0
  43. data/fixtures/rails_3.0.5/files/config/initializers/dragonfly.rb +4 -0
  44. data/fixtures/rails_3.0.5/files/features/manage_album_images.feature +38 -0
  45. data/fixtures/rails_3.0.5/files/features/step_definitions/helper_steps.rb +7 -0
  46. data/fixtures/rails_3.0.5/files/features/step_definitions/image_steps.rb +25 -0
  47. data/fixtures/rails_3.0.5/files/features/support/paths.rb +17 -0
  48. data/fixtures/rails_3.0.5/files/features/text_images.feature +7 -0
  49. data/fixtures/rails_3.0.5/template.rb +20 -0
  50. data/irbrc.rb +18 -0
  51. data/lib/dragonfly.rb +55 -0
  52. data/lib/dragonfly/active_model_extensions.rb +13 -0
  53. data/lib/dragonfly/active_model_extensions/attachment.rb +250 -0
  54. data/lib/dragonfly/active_model_extensions/attachment_class_methods.rb +148 -0
  55. data/lib/dragonfly/active_model_extensions/class_methods.rb +95 -0
  56. data/lib/dragonfly/active_model_extensions/instance_methods.rb +28 -0
  57. data/lib/dragonfly/active_model_extensions/validations.rb +41 -0
  58. data/lib/dragonfly/analyser.rb +58 -0
  59. data/lib/dragonfly/analysis/file_command_analyser.rb +32 -0
  60. data/lib/dragonfly/analysis/image_magick_analyser.rb +6 -0
  61. data/lib/dragonfly/app.rb +172 -0
  62. data/lib/dragonfly/config/heroku.rb +19 -0
  63. data/lib/dragonfly/config/image_magick.rb +6 -0
  64. data/lib/dragonfly/config/rails.rb +20 -0
  65. data/lib/dragonfly/configurable.rb +207 -0
  66. data/lib/dragonfly/core_ext/array.rb +7 -0
  67. data/lib/dragonfly/core_ext/hash.rb +7 -0
  68. data/lib/dragonfly/core_ext/object.rb +12 -0
  69. data/lib/dragonfly/core_ext/string.rb +9 -0
  70. data/lib/dragonfly/core_ext/symbol.rb +9 -0
  71. data/lib/dragonfly/data_storage.rb +9 -0
  72. data/lib/dragonfly/data_storage/couch_data_store.rb +64 -0
  73. data/lib/dragonfly/data_storage/file_data_store.rb +141 -0
  74. data/lib/dragonfly/data_storage/mongo_data_store.rb +86 -0
  75. data/lib/dragonfly/data_storage/s3data_store.rb +145 -0
  76. data/lib/dragonfly/encoder.rb +13 -0
  77. data/lib/dragonfly/encoding/image_magick_encoder.rb +6 -0
  78. data/lib/dragonfly/function_manager.rb +71 -0
  79. data/lib/dragonfly/generation/image_magick_generator.rb +6 -0
  80. data/lib/dragonfly/generator.rb +9 -0
  81. data/lib/dragonfly/hash_with_css_style_keys.rb +21 -0
  82. data/lib/dragonfly/image_magick/analyser.rb +51 -0
  83. data/lib/dragonfly/image_magick/config.rb +41 -0
  84. data/lib/dragonfly/image_magick/encoder.rb +57 -0
  85. data/lib/dragonfly/image_magick/generator.rb +145 -0
  86. data/lib/dragonfly/image_magick/processor.rb +99 -0
  87. data/lib/dragonfly/image_magick/utils.rb +72 -0
  88. data/lib/dragonfly/image_magick_utils.rb +4 -0
  89. data/lib/dragonfly/job.rb +451 -0
  90. data/lib/dragonfly/job_builder.rb +39 -0
  91. data/lib/dragonfly/job_definitions.rb +26 -0
  92. data/lib/dragonfly/job_endpoint.rb +15 -0
  93. data/lib/dragonfly/loggable.rb +28 -0
  94. data/lib/dragonfly/middleware.rb +20 -0
  95. data/lib/dragonfly/processing/image_magick_processor.rb +6 -0
  96. data/lib/dragonfly/processor.rb +9 -0
  97. data/lib/dragonfly/rails/images.rb +27 -0
  98. data/lib/dragonfly/response.rb +97 -0
  99. data/lib/dragonfly/routed_endpoint.rb +40 -0
  100. data/lib/dragonfly/serializer.rb +32 -0
  101. data/lib/dragonfly/server.rb +113 -0
  102. data/lib/dragonfly/simple_cache.rb +23 -0
  103. data/lib/dragonfly/temp_object.rb +175 -0
  104. data/lib/dragonfly/url_mapper.rb +78 -0
  105. data/samples/beach.png +0 -0
  106. data/samples/egg.png +0 -0
  107. data/samples/round.gif +0 -0
  108. data/samples/sample.docx +0 -0
  109. data/samples/taj.jpg +0 -0
  110. data/spec/dragonfly/active_model_extensions/model_spec.rb +1426 -0
  111. data/spec/dragonfly/active_model_extensions/spec_helper.rb +91 -0
  112. data/spec/dragonfly/analyser_spec.rb +123 -0
  113. data/spec/dragonfly/analysis/file_command_analyser_spec.rb +48 -0
  114. data/spec/dragonfly/app_spec.rb +135 -0
  115. data/spec/dragonfly/configurable_spec.rb +461 -0
  116. data/spec/dragonfly/core_ext/array_spec.rb +19 -0
  117. data/spec/dragonfly/core_ext/hash_spec.rb +19 -0
  118. data/spec/dragonfly/core_ext/string_spec.rb +17 -0
  119. data/spec/dragonfly/core_ext/symbol_spec.rb +17 -0
  120. data/spec/dragonfly/data_storage/couch_data_store_spec.rb +76 -0
  121. data/spec/dragonfly/data_storage/file_data_store_spec.rb +296 -0
  122. data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +57 -0
  123. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +258 -0
  124. data/spec/dragonfly/data_storage/shared_data_store_examples.rb +77 -0
  125. data/spec/dragonfly/function_manager_spec.rb +154 -0
  126. data/spec/dragonfly/hash_with_css_style_keys_spec.rb +24 -0
  127. data/spec/dragonfly/image_magick/analyser_spec.rb +64 -0
  128. data/spec/dragonfly/image_magick/encoder_spec.rb +41 -0
  129. data/spec/dragonfly/image_magick/generator_spec.rb +172 -0
  130. data/spec/dragonfly/image_magick/processor_spec.rb +233 -0
  131. data/spec/dragonfly/image_magick/utils_spec.rb +18 -0
  132. data/spec/dragonfly/job_builder_spec.rb +37 -0
  133. data/spec/dragonfly/job_definitions_spec.rb +35 -0
  134. data/spec/dragonfly/job_endpoint_spec.rb +173 -0
  135. data/spec/dragonfly/job_spec.rb +1046 -0
  136. data/spec/dragonfly/loggable_spec.rb +80 -0
  137. data/spec/dragonfly/middleware_spec.rb +47 -0
  138. data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
  139. data/spec/dragonfly/serializer_spec.rb +61 -0
  140. data/spec/dragonfly/server_spec.rb +278 -0
  141. data/spec/dragonfly/simple_cache_spec.rb +27 -0
  142. data/spec/dragonfly/temp_object_spec.rb +306 -0
  143. data/spec/dragonfly/url_mapper_spec.rb +126 -0
  144. data/spec/functional/deprecations_spec.rb +51 -0
  145. data/spec/functional/image_magick_app_spec.rb +27 -0
  146. data/spec/functional/model_urls_spec.rb +85 -0
  147. data/spec/functional/remote_on_the_fly_spec.rb +51 -0
  148. data/spec/functional/to_response_spec.rb +31 -0
  149. data/spec/spec_helper.rb +51 -0
  150. data/spec/support/argument_matchers.rb +19 -0
  151. data/spec/support/image_matchers.rb +47 -0
  152. data/spec/support/simple_matchers.rb +53 -0
  153. data/yard/handlers/configurable_attr_handler.rb +38 -0
  154. data/yard/setup.rb +15 -0
  155. data/yard/templates/default/fulldoc/html/css/common.css +107 -0
  156. data/yard/templates/default/layout/html/layout.erb +89 -0
  157. data/yard/templates/default/module/html/configuration_summary.erb +31 -0
  158. data/yard/templates/default/module/setup.rb +17 -0
  159. metadata +544 -0
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require File.dirname(__FILE__) + '/shared_data_store_examples'
4
+ require 'mongo'
5
+
6
+ describe Dragonfly::DataStorage::MongoDataStore do
7
+
8
+ before(:each) do
9
+ begin
10
+ Mongo::Connection.new
11
+ rescue Mongo::ConnectionFailure => e
12
+ pending "You need to start mongo on localhost:27017 to test the MongoDataStore"
13
+ end
14
+ @data_store = Dragonfly::DataStorage::MongoDataStore.new :database => 'dragonfly_test'
15
+ end
16
+
17
+ it_should_behave_like 'data_store'
18
+
19
+ describe "authenticating" do
20
+ before(:each) do
21
+ @temp_object = Dragonfly::TempObject.new('Feijão verde')
22
+ end
23
+
24
+ it "should not attempt to authenticate if a username is not given" do
25
+ @data_store.db.should_not_receive(:authenticate)
26
+ @data_store.store(@temp_object)
27
+ end
28
+
29
+ it "should attempt to authenticate once if a username is given" do
30
+ @data_store.username = 'terry'
31
+ @data_store.password = 'butcher'
32
+ @data_store.db.should_receive(:authenticate).exactly(:once).with('terry','butcher').and_return(true)
33
+ uid = @data_store.store(@temp_object)
34
+ @data_store.retrieve(uid)
35
+ end
36
+ end
37
+
38
+ describe "sharing already configured stuff" do
39
+ before(:each) do
40
+ @connection = Mongo::Connection.new
41
+ @temp_object = Dragonfly::TempObject.new('asdf')
42
+ end
43
+
44
+ it "should allow sharing the connection" do
45
+ @data_store.connection = @connection
46
+ @connection.should_receive(:db).with('dragonfly_test').and_return(db=mock)
47
+ @data_store.db.should == db
48
+ end
49
+
50
+ it "should allow sharing the db" do
51
+ db = @connection.db('dragonfly_test_yo')
52
+ @data_store.db = db
53
+ @data_store.grid.instance_eval{@db}.should == db # so wrong
54
+ end
55
+ end
56
+
57
+ end
@@ -0,0 +1,258 @@
1
+ require 'spec_helper'
2
+ require File.dirname(__FILE__) + '/shared_data_store_examples'
3
+ require 'yaml'
4
+
5
+ describe Dragonfly::DataStorage::S3DataStore do
6
+
7
+ # To run these tests, put a file ".s3_spec.yml" in the dragonfly root dir, like this:
8
+ # key: XXXXXXXXXX
9
+ # secret: XXXXXXXXXX
10
+ # enabled: true
11
+ if File.exist?(file = File.expand_path('../../../../.s3_spec.yml', __FILE__))
12
+ config = YAML.load_file(file)
13
+ KEY = config['key']
14
+ SECRET = config['secret']
15
+ enabled = config['enabled']
16
+ else
17
+ enabled = false
18
+ end
19
+
20
+ if enabled
21
+
22
+ # Make sure it's a new bucket name
23
+ BUCKET_NAME = "dragonfly-test-#{Time.now.to_i.to_s(36)}"
24
+
25
+ before(:each) do
26
+ WebMock.allow_net_connect!
27
+ @data_store = Dragonfly::DataStorage::S3DataStore.new
28
+ @data_store.configure do |d|
29
+ d.bucket_name = BUCKET_NAME
30
+ d.access_key_id = KEY
31
+ d.secret_access_key = SECRET
32
+ d.region = 'eu-west-1'
33
+ end
34
+ end
35
+
36
+ else
37
+
38
+ BUCKET_NAME = 'test-bucket'
39
+
40
+ before(:each) do
41
+ Fog.mock!
42
+ @data_store = Dragonfly::DataStorage::S3DataStore.new
43
+ @data_store.configure do |d|
44
+ d.bucket_name = BUCKET_NAME
45
+ d.access_key_id = 'XXXXXXXXX'
46
+ d.secret_access_key = 'XXXXXXXXX'
47
+ d.region = 'eu-west-1'
48
+ end
49
+ end
50
+
51
+ end
52
+
53
+ it_should_behave_like 'data_store'
54
+
55
+ describe "store" do
56
+ it "should return a unique identifier for each storage" do
57
+ temp_object = Dragonfly::TempObject.new('gollum')
58
+ temp_object2 = Dragonfly::TempObject.new('gollum')
59
+ @data_store.store(temp_object).should_not == @data_store.store(temp_object2)
60
+ end
61
+
62
+ it "should use the name in the meta if set" do
63
+ temp_object = Dragonfly::TempObject.new('eggheads')
64
+ uid = @data_store.store(temp_object, :meta => {:name => 'doobie'})
65
+ uid.should =~ /doobie$/
66
+ data, meta = @data_store.retrieve(uid)
67
+ data.should == 'eggheads'
68
+ end
69
+
70
+ it "should work ok with files with funny names" do
71
+ temp_object = Dragonfly::TempObject.new('eggheads')
72
+ uid = @data_store.store(temp_object, :meta => {:name => 'A Picture with many spaces in its name (at 20:00 pm).png'})
73
+ uid.should =~ /A_Picture_with_many_spaces_in_its_name_at_20_00_pm_\.png$/
74
+ data, meta = @data_store.retrieve(uid)
75
+ data.should == 'eggheads'
76
+ end
77
+
78
+ it "should allow for setting the path manually" do
79
+ temp_object = Dragonfly::TempObject.new('eggheads')
80
+ uid = @data_store.store(temp_object, :path => 'hello/there')
81
+ uid.should == 'hello/there'
82
+ data, meta = @data_store.retrieve(uid)
83
+ data.should == 'eggheads'
84
+ end
85
+
86
+ it "should work fine when not using the filesystem" do
87
+ @data_store.use_filesystem = false
88
+ temp_object = Dragonfly::TempObject.new('gollum')
89
+ uid = @data_store.store(temp_object)
90
+ @data_store.retrieve(uid).first.should == "gollum"
91
+ end
92
+
93
+ describe "generate_uid" do
94
+ context "without a specific_uid" do
95
+ it 'should the default value' do
96
+ @data_store.send(:generate_uid, "hello").should =~ /\d+\/\d+\/\d+\/\d+\/\d+\/\d+\/\w+\/hello/
97
+ end
98
+ end
99
+
100
+ context "with a specific_uid" do
101
+ before do
102
+ @data_store.specific_uid = lambda{|name| name}
103
+ end
104
+
105
+ after do
106
+ @data_store.specific_uid = nil
107
+ end
108
+
109
+ it 'should call the specific_uid lambda' do
110
+ @data_store.send(:generate_uid, "hello").should == 'hello'
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ if enabled # Fog.mock! doesn't work consistently with real one here
117
+
118
+ describe "destroy" do
119
+ before(:each) do
120
+ @temp_object = Dragonfly::TempObject.new('gollum')
121
+ end
122
+ it "should raise an error if the data doesn't exist on destroy" do
123
+ uid = @data_store.store(@temp_object)
124
+ @data_store.destroy(uid)
125
+ lambda{
126
+ @data_store.destroy(uid)
127
+ }.should raise_error(Dragonfly::DataStorage::DataNotFound)
128
+ end
129
+ end
130
+
131
+ end
132
+
133
+ describe "domain" do
134
+ it "should default to the US" do
135
+ @data_store.region = nil
136
+ @data_store.domain.should == 's3.amazonaws.com'
137
+ end
138
+
139
+ it "should return the correct domain" do
140
+ @data_store.region = 'eu-west-1'
141
+ @data_store.domain.should == 's3-eu-west-1.amazonaws.com'
142
+ end
143
+
144
+ it "does raise an error if an unknown region is given" do
145
+ @data_store.region = 'latvia-central'
146
+ lambda{
147
+ @data_store.domain
148
+ }.should raise_error
149
+ end
150
+ end
151
+
152
+ describe "not configuring stuff properly" do
153
+ before(:each) do
154
+ @temp_object = Dragonfly::TempObject.new("Hi guys")
155
+ end
156
+
157
+ it "should require a bucket name on store" do
158
+ @data_store.bucket_name = nil
159
+ proc{ @data_store.store(@temp_object) }.should raise_error(Dragonfly::Configurable::NotConfigured)
160
+ end
161
+
162
+ it "should require an access_key_id on store" do
163
+ @data_store.access_key_id = nil
164
+ proc{ @data_store.store(@temp_object) }.should raise_error(Dragonfly::Configurable::NotConfigured)
165
+ end
166
+
167
+ it "should require a secret access key on store" do
168
+ @data_store.secret_access_key = nil
169
+ proc{ @data_store.store(@temp_object) }.should raise_error(Dragonfly::Configurable::NotConfigured)
170
+ end
171
+
172
+ it "should require a bucket name on retrieve" do
173
+ @data_store.bucket_name = nil
174
+ proc{ @data_store.retrieve('asdf') }.should raise_error(Dragonfly::Configurable::NotConfigured)
175
+ end
176
+
177
+ it "should require an access_key_id on retrieve" do
178
+ @data_store.access_key_id = nil
179
+ proc{ @data_store.retrieve('asdf') }.should raise_error(Dragonfly::Configurable::NotConfigured)
180
+ end
181
+
182
+ it "should require a secret access key on retrieve" do
183
+ @data_store.secret_access_key = nil
184
+ proc{ @data_store.retrieve('asdf') }.should raise_error(Dragonfly::Configurable::NotConfigured)
185
+ end
186
+ end
187
+
188
+ describe "autocreating the bucket" do
189
+ it "should create the bucket on store if it doesn't exist" do
190
+ @data_store.bucket_name = "dragonfly-test-blah-blah-#{rand(100000000)}"
191
+ @data_store.store(Dragonfly::TempObject.new("asdfj"))
192
+ end
193
+
194
+ it "should not try to create the bucket on retrieve if it doesn't exist" do
195
+ @data_store.bucket_name = "dragonfly-test-blah-blah-#{rand(100000000)}"
196
+ @data_store.send(:storage).should_not_receive(:put_bucket)
197
+ proc{ @data_store.retrieve("gungle") }.should raise_error(Dragonfly::DataStorage::DataNotFound)
198
+ end
199
+ end
200
+
201
+ describe "headers" do
202
+ before(:each) do
203
+ @temp_object = Dragonfly::TempObject.new('fjkdlsa')
204
+ @data_store.storage_headers = {'x-amz-foo' => 'biscuithead'}
205
+ end
206
+
207
+ it "should allow configuring globally" do
208
+ @data_store.storage.should_receive(:put_object).with('test-bucket', anything, anything,
209
+ hash_including('x-amz-foo' => 'biscuithead')
210
+ )
211
+ @data_store.store(@temp_object)
212
+ end
213
+
214
+ it "should allow adding per-store" do
215
+ @data_store.storage.should_receive(:put_object).with('test-bucket', anything, anything,
216
+ hash_including('x-amz-foo' => 'biscuithead', 'hello' => 'there')
217
+ )
218
+ @data_store.store(@temp_object, :headers => {'hello' => 'there'})
219
+ end
220
+
221
+ it "should let the per-store one take precedence" do
222
+ @data_store.storage.should_receive(:put_object).with('test-bucket', anything, anything,
223
+ hash_including('x-amz-foo' => 'override!')
224
+ )
225
+ @data_store.store(@temp_object, :headers => {'x-amz-foo' => 'override!'})
226
+ end
227
+
228
+ it "should not mess with the meta" do
229
+ @data_store.storage.should_receive(:put_object) do |_, __, ___, headers|
230
+ headers['x-amz-meta-extra'].should =~ /^\w+$/
231
+ end
232
+ @data_store.store(@temp_object, :headers => {'hello' => 'there'})
233
+ end
234
+ end
235
+
236
+ describe "urls for serving directly" do
237
+
238
+ before(:each) do
239
+ @uid = 'some/path/on/s3'
240
+ end
241
+
242
+ it "should use the bucket subdomain" do
243
+ @data_store.url_for(@uid).should == "http://#{BUCKET_NAME}.s3.amazonaws.com/some/path/on/s3"
244
+ end
245
+
246
+ it "should use the bucket subdomain for other regions too" do
247
+ @data_store.region = 'eu-west-1'
248
+ @data_store.url_for(@uid).should == "http://#{BUCKET_NAME}.s3.amazonaws.com/some/path/on/s3"
249
+ end
250
+
251
+ it "should give an expiring url" do
252
+ @data_store.url_for(@uid, :expires => 1301476942).should =~
253
+ %r{^https://#{@data_store.domain}/#{BUCKET_NAME}/some/path/on/s3\?AWSAccessKeyId=#{@data_store.access_key_id}&Signature=[\w%]+&Expires=1301476942$}
254
+ end
255
+
256
+ end
257
+
258
+ end
@@ -0,0 +1,77 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for "data_store" do
4
+
5
+ # Using these shared spec requires you to set the inst var @data_store
6
+
7
+ before(:each) do
8
+ @temp_object = Dragonfly::TempObject.new('gollum')
9
+ end
10
+
11
+ describe "store" do
12
+ it "should return a unique identifier for each storage" do
13
+ temp_object2 = Dragonfly::TempObject.new('gollum')
14
+ @data_store.store(@temp_object).should_not == @data_store.store(temp_object2)
15
+ end
16
+ it "should return a unique identifier for each storage even when the first is deleted" do
17
+ uid1 = @data_store.store(@temp_object)
18
+ @data_store.destroy(uid1)
19
+ uid2 = @data_store.store(@temp_object)
20
+ uid1.should_not == uid2
21
+ end
22
+ it "should allow for passing in options as a second argument" do
23
+ @data_store.store(@temp_object, :some => :option)
24
+ end
25
+ end
26
+
27
+ describe "retrieve" do
28
+
29
+ describe "without meta" do
30
+ before(:each) do
31
+ uid = @data_store.store(@temp_object)
32
+ @obj, @meta = @data_store.retrieve(uid)
33
+ end
34
+
35
+ it "should retrieve the stored data" do
36
+ Dragonfly::TempObject.new(@obj).data.should == @temp_object.data
37
+ end
38
+
39
+ it "should return a meta hash (probably empty)" do
40
+ @meta.should be_a(Hash)
41
+ end
42
+
43
+ end
44
+
45
+ describe "when meta is given" do
46
+ before(:each) do
47
+ temp_object = Dragonfly::TempObject.new('gollum')
48
+ @uid = @data_store.store(temp_object, :meta => {:bitrate => '35', :name => 'danny.boy'})
49
+ @obj, @meta = @data_store.retrieve(@uid)
50
+ end
51
+
52
+ it "should return the stored meta" do
53
+ @meta[:bitrate].should == '35'
54
+ @meta[:name].should == 'danny.boy'
55
+ end
56
+ end
57
+
58
+ it "should raise an exception if the data doesn't exist" do
59
+ lambda{
60
+ @data_store.retrieve('gooble/gubbub')
61
+ }.should raise_error(Dragonfly::DataStorage::DataNotFound)
62
+ end
63
+ end
64
+
65
+ describe "destroy" do
66
+
67
+ it "should destroy the stored data" do
68
+ uid = @data_store.store(@temp_object)
69
+ @data_store.destroy(uid)
70
+ lambda{
71
+ @data_store.retrieve(uid)
72
+ }.should raise_error(Dragonfly::DataStorage::DataNotFound)
73
+ end
74
+
75
+ end
76
+
77
+ end
@@ -0,0 +1,154 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec::Matchers.define :have_keys do |*keys|
4
+ match do |given|
5
+ given.keys.map{|sym| sym.to_s }.sort == keys.map{|sym| sym.to_s }.sort
6
+ end
7
+ end
8
+
9
+ describe Dragonfly::FunctionManager do
10
+
11
+ before(:each) do
12
+ @fm = Dragonfly::FunctionManager.new
13
+ end
14
+
15
+ describe "registering functions" do
16
+
17
+ describe "registering procs" do
18
+
19
+ let(:func){ proc{ "HELLO" } }
20
+
21
+ it "should allow registering procs" do
22
+ @fm.add :hello, func
23
+ @fm.functions.should == {:hello => [func]}
24
+ end
25
+
26
+ it "should allow registering using block syntax" do
27
+ @fm.add(:hello, &func)
28
+ @fm.functions.should == {:hello => [func]}
29
+ end
30
+
31
+ end
32
+
33
+ describe "registering classes" do
34
+
35
+ before(:each) do
36
+ @class = Class.new do
37
+ def doogie(buff)
38
+ "eggheads #{buff}"
39
+ end
40
+ def bumfries(smarmey)
41
+ "sharkboy"
42
+ end
43
+ end
44
+ @fm.register(@class)
45
+ end
46
+
47
+ it "should add the methods" do
48
+ @fm.functions.should have_keys(:doogie, :bumfries)
49
+ end
50
+
51
+ it "should record the registered object" do
52
+ @fm.objects.length.should eql(1)
53
+ @fm.objects.first.should be_a(@class)
54
+ end
55
+
56
+ it "should work when calling" do
57
+ @fm.call_last(:doogie, 3).should == "eggheads 3"
58
+ end
59
+
60
+ it "should return the object when registering" do
61
+ @fm.register(@class).should be_a(@class)
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+
68
+ describe "configuring on registration" do
69
+
70
+ before(:each) do
71
+ @class = Class.new do
72
+ include Dragonfly::Configurable
73
+ configurable_attr :height, 183
74
+ def initialize(age=6)
75
+ @age = age
76
+ end
77
+ def height_and_age
78
+ [height, @age]
79
+ end
80
+ end
81
+ @fm.register(@class)
82
+ end
83
+
84
+ it "should pass the args on register to the object initializer" do
85
+ @fm.register(@class, 43)
86
+ @fm.call_last(:height_and_age).should == [183, 43]
87
+ end
88
+
89
+ it "should run configure if a block given" do
90
+ @fm.register(@class){|c| c.height = 180 }
91
+ @fm.call_last(:height_and_age).should == [180, 6]
92
+ end
93
+
94
+ it "should not include configurable methods in the functions" do
95
+ @fm.functions.keys.should == [:height_and_age]
96
+ end
97
+ end
98
+
99
+ describe "calling" do
100
+
101
+ describe "errors" do
102
+ it "should raise an error for call_last if the function doesn't exist" do
103
+ lambda{
104
+ @fm.call_last(:i_dont_exist)
105
+ }.should raise_error(Dragonfly::FunctionManager::NotDefined)
106
+ end
107
+
108
+ it "should raise an error if the function is defined but unable to handle" do
109
+ @fm.add(:chicken){ throw :unable_to_handle }
110
+ lambda{
111
+ @fm.call_last(:chicken)
112
+ }.should raise_error(Dragonfly::FunctionManager::UnableToHandle)
113
+ end
114
+ end
115
+
116
+ describe "simple" do
117
+ it "should correctly call a registered block" do
118
+ @fm.add(:egg){|num| num + 1 }
119
+ @fm.call_last(:egg, 4).should == 5
120
+ end
121
+ it "should correctly call a registered class" do
122
+ klass = Class.new do
123
+ def dog(num)
124
+ num * 2
125
+ end
126
+ end
127
+ @fm.register(klass)
128
+ @fm.call_last(:dog, 4).should == 8
129
+ end
130
+ it "should correctly call an object that responds to 'call'" do
131
+ obj = Object.new
132
+ def obj.call(num); num - 3; end
133
+ @fm.add(:spoon, obj)
134
+ @fm.call_last(:spoon, 4).should == 1
135
+ end
136
+ end
137
+
138
+ describe "with more than one implementation of same function" do
139
+ it "should use the last registered" do
140
+ @fm.add(:bingo){|num| num + 1 }
141
+ @fm.add(:bingo){|num| num - 1 }
142
+ @fm.call_last(:bingo, 4).should == 3
143
+ end
144
+
145
+ it "should skip methods that throw :unable_to_handle" do
146
+ @fm.add(:bingo){|num| num + 1 }
147
+ @fm.add(:bingo){|num| throw :unable_to_handle }
148
+ @fm.call_last(:bingo, 4).should == 5
149
+ end
150
+ end
151
+
152
+ end
153
+
154
+ end