oahu-dragonfly 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dragonfly::ImageMagick::Utils do
4
+
5
+ before(:each) do
6
+ @obj = Object.new
7
+ @obj.extend(Dragonfly::ImageMagick::Utils)
8
+ end
9
+
10
+ it "should raise an error if the identify command isn't found" do
11
+ suppressing_stderr do
12
+ lambda{
13
+ @obj.send(:run, "non-existent-command")
14
+ }.should raise_error(Dragonfly::ImageMagick::Utils::ShellCommandFailed)
15
+ end
16
+ end
17
+
18
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dragonfly::JobBuilder do
4
+
5
+ describe "a multi-step job" do
6
+
7
+ before(:each) do
8
+ @job_builder = Dragonfly::JobBuilder.new do |size, format|
9
+ process :thumb, size
10
+ encode format unless format.nil?
11
+ end
12
+ end
13
+
14
+ it "should correctly call job steps" do
15
+ job = mock
16
+ job.should_receive(:process).with(:thumb, '30x30#').and_return(job2=mock)
17
+ job2.should_receive(:encode).with(:jpg).and_return(job3=mock)
18
+ @job_builder.build(job, '30x30#', :jpg).should == job3
19
+ end
20
+
21
+ it "should work consistently with bang methods" do
22
+ job = mock
23
+ job.should_receive(:process!).with(:thumb, '30x30#').and_return(job)
24
+ job.should_receive(:encode!).with(:jpg).and_return(job)
25
+ @job_builder.build!(job, '30x30#', :jpg).should == job
26
+ end
27
+
28
+ it "should yield nil if the arg isn't passed in" do
29
+ job = mock
30
+ job.should_receive(:process).with(:thumb, '30x30#').and_return(job2=mock)
31
+ job2.should_not_receive(:encode)
32
+ @job_builder.build(job, '30x30#').should == job2
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dragonfly::JobDefinitions do
4
+
5
+ describe "defining jobs" do
6
+
7
+ before(:each) do
8
+ @job_definitions = Dragonfly::JobDefinitions.new
9
+ @object = Object.new
10
+ @object.extend @job_definitions
11
+ end
12
+
13
+ describe "a simple job" do
14
+
15
+ before(:each) do
16
+ @job_definitions.add :thumb do |size|
17
+ process :thumb, size
18
+ end
19
+ end
20
+
21
+ it "correctly call job steps" do
22
+ @object.should_receive(:process).with(:thumb, '30x30#').and_return(job=mock)
23
+ @object.thumb('30x30#').should == job
24
+ end
25
+
26
+ it "should correctly call job steps when bang is given" do
27
+ @object.should_receive(:process!).with(:thumb, '30x30#').and_return(@object)
28
+ @object.thumb!('30x30#').should == @object
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,173 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ ## General tests for Response go here as it's a pretty simple wrapper around that
5
+
6
+ describe "Dragonfly::JobEndpoint Rack::Lint tests" do
7
+ before(:each) do
8
+ @app = test_app
9
+ @app.generator.add(:test_data){ "Test Data" }
10
+ @job = @app.generate(:test_data)
11
+ @endpoint = Rack::Lint.new(Dragonfly::JobEndpoint.new(@job))
12
+ end
13
+
14
+ it "should pass for HEAD requests" do
15
+ Rack::MockRequest.new(@endpoint).request("HEAD", '')
16
+ end
17
+
18
+ it "should pass for GET requests" do
19
+ Rack::MockRequest.new(@endpoint).request("GET", '')
20
+ end
21
+
22
+ it "should pass for POST requests" do
23
+ Rack::MockRequest.new(@endpoint).request("POST", '')
24
+ end
25
+
26
+ it "should pass for PUT requests" do
27
+ Rack::MockRequest.new(@endpoint).request("PUT", '')
28
+ end
29
+
30
+ it "should pass for DELETE requests" do
31
+ Rack::MockRequest.new(@endpoint).request("DELETE", '')
32
+ end
33
+ end
34
+
35
+ describe Dragonfly::JobEndpoint do
36
+
37
+ def make_request(job, opts={})
38
+ endpoint = Dragonfly::JobEndpoint.new(job)
39
+ method = (opts.delete(:method) || :get).to_s.upcase
40
+ Rack::MockRequest.new(endpoint).request(method, '', opts)
41
+ end
42
+
43
+ before(:each) do
44
+ @app = test_app
45
+ @app.datastore.stub!(:retrieve).with('egg').and_return(["GUNGLE", {:name => 'gung.txt'}])
46
+ @job = @app.new_job.fetch('egg')
47
+ end
48
+
49
+ it "should return a correct response to a successful GET request" do
50
+ response = make_request(@job)
51
+ response.status.should == 200
52
+ response['ETag'].should =~ /^"\w+"$/
53
+ response['Cache-Control'].should == "public, max-age=31536000"
54
+ response['Content-Type'].should == 'text/plain'
55
+ response['Content-Length'].should == '6'
56
+ response['Content-Disposition'].should == 'filename="gung.txt"'
57
+ response.body.should == 'GUNGLE'
58
+ end
59
+
60
+ it "should return the correct headers and no content to a successful HEAD request" do
61
+ response = make_request(@job, :method => :head)
62
+ response.status.should == 200
63
+ response['ETag'].should =~ /^"\w+"$/
64
+ response['Cache-Control'].should == "public, max-age=31536000"
65
+ response['Content-Type'].should == 'text/plain'
66
+ response['Content-Length'].should == '6'
67
+ response['Content-Disposition'].should == 'filename="gung.txt"'
68
+ response.body.should == ''
69
+ end
70
+
71
+ %w(POST PUT DELETE CUSTOM_METHOD).each do |method|
72
+
73
+ it "should return a 405 error for a #{method} request" do
74
+ response = make_request(@job, :method => method)
75
+ response.status.should == 405
76
+ response['Allow'].should == "GET, HEAD"
77
+ response['Content-Type'].should == 'text/plain'
78
+ response.body.should == "#{method} method not allowed"
79
+ end
80
+
81
+ end
82
+
83
+ it "should return 404 if the datastore raises data not found" do
84
+ @job.should_receive(:apply).and_raise(Dragonfly::DataStorage::DataNotFound)
85
+ response = make_request(@job)
86
+ response.status.should == 404
87
+ end
88
+
89
+ describe "ETag" do
90
+ it "should return an ETag" do
91
+ response = make_request(@job)
92
+ response.headers['ETag'].should =~ /^"\w+"$/
93
+ end
94
+
95
+ [
96
+ "dingle",
97
+ "dingle, eggheads",
98
+ '"dingle", "eggheads"',
99
+ '*'
100
+ ].each do |header|
101
+ it "should return a 304 if the correct ETag is specified in HTTP_IF_NONE_MATCH header e.g. #{header}" do
102
+ @job.should_receive(:unique_signature).at_least(:once).and_return('dingle')
103
+ response = make_request(@job, 'HTTP_IF_NONE_MATCH' => header)
104
+ response.status.should == 304
105
+ response['ETag'].should == '"dingle"'
106
+ response['Cache-Control'].should == "public, max-age=31536000"
107
+ response.body.should be_empty
108
+ end
109
+ end
110
+
111
+ it "should not have applied any steps if the correct ETag is specified in HTTP_IF_NONE_MATCH header" do
112
+ response = make_request(@job, 'HTTP_IF_NONE_MATCH' => @job.unique_signature)
113
+ @job.applied_steps.should be_empty
114
+ end
115
+ end
116
+
117
+ describe "Content Disposition" do
118
+ before(:each) do
119
+ @app.encoder.add{|temp_object, format| temp_object }
120
+ end
121
+
122
+ describe "filename" do
123
+ it "should return the original name" do
124
+ response = make_request(@job)
125
+ response['Content-Disposition'].should == 'filename="gung.txt"'
126
+ end
127
+ it "should return a filename with a different extension if it's been encoded" do
128
+ response = make_request(@job.encode(:doogs))
129
+ response['Content-Disposition'].should == 'filename="gung.doogs"'
130
+ end
131
+ it "should not have the filename if name doesn't exist" do
132
+ response = make_request(@app.new_job("ADFSDF"))
133
+ response['Content-Disposition'].should be_nil
134
+ end
135
+ it "should cope with filenames with no ext" do
136
+ response = make_request(@app.new_job("ASDF", :name => 'asdf'))
137
+ response['Content-Disposition'].should == 'filename="asdf"'
138
+ end
139
+ it "should uri encode funny characters" do
140
+ response = make_request(@app.new_job("ASDF", :name => '£@$£ `'))
141
+ response['Content-Disposition'].should == 'filename="%C2%A3@$%C2%A3%20%60"'
142
+ end
143
+ it "should allow for setting the filename using a block" do
144
+ @app.content_filename = proc{|job, request|
145
+ job.basename.reverse.upcase + request['a']
146
+ }
147
+ response = make_request(@job, 'QUERY_STRING' => 'a=egg')
148
+ response['Content-Disposition'].should == 'filename="GNUGegg"'
149
+ end
150
+ it "should not include the filename if configured to be nil" do
151
+ @app.content_filename = nil
152
+ response = make_request(@job)
153
+ response['Content-Disposition'].should be_nil
154
+ end
155
+ end
156
+
157
+ describe "content disposition" do
158
+ it "should use the app's configured content-disposition" do
159
+ @app.content_disposition = :attachment
160
+ response = make_request(@job)
161
+ response['Content-Disposition'].should == 'attachment; filename="gung.txt"'
162
+ end
163
+ it "should allow using a block to set the content disposition" do
164
+ @app.content_disposition = proc{|job, request|
165
+ job.basename + request['blah']
166
+ }
167
+ response = make_request(@job, 'QUERY_STRING' => 'blah=yo')
168
+ response['Content-Disposition'].should == 'gungyo; filename="gung.txt"'
169
+ end
170
+ end
171
+ end
172
+
173
+ end
@@ -0,0 +1,1046 @@
1
+ require 'spec_helper'
2
+
3
+ # Matchers
4
+ RSpec::Matchers.define :match_steps do |steps|
5
+ match do |given|
6
+ given.map{|step| step.class } == steps
7
+ end
8
+ end
9
+
10
+ describe Dragonfly::Job do
11
+
12
+ describe "Step types" do
13
+
14
+ {
15
+ Dragonfly::Job::Fetch => :fetch,
16
+ Dragonfly::Job::Process => :process,
17
+ Dragonfly::Job::Encode => :encode,
18
+ Dragonfly::Job::Generate => :generate,
19
+ Dragonfly::Job::FetchFile => :fetch_file,
20
+ Dragonfly::Job::FetchUrl => :fetch_url
21
+ }.each do |klass, step_name|
22
+ it "should return the correct step name for #{klass}" do
23
+ klass.step_name.should == step_name
24
+ end
25
+ end
26
+
27
+ {
28
+ Dragonfly::Job::Fetch => :f,
29
+ Dragonfly::Job::Process => :p,
30
+ Dragonfly::Job::Encode => :e,
31
+ Dragonfly::Job::Generate => :g,
32
+ Dragonfly::Job::FetchFile => :ff,
33
+ Dragonfly::Job::FetchUrl => :fu
34
+ }.each do |klass, abbreviation|
35
+ it "should return the correct abbreviation for #{klass}" do
36
+ klass.abbreviation.should == abbreviation
37
+ end
38
+ end
39
+
40
+ describe "step_names" do
41
+ it "should return the available step names" do
42
+ Dragonfly::Job.step_names.should == [:fetch, :process, :encode, :generate, :fetch_file, :fetch_url]
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ describe "without content" do
49
+
50
+ before(:each) do
51
+ @app = mock_app
52
+ @job = Dragonfly::Job.new(@app)
53
+ end
54
+
55
+ it "should allow initializing with content" do
56
+ job = Dragonfly::Job.new(@app, 'eggheads')
57
+ job.data.should == 'eggheads'
58
+ end
59
+
60
+ describe "fetch" do
61
+ before(:each) do
62
+ @job.fetch!('some_uid')
63
+ end
64
+
65
+ it { @job.steps.should match_steps([Dragonfly::Job::Fetch]) }
66
+
67
+ it "should retrieve from the app's datastore when applied" do
68
+ @app.datastore.should_receive(:retrieve).with('some_uid').and_return('HELLO')
69
+ @job.data.should == 'HELLO'
70
+ end
71
+
72
+ it "should set extra data if returned from the datastore" do
73
+ @app.datastore.should_receive(:retrieve).with('some_uid').and_return(['HELLO', {:name => 'test.txt'}])
74
+ @job.data.should == 'HELLO'
75
+ @job.meta.should == {:name => 'test.txt'}
76
+ end
77
+ end
78
+
79
+ describe "process" do
80
+ it "should raise an error when applying" do
81
+ @job.process!(:resize, '20x30')
82
+ lambda{
83
+ @job.apply
84
+ }.should raise_error(Dragonfly::Job::NothingToProcess)
85
+ end
86
+ end
87
+
88
+ describe "encode" do
89
+ it "should raise an error when applying" do
90
+ @job.encode!(:gif)
91
+ lambda{
92
+ @job.apply
93
+ }.should raise_error(Dragonfly::Job::NothingToEncode)
94
+ end
95
+ end
96
+
97
+ describe "analyse" do
98
+ it "should raise an error" do
99
+ lambda{
100
+ @job.analyse(:width)
101
+ }.should raise_error(Dragonfly::Job::NothingToAnalyse)
102
+ end
103
+ end
104
+
105
+ describe "generate" do
106
+ before(:each) do
107
+ @job.generate!(:plasma, 20, 30)
108
+ end
109
+
110
+ it { @job.steps.should match_steps([Dragonfly::Job::Generate]) }
111
+
112
+ it "should use the generator when applied" do
113
+ @app.generator.should_receive(:generate).with(:plasma, 20, 30).and_return('hi')
114
+ @job.data.should == 'hi'
115
+ end
116
+
117
+ it "should save extra data if the generator returns it" do
118
+ @app.generator.should_receive(:generate).with(:plasma, 20, 30).and_return(['hi', {:name => 'plasma.png'}])
119
+ @job.data.should == 'hi'
120
+ @job.meta.should == {:name => 'plasma.png'}
121
+ end
122
+ end
123
+
124
+ describe "fetch_file" do
125
+ before(:each) do
126
+ @job.fetch_file!(File.dirname(__FILE__) + '/../../samples/egg.png')
127
+ end
128
+
129
+ it { @job.steps.should match_steps([Dragonfly::Job::FetchFile]) }
130
+
131
+ it "should fetch the specified file when applied" do
132
+ @job.size.should == 62664
133
+ end
134
+
135
+ it "should set the name" do
136
+ @job.meta[:name].should == 'egg.png'
137
+ end
138
+ end
139
+
140
+ describe "fetch_url" do
141
+ before(:each) do
142
+ stub_request(:get, 'http://some.place.com').to_return(:body => 'result!')
143
+ stub_request(:get, 'https://some.place.com').to_return(:body => 'secure result!')
144
+ end
145
+
146
+ it {
147
+ @job.fetch_url!('some.url')
148
+ @job.steps.should match_steps([Dragonfly::Job::FetchUrl])
149
+ }
150
+
151
+ it "should fetch the specified url when applied" do
152
+ @job.fetch_url!('http://some.place.com')
153
+ @job.data.should == "result!"
154
+ end
155
+
156
+ it "should default to http" do
157
+ @job.fetch_url!('some.place.com')
158
+ @job.data.should == "result!"
159
+ end
160
+
161
+ it "should also work with https" do
162
+ @job.fetch_url!('https://some.place.com')
163
+ @job.data.should == "secure result!"
164
+ end
165
+
166
+ it "should set the name if there is one" do
167
+ @job.fetch_url!('some.place.com/dung.beetle')
168
+ @job.meta[:name].should == 'dung.beetle'
169
+ end
170
+
171
+ ["some.place.com", "some.place.com/", "some.place.com/eggs/"].each do |url|
172
+ it "should not set the name if there isn't one, e.g. #{url}" do
173
+ @job.fetch_url!(url)
174
+ @job.meta[:name].should be_nil
175
+ end
176
+ end
177
+ end
178
+
179
+ end
180
+
181
+ describe "with content already there" do
182
+
183
+ before(:each) do
184
+ @app = mock_app
185
+ @job = Dragonfly::Job.new(@app, 'HELLO', :name => 'hello.txt', :a => :b)
186
+ @temp_object = @job.temp_object
187
+ end
188
+
189
+ describe "apply" do
190
+ it "should return itself" do
191
+ @job.apply.should == @job
192
+ end
193
+ end
194
+
195
+ describe "process" do
196
+ before(:each) do
197
+ @job.process!(:resize, '20x30')
198
+ end
199
+
200
+ it { @job.steps.should match_steps([Dragonfly::Job::Process]) }
201
+
202
+ it "should use the processor when applied" do
203
+ @app.processor.should_receive(:process).with(@temp_object, :resize, '20x30').and_return('hi')
204
+ @job.data.should == 'hi'
205
+ end
206
+
207
+ it "should maintain the meta attributes" do
208
+ @app.processor.should_receive(:process).with(@temp_object, :resize, '20x30').and_return('hi')
209
+ @job.data.should == 'hi'
210
+ @job.meta.should == {:name => 'hello.txt', :a => :b}
211
+ end
212
+
213
+ it "should allow returning an array with extra attributes from the processor" do
214
+ @app.processor.should_receive(:process).with(@temp_object, :resize, '20x30').and_return(['hi', {:name => 'hello_20x30.txt', :eggs => 'asdf'}])
215
+ @job.data.should == 'hi'
216
+ @job.meta.should == {:name => 'hello_20x30.txt', :a => :b, :eggs => 'asdf'}
217
+ end
218
+ end
219
+
220
+ describe "encode" do
221
+ before(:each) do
222
+ @job.encode!(:gif, :bitrate => 'mumma')
223
+ end
224
+
225
+ it { @job.steps.should match_steps([Dragonfly::Job::Encode]) }
226
+
227
+ it "should use the encoder when applied" do
228
+ @app.encoder.should_receive(:encode).with(@temp_object, :gif, :bitrate => 'mumma').and_return('alo')
229
+ @job.data.should == 'alo'
230
+ end
231
+
232
+ it "should maintain the meta and update the format" do
233
+ @app.encoder.should_receive(:encode).with(@temp_object, :gif, :bitrate => 'mumma').and_return('alo')
234
+ @job.data.should == 'alo'
235
+ @job.meta.should == {:name => 'hello.txt', :a => :b, :format => :gif}
236
+ end
237
+
238
+ it "should update the format even when not applied" do
239
+ @app.encoder.should_not_receive(:encode)
240
+ @job.meta[:format].should == :gif
241
+ end
242
+
243
+ it "should allow returning an array with extra attributes form the encoder" do
244
+ @app.encoder.should_receive(:encode).with(@temp_object, :gif, :bitrate => 'mumma').and_return(['alo', {:name => 'doobie', :eggs => 'fish'}])
245
+ @job.data.should == 'alo'
246
+ @job.meta.should == {:name => 'doobie', :a => :b, :eggs => 'fish', :format => :gif}
247
+ end
248
+
249
+ it "not allow overriding the format" do
250
+ @app.encoder.should_receive(:encode).with(@temp_object, :gif, :bitrate => 'mumma').and_return(['alo', {:format => :png}])
251
+ @job.apply.meta[:format].should == :gif
252
+ end
253
+ end
254
+ end
255
+
256
+ describe "analysis" do
257
+ before(:each) do
258
+ @app = test_app
259
+ @job = @app.new_job('HELLO')
260
+ @app.analyser.add(:num_letters){|temp_object, letter| temp_object.data.count(letter) }
261
+ end
262
+ it "should return correctly when calling analyse" do
263
+ @job.analyse(:num_letters, 'L').should == 2
264
+ end
265
+ it "should have mixed in the analyser method" do
266
+ @job.num_letters('L').should == 2
267
+ end
268
+ it "should return nil from analyse if calling any old method" do
269
+ @job.analyse(:robin_van_persie).should be_nil
270
+ end
271
+ it "should not allow calling any old method" do
272
+ lambda{
273
+ @job.robin_van_persie
274
+ }.should raise_error(NoMethodError)
275
+ end
276
+ it "should work correctly with chained jobs, applying before analysing" do
277
+ @app.processor.add(:double){|temp_object| temp_object.data * 2 }
278
+ @job.process(:double).num_letters('L').should == 4
279
+ end
280
+ end
281
+
282
+ describe "defining extra steps after applying" do
283
+ before(:each) do
284
+ @app = mock_app
285
+ @job = Dragonfly::Job.new(@app)
286
+ @job.temp_object = Dragonfly::TempObject.new("hello")
287
+ @job.process! :resize
288
+ @job.apply
289
+ @job.encode! :micky
290
+ end
291
+ it "should not call apply on already applied steps" do
292
+ @job.steps[0].should_not_receive(:apply)
293
+ @job.apply
294
+ end
295
+ it "should call apply on not yet applied steps" do
296
+ @job.steps[1].should_receive(:apply)
297
+ @job.apply
298
+ end
299
+ it "should return all steps" do
300
+ @job.steps.should match_steps([
301
+ Dragonfly::Job::Process,
302
+ Dragonfly::Job::Encode
303
+ ])
304
+ end
305
+ it "should return applied steps" do
306
+ @job.applied_steps.should match_steps([
307
+ Dragonfly::Job::Process
308
+ ])
309
+ end
310
+ it "should return the pending steps" do
311
+ @job.pending_steps.should match_steps([
312
+ Dragonfly::Job::Encode
313
+ ])
314
+ end
315
+ it "should not call apply on any steps when already applied" do
316
+ @job.apply
317
+ @job.steps[0].should_not_receive(:apply)
318
+ @job.steps[1].should_not_receive(:apply)
319
+ @job.apply
320
+ end
321
+ end
322
+
323
+ describe "chaining" do
324
+
325
+ before(:each) do
326
+ @app = mock_app
327
+ @job = Dragonfly::Job.new(@app)
328
+ end
329
+
330
+ it "should return itself if bang is used" do
331
+ @job.fetch!('some_uid').should == @job
332
+ end
333
+
334
+ it "should return a new job if bang is not used" do
335
+ @job.fetch('some_uid').should_not == @job
336
+ end
337
+
338
+ describe "when a chained job is defined" do
339
+ before(:each) do
340
+ @job.fetch!('some_uid')
341
+ @job2 = @job.process(:resize, '30x30')
342
+ end
343
+
344
+ it "should return the correct steps for the original job" do
345
+ @job.applied_steps.should match_steps([
346
+ ])
347
+ @job.pending_steps.should match_steps([
348
+ Dragonfly::Job::Fetch
349
+ ])
350
+ end
351
+
352
+ it "should return the correct data for the original job" do
353
+ @job.data.should == 'SOME_DATA'
354
+ end
355
+
356
+ it "should return the correct steps for the new job" do
357
+ @job2.applied_steps.should match_steps([
358
+ ])
359
+ @job2.pending_steps.should match_steps([
360
+ Dragonfly::Job::Fetch,
361
+ Dragonfly::Job::Process
362
+ ])
363
+ end
364
+
365
+ it "should return the correct data for the new job" do
366
+ @job2.data.should == 'SOME_PROCESSED_DATA'
367
+ end
368
+
369
+ it "should not affect the other one when one is applied" do
370
+ @job.apply
371
+ @job.applied_steps.should match_steps([
372
+ Dragonfly::Job::Fetch
373
+ ])
374
+ @job.pending_steps.should match_steps([
375
+ ])
376
+ @job.temp_object.data.should == 'SOME_DATA'
377
+ @job2.applied_steps.should match_steps([
378
+ ])
379
+ @job2.pending_steps.should match_steps([
380
+ Dragonfly::Job::Fetch,
381
+ Dragonfly::Job::Process
382
+ ])
383
+ @job2.temp_object.should be_nil
384
+ end
385
+ end
386
+
387
+ end
388
+
389
+ describe "applied?" do
390
+ before(:each) do
391
+ @app = test_app
392
+ end
393
+ it "should return true when empty" do
394
+ @app.new_job.should be_applied
395
+ end
396
+ it "should return false when not applied" do
397
+ @app.fetch('eggs').should_not be_applied
398
+ end
399
+ it "should return true when applied" do
400
+ @app.datastore.should_receive(:retrieve).with('eggs').and_return("cracked")
401
+ job = @app.fetch('eggs').apply
402
+ job.should be_applied
403
+ end
404
+ end
405
+
406
+ describe "to_a" do
407
+ before(:each) do
408
+ @app = mock_app
409
+ end
410
+ it "should represent all the steps in array form" do
411
+ job = Dragonfly::Job.new(@app)
412
+ job.fetch! 'some_uid'
413
+ job.generate! :plasma # you wouldn't really call this after fetch but still works
414
+ job.process! :resize, '30x40'
415
+ job.encode! :gif, :bitrate => 20
416
+ job.to_a.should == [
417
+ [:f, 'some_uid'],
418
+ [:g, :plasma],
419
+ [:p, :resize, '30x40'],
420
+ [:e, :gif, {:bitrate => 20}]
421
+ ]
422
+ end
423
+ end
424
+
425
+ describe "from_a" do
426
+
427
+ before(:each) do
428
+ @app = test_app
429
+ end
430
+
431
+ describe "a well-defined array" do
432
+ before(:each) do
433
+ @job = Dragonfly::Job.from_a([
434
+ [:f, 'some_uid'],
435
+ [:g, :plasma],
436
+ [:p, :resize, '30x40'],
437
+ [:e, :gif, {:bitrate => 20}]
438
+ ], @app)
439
+ end
440
+ it "should have the correct step types" do
441
+ @job.steps.should match_steps([
442
+ Dragonfly::Job::Fetch,
443
+ Dragonfly::Job::Generate,
444
+ Dragonfly::Job::Process,
445
+ Dragonfly::Job::Encode
446
+ ])
447
+ end
448
+ it "should have the correct args" do
449
+ @job.steps[0].args.should == ['some_uid']
450
+ @job.steps[1].args.should == [:plasma]
451
+ @job.steps[2].args.should == [:resize, '30x40']
452
+ @job.steps[3].args.should == [:gif, {:bitrate => 20}]
453
+ end
454
+ it "should have no applied steps" do
455
+ @job.applied_steps.should be_empty
456
+ end
457
+ it "should have all steps pending" do
458
+ @job.steps.should == @job.pending_steps
459
+ end
460
+ end
461
+
462
+ [
463
+ :f,
464
+ [:f],
465
+ [[]],
466
+ [[:egg]]
467
+ ].each do |object|
468
+ it "should raise an error if the object passed in is #{object.inspect}" do
469
+ lambda {
470
+ Dragonfly::Job.from_a(object, @app)
471
+ }.should raise_error(Dragonfly::Job::InvalidArray)
472
+ end
473
+ end
474
+
475
+ it "should initialize an empty job if the array is empty" do
476
+ job = Dragonfly::Job.from_a([], @app)
477
+ job.steps.should be_empty
478
+ end
479
+ end
480
+
481
+ describe "serialization" do
482
+ before(:each) do
483
+ @app = test_app
484
+ @job = Dragonfly::Job.new(@app).fetch('uid').process(:resize_and_crop, :width => 270, :height => 92, :gravity => 'n')
485
+ end
486
+ it "should serialize itself" do
487
+ @job.serialize.should =~ /^\w{1,}$/
488
+ end
489
+ it "should deserialize to the same as the original" do
490
+ new_job = Dragonfly::Job.deserialize(@job.serialize, @app)
491
+ new_job.to_a.should == @job.to_a
492
+ end
493
+ it "should correctly deserialize a string serialized with ruby 1.8.7" do
494
+ job = Dragonfly::Job.deserialize('BAhbB1sHOgZmSSIIdWlkBjoGRVRbCDoGcDoUcmVzaXplX2FuZF9jcm9wewg6CndpZHRoaQIOAToLaGVpZ2h0aWE6DGdyYXZpdHlJIgZuBjsGVA', @app)
495
+ job.to_a.should == @job.to_a
496
+ end
497
+ it "should correctly deserialize a string serialized with ruby 1.9.2" do
498
+ job = Dragonfly::Job.deserialize('BAhbB1sHOgZmIgh1aWRbCDoGcDoUcmVzaXplX2FuZF9jcm9wewg6CndpZHRoaQIOAToLaGVpZ2h0aWE6DGdyYXZpdHkiBm4', @app)
499
+ job.to_a.should == @job.to_a
500
+ end
501
+ end
502
+
503
+ describe "to_app" do
504
+ before(:each) do
505
+ @app = test_app
506
+ @job = Dragonfly::Job.new(@app)
507
+ end
508
+ it "should return an endpoint" do
509
+ endpoint = @job.to_app
510
+ endpoint.should be_a(Dragonfly::JobEndpoint)
511
+ endpoint.job.should == @job
512
+ end
513
+ end
514
+
515
+ describe "url" do
516
+ before(:each) do
517
+ @app = test_app
518
+ @job = Dragonfly::Job.new(@app)
519
+ end
520
+
521
+ it "should return nil if there are no steps" do
522
+ @job.url.should be_nil
523
+ end
524
+
525
+ describe "using meta in the url" do
526
+ before(:each) do
527
+ @app.server.url_format = '/media/:job/:zoo'
528
+ @job.generate!(:fish)
529
+ end
530
+ it "should act as per usual if no params given" do
531
+ @job.url.should == "/media/#{@job.serialize}"
532
+ end
533
+ it "should add given params" do
534
+ @job.url(:zoo => 'jokes', :on => 'me').should == "/media/#{@job.serialize}/jokes?on=me"
535
+ end
536
+ it "should use the meta if it exists" do
537
+ @job.meta[:zoo] = 'hair'
538
+ @job.url.should == "/media/#{@job.serialize}/hair"
539
+ end
540
+ it "should not add an meta that isn't needed" do
541
+ @job.meta[:gump] = 'flub'
542
+ @job.url.should == "/media/#{@job.serialize}"
543
+ end
544
+ it "should override if a param is passed in" do
545
+ @job.meta[:zoo] = 'hair'
546
+ @job.url(:zoo => 'dare').should == "/media/#{@job.serialize}/dare"
547
+ end
548
+
549
+ describe "basename" do
550
+ before(:each) do
551
+ @app.server.url_format = '/:job/:basename'
552
+ @job.meta = {:name => 'hello.egg', :basename => 'hi'}
553
+ end
554
+ it "should use the meta if it exists" do
555
+ @job.url.should == "/#{@job.serialize}/hi"
556
+ end
557
+ it "should use the name if basename meta doesn't exist" do
558
+ @job.meta.delete(:basename)
559
+ @job.url.should == "/#{@job.serialize}/hello"
560
+ end
561
+ it "should not set if neither exist" do
562
+ @job.meta = {}
563
+ @job.url.should == "/#{@job.serialize}"
564
+ end
565
+ end
566
+
567
+ describe "ext" do
568
+ before(:each) do
569
+ @app.server.url_format = '/:job.:ext'
570
+ @job.meta = {:name => 'hello.egg', :ext => 'hi'}
571
+ end
572
+ it "should use the meta if it exists" do
573
+ @job.url.should == "/#{@job.serialize}.hi"
574
+ end
575
+ it "should use the name if ext meta doesn't exist" do
576
+ @job.meta.delete(:ext)
577
+ @job.url.should == "/#{@job.serialize}.egg"
578
+ end
579
+ it "should not set if neither exist" do
580
+ @job.meta = {}
581
+ @job.url.should == "/#{@job.serialize}"
582
+ end
583
+ end
584
+
585
+ describe "format" do
586
+ before(:each) do
587
+ @app.server.url_format = '/:job.:format'
588
+ @job.stub!(:ext).and_return("hi")
589
+ end
590
+ it "should use the meta if it exists" do
591
+ @job.meta = {:format => :txt}
592
+ @job.url.should == "/#{@job.serialize}.txt"
593
+ end
594
+ it "should use the ext if format meta doesn't exist" do
595
+ @job.url.should == "/#{@job.serialize}.hi"
596
+ end
597
+ it "should not use the ext if format meta doesn't exist and trust_file_extensions is switched off" do
598
+ @app.trust_file_extensions = false
599
+ @job.url.should == "/#{@job.serialize}"
600
+ end
601
+ it "should not set if neither exist" do
602
+ @job.should_receive(:ext).and_return nil
603
+ @job.url.should == "/#{@job.serialize}"
604
+ end
605
+ end
606
+ end
607
+ end
608
+
609
+ describe "to_fetched_job" do
610
+ before(:each) do
611
+ @app = test_app
612
+ @job = @app.create("HELLO")
613
+ end
614
+ it "should maintain the same temp_object and be already applied" do
615
+ new_job = @job.to_fetched_job('some_uid')
616
+ new_job.data.should == 'HELLO'
617
+ new_job.to_a.should == [
618
+ [:f, 'some_uid']
619
+ ]
620
+ new_job.pending_steps.should be_empty
621
+ end
622
+ it "should maintain the meta" do
623
+ @job.meta = {:right => 'said fred'}
624
+ new_job = @job.to_fetched_job('some_uid')
625
+ new_job.meta.should == {:right => 'said fred'}
626
+ end
627
+ end
628
+
629
+ describe "to_unique_s" do
630
+ it "should use the arrays of args to create the string" do
631
+ job = test_app.fetch('uid').process(:gug, 4, :some => 'arg', :and => 'more')
632
+ job.to_unique_s.should == 'fuidpgug4andmoresomearg'
633
+ end
634
+ end
635
+
636
+ describe "sha" do
637
+ before(:each) do
638
+ @app = test_app
639
+ @job = @app.fetch('eggs')
640
+ end
641
+
642
+ it "should be of the correct format" do
643
+ @job.sha.should =~ /^\w{8}$/
644
+ end
645
+
646
+ it "should be the same for the same job steps" do
647
+ @app.fetch('eggs').sha.should == @job.sha
648
+ end
649
+
650
+ it "should be different for different jobs" do
651
+ @app.fetch('figs').sha.should_not == @job.sha
652
+ end
653
+ end
654
+
655
+ describe "validate_sha!" do
656
+ before(:each) do
657
+ @app = test_app
658
+ @job = @app.fetch('eggs')
659
+ end
660
+ it "should raise an error if nothing is given" do
661
+ lambda{
662
+ @job.validate_sha!(nil)
663
+ }.should raise_error(Dragonfly::Job::NoSHAGiven)
664
+ end
665
+ it "should raise an error if the wrong SHA is given" do
666
+ lambda{
667
+ @job.validate_sha!('asdf')
668
+ }.should raise_error(Dragonfly::Job::IncorrectSHA)
669
+ end
670
+ it "should return self if ok" do
671
+ @job.validate_sha!(@job.sha).should == @job
672
+ end
673
+ end
674
+
675
+ describe "setting the name" do
676
+ before(:each) do
677
+ @app = test_app
678
+ @job = @app.new_job("HELLO", :name => 'not.me')
679
+ end
680
+ it "should allow setting the name" do
681
+ @job.name = 'wassup.doc'
682
+ @job.name.should == 'wassup.doc'
683
+ end
684
+ end
685
+
686
+ describe "setting the meta" do
687
+ before(:each) do
688
+ @app = test_app
689
+ @job = @app.new_job("HiThere", :five => 'beans')
690
+ end
691
+ it "should allow setting the meta" do
692
+ @job.meta = {:doogie => 'ladders'}
693
+ @job.meta.should == {:doogie => 'ladders'}
694
+ end
695
+ it "should allow updating the meta" do
696
+ @job.meta[:doogie] = 'ladders'
697
+ @job.meta.should == {:five => 'beans', :doogie => 'ladders'}
698
+ end
699
+ end
700
+
701
+ describe "b64_data" do
702
+ before(:each) do
703
+ @app = test_app
704
+ end
705
+ it "should return a string using the data:URI schema" do
706
+ job = @app.new_job("HELLO", :name => 'text.txt')
707
+ job.b64_data.should == "data:text/plain;base64,SEVMTE8=\n"
708
+ end
709
+ end
710
+
711
+ describe "querying stuff without applying steps" do
712
+ before(:each) do
713
+ @app = test_app
714
+ end
715
+
716
+ describe "fetch_step" do
717
+ it "should return nil if it doesn't exist" do
718
+ @app.generate(:ponies).process(:jam).fetch_step.should be_nil
719
+ end
720
+ it "should return the fetch step otherwise" do
721
+ step = @app.fetch('hello').process(:cheese).fetch_step
722
+ step.should be_a(Dragonfly::Job::Fetch)
723
+ step.uid.should == 'hello'
724
+ end
725
+ end
726
+ describe "fetched uid" do
727
+ describe "when there's no fetch step" do
728
+ before(:each) do
729
+ @job = @app.new_job("AGG")
730
+ end
731
+ it "should return nil for uid" do
732
+ @job.uid.should be_nil
733
+ end
734
+ it "should return nil for uid_basename" do
735
+ @job.uid_basename.should be_nil
736
+ end
737
+ it "should return nil for uid_extname" do
738
+ @job.uid_extname.should be_nil
739
+ end
740
+ end
741
+ describe "when there is a fetch step" do
742
+ before(:each) do
743
+ @job = @app.fetch('gungedin/innit.blud')
744
+ end
745
+ it "should return the uid" do
746
+ @job.uid.should == 'gungedin/innit.blud'
747
+ end
748
+ it "should return the uid_basename" do
749
+ @job.uid_basename.should == 'innit'
750
+ end
751
+ it "should return the uid_extname" do
752
+ @job.uid_extname.should == '.blud'
753
+ end
754
+ end
755
+ end
756
+
757
+ describe "fetch_file_step" do
758
+ it "should return nil if it doesn't exist" do
759
+ @app.generate(:ponies).process(:jam).fetch_file_step.should be_nil
760
+ end
761
+ it "should return the fetch_file step otherwise" do
762
+ step = @app.fetch_file('/my/file.png').process(:cheese).fetch_file_step
763
+ step.should be_a(Dragonfly::Job::FetchFile)
764
+ step.path.should == '/my/file.png'
765
+ end
766
+ end
767
+
768
+ describe "fetch_url_step" do
769
+ it "should return nil if it doesn't exist" do
770
+ @app.generate(:ponies).fetch_url_step.should be_nil
771
+ end
772
+ it "should return the fetch_url step otherwise" do
773
+ step = @app.fetch_url('egg.heads').process(:cheese).fetch_url_step
774
+ step.should be_a(Dragonfly::Job::FetchUrl)
775
+ step.url.should == 'http://egg.heads'
776
+ end
777
+ end
778
+
779
+ describe "generate_step" do
780
+ it "should return nil if it doesn't exist" do
781
+ @app.fetch('many/ponies').process(:jam).generate_step.should be_nil
782
+ end
783
+ it "should return the generate step otherwise" do
784
+ step = @app.generate(:ponies).process(:cheese).generate_step
785
+ step.should be_a(Dragonfly::Job::Generate)
786
+ step.args.should == [:ponies]
787
+ end
788
+ end
789
+
790
+ describe "process_steps" do
791
+ it "should return the processing steps" do
792
+ job = @app.fetch('many/ponies').process(:jam).process(:eggs).encode(:gif)
793
+ job.process_steps.should match_steps([
794
+ Dragonfly::Job::Process,
795
+ Dragonfly::Job::Process
796
+ ])
797
+ end
798
+ end
799
+
800
+ describe "encode_step" do
801
+ it "should return nil if it doesn't exist" do
802
+ @app.generate(:ponies).encode_step.should be_nil
803
+ end
804
+ it "should return the last encode step otherwise" do
805
+ step = @app.fetch('hello').encode(:smells).encode(:cheese).encode_step
806
+ step.should be_a(Dragonfly::Job::Encode)
807
+ step.format.should == :cheese
808
+ end
809
+ end
810
+ describe "encoded_format" do
811
+ it "should return nil if there's no encode step" do
812
+ @app.new_job('asdf').encoded_format.should be_nil
813
+ end
814
+ it "should return the last encoded format if it exists" do
815
+ @app.fetch('gungedin').encode(:a).encode(:b).encoded_format.should == :b
816
+ end
817
+ end
818
+ describe "encoded_extname" do
819
+ it "should return nil if there's no encode step" do
820
+ @app.new_job('asdf').encoded_extname.should be_nil
821
+ end
822
+ it "should return the last encoded format as an extname if it exists" do
823
+ @app.fetch('gungedin').encode(:a).encode(:b).encoded_extname.should == '.b'
824
+ end
825
+ end
826
+ end
827
+
828
+ describe "meta" do
829
+ before(:each) do
830
+ @app = test_app
831
+ @job = @app.new_job
832
+ end
833
+ it "should default meta to an empty hash" do
834
+ @job.meta.should == {}
835
+ end
836
+ it "should allow setting" do
837
+ @job.meta = {:a => :b}
838
+ @job.meta.should == {:a => :b}
839
+ end
840
+ it "should not allow setting as anything other than a hash" do
841
+ lambda{
842
+ @job.meta = 3
843
+ }.should raise_error(ArgumentError)
844
+ end
845
+ it "should allow setting on initialize" do
846
+ job = @app.new_job('asdf', :b => :c)
847
+ job.meta.should == {:b => :c}
848
+ end
849
+ it "should keep them when chained" do
850
+ @job.meta[:darn] = 'it'
851
+ @job.generate(:gollum).meta.should == {:darn => 'it'}
852
+ end
853
+ end
854
+
855
+ describe "name" do
856
+ before(:each) do
857
+ @app = test_app
858
+ end
859
+ it "should default to nil" do
860
+ job = @app.new_job('HELLO')
861
+ job.name.should be_nil
862
+ end
863
+ it "should use the meta" do
864
+ job = @app.new_job('HELLO')
865
+ job.meta[:name] = 'monkey.egg'
866
+ job.name.should == 'monkey.egg'
867
+ end
868
+ it "should allow setting" do
869
+ job = @app.new_job('HELLO')
870
+ job.name = "jonny.briggs"
871
+ job.meta[:name].should == 'jonny.briggs'
872
+ end
873
+
874
+ describe "ext" do
875
+ before(:each) do
876
+ @job = @app.new_job('asdf')
877
+ end
878
+ it "should use the correct extension from name" do
879
+ @job.name = 'hello.there.mate'
880
+ @job.ext.should == 'mate'
881
+ end
882
+ it "should be nil if name has none" do
883
+ @job.name = 'hello'
884
+ @job.ext.should be_nil
885
+ end
886
+ it "should be nil if name is nil" do
887
+ @job.name = nil
888
+ @job.ext.should be_nil
889
+ end
890
+ it "should use the meta first if set" do
891
+ @job.meta[:ext] = 'duggs'
892
+ @job.name = 'hello.there.mate'
893
+ @job.ext.should == 'duggs'
894
+ end
895
+ end
896
+
897
+ describe "basename" do
898
+ before(:each) do
899
+ @job = @app.new_job('asdf')
900
+ end
901
+ it "should use the correct basename from name" do
902
+ @job.name = 'hello.there.mate'
903
+ @job.basename.should == 'hello.there'
904
+ end
905
+ it "should be the name if it has no ext" do
906
+ @job.name = 'hello'
907
+ @job.basename.should == 'hello'
908
+ end
909
+ it "should be nil if name is nil" do
910
+ @job.name = nil
911
+ @job.basename.should be_nil
912
+ end
913
+ it "should use the meta first if set" do
914
+ @job.meta[:basename] = 'duggs'
915
+ @job.name = 'hello.there.mate'
916
+ @job.basename.should == 'duggs'
917
+ end
918
+ end
919
+
920
+ describe "format" do
921
+ before(:each) do
922
+ @app = test_app
923
+ end
924
+ it "should default to nil" do
925
+ job = @app.new_job("HELLO")
926
+ job.format.should be_nil
927
+ end
928
+ it "should use the meta format if it exists" do
929
+ job = @app.new_job("HELLO")
930
+ job.meta[:format] = :txt
931
+ job.format.should == :txt
932
+ end
933
+ it "should use the analyser format if it exists" do
934
+ @app.analyser.add :format do |temp_object|
935
+ :egg
936
+ end
937
+ job = @app.new_job("HELLO")
938
+ job.format.should == :egg
939
+ end
940
+ it "should use the file extension if it has no format" do
941
+ @job = @app.new_job("HIMATE", :name => 'test.pdf')
942
+ @job.format.should == :pdf
943
+ end
944
+ it "should not use the file extension if it's been switched off" do
945
+ @app.trust_file_extensions = false
946
+ @job = @app.new_job("HIMATE", :name => 'test.pdf')
947
+ @job.format.should be_nil
948
+ end
949
+ it "should prefer the set format over the file extension" do
950
+ job = @app.new_job("HELLO", :name => 'test.pdf', :format => :txt)
951
+ job.format.should == :txt
952
+ end
953
+ it "should prefer the file extension over the analysed format" do
954
+ @app.analyser.add :format do |temp_object|
955
+ :egg
956
+ end
957
+ job = @app.new_job("HELLO", :name => 'test.pdf')
958
+ job.format.should == :pdf
959
+ end
960
+ it "should apply the job" do
961
+ @app.generator.add(:test){ ["skid marks", {:name => 'terry.burton'}] }
962
+ job = @app.generate(:test)
963
+ job.format.should == :burton
964
+ job.should be_applied
965
+ end
966
+ end
967
+
968
+ describe "mime_type" do
969
+ before(:each) do
970
+ @app = test_app
971
+ end
972
+ it "should return the correct mime_type if the format is given" do
973
+ @job = @app.new_job("HIMATE")
974
+ @job.should_receive(:format).and_return(:tiff)
975
+ @job.mime_type.should == 'image/tiff'
976
+ end
977
+ it "should fall back to the mime_type analyser if the format is nil" do
978
+ @app.analyser.add :mime_type do |temp_object|
979
+ 'image/jpeg'
980
+ end
981
+ @job = @app.new_job("HIMATE")
982
+ @job.mime_type.should == 'image/jpeg'
983
+ end
984
+ it "should fall back to the fallback mime_type if neither format or analyser exist" do
985
+ @app.new_job("HIMATE").mime_type.should == 'application/octet-stream'
986
+ end
987
+ end
988
+
989
+ end
990
+
991
+ describe "store" do
992
+ before(:each) do
993
+ @app = test_app
994
+ @app.generator.add(:test){ ["Toes", {:name => 'doogie.txt'}] }
995
+ @job = @app.generate(:test)
996
+ end
997
+ it "should store its data along with the meta" do
998
+ @job.meta[:eggs] = 'doolally'
999
+ @app.datastore.should_receive(:store).with(a_temp_object_with_data("Toes"), :meta => {:name => 'doogie.txt', :eggs => 'doolally'})
1000
+ @job.store
1001
+ end
1002
+ it "should add extra opts" do
1003
+ @app.datastore.should_receive(:store).with(a_temp_object_with_data("Toes"), :meta => {:name => 'doogie.txt'}, :path => 'blah')
1004
+ @job.store(:path => 'blah')
1005
+ end
1006
+ end
1007
+
1008
+ describe "dealing with original_filename" do
1009
+ before(:each) do
1010
+ @string = "terry"
1011
+ @string.stub!(:original_filename).and_return("gum.tree")
1012
+ @app = test_app
1013
+ @app.generator.add(:test){ @string }
1014
+ end
1015
+ it "should set it as the name" do
1016
+ @app.create(@string).name.should == 'gum.tree'
1017
+ end
1018
+ it "should prefer the initialized name over the original_filename" do
1019
+ @app.create(@string, :name => 'doo.berry').name.should == 'doo.berry'
1020
+ end
1021
+ it "should work with e.g. generators" do
1022
+ @app.generate(:test).apply.name.should == 'gum.tree'
1023
+ end
1024
+ it "should favour an e.g. generator returned name" do
1025
+ @app.generator.add(:test2){ [@string, {:name => 'gen.ome'}] }
1026
+ @app.generate(:test2).apply.name.should == 'gen.ome'
1027
+ end
1028
+ it "should not overwrite a set name" do
1029
+ job = @app.generate(:test)
1030
+ job.name = 'egg.mumma'
1031
+ job.apply.name.should == 'egg.mumma'
1032
+ end
1033
+ end
1034
+
1035
+ describe "deprecated meta format" do
1036
+ before(:each) do
1037
+ @app = test_app
1038
+ end
1039
+ it "should still work if the datastore/whatever returns meta nested in :meta key" do
1040
+ @app.datastore.should_receive(:retrieve).with('some_uid').and_return(['HELLO', {:name => 'test.txt', :meta => {:some => 'meta'}}])
1041
+ job = @app.fetch('some_uid').apply
1042
+ job.meta.should == {:name => 'test.txt', :some => 'meta'}
1043
+ end
1044
+ end
1045
+
1046
+ end