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,8 @@
1
+ Then "debug" do
2
+ debugger
3
+ true
4
+ end
5
+
6
+ Then 'show "(.*)"' do |code|
7
+ eval "puts #{code}"
8
+ end
@@ -0,0 +1,66 @@
1
+ require 'tempfile'
2
+
3
+ Given /^we are using the app for (\w+)$/ do |app_name|
4
+ $app = Dragonfly[app_name.to_sym]
5
+ end
6
+
7
+ Given /^a stored file "(.+?)"$/ do |name|
8
+ file = File.new(File.dirname(__FILE__) + "/../../samples/#{name}")
9
+ uid = $app.store(file)
10
+ TEMP_FILES[name] = uid
11
+ end
12
+
13
+ Given /^a stored image "(.+?)" with dimensions (\d+)x(\d+)$/ do |name, width, height|
14
+ tempfile = Tempfile.new(name)
15
+ `convert -resize #{width}x#{height}! #{SAMPLE_IMAGE_PATH} #{tempfile.path}`
16
+ uid = $app.store(tempfile)
17
+ TEMP_FILES[name] = uid
18
+ end
19
+
20
+ When /^I go to the url for "(.+?)"$/ do |name|
21
+ uid = TEMP_FILES[name]
22
+ make_request $app.fetch(uid)
23
+ end
24
+
25
+ When /^I go to the url for "(.+?)", with format '([^']+?)'$/ do |name, format|
26
+ uid = TEMP_FILES[name]
27
+ make_request $app.fetch(uid).encode(format)
28
+ end
29
+
30
+ When /^I go to the url for "(.+?)", with format '(.+?)' and resize geometry '(.+?)'$/ do |name, format, geometry|
31
+ uid = TEMP_FILES[name]
32
+ make_request $app.fetch(uid).process(:resize, geometry).encode(format)
33
+ end
34
+
35
+ When /^I go to the url for "(.+?)", with shortcut '([^']+?)'$/ do |name, geometry|
36
+ uid = TEMP_FILES[name]
37
+ make_request $app.fetch(uid).thumb(geometry)
38
+ end
39
+
40
+ Then "the response should be OK" do
41
+ @response.status.should == 200
42
+ end
43
+
44
+ Then /the response should have mime-type '(.+?)'/ do |mime_type|
45
+ @response.headers['Content-Type'].should == mime_type
46
+ end
47
+
48
+ Then /^the image should have width '(.+?)'$/ do |width|
49
+ @response.body.should have_width(width.to_i)
50
+ end
51
+
52
+ Then /^the image should have height '(.+?)'$/ do |height|
53
+ @response.body.should have_height(height.to_i)
54
+ end
55
+
56
+ Then /^the image should have format '(.+?)'$/ do |format|
57
+ @response.body.should have_format(format)
58
+ end
59
+
60
+ Then /^the response should have the same content as the file "([^\"]*)"$/ do |name|
61
+ if RUBY_VERSION =~ /^1\.8/
62
+ @response.body.should == $app.fetch(TEMP_FILES[name]).data
63
+ else
64
+ @response.body.force_encoding('BINARY').should == $app.fetch(TEMP_FILES[name]).data.force_encoding('BINARY')
65
+ end
66
+ end
@@ -0,0 +1,39 @@
1
+ RAILS_APP_NAME = 'tmp_app'
2
+ FIXTURES_PATH = ROOT_PATH + "/fixtures"
3
+ GEMFILES = {
4
+ '2.3.5' => ROOT_PATH + '/Gemfile.rails.2.3.5',
5
+ '3.0.3' => ROOT_PATH + '/Gemfile',
6
+ }
7
+
8
+ def fixture_path(version)
9
+ "#{FIXTURES_PATH}/rails_#{version}"
10
+ end
11
+
12
+ def app_path(version)
13
+ "#{fixture_path(version)}/#{RAILS_APP_NAME}"
14
+ end
15
+
16
+ ##############################################################################
17
+
18
+ {
19
+ '2.3.5' => "BUNDLE_GEMFILE=#{GEMFILES['2.3.5']} rails #{RAILS_APP_NAME} -m template.rb",
20
+ '3.0.3' => "BUNDLE_GEMFILE=#{GEMFILES['3.0.3']} bundle exec rails new #{RAILS_APP_NAME} -m template.rb"
21
+ }.each do |version, rails_command|
22
+
23
+ Given /^a Rails #{version} application set up for using dragonfly$/ do
24
+ raise "Problem setting up Rails app" unless `
25
+ cd #{fixture_path(version)} &&
26
+ rm -rf #{RAILS_APP_NAME} &&
27
+ #{rails_command}`
28
+ end
29
+
30
+ end
31
+
32
+ Then /^the (.+) cucumber features in my Rails (.+) app should pass$/ do |filename, version|
33
+ puts "\n*** RUNNING FEATURES IN THE RAILS APP... ***\n"
34
+ path = File.join(fixture_path(version), RAILS_APP_NAME)
35
+ `cd #{path} && BUNDLE_GEMFILE=#{GEMFILES[version]} RAILS_ENV=cucumber rake db:migrate`
36
+ features_passed = system "cd #{path} && BUNDLE_GEMFILE=#{GEMFILES[version]} cucumber features/#{filename}.feature"
37
+ puts "\n*** FINISHED RUNNING FEATURES IN THE RAILS APP ***\n"
38
+ raise "Features failed" unless features_passed
39
+ end
@@ -0,0 +1,40 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
+ require 'dragonfly'
3
+ require 'spec/expectations'
4
+ require 'test/unit/assertions'
5
+ require File.dirname(__FILE__) + '/../../spec/image_matchers.rb'
6
+
7
+ ROOT_PATH = File.expand_path(File.dirname(__FILE__) + "/../..")
8
+
9
+ # A hash of <name for reference> => <dragonfly uid> pairs
10
+ TEMP_FILES = {}
11
+
12
+ Dragonfly[:images].configure_with(:imagemagick)
13
+ Dragonfly[:files].configure do |c|
14
+ c.analyser.register(Dragonfly::Analysis::FileCommandAnalyser)
15
+ end
16
+
17
+ SAMPLE_IMAGE_PATH = File.dirname(__FILE__)+'/../../samples/beach.png'
18
+
19
+ Before do
20
+ # Remove temporary images
21
+ TEMP_FILES.each do |name, uid|
22
+ $app.datastore.destroy(uid)
23
+ TEMP_FILES.delete(name)
24
+ end
25
+ end
26
+
27
+ AfterStep do |scenario|
28
+ Dir["#{ROOT_PATH}/Gemfile*.lock"].each{|f| FileUtils.rm_f(f) }
29
+ end
30
+
31
+ module MyHelpers
32
+
33
+ def make_request(job)
34
+ request = Rack::MockRequest.new($app)
35
+ @response = request.get(job.url)
36
+ end
37
+
38
+ end
39
+
40
+ World(MyHelpers)
@@ -0,0 +1,3 @@
1
+ class Album < ActiveRecord::Base
2
+ image_accessor :cover_image
3
+ end
@@ -0,0 +1,4 @@
1
+ <% form_for @album, :html => {:multipart => true} do |f| %>
2
+ <%= f.file_field :cover_image %>
3
+ <%= f.submit :value => 'Create' %>
4
+ <% end %>
@@ -0,0 +1,4 @@
1
+ <%= flash[:notice] %>
2
+ Look at this cover image!
3
+ <%= image_tag @album.cover_image.thumb('200x100!').url %>
4
+ <%= link_to 'Index', albums_path %>
@@ -0,0 +1,4 @@
1
+ # This is a hack to get the generated rails apps to use the version of dragonfly being worked on.
2
+ $:.unshift(File.expand_path(File.dirname(__FILE__)+'/../../../../../lib'))
3
+ require 'dragonfly/rails/images'
4
+
@@ -0,0 +1,12 @@
1
+ Feature: champion adds cover images to his albums
2
+ In order to be a champion
3
+ A user adds an image to his album
4
+
5
+ Scenario: Add and view image
6
+ When I go to the new album page
7
+ And I attach the file "../../../samples/beach.png" to "album[cover_image]"
8
+ And I press "Create"
9
+ Then I should see "successfully created"
10
+ And I should see "Look at this cover image!"
11
+ When I look at the generated beach image
12
+ And I should see a PNG image of size 200x100
@@ -0,0 +1,15 @@
1
+ When /^I look at the generated (.+) image$/ do |image_name|
2
+ page.body =~ %r{src="(/media[^"]+?)"}
3
+ url = $1
4
+ visit(url)
5
+ end
6
+
7
+ Then /^I should see a (.+) image of size (.+)$/ do |format, size|
8
+ tempfile = Tempfile.new('wicked')
9
+ page.body.force_encoding('UTF-8').encode! if page.body.respond_to?(:force_encoding) # For some reason need this on Ruby 1.9.2
10
+ tempfile.write page.body
11
+ tempfile.close
12
+ output = `identify #{tempfile.path}`.split(' ')
13
+ output[1].should == format
14
+ output[2].should == size
15
+ end
@@ -0,0 +1,15 @@
1
+ module NavigationHelpers
2
+ def path_to(page_name)
3
+ case page_name
4
+ when "the new album page"
5
+ '/albums/new'
6
+ when /^the image for text "(.+)", size "(.+)"$/
7
+ "/text/#{$1}/#{$2}"
8
+ else
9
+ raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
10
+ "Now, go and add a mapping in #{__FILE__}"
11
+ end
12
+ end
13
+ end
14
+
15
+ World(NavigationHelpers)
@@ -0,0 +1,7 @@
1
+ Feature: champion adds text images to his app
2
+ In order to be a champion
3
+ A user adds text images to his app
4
+
5
+ Scenario: View text image
6
+ When I go to the image for text "Hello", size "300x150!"
7
+ Then I should see a PNG image of size 300x150
@@ -0,0 +1,10 @@
1
+ gem 'rack-cache', :lib => 'rack/cache'
2
+ gem 'cucumber'
3
+ generate 'cucumber'
4
+
5
+ generate 'scaffold albums cover_image_uid:string'
6
+ rake 'db:migrate'
7
+
8
+ # Copy over all files from the template dir
9
+ files_dir = File.expand_path(File.dirname(__FILE__) + '/../../files')
10
+ run "cp -r #{files_dir}/** ."
@@ -0,0 +1,20 @@
1
+ gem 'rack-cache', :require => 'rack/cache'
2
+
3
+ gem 'capybara'
4
+ gem 'cucumber-rails'
5
+ gem 'cucumber', '0.8.5'
6
+
7
+ generate 'cucumber:install'
8
+
9
+ generate 'scaffold albums cover_image_uid:string'
10
+ rake 'db:migrate'
11
+
12
+ # Copy over all files from the template dir
13
+ files_dir = File.expand_path(File.dirname(__FILE__) + '/../files')
14
+ run "cp -r #{files_dir}/** ."
15
+
16
+ route <<ROUTES
17
+ match '/text/:text/:size' => Dragonfly[:images].endpoint{|params, app|
18
+ app.generate(:text, params[:text]).thumb(params[:size])
19
+ }
20
+ ROUTES
@@ -0,0 +1,17 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+ require File.dirname(__FILE__) + '/lib/dragonfly'
4
+ APP = Dragonfly[:images].configure_with(:imagemagick)
5
+
6
+ # available_uids = `find #{APP.datastore.root_path} ! -type d`.split("\n").map do |file|
7
+ # file.sub("#{APP.datastore.root_path}/", '')
8
+ # end
9
+
10
+ puts "Loaded stuff from dragonfly irbrc"
11
+ # puts "\nAvailable uids:\n"
12
+ # puts available_uids
13
+ puts "\nAvailable sample images:\n"
14
+ puts Dir['samples/*']
15
+ puts "\nAvailable constants:\n"
16
+ puts "APP"
17
+ puts
@@ -0,0 +1,45 @@
1
+ # AUTOLOAD EVERYTHING IN THE DRAGONFLY DIRECTORY TREE
2
+
3
+ # The convention is that dirs are modules
4
+ # so declare them here and autoload any modules/classes inside them
5
+ # All paths here are absolute
6
+ def camelize(path)
7
+ # e.g. 'test/this_one' => Test::ThisOne
8
+ "#{path}".
9
+ chomp('/').
10
+ gsub('/','::').
11
+ gsub(/([^a-z])(\w)/){ "#{$1}#{$2.upcase}" }.
12
+ gsub('_','').
13
+ sub(/^(\w)/){ $1.upcase }
14
+ end
15
+ def autoload_files_in_dir(path, namespace)
16
+ # Define the module
17
+ eval("module #{namespace}; end")
18
+ # Autoload modules/classes in that module
19
+ Dir.glob("#{path}/*.rb").each do |file|
20
+ file = File.expand_path(file)
21
+ sub_const_name = camelize( File.basename(file, '.rb') )
22
+ eval("#{namespace}.autoload('#{sub_const_name}', '#{file}')")
23
+ end
24
+ # Recurse on subdirectories
25
+ Dir.glob("#{path}/*/").each do |dir|
26
+ sub_namespace = camelize( File.basename(dir) )
27
+ autoload_files_in_dir(dir, "#{namespace}::#{sub_namespace}")
28
+ end
29
+ end
30
+
31
+ autoload_files_in_dir("#{File.dirname(__FILE__)}/dragonfly", 'Dragonfly')
32
+
33
+ require File.dirname(__FILE__) + '/dragonfly/core_ext/object'
34
+ require File.dirname(__FILE__) + '/dragonfly/core_ext/string'
35
+ require File.dirname(__FILE__) + '/dragonfly/core_ext/symbol'
36
+
37
+ module Dragonfly
38
+ class << self
39
+
40
+ def [](*args)
41
+ App[*args]
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,13 @@
1
+ module Dragonfly
2
+
3
+ module ActiveModelExtensions
4
+
5
+ def self.extended(klass)
6
+ unless klass.include?(InstanceMethods)
7
+ klass.extend(ClassMethods)
8
+ klass.class_eval{ include InstanceMethods }
9
+ end
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,169 @@
1
+ require 'forwardable'
2
+
3
+ module Dragonfly
4
+ module ActiveModelExtensions
5
+
6
+ class Attachment
7
+
8
+ extend Forwardable
9
+ def_delegators :job,
10
+ :data, :to_file, :file, :tempfile, :path,
11
+ :process, :encode, :analyse,
12
+ :meta, :meta=,
13
+ :url
14
+
15
+ def initialize(app, parent_model, attribute_name)
16
+ @app, @parent_model, @attribute_name = app, parent_model, attribute_name
17
+ self.extend app.analyser.analysis_methods
18
+ self.extend app.job_definitions
19
+ self.uid = parent_uid
20
+ self.job = app.fetch(uid) if uid
21
+ end
22
+
23
+ def assign(value)
24
+ if value.nil?
25
+ self.job = nil
26
+ reset_magic_attributes
27
+ else
28
+ self.job = case value
29
+ when Job then value.dup
30
+ when self.class then value.job.dup
31
+ else app.new_job(value)
32
+ end
33
+ set_magic_attributes
34
+ end
35
+ set_uid_and_parent_uid(nil)
36
+ value
37
+ end
38
+
39
+ def destroy!
40
+ destroy_previous!
41
+ destroy_content(uid) if uid
42
+ end
43
+
44
+ def save!
45
+ sync_with_parent!
46
+ destroy_previous!
47
+ if job && !uid
48
+ set_uid_and_parent_uid job.store(
49
+ :meta => {
50
+ :model_class => parent_model.class.name,
51
+ :model_attachment => attribute_name
52
+ }
53
+ )
54
+ self.job = job.to_fetched_job(uid)
55
+ end
56
+ end
57
+
58
+ def to_value
59
+ self if job
60
+ end
61
+
62
+ def analyse(meth, *args)
63
+ has_magic_attribute_for?(meth) ? magic_attribute_for(meth) : job.send(meth)
64
+ end
65
+
66
+ [:size, :ext, :name].each do |meth|
67
+ define_method meth do
68
+ analyse(meth)
69
+ end
70
+ end
71
+
72
+ def name=(name)
73
+ job.name = name
74
+ set_magic_attribute(:name, name) if has_magic_attribute_for?(:name)
75
+ name
76
+ end
77
+
78
+ def process!(*args)
79
+ assign(process(*args))
80
+ self
81
+ end
82
+
83
+ def encode!(*args)
84
+ assign(encode(*args))
85
+ self
86
+ end
87
+
88
+ protected
89
+
90
+ attr_reader :job
91
+
92
+ private
93
+
94
+ def destroy_content(uid)
95
+ app.datastore.destroy(uid)
96
+ rescue DataStorage::DataNotFound => e
97
+ app.log.warn("*** WARNING ***: tried to destroy data with uid #{uid}, but got error: #{e}")
98
+ end
99
+
100
+ def destroy_previous!
101
+ if previous_uid
102
+ destroy_content(previous_uid)
103
+ self.previous_uid = nil
104
+ end
105
+ end
106
+
107
+ def sync_with_parent!
108
+ # If the parent uid has been set manually
109
+ if uid != parent_uid
110
+ self.uid = parent_uid
111
+ end
112
+ end
113
+
114
+ def set_uid_and_parent_uid(uid)
115
+ self.uid = uid
116
+ self.parent_uid = uid
117
+ end
118
+
119
+ def parent_uid=(uid)
120
+ parent_model.send("#{attribute_name}_uid=", uid)
121
+ end
122
+
123
+ def parent_uid
124
+ parent_model.send("#{attribute_name}_uid")
125
+ end
126
+
127
+ attr_reader :app, :parent_model, :attribute_name
128
+ attr_writer :job
129
+ attr_accessor :previous_uid
130
+ attr_reader :uid
131
+
132
+ def uid=(uid)
133
+ self.previous_uid = @uid if @uid
134
+ @uid = uid
135
+ end
136
+
137
+ def allowed_magic_attributes
138
+ app.analyser.analysis_method_names + [:size, :ext, :name]
139
+ end
140
+
141
+ def magic_attributes
142
+ @magic_attributes ||= parent_model.public_methods.select { |name|
143
+ name.to_s =~ /^#{attribute_name}_(.+)$/ && allowed_magic_attributes.include?($1.to_sym)
144
+ }.map{|name| name.to_s.sub("#{attribute_name}_", '').to_sym }
145
+ end
146
+
147
+ def set_magic_attribute(property, value)
148
+ parent_model.send("#{attribute_name}_#{property}=", value)
149
+ end
150
+
151
+ def set_magic_attributes
152
+ magic_attributes.each{|property| set_magic_attribute(property, job.send(property)) }
153
+ end
154
+
155
+ def reset_magic_attributes
156
+ magic_attributes.each{|property| set_magic_attribute(property, nil) }
157
+ end
158
+
159
+ def has_magic_attribute_for?(property)
160
+ magic_attributes.include?(property.to_sym)
161
+ end
162
+
163
+ def magic_attribute_for(property)
164
+ parent_model.send("#{attribute_name}_#{property}")
165
+ end
166
+
167
+ end
168
+ end
169
+ end