dragonfly 0.5.7 → 0.6.0

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

Potentially problematic release.


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

Files changed (77) hide show
  1. data/.gitignore +1 -0
  2. data/.yardopts +1 -0
  3. data/History.md +109 -0
  4. data/VERSION +1 -1
  5. data/config.rb +1 -1
  6. data/dragonfly.gemspec +19 -16
  7. data/extra_docs/ActiveRecord.md +8 -7
  8. data/extra_docs/Analysers.md +1 -1
  9. data/extra_docs/Encoding.md +1 -1
  10. data/extra_docs/ExampleUseCases.md +66 -73
  11. data/extra_docs/GettingStarted.md +1 -1
  12. data/extra_docs/Processing.md +1 -1
  13. data/extra_docs/Shortcuts.md +2 -2
  14. data/extra_docs/UsingWithRails.md +25 -37
  15. data/features/rails_2.3.5.feature +1 -8
  16. data/features/rails_3.0.0.beta3.feature +7 -0
  17. data/features/steps/rails_steps.rb +1 -11
  18. data/features/support/env.rb +1 -1
  19. data/fixtures/files/app/views/albums/show.html.erb +1 -0
  20. data/fixtures/files/config/initializers/{aaa_dragonfly_load_path.rb → dragonfly.rb} +1 -0
  21. data/fixtures/rails_2.3.5/template.rb +4 -6
  22. data/fixtures/rails_3.0.0.beta3/template.rb +16 -0
  23. data/lib/dragonfly.rb +23 -1
  24. data/lib/dragonfly/active_record_extensions/attachment.rb +1 -1
  25. data/lib/dragonfly/analyser_list.rb +4 -0
  26. data/lib/dragonfly/analysis/base.rb +1 -0
  27. data/lib/dragonfly/analysis/r_magick_analyser.rb +7 -0
  28. data/lib/dragonfly/app.rb +3 -11
  29. data/lib/dragonfly/belongs_to_app.rb +24 -0
  30. data/lib/dragonfly/config/heroku_rails_images.rb +23 -0
  31. data/lib/dragonfly/config/r_magick_images.rb +69 -0
  32. data/lib/dragonfly/config/r_magick_text.rb +25 -0
  33. data/lib/dragonfly/config/rails_defaults.rb +18 -0
  34. data/lib/dragonfly/config/rails_images.rb +13 -0
  35. data/lib/dragonfly/configurable.rb +4 -3
  36. data/lib/dragonfly/data_storage/base.rb +2 -0
  37. data/lib/dragonfly/data_storage/s3data_store.rb +11 -4
  38. data/lib/dragonfly/delegator.rb +22 -10
  39. data/lib/dragonfly/encoder_list.rb +4 -0
  40. data/lib/dragonfly/encoding/base.rb +1 -0
  41. data/lib/dragonfly/encoding/r_magick_encoder.rb +52 -8
  42. data/lib/dragonfly/extended_temp_object.rb +26 -27
  43. data/lib/dragonfly/processing/base.rb +1 -0
  44. data/lib/dragonfly/processing/r_magick_processor.rb +12 -127
  45. data/lib/dragonfly/processing/r_magick_text_processor.rb +155 -0
  46. data/lib/dragonfly/processor_list.rb +4 -0
  47. data/lib/dragonfly/rails/images.rb +2 -14
  48. data/lib/dragonfly/temp_object.rb +41 -34
  49. data/spec/dragonfly/active_record_extensions/migration.rb +7 -0
  50. data/spec/dragonfly/active_record_extensions/model_spec.rb +10 -11
  51. data/spec/dragonfly/active_record_extensions/spec_helper.rb +1 -1
  52. data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +14 -1
  53. data/spec/dragonfly/belongs_to_app_spec.rb +55 -0
  54. data/spec/dragonfly/configurable_spec.rb +21 -6
  55. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +1 -0
  56. data/spec/dragonfly/delegator_spec.rb +23 -12
  57. data/spec/dragonfly/extended_temp_object_spec.rb +13 -29
  58. data/spec/dragonfly/processing/{rmagick_processor_spec.rb → r_magick_processor_spec.rb} +8 -75
  59. data/spec/dragonfly/processing/r_magick_text_processor_spec.rb +84 -0
  60. data/spec/dragonfly/temp_object_spec.rb +126 -151
  61. data/spec/dragonfly_spec.rb +12 -0
  62. data/spec/ginger_scenarios.rb +2 -2
  63. data/spec/image_matchers.rb +2 -2
  64. data/yard/setup.rb +12 -2
  65. data/yard/templates/default/fulldoc/html/css/common.css +1 -2
  66. data/yard/templates/default/layout/html/layout.erb +3 -2
  67. metadata +21 -18
  68. data/History.txt +0 -75
  69. data/features/rails_3.0.0.beta.feature +0 -15
  70. data/fixtures/dragonfly_setup.rb +0 -1
  71. data/fixtures/rails +0 -22
  72. data/fixtures/rails_3.0.0.beta/template.rb +0 -13
  73. data/generators/dragonfly_app/USAGE +0 -16
  74. data/generators/dragonfly_app/dragonfly_app_generator.rb +0 -24
  75. data/generators/dragonfly_app/templates/initializer.erb +0 -35
  76. data/lib/dragonfly/r_magick_configuration.rb +0 -67
  77. data/spec/dragonfly/active_record_extensions/initializer.rb +0 -1
@@ -45,7 +45,7 @@ Example: Using to serve resized images
45
45
  require 'rack/cache'
46
46
 
47
47
  app = Dragonfly::App[:images]
48
- app.configure_with(Dragonfly::RMagickConfiguration)
48
+ app.configure_with(Dragonfly::Config::RMagickImages)
49
49
 
50
50
  use Rack::Cache,
51
51
  :verbose => true,
@@ -24,7 +24,7 @@ give us the processing methods `resize`, `crop`, `resize_and_crop`, `rotate`, et
24
24
  temp_object.process(:resize, :geometry => '30x30!') # => returns a new temp_object with width x height = 30x30
25
25
  temp_object.process!(:resize, :geometry => '30x30!') # => resizes its own data
26
26
 
27
- The saved configuration {Dragonfly::RMagickConfiguration RMagickConfiguration} registers the above processor automatically.
27
+ The saved configuration {Dragonfly::Config::RMagickImages RMagickImages} registers the above processor automatically.
28
28
 
29
29
  Custom Processing
30
30
  -----------------
@@ -13,10 +13,10 @@ The parameters are the following:
13
13
  - `:format` - the format to encode the data with, e.g. 'png'
14
14
  - `:encoding` - an options hash passed to the encoder for other options, e.g. bitrate, etc.
15
15
 
16
- Say we have an app configured with the {Dragonfly::RMagickConfiguration RMagickConfiguration}
16
+ Say we have an app configured with the {Dragonfly::Config::RMagickImages RMagickImages}
17
17
 
18
18
  app = Dragonfly::App[:my_app]
19
- app.configure_with(Dragonfly::RMagickConfiguration)
19
+ app.configure_with(Dragonfly::Config::RMagickImages)
20
20
 
21
21
  we can call things like
22
22
 
@@ -5,7 +5,7 @@ Dragonfly works with both Rails 2.3 and Rails 3.
5
5
 
6
6
  The main way to use Dragonfly with Rails is as a {Dragonfly::Middleware middleware}.
7
7
 
8
- 1. The initializer
8
+ 1. Setting up
9
9
  ------------------
10
10
 
11
11
  The quick way
@@ -20,48 +20,26 @@ registers the app so that you can use ActiveRecord accessors, and inserts it int
20
20
 
21
21
  The more explicit way
22
22
  ---------------------
23
- If you want to set up and configure the Dragonfly app yourself, then you can put something like the code below in an initializer and
24
- modify accordingly:
23
+ You can do the above explicitly.
24
+
25
+ config/initializers/dragonfly.rb:
25
26
 
26
27
  require 'dragonfly'
27
28
 
28
- # Set up and configure the dragonfly app
29
29
  app = Dragonfly::App[:images]
30
- app.configure_with(Dragonfly::RMagickConfiguration)
31
- app.configure do |c|
32
- c.log = Rails.logger
33
- c.datastore.configure do |d|
34
- d.root_path = "#{Rails.root}/public/system/dragonfly/#{Rails.env}"
35
- end
36
- c.url_handler.configure do |u|
37
- u.secret = 'insert some secret here to protect from DOS attacks!'
38
- u.path_prefix = '/media'
39
- end
40
- end
41
-
42
- # Extend ActiveRecord
43
- # This allows you to use e.g.
44
- # image_accessor :my_attribute
45
- # in your models.
46
- ActiveRecord::Base.extend Dragonfly::ActiveRecordExtensions
47
- ActiveRecord::Base.register_dragonfly_app(:image, Dragonfly::App[:images])
48
-
49
- ### Insert the middleware ###
50
- # Where the middleware is depends on the version of Rails
51
- middleware = Rails.respond_to?(:application) ? Rails.application.middleware : ActionController::Dispatcher.middleware
52
- middleware.insert_after Rack::Lock, Dragonfly::Middleware, :images
30
+ app.configure_with(Dragonfly::Config::RailsImages)
31
+
32
+ # Define the method 'image_accessor' in ActiveRecord models
33
+ Dragonfly.active_record_macro(:image, app)
53
34
 
54
- # # UNCOMMENT THIS IF YOU WANT TO CACHE REQUESTS WITH Rack::Cache
55
- # require 'rack/cache'
56
- # middleware.insert_before Dragonfly::Middleware, Rack::Cache, {
57
- # :verbose => true,
58
- # :metastore => "file:#{Rails.root}/tmp/dragonfly/cache/meta",
59
- # :entitystore => "file:#{Rails.root}/tmp/dragonfly/cache/body"
60
- # }
35
+ environment.rb (application.rb in Rails 3):
61
36
 
62
- If you can't be bothered to copy and paste, then there's actually a generator for Rails 2.3 (not Rails 3 yet) that will do something like the above for you:
63
-
64
- ./script/generate dragonfly_app images
37
+ config.middleware.insert_after 'Rack::Lock', 'Dragonfly::Middleware', :images
38
+ config.middleware.insert_before 'Dragonfly::Middleware', 'Rack::Cache', {
39
+ :verbose => true,
40
+ :metastore => "file:#{Rails.root}/tmp/dragonfly/cache/meta",
41
+ :entitystore => "file:#{Rails.root}/tmp/dragonfly/cache/body"
42
+ }
65
43
 
66
44
  2. Gem dependencies
67
45
  -------------------
@@ -91,3 +69,13 @@ Now that you have a parasitic Dragonfly app living inside your Rails app, you ca
91
69
  To see what you can do with the active record accessors, see {file:ActiveRecord}.
92
70
 
93
71
  For more info about general Dragonfly setup, including avoiding denial-of-service attacks, see {file:GettingStarted}.
72
+
73
+ Extra Config
74
+ ------------
75
+ There are one or two config options you may commonly want to tweak.
76
+ In this case, add something like the following to your initializer:
77
+
78
+ Dragonfly::App[:images].configure do |c|
79
+ c.url_handler.path_prefix = '/attachments' # configures where the Dragonfly app is served from - default '/media'
80
+ c.url_handler.secret = 'PUT A SECRET HERE!!' # for protecting from Denial-Of-Service attacks
81
+ end
@@ -2,13 +2,6 @@ Feature: champion uses dragonfly in his Rails 2.3.5 application
2
2
  In order to be a champion
3
3
  A user uses dragonfly in his Rails 2.3.5 application
4
4
 
5
- Background:
6
- Given a Rails 2.3.5 application set up for using dragonfly
7
-
8
- Scenario: Set up dragonfly using the generator
9
- When I use the Rails 2.3.5 generator to set up dragonfly
10
- Then the cucumber features in my Rails 2.3.5 app should pass
11
-
12
5
  Scenario: Set up dragonfly using the provided initializer
13
- When I use the provided 2.3.5 initializer
6
+ Given a Rails 2.3.5 application set up for using dragonfly
14
7
  Then the cucumber features in my Rails 2.3.5 app should pass
@@ -0,0 +1,7 @@
1
+ Feature: champion uses dragonfly in his Rails 3.0.0.beta3 application
2
+ In order to be a champion
3
+ A user uses dragonfly in his Rails 3.0.0.beta3 application
4
+
5
+ Scenario: Set up dragonfly using initializer
6
+ Given a Rails 3.0.0.beta3 application set up for using dragonfly
7
+ Then the cucumber features in my Rails 3.0.0.beta3 app should pass
@@ -15,17 +15,7 @@ Given /^a Rails (.+) application set up for using dragonfly$/ do |version|
15
15
  raise "Problem setting up Rails app" unless `
16
16
  cd #{fixture_path(version)} &&
17
17
  rm -rf #{RAILS_APP_NAME} &&
18
- ../rails _#{version}_ #{RAILS_APP_NAME} -m template.rb`
19
- end
20
-
21
- When /^I use the Rails (.+) generator to set up dragonfly$/ do |version|
22
- raise "Problem using the generator" unless `
23
- cd #{fixture_path(version)}/#{RAILS_APP_NAME} &&
24
- ./script/generate dragonfly_app images`
25
- end
26
-
27
- When /^I use the provided (.+) initializer$/ do |version|
28
- FileUtils.cp("#{FIXTURES_PATH}/dragonfly_setup.rb", "#{app_path(version)}/config/initializers")
18
+ rails _#{version}_ #{RAILS_APP_NAME} -m template.rb`
29
19
  end
30
20
 
31
21
  Then /^the cucumber features in my Rails (.+) app should pass$/ do |version|
@@ -12,7 +12,7 @@ ENV['PATH'] += ':' + extra_paths.join(':')
12
12
  # A hash of <name for reference> => <dragonfly uid> pairs
13
13
  TEMP_FILES = {}
14
14
 
15
- Dragonfly::App[:images].configure_with(Dragonfly::RMagickConfiguration)
15
+ Dragonfly::App[:images].configure_with(Dragonfly::Config::RMagickImages)
16
16
  Dragonfly::App[:files].configure do |c|
17
17
  c.register_analyser(Dragonfly::Analysis::FileCommandAnalyser)
18
18
  c.register_encoder(Dragonfly::Encoding::TransparentEncoder)
@@ -1,3 +1,4 @@
1
+ <%= flash[:notice] %>
1
2
  Look at this cover image!
2
3
  <%= image_tag @album.cover_image.url('200x100!') %>
3
4
  <%= link_to 'Index', albums_path %>
@@ -1,3 +1,4 @@
1
1
  # This is a hack to get the generated rails apps to use the version of dragonfly being worked on.
2
2
  $:.unshift(File.expand_path(File.dirname(__FILE__)+'/../../../../../lib'))
3
+ require 'dragonfly/rails/images'
3
4
 
@@ -1,12 +1,10 @@
1
- generate 'scaffold albums cover_image_uid:string'
2
- rake 'db:migrate'
3
-
4
- # Set up webrat and cucumber
1
+ gem 'rack-cache', :lib => 'rack/cache'
2
+ gem 'rmagick', :lib => 'RMagick'
5
3
  gem 'cucumber'
6
4
  generate 'cucumber'
7
5
 
8
- gem 'rack-cache', :lib => 'rack/cache'
9
- gem 'rmagick', :lib => 'RMagick'
6
+ generate 'scaffold albums cover_image_uid:string'
7
+ rake 'db:migrate'
10
8
 
11
9
  # Copy over all files from the template dir
12
10
  files_dir = File.expand_path(File.dirname(__FILE__) + '/../../files')
@@ -0,0 +1,16 @@
1
+ gem 'rack-cache', :require => 'rack/cache'
2
+ gem 'rmagick', :require => 'RMagick'
3
+
4
+ gem 'capybara'
5
+ gem 'cucumber-rails'
6
+ gem 'cucumber', '0.7.2'
7
+ gem 'rspec-rails', '2.0.0.beta.8'
8
+
9
+ generate 'cucumber:skeleton'
10
+
11
+ generate 'scaffold albums cover_image_uid:string'
12
+ rake 'db:migrate'
13
+
14
+ # Copy over all files from the template dir
15
+ files_dir = File.expand_path(File.dirname(__FILE__) + '/../../files')
16
+ run "cp -r #{files_dir}/** ."
data/lib/dragonfly.rb CHANGED
@@ -29,7 +29,29 @@ end
29
29
 
30
30
  autoload_files_in_dir("#{File.dirname(__FILE__)}/dragonfly", 'Dragonfly')
31
31
 
32
- require 'rubygems'
33
32
  require File.dirname(__FILE__) + '/dragonfly/core_ext/object'
34
33
  require File.dirname(__FILE__) + '/dragonfly/core_ext/string'
35
34
  require File.dirname(__FILE__) + '/dragonfly/core_ext/symbol'
35
+
36
+ module Dragonfly
37
+ class << self
38
+
39
+ def const_missing(const)
40
+ case const
41
+ when :RMagickConfiguration
42
+ puts "WARNING: RMagickConfiguration is deprecated and will be removed in future "+
43
+ "versions of Dragonfly. Please change to Dragonfly::Config::RMagickImages"
44
+ const_set(:RMagickConfiguration, Config::RMagickImages)
45
+ else
46
+ super
47
+ end
48
+ end
49
+
50
+ def active_record_macro(prefix, app)
51
+ already_extended = (class << ActiveRecord::Base; self; end).included_modules.include?(ActiveRecordExtensions)
52
+ ActiveRecord::Base.extend(ActiveRecordExtensions) unless already_extended
53
+ ActiveRecord::Base.register_dragonfly_app(prefix, app)
54
+ end
55
+
56
+ end
57
+ end
@@ -124,7 +124,7 @@ module Dragonfly
124
124
  end
125
125
 
126
126
  def methods_to_delegate_to_temp_object
127
- analyser.callable_methods
127
+ analyser.delegatable_methods
128
128
  end
129
129
 
130
130
  def can_delegate_to_temp_object?(meth)
@@ -1,5 +1,9 @@
1
1
  module Dragonfly
2
2
  class AnalyserList
3
3
  include Delegator
4
+
5
+ def initialize(app)
6
+ @app = app
7
+ end
4
8
  end
5
9
  end
@@ -2,6 +2,7 @@ module Dragonfly
2
2
  module Analysis
3
3
  class Base
4
4
 
5
+ include BelongsToApp
5
6
  include Delegatable
6
7
 
7
8
  end
@@ -26,11 +26,18 @@ module Dragonfly
26
26
  rmagick_image(image).number_colors
27
27
  end
28
28
  alias number_of_colors number_of_colours
29
+
30
+ def format(image)
31
+ rmagick_image(image).format.downcase.to_sym
32
+ end
29
33
 
30
34
  private
31
35
 
32
36
  def rmagick_image(image)
33
37
  Magick::Image.from_blob(image.data).first
38
+ rescue Magick::ImageMagickError => e
39
+ log.warn("Unable to handle content in #{self.class} - got:\n#{e}")
40
+ throw :unable_to_handle
34
41
  end
35
42
 
36
43
  end
data/lib/dragonfly/app.rb CHANGED
@@ -70,10 +70,9 @@ module Dragonfly
70
70
  end
71
71
 
72
72
  def initialize
73
- @analysers, @processors, @encoders = AnalyserList.new, ProcessorList.new, EncoderList.new
73
+ @analysers, @processors, @encoders = AnalyserList.new(self), ProcessorList.new(self), EncoderList.new(self)
74
74
  @parameters_class = Class.new(Parameters)
75
75
  @url_handler = UrlHandler.new(@parameters_class)
76
- initialize_temp_object_class
77
76
  end
78
77
 
79
78
  # @see Analysis::AnalyserList
@@ -86,8 +85,6 @@ module Dragonfly
86
85
  attr_reader :url_handler
87
86
  # @see Parameters
88
87
  attr_reader :parameters_class
89
- # @see TempObject, and ExtendedTempObject
90
- attr_reader :temp_object_class
91
88
 
92
89
  alias parameters parameters_class
93
90
 
@@ -134,7 +131,7 @@ module Dragonfly
134
131
  # @param [String, File, Tempfile, TempObject] initialization_object the object holding the data
135
132
  # @return [ExtendedTempObject] a temp_object holding the data
136
133
  def create_object(initialization_object)
137
- temp_object_class.new(initialization_object)
134
+ ExtendedTempObject.new(initialization_object, self)
138
135
  end
139
136
 
140
137
  # Fetch an object from the database and optionally transform
@@ -150,7 +147,7 @@ module Dragonfly
150
147
  # app.fetch('abcd1234', '20x20!') # returns a transformed temp_object, in this case with image data resized to 20x20
151
148
  # @see Parameters
152
149
  def fetch(uid, *args)
153
- temp_object = temp_object_class.new(datastore.retrieve(uid))
150
+ temp_object = ExtendedTempObject.new(datastore.retrieve(uid), self)
154
151
  temp_object.transform(*args)
155
152
  end
156
153
 
@@ -202,11 +199,6 @@ module Dragonfly
202
199
  end
203
200
 
204
201
  private
205
-
206
- def initialize_temp_object_class
207
- @temp_object_class = Class.new(ExtendedTempObject)
208
- @temp_object_class.app = self
209
- end
210
202
 
211
203
  def warn_with_info(message, env)
212
204
  log.warn "Got error: #{message}\nPath was #{env['PATH_INFO'].inspect} and query was #{env['QUERY_STRING'].inspect}"
@@ -0,0 +1,24 @@
1
+ require 'logger'
2
+
3
+ module Dragonfly
4
+ module BelongsToApp
5
+
6
+ # Exceptions
7
+ class NotConfigured < RuntimeError; end
8
+
9
+ attr_writer :app
10
+
11
+ def app
12
+ @app || raise(NotConfigured, "#{self.inspect} has no app set")
13
+ end
14
+
15
+ def app_set?
16
+ !!@app
17
+ end
18
+
19
+ def log
20
+ app_set? ? app.log : (@log ||= Logger.new(STDOUT))
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ module Dragonfly
2
+ module Config
3
+
4
+ module HerokuRailsImages
5
+
6
+ def self.apply_configuration(app, bucket_name)
7
+ app.configure_with(RMagickImages)
8
+ app.configure_with(RailsDefaults) do |c|
9
+ # Use S3 for production
10
+ if ::Rails.env == 'production'
11
+ c.datastore = Dragonfly::DataStorage::S3DataStore.new
12
+ c.datastore.configure do |d|
13
+ d.bucket_name = bucket_name
14
+ d.access_key_id = ENV['S3_KEY'] || raise("ENV variable 'S3_KEY' needs to be set - use\n\theroku config:add S3_KEY=XXXXXXXXX")
15
+ d.secret_access_key = ENV['S3_SECRET'] || raise("ENV variable 'S3_SECRET' needs to be set - use\n\theroku config:add S3_SECRET=XXXXXXXXX")
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,69 @@
1
+ module Dragonfly
2
+ module Config
3
+
4
+ # RMagickImages is a saved configuration for Dragonfly apps, which does the following:
5
+ # - registers an rmagick analyser
6
+ # - registers an rmagick processor
7
+ # - registers an rmagick encoder
8
+ # - adds parameter shortcuts like '280x140!', etc.
9
+ # Look at the source code for apply_configuration to see exactly how it configures the app.
10
+ module RMagickImages
11
+
12
+ def self.apply_configuration(app)
13
+ app.configure do |c|
14
+ c.register_analyser(Analysis::FileCommandAnalyser)
15
+ c.register_analyser(Analysis::RMagickAnalyser)
16
+ c.register_processor(Processing::RMagickProcessor)
17
+ c.register_encoder(Encoding::RMagickEncoder)
18
+ c.parameters.configure do |p|
19
+ p.default_format = :jpg
20
+ # Standard resizing like '30x40!', etc.
21
+ p.add_shortcut(Symbol) do |format|
22
+ {:format => format}
23
+ end
24
+ p.add_shortcut(/^\d*x\d*[><%^!]?$|^\d+@$/) do |geometry, match_data|
25
+ {
26
+ :processing_method => :resize,
27
+ :processing_options => {:geometry => geometry}
28
+ }
29
+ end
30
+ # Cropped resizing like '20x50#ne'
31
+ p.add_shortcut(/^(\d+)x(\d+)#(\w{1,2})?/) do |geometry, match_data|
32
+ {
33
+ :processing_method => :resize_and_crop,
34
+ :processing_options => {:width => match_data[1], :height => match_data[2], :gravity => match_data[3]}
35
+ }
36
+ end
37
+ # Cropping like '30x30+10+10ne'
38
+ p.add_shortcut(/^(\d+)x(\d+)([+-]\d+)([+-]\d+)(\w{1,2})?/) do |geometry, match_data|
39
+ {
40
+ :processing_method => :crop,
41
+ :processing_options => {
42
+ :width => match_data[1],
43
+ :height => match_data[2],
44
+ :x => match_data[3],
45
+ :y => match_data[4],
46
+ :gravity => match_data[5]
47
+ }
48
+ }
49
+ end
50
+ p.add_shortcut(/^\d*x/, Symbol) do |geometry, format|
51
+ p.hash_from_shortcut(geometry).merge(:format => format)
52
+ end
53
+ p.add_shortcut(:rotate, Numeric) do |_, amount|
54
+ {
55
+ :processing_method => :rotate,
56
+ :processing_options => {:amount => amount, :background_colour => '#0000'}
57
+ }
58
+ end
59
+ p.add_shortcut(:rotate, Numeric, Symbol) do |a, b, format|
60
+ p.hash_from_shortcut(a,b).merge(:format => format)
61
+ end
62
+ end
63
+ end
64
+
65
+ end
66
+
67
+ end
68
+ end
69
+ end