fog-dragonfly 0.8.1

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

Potentially problematic release.


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

Files changed (155) hide show
  1. data/.specopts +2 -0
  2. data/.yardopts +23 -0
  3. data/Gemfile +23 -0
  4. data/Gemfile.rails.2.3.5 +14 -0
  5. data/History.md +266 -0
  6. data/LICENSE +20 -0
  7. data/README.md +88 -0
  8. data/Rakefile +92 -0
  9. data/VERSION +1 -0
  10. data/config.ru +13 -0
  11. data/docs.watchr +1 -0
  12. data/dragonfly.gemspec +293 -0
  13. data/extra_docs/Analysers.md +108 -0
  14. data/extra_docs/Caching.md +23 -0
  15. data/extra_docs/Configuration.md +138 -0
  16. data/extra_docs/DataStorage.md +136 -0
  17. data/extra_docs/Encoding.md +96 -0
  18. data/extra_docs/GeneralUsage.md +121 -0
  19. data/extra_docs/Generators.md +102 -0
  20. data/extra_docs/Heroku.md +50 -0
  21. data/extra_docs/Index.md +36 -0
  22. data/extra_docs/MimeTypes.md +40 -0
  23. data/extra_docs/Models.md +266 -0
  24. data/extra_docs/Mongo.md +45 -0
  25. data/extra_docs/Processing.md +130 -0
  26. data/extra_docs/Rack.md +52 -0
  27. data/extra_docs/Rails2.md +55 -0
  28. data/extra_docs/Rails3.md +62 -0
  29. data/extra_docs/Sinatra.md +25 -0
  30. data/extra_docs/URLs.md +169 -0
  31. data/features/3.0.3.feature +8 -0
  32. data/features/images.feature +47 -0
  33. data/features/no_processing.feature +14 -0
  34. data/features/rails_2.3.5.feature +7 -0
  35. data/features/steps/common_steps.rb +8 -0
  36. data/features/steps/dragonfly_steps.rb +66 -0
  37. data/features/steps/rails_steps.rb +39 -0
  38. data/features/support/env.rb +40 -0
  39. data/fixtures/files/app/models/album.rb +3 -0
  40. data/fixtures/files/app/views/albums/new.html.erb +4 -0
  41. data/fixtures/files/app/views/albums/show.html.erb +4 -0
  42. data/fixtures/files/config/initializers/dragonfly.rb +4 -0
  43. data/fixtures/files/features/manage_album_images.feature +12 -0
  44. data/fixtures/files/features/step_definitions/image_steps.rb +15 -0
  45. data/fixtures/files/features/support/paths.rb +15 -0
  46. data/fixtures/files/features/text_images.feature +7 -0
  47. data/fixtures/rails_2.3.5/template.rb +10 -0
  48. data/fixtures/rails_3.0.3/template.rb +20 -0
  49. data/irbrc.rb +17 -0
  50. data/lib/dragonfly.rb +45 -0
  51. data/lib/dragonfly/active_model_extensions.rb +13 -0
  52. data/lib/dragonfly/active_model_extensions/attachment.rb +169 -0
  53. data/lib/dragonfly/active_model_extensions/class_methods.rb +45 -0
  54. data/lib/dragonfly/active_model_extensions/instance_methods.rb +28 -0
  55. data/lib/dragonfly/active_model_extensions/validations.rb +37 -0
  56. data/lib/dragonfly/analyser.rb +59 -0
  57. data/lib/dragonfly/analysis/file_command_analyser.rb +32 -0
  58. data/lib/dragonfly/analysis/image_magick_analyser.rb +47 -0
  59. data/lib/dragonfly/analysis/r_magick_analyser.rb +63 -0
  60. data/lib/dragonfly/app.rb +182 -0
  61. data/lib/dragonfly/config/heroku.rb +19 -0
  62. data/lib/dragonfly/config/image_magick.rb +41 -0
  63. data/lib/dragonfly/config/r_magick.rb +46 -0
  64. data/lib/dragonfly/config/rails.rb +17 -0
  65. data/lib/dragonfly/configurable.rb +119 -0
  66. data/lib/dragonfly/core_ext/object.rb +8 -0
  67. data/lib/dragonfly/core_ext/string.rb +9 -0
  68. data/lib/dragonfly/core_ext/symbol.rb +9 -0
  69. data/lib/dragonfly/data_storage.rb +9 -0
  70. data/lib/dragonfly/data_storage/file_data_store.rb +114 -0
  71. data/lib/dragonfly/data_storage/mongo_data_store.rb +82 -0
  72. data/lib/dragonfly/data_storage/s3data_store.rb +115 -0
  73. data/lib/dragonfly/encoder.rb +13 -0
  74. data/lib/dragonfly/encoding/image_magick_encoder.rb +57 -0
  75. data/lib/dragonfly/encoding/r_magick_encoder.rb +61 -0
  76. data/lib/dragonfly/function_manager.rb +69 -0
  77. data/lib/dragonfly/generation/hash_with_css_style_keys.rb +23 -0
  78. data/lib/dragonfly/generation/image_magick_generator.rb +140 -0
  79. data/lib/dragonfly/generation/r_magick_generator.rb +155 -0
  80. data/lib/dragonfly/generator.rb +9 -0
  81. data/lib/dragonfly/image_magick_utils.rb +81 -0
  82. data/lib/dragonfly/job.rb +371 -0
  83. data/lib/dragonfly/job_builder.rb +39 -0
  84. data/lib/dragonfly/job_definitions.rb +26 -0
  85. data/lib/dragonfly/job_endpoint.rb +15 -0
  86. data/lib/dragonfly/loggable.rb +28 -0
  87. data/lib/dragonfly/middleware.rb +34 -0
  88. data/lib/dragonfly/processing/image_magick_processor.rb +99 -0
  89. data/lib/dragonfly/processing/r_magick_processor.rb +126 -0
  90. data/lib/dragonfly/processor.rb +9 -0
  91. data/lib/dragonfly/r_magick_utils.rb +48 -0
  92. data/lib/dragonfly/rails/images.rb +22 -0
  93. data/lib/dragonfly/response.rb +82 -0
  94. data/lib/dragonfly/routed_endpoint.rb +40 -0
  95. data/lib/dragonfly/serializer.rb +32 -0
  96. data/lib/dragonfly/simple_cache.rb +23 -0
  97. data/lib/dragonfly/simple_endpoint.rb +63 -0
  98. data/lib/dragonfly/temp_object.rb +220 -0
  99. data/samples/beach.png +0 -0
  100. data/samples/egg.png +0 -0
  101. data/samples/round.gif +0 -0
  102. data/samples/sample.docx +0 -0
  103. data/samples/taj.jpg +0 -0
  104. data/spec/argument_matchers.rb +19 -0
  105. data/spec/dragonfly/active_model_extensions/active_model_setup.rb +97 -0
  106. data/spec/dragonfly/active_model_extensions/active_record_setup.rb +85 -0
  107. data/spec/dragonfly/active_model_extensions/model_spec.rb +723 -0
  108. data/spec/dragonfly/active_model_extensions/spec_helper.rb +11 -0
  109. data/spec/dragonfly/analyser_spec.rb +123 -0
  110. data/spec/dragonfly/analysis/file_command_analyser_spec.rb +57 -0
  111. data/spec/dragonfly/analysis/image_magick_analyser_spec.rb +15 -0
  112. data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +27 -0
  113. data/spec/dragonfly/analysis/shared_analyser_spec.rb +51 -0
  114. data/spec/dragonfly/app_spec.rb +280 -0
  115. data/spec/dragonfly/config/r_magick_spec.rb +25 -0
  116. data/spec/dragonfly/configurable_spec.rb +220 -0
  117. data/spec/dragonfly/core_ext/string_spec.rb +17 -0
  118. data/spec/dragonfly/core_ext/symbol_spec.rb +17 -0
  119. data/spec/dragonfly/data_storage/data_store_spec.rb +76 -0
  120. data/spec/dragonfly/data_storage/file_data_store_spec.rb +169 -0
  121. data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +38 -0
  122. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +94 -0
  123. data/spec/dragonfly/deprecation_spec.rb +20 -0
  124. data/spec/dragonfly/encoding/image_magick_encoder_spec.rb +41 -0
  125. data/spec/dragonfly/encoding/r_magick_encoder_spec.rb +37 -0
  126. data/spec/dragonfly/function_manager_spec.rb +154 -0
  127. data/spec/dragonfly/generation/hash_with_css_style_keys_spec.rb +24 -0
  128. data/spec/dragonfly/generation/image_magick_generator_spec.rb +12 -0
  129. data/spec/dragonfly/generation/r_magick_generator_spec.rb +24 -0
  130. data/spec/dragonfly/generation/shared_generator_spec.rb +91 -0
  131. data/spec/dragonfly/image_magick_utils_spec.rb +16 -0
  132. data/spec/dragonfly/job_builder_spec.rb +37 -0
  133. data/spec/dragonfly/job_definitions_spec.rb +35 -0
  134. data/spec/dragonfly/job_endpoint_spec.rb +120 -0
  135. data/spec/dragonfly/job_spec.rb +773 -0
  136. data/spec/dragonfly/loggable_spec.rb +80 -0
  137. data/spec/dragonfly/middleware_spec.rb +68 -0
  138. data/spec/dragonfly/processing/image_magick_processor_spec.rb +29 -0
  139. data/spec/dragonfly/processing/r_magick_processor_spec.rb +26 -0
  140. data/spec/dragonfly/processing/shared_processing_spec.rb +215 -0
  141. data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
  142. data/spec/dragonfly/serializer_spec.rb +61 -0
  143. data/spec/dragonfly/simple_cache_spec.rb +27 -0
  144. data/spec/dragonfly/simple_endpoint_spec.rb +89 -0
  145. data/spec/dragonfly/temp_object_spec.rb +352 -0
  146. data/spec/image_matchers.rb +47 -0
  147. data/spec/simple_matchers.rb +44 -0
  148. data/spec/spec_helper.rb +58 -0
  149. data/yard/handlers/configurable_attr_handler.rb +38 -0
  150. data/yard/setup.rb +15 -0
  151. data/yard/templates/default/fulldoc/html/css/common.css +107 -0
  152. data/yard/templates/default/layout/html/layout.erb +87 -0
  153. data/yard/templates/default/module/html/configuration_summary.erb +31 -0
  154. data/yard/templates/default/module/setup.rb +17 -0
  155. metadata +550 -0
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ # Needs: @generator
4
+ describe "image generator", :shared => true do
5
+
6
+ describe "generating an image with the given dimensions" do
7
+ before(:each) do
8
+ @image, @extra = @generator.plasma(23,12)
9
+ end
10
+ it {@image.should have_width(23)}
11
+ it {@image.should have_height(12)}
12
+ it {@image.should have_format('png')}
13
+ it {@extra.should == {:format => :png, :name => 'plasma.png'}}
14
+ end
15
+
16
+ describe "specifying the format" do
17
+ before(:each) do
18
+ @image, @extra = @generator.plasma(23, 12, :gif)
19
+ end
20
+ it {@image.should have_format('gif')}
21
+ it {@extra.should == {:format => :gif, :name => 'plasma.gif'}}
22
+ end
23
+
24
+ describe "text" do
25
+ before(:each) do
26
+ @text = "mmm"
27
+ end
28
+
29
+ describe "creating a text image" do
30
+ before(:each) do
31
+ @image, @extra = @generator.text(@text, :font_size => 12)
32
+ end
33
+ it {@image.should have_width(20..40)} # approximate
34
+ it {@image.should have_height(10..20)}
35
+ it {@image.should have_format('png')}
36
+ it {@extra.should == {:format => :png, :name => 'text.png'}}
37
+ end
38
+
39
+ describe "specifying the format" do
40
+ before(:each) do
41
+ @image, @extra = @generator.text(@text, :format => :gif)
42
+ end
43
+ it {@image.should have_format('gif')}
44
+ it {@extra.should == {:format => :gif, :name => 'text.gif'}}
45
+ end
46
+
47
+ describe "padding" do
48
+ before(:each) do
49
+ no_padding_text, extra = @generator.text(@text, :font_size => 12)
50
+ @width = image_properties(no_padding_text)[:width].to_i
51
+ @height = image_properties(no_padding_text)[:height].to_i
52
+ end
53
+ it "1 number shortcut" do
54
+ image, extra = @generator.text(@text, :padding => '10')
55
+ image.should have_width(@width + 20)
56
+ image.should have_height(@height + 20)
57
+ end
58
+ it "2 numbers shortcut" do
59
+ image, extra = @generator.text(@text, :padding => '10 5')
60
+ image.should have_width(@width + 10)
61
+ image.should have_height(@height + 20)
62
+ end
63
+ it "3 numbers shortcut" do
64
+ image, extra = @generator.text(@text, :padding => '10 5 8')
65
+ image.should have_width(@width + 10)
66
+ image.should have_height(@height + 18)
67
+ end
68
+ it "4 numbers shortcut" do
69
+ image, extra = @generator.text(@text, :padding => '1 2 3 4')
70
+ image.should have_width(@width + 6)
71
+ image.should have_height(@height + 4)
72
+ end
73
+ it "should override the general padding declaration with the specific one (e.g. 'padding-left')" do
74
+ image, extra = @generator.text(@text, :padding => '10', 'padding-left' => 9)
75
+ image.should have_width(@width + 19)
76
+ image.should have_height(@height + 20)
77
+ end
78
+ it "should ignore 'px' suffixes" do
79
+ image, extra = @generator.text(@text, :padding => '1px 2px 3px 4px')
80
+ image.should have_width(@width + 6)
81
+ image.should have_height(@height + 4)
82
+ end
83
+ it "bad padding string" do
84
+ lambda{
85
+ @generator.text(@text, :padding => '1 2 3 4 5')
86
+ }.should raise_error(ArgumentError)
87
+ end
88
+ end
89
+ end
90
+
91
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dragonfly::ImageMagickUtils do
4
+
5
+ before(:each) do
6
+ @obj = Object.new
7
+ @obj.extend(Dragonfly::ImageMagickUtils)
8
+ end
9
+
10
+ it "should raise an error if the identify command isn't found" do
11
+ lambda{
12
+ @obj.send(:run, "non-existent-command")
13
+ }.should raise_error(Dragonfly::ImageMagickUtils::ShellCommandFailed)
14
+ end
15
+
16
+ end
@@ -0,0 +1,37 @@
1
+ require File.dirname(__FILE__) + '/../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 File.dirname(__FILE__) + '/../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,120 @@
1
+ # encoding: utf-8
2
+ require File.dirname(__FILE__) + '/../spec_helper'
3
+
4
+ ## General tests for Response go here as it's a pretty simple wrapper around that
5
+
6
+ describe Dragonfly::JobEndpoint do
7
+
8
+ def make_request(job, opts={})
9
+ endpoint = Dragonfly::JobEndpoint.new(job)
10
+ Rack::MockRequest.new(endpoint).get('', opts)
11
+ end
12
+
13
+ before(:each) do
14
+ @app = test_app
15
+ @app.datastore.stub!(:retrieve).with('egg').and_return(["GUNGLE", {:name => 'gung.txt'}])
16
+ @job = Dragonfly::Job.new(@app).fetch('egg')
17
+ end
18
+
19
+ it "should return a correct response if successful" do
20
+ response = make_request(@job)
21
+ response.status.should == 200
22
+ response['ETag'].should =~ /^"\w+"$/
23
+ response['Cache-Control'].should == "public, max-age=31536000"
24
+ response['Content-Type'].should == 'text/plain'
25
+ response['Content-Length'].should == '6'
26
+ response['Content-Disposition'].should == 'filename="gung.txt"'
27
+ response.body.should == 'GUNGLE'
28
+ end
29
+
30
+ it "should return 404 if the datastore raises data not found" do
31
+ @job.should_receive(:apply).and_raise(Dragonfly::DataStorage::DataNotFound)
32
+ response = make_request(@job)
33
+ response.status.should == 404
34
+ end
35
+
36
+ describe "ETag" do
37
+ it "should return an ETag" do
38
+ response = make_request(@job)
39
+ response.headers['ETag'].should =~ /^"\w+"$/
40
+ end
41
+
42
+ [
43
+ "dingle",
44
+ "dingle, eggheads",
45
+ '"dingle", "eggheads"',
46
+ '*'
47
+ ].each do |header|
48
+ it "should return a 304 if the correct ETag is specified in HTTP_IF_NONE_MATCH header e.g. #{header}" do
49
+ @job.should_receive(:unique_signature).at_least(:once).and_return('dingle')
50
+ response = make_request(@job, 'HTTP_IF_NONE_MATCH' => header)
51
+ response.status.should == 304
52
+ response['ETag'].should == '"dingle"'
53
+ response['Cache-Control'].should == "public, max-age=31536000"
54
+ response.body.should be_empty
55
+ end
56
+ end
57
+
58
+ it "should not have applied any steps if the correct ETag is specified in HTTP_IF_NONE_MATCH header" do
59
+ response = make_request(@job, 'HTTP_IF_NONE_MATCH' => @job.unique_signature)
60
+ @job.applied_steps.should be_empty
61
+ end
62
+ end
63
+
64
+ describe "Content Disposition" do
65
+ before(:each) do
66
+ @app.encoder.add{|temp_object, format| temp_object }
67
+ end
68
+
69
+ describe "filename" do
70
+ it "should return the original name" do
71
+ response = make_request(@job)
72
+ response['Content-Disposition'].should == 'filename="gung.txt"'
73
+ end
74
+ it "should return a filename with a different extension if it's been encoded" do
75
+ response = make_request(@job.encode(:doogs))
76
+ response['Content-Disposition'].should == 'filename="gung.doogs"'
77
+ end
78
+ it "should not have the filename if name doesn't exist" do
79
+ response = make_request(@app.new_job("ADFSDF"))
80
+ response['Content-Disposition'].should be_nil
81
+ end
82
+ it "should cope with filenames with no ext" do
83
+ response = make_request(@app.new_job("ASDF", :name => 'asdf'))
84
+ response['Content-Disposition'].should == 'filename="asdf"'
85
+ end
86
+ it "should uri encode funny characters" do
87
+ response = make_request(@app.new_job("ASDF", :name => '£@$£ `'))
88
+ response['Content-Disposition'].should == 'filename="%C2%A3@$%C2%A3%20%60"'
89
+ end
90
+ it "should allow for setting the filename using a block" do
91
+ @app.content_filename = proc{|job, request|
92
+ job.basename.reverse.upcase + request['a']
93
+ }
94
+ response = make_request(@job, 'QUERY_STRING' => 'a=egg')
95
+ response['Content-Disposition'].should == 'filename="GNUGegg"'
96
+ end
97
+ it "should not include the filename if configured to be nil" do
98
+ @app.content_filename = nil
99
+ response = make_request(@job)
100
+ response['Content-Disposition'].should be_nil
101
+ end
102
+ end
103
+
104
+ describe "content disposition" do
105
+ it "should use the app's configured content-disposition" do
106
+ @app.content_disposition = :attachment
107
+ response = make_request(@job)
108
+ response['Content-Disposition'].should == 'attachment; filename="gung.txt"'
109
+ end
110
+ it "should allow using a block to set the content disposition" do
111
+ @app.content_disposition = proc{|job, request|
112
+ job.basename + request['blah']
113
+ }
114
+ response = make_request(@job, 'QUERY_STRING' => 'blah=yo')
115
+ response['Content-Disposition'].should == 'gungyo; filename="gung.txt"'
116
+ end
117
+ end
118
+ end
119
+
120
+ end
@@ -0,0 +1,773 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ # Matchers
4
+ Spec::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
+ }.each do |klass, step_name|
21
+ it "should return the correct step name for #{klass}" do
22
+ klass.step_name.should == step_name
23
+ end
24
+ end
25
+
26
+ {
27
+ Dragonfly::Job::Fetch => :f,
28
+ Dragonfly::Job::Process => :p,
29
+ Dragonfly::Job::Encode => :e,
30
+ Dragonfly::Job::Generate => :g,
31
+ Dragonfly::Job::FetchFile => :ff
32
+ }.each do |klass, abbreviation|
33
+ it "should return the correct abbreviation for #{klass}" do
34
+ klass.abbreviation.should == abbreviation
35
+ end
36
+ end
37
+
38
+ describe "step_names" do
39
+ it "should return the available step names" do
40
+ Dragonfly::Job.step_names.should == [:fetch, :process, :encode, :generate, :fetch_file]
41
+ end
42
+ end
43
+
44
+ end
45
+
46
+ describe "without temp_object" do
47
+
48
+ before(:each) do
49
+ @app = mock_app
50
+ @job = Dragonfly::Job.new(@app)
51
+ end
52
+
53
+ it "should allow initializing with content" do
54
+ job = Dragonfly::Job.new(@app, Dragonfly::TempObject.new('eggheads'))
55
+ job.temp_object.data.should == 'eggheads'
56
+ end
57
+
58
+ describe "fetch" do
59
+ before(:each) do
60
+ @job.fetch!('some_uid')
61
+ end
62
+
63
+ it { @job.steps.should match_steps([Dragonfly::Job::Fetch]) }
64
+
65
+ it "should retrieve from the app's datastore when applied" do
66
+ @app.datastore.should_receive(:retrieve).with('some_uid').and_return('HELLO')
67
+ @job.apply
68
+ @job.temp_object.data.should == 'HELLO'
69
+ end
70
+
71
+ it "should set extra data if returned from the datastore" do
72
+ @app.datastore.should_receive(:retrieve).with('some_uid').and_return(['HELLO', {:name => 'test.txt', :meta => {1=>2}}])
73
+ @job.apply
74
+ @job.temp_object.data.should == 'HELLO'
75
+ @job.temp_object.name.should == 'test.txt'
76
+ @job.temp_object.meta.should == {1 => 2}
77
+ end
78
+ end
79
+
80
+ describe "process" do
81
+ it "should raise an error when applying" do
82
+ @job.process!(:resize, '20x30')
83
+ lambda{
84
+ @job.apply
85
+ }.should raise_error(Dragonfly::Job::NothingToProcess)
86
+ end
87
+ end
88
+
89
+ describe "encode" do
90
+ it "should raise an error when applying" do
91
+ @job.encode!(:gif)
92
+ lambda{
93
+ @job.apply
94
+ }.should raise_error(Dragonfly::Job::NothingToEncode)
95
+ end
96
+ end
97
+
98
+ describe "analyse" do
99
+ it "should raise an error" do
100
+ lambda{
101
+ @job.analyse(:width)
102
+ }.should raise_error(Dragonfly::Job::NothingToAnalyse)
103
+ end
104
+ end
105
+
106
+ describe "generate" do
107
+ before(:each) do
108
+ @job.generate!(:plasma, 20, 30)
109
+ end
110
+
111
+ it { @job.steps.should match_steps([Dragonfly::Job::Generate]) }
112
+
113
+ it "should use the generator when applied" do
114
+ @app.generator.should_receive(:generate).with(:plasma, 20, 30).and_return('hi')
115
+ @job.apply.data.should == 'hi'
116
+ end
117
+
118
+ it "should save extra data if the generator returns it" do
119
+ @app.generator.should_receive(:generate).with(:plasma, 20, 30).and_return(['hi', {:name => 'plasma.png', :format => :png, :meta => {:a => :b}}])
120
+ @job.apply
121
+ @job.temp_object.data.should == 'hi'
122
+ @job.temp_object.name.should == 'plasma.png'
123
+ @job.temp_object.format.should == :png
124
+ @job.temp_object.meta.should == {:a => :b}
125
+ end
126
+ end
127
+
128
+ describe "fetch_file" do
129
+ before(:each) do
130
+ @job.fetch_file!(File.dirname(__FILE__) + '/../../samples/egg.png')
131
+ end
132
+
133
+ it { @job.steps.should match_steps([Dragonfly::Job::FetchFile]) }
134
+
135
+ it "should fetch the specified file when applied" do
136
+ @job.apply
137
+ @job.temp_object.size.should == 62664
138
+ end
139
+
140
+ end
141
+
142
+ end
143
+
144
+ describe "with temp_object already there" do
145
+
146
+ before(:each) do
147
+ @app = mock_app
148
+ @temp_object = Dragonfly::TempObject.new('HELLO', :name => 'hello.txt', :meta => {:a => :b}, :format => :txt)
149
+ @job = Dragonfly::Job.new(@app)
150
+ @job.temp_object = @temp_object
151
+ end
152
+
153
+ describe "apply" do
154
+ it "should return itself" do
155
+ @job.apply.should == @job
156
+ end
157
+ end
158
+
159
+ describe "process" do
160
+ before(:each) do
161
+ @job.process!(:resize, '20x30')
162
+ end
163
+
164
+ it { @job.steps.should match_steps([Dragonfly::Job::Process]) }
165
+
166
+ it "should use the processor when applied" do
167
+ @app.processor.should_receive(:process).with(@temp_object, :resize, '20x30').and_return('hi')
168
+ @job.apply.data.should == 'hi'
169
+ end
170
+
171
+ it "should maintain the temp object attributes" do
172
+ @app.processor.should_receive(:process).with(@temp_object, :resize, '20x30').and_return('hi')
173
+ temp_object = @job.apply.temp_object
174
+ temp_object.data.should == 'hi'
175
+ temp_object.name.should == 'hello.txt'
176
+ temp_object.meta.should == {:a => :b}
177
+ temp_object.format.should == :txt
178
+ end
179
+
180
+ it "should allow returning an array with extra attributes from the processor" do
181
+ @app.processor.should_receive(:process).with(@temp_object, :resize, '20x30').and_return(['hi', {:name => 'hello_20x30.txt', :meta => {:eggs => 'asdf'}}])
182
+ temp_object = @job.apply.temp_object
183
+ temp_object.data.should == 'hi'
184
+ temp_object.name.should == 'hello_20x30.txt'
185
+ temp_object.meta.should == {:a => :b, :eggs => 'asdf'}
186
+ temp_object.format.should == :txt
187
+ end
188
+ end
189
+
190
+ describe "encode" do
191
+ before(:each) do
192
+ @job.encode!(:gif, :bitrate => 'mumma')
193
+ end
194
+
195
+ it { @job.steps.should match_steps([Dragonfly::Job::Encode]) }
196
+
197
+ it "should use the encoder when applied" do
198
+ @app.encoder.should_receive(:encode).with(@temp_object, :gif, :bitrate => 'mumma').and_return('alo')
199
+ @job.apply.data.should == 'alo'
200
+ end
201
+
202
+ it "should maintain the temp object attributes (except format)" do
203
+ @app.encoder.should_receive(:encode).with(@temp_object, :gif, :bitrate => 'mumma').and_return('alo')
204
+ temp_object = @job.apply.temp_object
205
+ temp_object.data.should == 'alo'
206
+ temp_object.name.should == 'hello.txt'
207
+ temp_object.meta.should == {:a => :b}
208
+ end
209
+
210
+ it "should update the format" do
211
+ @app.encoder.should_receive(:encode).with(@temp_object, :gif, :bitrate => 'mumma').and_return('alo')
212
+ @job.apply.temp_object.format.should == :gif
213
+ end
214
+
215
+ it "should allow returning an array with extra attributes form the encoder" do
216
+ @app.encoder.should_receive(:encode).with(@temp_object, :gif, :bitrate => 'mumma').and_return(['alo', {:name => 'doobie', :meta => {:eggs => 'fish'}}])
217
+ temp_object = @job.apply.temp_object
218
+ temp_object.data.should == 'alo'
219
+ temp_object.name.should == 'doobie'
220
+ temp_object.meta.should == {:a => :b, :eggs => 'fish'}
221
+ end
222
+
223
+ it "not allow overriding the format" do
224
+ @app.encoder.should_receive(:encode).with(@temp_object, :gif, :bitrate => 'mumma').and_return(['alo', {:format => :png}])
225
+ temp_object = @job.apply.temp_object
226
+ temp_object.format.should == :gif
227
+ end
228
+ end
229
+ end
230
+
231
+ describe "analysis" do
232
+ before(:each) do
233
+ @app = test_app
234
+ @job = Dragonfly::Job.new(@app, Dragonfly::TempObject.new('HELLO'))
235
+ @app.analyser.add(:num_letters){|temp_object, letter| temp_object.data.count(letter) }
236
+ end
237
+ it "should return correctly when calling analyse" do
238
+ @job.analyse(:num_letters, 'L').should == 2
239
+ end
240
+ it "should have mixed in the analyser method" do
241
+ @job.num_letters('L').should == 2
242
+ end
243
+ it "should return nil from analyse if calling any old method" do
244
+ @job.analyse(:robin_van_persie).should be_nil
245
+ end
246
+ it "should not allow calling any old method" do
247
+ lambda{
248
+ @job.robin_van_persie
249
+ }.should raise_error(NoMethodError)
250
+ end
251
+ it "should work correctly with chained jobs, applying before analysing" do
252
+ @app.processor.add(:double){|temp_object| temp_object.data * 2 }
253
+ @job.process(:double).num_letters('L').should == 4
254
+ end
255
+ end
256
+
257
+ describe "adding jobs" do
258
+
259
+ before(:each) do
260
+ @app = mock_app
261
+ end
262
+
263
+ it "should raise an error if the app is different" do
264
+ job1 = Dragonfly::Job.new(@app)
265
+ job2 = Dragonfly::Job.new(mock_app)
266
+ lambda {
267
+ job1 + job2
268
+ }.should raise_error(Dragonfly::Job::AppDoesNotMatch)
269
+ end
270
+
271
+ describe "both belonging to the same app" do
272
+ before(:each) do
273
+ @job1 = Dragonfly::Job.new(@app, Dragonfly::TempObject.new('hello'))
274
+ @job1.process! :resize
275
+ @job2 = Dragonfly::Job.new(@app, Dragonfly::TempObject.new('hola'))
276
+ @job2.encode! :png
277
+ end
278
+
279
+ it "should concatenate jobs" do
280
+ job3 = @job1 + @job2
281
+ job3.steps.should match_steps([
282
+ Dragonfly::Job::Process,
283
+ Dragonfly::Job::Encode
284
+ ])
285
+ end
286
+
287
+ it "should raise an error if the second job has applied steps" do
288
+ @job2.apply
289
+ lambda {
290
+ @job1 + @job2
291
+ }.should raise_error(Dragonfly::Job::JobAlreadyApplied)
292
+ end
293
+
294
+ it "should not raise an error if the first job has applied steps" do
295
+ @job1.apply
296
+ lambda {
297
+ @job1 + @job2
298
+ }.should_not raise_error
299
+ end
300
+
301
+ it "should have the first job's temp_object" do
302
+ (@job1 + @job2).temp_object.data.should == 'hello'
303
+ end
304
+
305
+ it "should have the correct applied steps" do
306
+ @job1.apply
307
+ (@job1 + @job2).applied_steps.should match_steps([
308
+ Dragonfly::Job::Process
309
+ ])
310
+ end
311
+
312
+ it "should have the correct pending steps" do
313
+ @job1.apply
314
+ (@job1 + @job2).pending_steps.should match_steps([
315
+ Dragonfly::Job::Encode
316
+ ])
317
+ end
318
+ end
319
+
320
+ end
321
+
322
+ describe "defining extra steps after applying" do
323
+ before(:each) do
324
+ @app = mock_app
325
+ @job = Dragonfly::Job.new(@app)
326
+ @job.temp_object = Dragonfly::TempObject.new("hello")
327
+ @job.process! :resize
328
+ @job.apply
329
+ @job.encode! :micky
330
+ end
331
+ it "should not call apply on already applied steps" do
332
+ @job.steps[0].should_not_receive(:apply)
333
+ @job.apply
334
+ end
335
+ it "should call apply on not yet applied steps" do
336
+ @job.steps[1].should_receive(:apply)
337
+ @job.apply
338
+ end
339
+ it "should return all steps" do
340
+ @job.steps.should match_steps([
341
+ Dragonfly::Job::Process,
342
+ Dragonfly::Job::Encode
343
+ ])
344
+ end
345
+ it "should return applied steps" do
346
+ @job.applied_steps.should match_steps([
347
+ Dragonfly::Job::Process
348
+ ])
349
+ end
350
+ it "should return the pending steps" do
351
+ @job.pending_steps.should match_steps([
352
+ Dragonfly::Job::Encode
353
+ ])
354
+ end
355
+ it "should not call apply on any steps when already applied" do
356
+ @job.apply
357
+ @job.steps[0].should_not_receive(:apply)
358
+ @job.steps[1].should_not_receive(:apply)
359
+ @job.apply
360
+ end
361
+ end
362
+
363
+ describe "chaining" do
364
+
365
+ before(:each) do
366
+ @app = mock_app
367
+ @job = Dragonfly::Job.new(@app)
368
+ end
369
+
370
+ it "should return itself if bang is used" do
371
+ @job.fetch!('some_uid').should == @job
372
+ end
373
+
374
+ it "should return a new job if bang is not used" do
375
+ @job.fetch('some_uid').should_not == @job
376
+ end
377
+
378
+ describe "when a chained job is defined" do
379
+ before(:each) do
380
+ @job.fetch!('some_uid')
381
+ @job2 = @job.process(:resize, '30x30')
382
+ end
383
+
384
+ it "should return the correct steps for the original job" do
385
+ @job.applied_steps.should match_steps([
386
+ ])
387
+ @job.pending_steps.should match_steps([
388
+ Dragonfly::Job::Fetch
389
+ ])
390
+ end
391
+
392
+ it "should return the correct data for the original job" do
393
+ @job.data.should == 'SOME_DATA'
394
+ end
395
+
396
+ it "should return the correct steps for the new job" do
397
+ @job2.applied_steps.should match_steps([
398
+ ])
399
+ @job2.pending_steps.should match_steps([
400
+ Dragonfly::Job::Fetch,
401
+ Dragonfly::Job::Process
402
+ ])
403
+ end
404
+
405
+ it "should return the correct data for the new job" do
406
+ @job2.data.should == 'SOME_PROCESSED_DATA'
407
+ end
408
+
409
+ it "should not affect the other one when one is applied" do
410
+ @job.apply
411
+ @job.applied_steps.should match_steps([
412
+ Dragonfly::Job::Fetch
413
+ ])
414
+ @job.pending_steps.should match_steps([
415
+ ])
416
+ @job.temp_object.data.should == 'SOME_DATA'
417
+ @job2.applied_steps.should match_steps([
418
+ ])
419
+ @job2.pending_steps.should match_steps([
420
+ Dragonfly::Job::Fetch,
421
+ Dragonfly::Job::Process
422
+ ])
423
+ @job2.temp_object.should be_nil
424
+ end
425
+ end
426
+
427
+ end
428
+
429
+ describe "to_a" do
430
+ before(:each) do
431
+ @app = mock_app
432
+ end
433
+ it "should represent all the steps in array form" do
434
+ job = Dragonfly::Job.new(@app)
435
+ job.fetch! 'some_uid'
436
+ job.generate! :plasma # you wouldn't really call this after fetch but still works
437
+ job.process! :resize, '30x40'
438
+ job.encode! :gif, :bitrate => 20
439
+ job.to_a.should == [
440
+ [:f, 'some_uid'],
441
+ [:g, :plasma],
442
+ [:p, :resize, '30x40'],
443
+ [:e, :gif, {:bitrate => 20}]
444
+ ]
445
+ end
446
+ end
447
+
448
+ describe "from_a" do
449
+
450
+ before(:each) do
451
+ @app = test_app
452
+ end
453
+
454
+ describe "a well-defined array" do
455
+ before(:each) do
456
+ @job = Dragonfly::Job.from_a([
457
+ [:f, 'some_uid'],
458
+ [:g, :plasma],
459
+ [:p, :resize, '30x40'],
460
+ [:e, :gif, {:bitrate => 20}]
461
+ ], @app)
462
+ end
463
+ it "should have the correct step types" do
464
+ @job.steps.should match_steps([
465
+ Dragonfly::Job::Fetch,
466
+ Dragonfly::Job::Generate,
467
+ Dragonfly::Job::Process,
468
+ Dragonfly::Job::Encode
469
+ ])
470
+ end
471
+ it "should have the correct args" do
472
+ @job.steps[0].args.should == ['some_uid']
473
+ @job.steps[1].args.should == [:plasma]
474
+ @job.steps[2].args.should == [:resize, '30x40']
475
+ @job.steps[3].args.should == [:gif, {:bitrate => 20}]
476
+ end
477
+ it "should have no applied steps" do
478
+ @job.applied_steps.should be_empty
479
+ end
480
+ it "should have all steps pending" do
481
+ @job.steps.should == @job.pending_steps
482
+ end
483
+ end
484
+
485
+ [
486
+ :f,
487
+ [:f],
488
+ [[]],
489
+ [[:egg]]
490
+ ].each do |object|
491
+ it "should raise an error if the object passed in is #{object.inspect}" do
492
+ lambda {
493
+ Dragonfly::Job.from_a(object, @app)
494
+ }.should raise_error(Dragonfly::Job::InvalidArray)
495
+ end
496
+ end
497
+
498
+ it "should initialize an empty job if the array is empty" do
499
+ job = Dragonfly::Job.from_a([], @app)
500
+ job.steps.should be_empty
501
+ end
502
+ end
503
+
504
+ describe "from_path" do
505
+ before(:each) do
506
+ @app = test_app
507
+ @serialized = @app.fetch('eggs').serialize
508
+ end
509
+ it "should work with a simple path" do
510
+ Dragonfly::Job.from_path("/#{@serialized}", @app).should be_a(Dragonfly::Job)
511
+ end
512
+ it "should work with no slash" do
513
+ Dragonfly::Job.from_path(@serialized, @app).should be_a(Dragonfly::Job)
514
+ end
515
+ it "should ignore the app's url_path_prefix" do
516
+ @app.url_path_prefix = '/images/yo'
517
+ Dragonfly::Job.from_path("/images/yo/#{@serialized}", @app).should be_a(Dragonfly::Job)
518
+ end
519
+ it "should not work with an incorrect url_path_prefix" do
520
+ @app.url_path_prefix = '/images/yo'
521
+ lambda{
522
+ Dragonfly::Job.from_path("/images/#{@serialized}", @app).should be_a(Dragonfly::Job)
523
+ }.should raise_error(Dragonfly::Serializer::BadString)
524
+ end
525
+ it "should ignore any suffix" do
526
+ Dragonfly::Job.from_path("/#{@serialized}asdfJASKLDF*()!@$%{}|/GGG/.png.your.mum", @app).should be_a(Dragonfly::Job)
527
+ end
528
+ end
529
+
530
+ describe "serialization" do
531
+ before(:each) do
532
+ @app = test_app
533
+ @job = Dragonfly::Job.new(@app).fetch('mumma').process(:resize, '1x50')
534
+ end
535
+ it "should serialize itself" do
536
+ @job.serialize.should =~ /^\w{1,}$/
537
+ end
538
+ it "should deserialize to the same as the original" do
539
+ new_job = Dragonfly::Job.deserialize(@job.serialize, @app)
540
+ new_job.to_a.should == @job.to_a
541
+ end
542
+ end
543
+
544
+ describe "to_app" do
545
+ before(:each) do
546
+ @app = test_app
547
+ @job = Dragonfly::Job.new(@app)
548
+ end
549
+ it "should return an endpoint" do
550
+ endpoint = @job.to_app
551
+ endpoint.should be_a(Dragonfly::JobEndpoint)
552
+ endpoint.job.should == @job
553
+ end
554
+ end
555
+
556
+ describe "url" do
557
+ before(:each) do
558
+ @app = mock_app(:url_for => 'hello')
559
+ @job = Dragonfly::Job.new(@app)
560
+ end
561
+ it "should return a url" do
562
+ @job.generate!(:plasma)
563
+ @job.url.should == 'hello'
564
+ end
565
+ it "should return nil if there are no steps" do
566
+ @job.url.should be_nil
567
+ end
568
+ end
569
+
570
+ describe "to_fetched_job" do
571
+ it "should maintain the same temp_object and be already applied" do
572
+ app = mock_app
573
+ job = Dragonfly::Job.new(app, Dragonfly::TempObject.new("HELLO"))
574
+ new_job = job.to_fetched_job('some_uid')
575
+ new_job.temp_object.data.should == 'HELLO'
576
+ new_job.to_a.should == [
577
+ [:f, 'some_uid']
578
+ ]
579
+ new_job.pending_steps.should be_empty
580
+ end
581
+ end
582
+
583
+ describe "format" do
584
+ before(:each) do
585
+ @app = test_app
586
+ end
587
+ it "should default to nil" do
588
+ job = @app.new_job("HELLO")
589
+ job.format.should be_nil
590
+ end
591
+ it "should use the temp_object format if it exists" do
592
+ job = @app.new_job("HELLO", :format => :txt)
593
+ job.format.should == :txt
594
+ end
595
+ it "should use the analyser format if it exists" do
596
+ @app.analyser.add :format do |temp_object|
597
+ :egg
598
+ end
599
+ job = @app.new_job("HELLO")
600
+ job.format.should == :egg
601
+ end
602
+ it "should prefer the temp_object format if both exist" do
603
+ @app.analyser.add :format do |temp_object|
604
+ :egg
605
+ end
606
+ job = @app.new_job("HELLO", :format => :txt)
607
+ job.format.should == :txt
608
+ end
609
+ end
610
+
611
+ describe "validate_sha!" do
612
+ before(:each) do
613
+ @app = test_app
614
+ @job = @app.fetch('eggs')
615
+ end
616
+ it "should raise an error if nothing is given" do
617
+ lambda{
618
+ @job.validate_sha!(nil)
619
+ }.should raise_error(Dragonfly::Job::NoSHAGiven)
620
+ end
621
+ it "should raise an error if the wrong SHA is given" do
622
+ lambda{
623
+ @job.validate_sha!('asdf')
624
+ }.should raise_error(Dragonfly::Job::IncorrectSHA)
625
+ end
626
+ it "should return self if ok" do
627
+ @job.validate_sha!(@job.sha).should == @job
628
+ end
629
+ end
630
+
631
+ describe "setting the name" do
632
+ before(:each) do
633
+ @app = test_app
634
+ @job = @app.new_job("HELLO", :name => 'not.me')
635
+ end
636
+ it "should allow setting the name" do
637
+ @job.name = 'wassup.doc'
638
+ @job.name.should == 'wassup.doc'
639
+ end
640
+ end
641
+
642
+ describe "setting the meta" do
643
+ before(:each) do
644
+ @app = test_app
645
+ @job = @app.new_job("HiThere", :meta => {:five => 'beans'})
646
+ end
647
+ it "should allow setting the meta" do
648
+ @job.meta = {:doogie => 'ladders'}
649
+ @job.meta.should == {:doogie => 'ladders'}
650
+ end
651
+ it "should allow updating the meta" do
652
+ @job.meta[:doogie] = 'ladders'
653
+ @job.meta.should == {:five => 'beans', :doogie => 'ladders'}
654
+ end
655
+ end
656
+
657
+ describe "b64_data" do
658
+ before(:each) do
659
+ @app = test_app
660
+ end
661
+ it "should return a string using the data:URI schema" do
662
+ job = @app.new_job("HELLO", :name => 'text.txt')
663
+ job.b64_data.should == "data:text/plain;base64,SEVMTE8=\n"
664
+ end
665
+ end
666
+
667
+ describe "querying stuff without applying steps" do
668
+ before(:each) do
669
+ @app = test_app
670
+ end
671
+
672
+ describe "fetch_step" do
673
+ it "should return nil if it doesn't exist" do
674
+ @app.generate(:ponies).process(:jam).fetch_step.should be_nil
675
+ end
676
+ it "should return the fetch step otherwise" do
677
+ step = @app.fetch('hello').process(:cheese).fetch_step
678
+ step.should be_a(Dragonfly::Job::Fetch)
679
+ step.uid.should == 'hello'
680
+ end
681
+ end
682
+ describe "fetched uid" do
683
+ describe "when there's no fetch step" do
684
+ before(:each) do
685
+ @job = @app.new_job("AGG")
686
+ end
687
+ it "should return nil for uid" do
688
+ @job.uid.should be_nil
689
+ end
690
+ it "should return nil for uid_basename" do
691
+ @job.uid_basename.should be_nil
692
+ end
693
+ it "should return nil for uid_extname" do
694
+ @job.uid_extname.should be_nil
695
+ end
696
+ end
697
+ describe "when there is a fetch step" do
698
+ before(:each) do
699
+ @job = @app.fetch('gungedin/innit.blud')
700
+ end
701
+ it "should return the uid" do
702
+ @job.uid.should == 'gungedin/innit.blud'
703
+ end
704
+ it "should return the uid_basename" do
705
+ @job.uid_basename.should == 'innit'
706
+ end
707
+ it "should return the uid_extname" do
708
+ @job.uid_extname.should == '.blud'
709
+ end
710
+ end
711
+ end
712
+
713
+ describe "fetch_file_step" do
714
+ it "should return nil if it doesn't exist" do
715
+ @app.generate(:ponies).process(:jam).fetch_file_step.should be_nil
716
+ end
717
+ it "should return the fetch_file step otherwise" do
718
+ step = @app.fetch_file('/my/file.png').process(:cheese).fetch_file_step
719
+ step.should be_a(Dragonfly::Job::FetchFile)
720
+ step.path.should == '/my/file.png'
721
+ end
722
+ end
723
+
724
+ describe "generate_step" do
725
+ it "should return nil if it doesn't exist" do
726
+ @app.fetch('many/ponies').process(:jam).generate_step.should be_nil
727
+ end
728
+ it "should return the generate step otherwise" do
729
+ step = @app.generate(:ponies).process(:cheese).generate_step
730
+ step.should be_a(Dragonfly::Job::Generate)
731
+ step.args.should == [:ponies]
732
+ end
733
+ end
734
+
735
+ describe "process_steps" do
736
+ it "should return the processing steps" do
737
+ job = @app.fetch('many/ponies').process(:jam).process(:eggs).encode(:gif)
738
+ job.process_steps.should match_steps([
739
+ Dragonfly::Job::Process,
740
+ Dragonfly::Job::Process
741
+ ])
742
+ end
743
+ end
744
+
745
+ describe "encode_step" do
746
+ it "should return nil if it doesn't exist" do
747
+ @app.generate(:ponies).encode_step.should be_nil
748
+ end
749
+ it "should return the last encode step otherwise" do
750
+ step = @app.fetch('hello').encode(:smells).encode(:cheese).encode_step
751
+ step.should be_a(Dragonfly::Job::Encode)
752
+ step.format.should == :cheese
753
+ end
754
+ end
755
+ describe "encoded_format" do
756
+ it "should return nil if there's no encode step" do
757
+ @app.new_job('asdf').encoded_format.should be_nil
758
+ end
759
+ it "should return the last encoded format if it exists" do
760
+ @app.fetch('gungedin').encode(:a).encode(:b).encoded_format.should == :b
761
+ end
762
+ end
763
+ describe "encoded_extname" do
764
+ it "should return nil if there's no encode step" do
765
+ @app.new_job('asdf').encoded_extname.should be_nil
766
+ end
767
+ it "should return the last encoded format as an extname if it exists" do
768
+ @app.fetch('gungedin').encode(:a).encode(:b).encoded_extname.should == '.b'
769
+ end
770
+ end
771
+ end
772
+
773
+ end