fog-dragonfly 0.8.1

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 (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