dragonfly 0.6.2 → 0.7.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.
- data/.gitignore +2 -0
- data/.specopts +2 -0
- data/.yardopts +11 -5
- data/Gemfile +22 -0
- data/Gemfile.rails.2.3.5 +13 -0
- data/History.md +49 -0
- data/README.md +18 -28
- data/Rakefile +24 -36
- data/VERSION +1 -1
- data/config.ru +4 -1
- data/dragonfly.gemspec +85 -99
- data/extra_docs/Analysers.md +66 -30
- data/extra_docs/Caching.md +22 -0
- data/extra_docs/Configuration.md +116 -0
- data/extra_docs/DataStorage.md +114 -14
- data/extra_docs/Encoding.md +62 -37
- data/extra_docs/GeneralUsage.md +118 -0
- data/extra_docs/Generators.md +92 -0
- data/extra_docs/Heroku.md +51 -0
- data/extra_docs/Index.md +8 -9
- data/extra_docs/MimeTypes.md +18 -17
- data/extra_docs/Models.md +251 -0
- data/extra_docs/Processing.md +94 -70
- data/extra_docs/Rack.md +53 -0
- data/extra_docs/Rails2.md +44 -0
- data/extra_docs/Rails3.md +51 -0
- data/extra_docs/Sinatra.md +21 -0
- data/extra_docs/URLs.md +114 -0
- data/features/images.feature +6 -7
- data/features/no_processing.feature +0 -6
- data/features/rails_2.3.5.feature +1 -1
- data/features/rails_3.0.0.rc.feature +8 -0
- data/features/steps/dragonfly_steps.rb +14 -12
- data/features/steps/rails_steps.rb +20 -9
- data/features/support/env.rb +10 -11
- data/fixtures/files/app/views/albums/new.html.erb +4 -4
- data/fixtures/files/app/views/albums/show.html.erb +1 -1
- data/fixtures/files/features/manage_album_images.feature +1 -1
- data/fixtures/files/features/step_definitions/{album_steps.rb → image_steps.rb} +4 -3
- data/fixtures/files/features/support/paths.rb +2 -0
- data/fixtures/files/features/text_images.feature +7 -0
- data/fixtures/rails_3.0.0.rc/template.rb +21 -0
- data/irbrc.rb +2 -1
- data/lib/dragonfly.rb +4 -16
- data/lib/dragonfly/{active_record_extensions.rb → active_model_extensions.rb} +1 -1
- data/lib/dragonfly/active_model_extensions/attachment.rb +146 -0
- data/lib/dragonfly/{active_record_extensions → active_model_extensions}/class_methods.rb +5 -6
- data/lib/dragonfly/{active_record_extensions → active_model_extensions}/instance_methods.rb +1 -1
- data/lib/dragonfly/{active_record_extensions → active_model_extensions}/validations.rb +5 -9
- data/lib/dragonfly/analyser.rb +59 -0
- data/lib/dragonfly/analysis/file_command_analyser.rb +1 -1
- data/lib/dragonfly/analysis/r_magick_analyser.rb +46 -31
- data/lib/dragonfly/app.rb +138 -173
- data/lib/dragonfly/config/heroku.rb +19 -0
- data/lib/dragonfly/config/r_magick.rb +37 -0
- data/lib/dragonfly/config/{rails_defaults.rb → rails.rb} +6 -7
- data/lib/dragonfly/configurable.rb +30 -27
- data/lib/dragonfly/core_ext/object.rb +1 -1
- data/lib/dragonfly/data_storage/file_data_store.rb +59 -26
- data/lib/dragonfly/data_storage/mongo_data_store.rb +65 -0
- data/lib/dragonfly/data_storage/s3data_store.rb +31 -12
- data/lib/dragonfly/encoder.rb +13 -0
- data/lib/dragonfly/encoding/r_magick_encoder.rb +10 -19
- data/lib/dragonfly/endpoint.rb +43 -0
- data/lib/dragonfly/function_manager.rb +65 -0
- data/lib/dragonfly/{processing/r_magick_text_processor.rb → generation/r_magick_generator.rb} +25 -11
- data/lib/dragonfly/generator.rb +9 -0
- data/lib/dragonfly/job.rb +290 -0
- data/lib/dragonfly/job_builder.rb +39 -0
- data/lib/dragonfly/job_definitions.rb +26 -0
- data/lib/dragonfly/job_endpoint.rb +17 -0
- data/lib/dragonfly/loggable.rb +28 -0
- data/lib/dragonfly/middleware.rb +21 -14
- data/lib/dragonfly/processing/r_magick_processor.rb +71 -48
- data/lib/dragonfly/processor.rb +9 -0
- data/lib/dragonfly/r_magick_utils.rb +24 -0
- data/lib/dragonfly/rails/images.rb +10 -7
- data/lib/dragonfly/routed_endpoint.rb +42 -0
- data/lib/dragonfly/serializer.rb +32 -0
- data/lib/dragonfly/simple_cache.rb +23 -0
- data/lib/dragonfly/simple_endpoint.rb +64 -0
- data/lib/dragonfly/temp_object.rb +77 -45
- data/spec/argument_matchers.rb +7 -17
- data/spec/dragonfly/active_model_extensions/active_model_setup.rb +97 -0
- data/spec/dragonfly/active_model_extensions/active_record_setup.rb +85 -0
- data/spec/dragonfly/{active_record_extensions → active_model_extensions}/model_spec.rb +282 -244
- data/spec/dragonfly/active_model_extensions/spec_helper.rb +11 -0
- data/spec/dragonfly/analyser_spec.rb +123 -0
- data/spec/dragonfly/analysis/file_command_analyser_spec.rb +2 -2
- data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +10 -1
- data/spec/dragonfly/app_spec.rb +175 -69
- data/spec/dragonfly/configurable_spec.rb +14 -0
- data/spec/dragonfly/data_storage/data_store_spec.rb +36 -9
- data/spec/dragonfly/data_storage/file_data_store_spec.rb +61 -38
- data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +18 -0
- data/spec/dragonfly/data_storage/s3_data_store_spec.rb +34 -39
- data/spec/dragonfly/deprecation_spec.rb +20 -0
- data/spec/dragonfly/function_manager_spec.rb +154 -0
- data/spec/dragonfly/generation/r_magick_generator_spec.rb +119 -0
- data/spec/dragonfly/job_builder_spec.rb +37 -0
- data/spec/dragonfly/job_definitions_spec.rb +35 -0
- data/spec/dragonfly/job_endpoint_spec.rb +66 -0
- data/spec/dragonfly/job_spec.rb +605 -0
- data/spec/dragonfly/loggable_spec.rb +80 -0
- data/spec/dragonfly/middleware_spec.rb +37 -17
- data/spec/dragonfly/processing/r_magick_processor_spec.rb +182 -166
- data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
- data/spec/dragonfly/serializer_spec.rb +61 -0
- data/spec/dragonfly/simple_cache_spec.rb +27 -0
- data/spec/dragonfly/simple_endpoint_spec.rb +78 -0
- data/spec/dragonfly/temp_object_spec.rb +154 -119
- data/spec/simple_matchers.rb +22 -0
- data/spec/spec_helper.rb +28 -4
- data/yard/templates/default/layout/html/layout.erb +18 -11
- metadata +89 -190
- data/config.rb +0 -5
- data/extra_docs/ActiveRecord.md +0 -196
- data/extra_docs/ExampleUseCases.md +0 -189
- data/extra_docs/GettingStarted.md +0 -114
- data/extra_docs/Shortcuts.md +0 -118
- data/extra_docs/UsingWithRails.md +0 -81
- data/features/rails_3.0.0.beta3.feature +0 -7
- data/fixtures/rails_3.0.0.beta3/template.rb +0 -16
- data/lib/dragonfly/active_record_extensions/attachment.rb +0 -170
- data/lib/dragonfly/analyser_list.rb +0 -9
- data/lib/dragonfly/analysis/base.rb +0 -10
- data/lib/dragonfly/belongs_to_app.rb +0 -24
- data/lib/dragonfly/config/heroku_rails_images.rb +0 -23
- data/lib/dragonfly/config/r_magick_images.rb +0 -69
- data/lib/dragonfly/config/r_magick_text.rb +0 -25
- data/lib/dragonfly/config/rails_images.rb +0 -13
- data/lib/dragonfly/data_storage/base.rb +0 -21
- data/lib/dragonfly/data_storage/base64_data_store.rb +0 -23
- data/lib/dragonfly/data_storage/transparent_data_store.rb +0 -21
- data/lib/dragonfly/delegatable.rb +0 -14
- data/lib/dragonfly/delegator.rb +0 -62
- data/lib/dragonfly/encoder_list.rb +0 -9
- data/lib/dragonfly/encoding/base.rb +0 -14
- data/lib/dragonfly/encoding/transparent_encoder.rb +0 -14
- data/lib/dragonfly/extended_temp_object.rb +0 -120
- data/lib/dragonfly/parameters.rb +0 -163
- data/lib/dragonfly/processing/base.rb +0 -10
- data/lib/dragonfly/processor_list.rb +0 -9
- data/lib/dragonfly/url_handler.rb +0 -147
- data/spec/dragonfly/active_record_extensions/attachment_spec.rb +0 -8
- data/spec/dragonfly/active_record_extensions/migration.rb +0 -42
- data/spec/dragonfly/active_record_extensions/models.rb +0 -6
- data/spec/dragonfly/active_record_extensions/spec_helper.rb +0 -24
- data/spec/dragonfly/belongs_to_app_spec.rb +0 -55
- data/spec/dragonfly/delegatable_spec.rb +0 -32
- data/spec/dragonfly/delegator_spec.rb +0 -145
- data/spec/dragonfly/extended_temp_object_spec.rb +0 -71
- data/spec/dragonfly/parameters_spec.rb +0 -298
- data/spec/dragonfly/processing/r_magick_text_processor_spec.rb +0 -84
- data/spec/dragonfly/url_handler_spec.rb +0 -247
- data/spec/dragonfly_spec.rb +0 -16
- data/spec/ginger_scenarios.rb +0 -13
data/extra_docs/Analysers.md
CHANGED
@@ -3,61 +3,97 @@ Analysers
|
|
3
3
|
|
4
4
|
Analysing data for things like width, mime_type, etc. come under the banner of Analysis.
|
5
5
|
|
6
|
-
|
6
|
+
You can register as many analysers as you like.
|
7
7
|
|
8
|
-
|
8
|
+
Let's say we have a Dragonfly app
|
9
9
|
|
10
|
-
|
10
|
+
app = Dragonfly[:images]
|
11
11
|
|
12
|
-
|
12
|
+
and an image object (actually a {Dragonfly::Job Job} object)...
|
13
13
|
|
14
|
-
|
15
|
-
the {Dragonfly::Analysis::RMagickAnalyser rmagick analyser}
|
14
|
+
image = app.fetch('some/uid')
|
16
15
|
|
17
|
-
|
16
|
+
...OR a Dragonfly model accessor...
|
18
17
|
|
19
|
-
|
18
|
+
image = @album.cover_image
|
20
19
|
|
21
|
-
|
22
|
-
# ...etc.
|
20
|
+
We can analyse it using any analysis methods that have been registered with the analyser.
|
23
21
|
|
24
|
-
|
22
|
+
RMagickAnalyser
|
23
|
+
---------------
|
24
|
+
The {Dragonfly::Analysis::RMagickAnalyser RMagickAnalyser} is registered by default by the
|
25
|
+
{Dragonfly::Config::RMagick RMagick configuration} used by 'dragonfly/rails/images'.
|
25
26
|
|
26
|
-
|
27
|
+
If not already registered:
|
27
28
|
|
28
|
-
|
29
|
+
app.analyser.register(Dragonfly::Analysis::RMagickAnalyser)
|
29
30
|
|
30
|
-
|
31
|
+
gives us these methods:
|
31
32
|
|
32
|
-
|
33
|
+
image.width # => 280
|
34
|
+
image.height # => 355
|
35
|
+
image.aspect_ratio # => 0.788732394366197
|
36
|
+
image.portrait? # => true
|
37
|
+
image.landscape? # => false
|
38
|
+
image.depth # => 8
|
39
|
+
image.number_of_colours # => 34703
|
40
|
+
image.format # => :png
|
33
41
|
|
34
|
-
|
35
|
-
|
36
|
-
|
42
|
+
FileCommandAnalyser
|
43
|
+
-------------------
|
44
|
+
The {Dragonfly::Analysis::FileCommandAnalyser FileCommandAnalyser} is registered by default by the
|
45
|
+
{Dragonfly::Config::Rails Rails configuration} used by 'dragonfly/rails/images'.
|
46
|
+
|
47
|
+
As the name suggests, it uses the UNIX 'file' command.
|
48
|
+
|
49
|
+
If not already registered:
|
50
|
+
|
51
|
+
app.analyser.register(Dragonfly::Analysis::FileCommandAnalyser)
|
52
|
+
|
53
|
+
gives us:
|
37
54
|
|
38
|
-
|
55
|
+
image.mime_type # => 'image/png'
|
56
|
+
|
57
|
+
It doesn't use the filesystem by default (it operates on in-memory strings), but we can make it do so by using
|
58
|
+
|
59
|
+
app.analyser.register(Dragonfly::Analysis::FileCommandAnalyser) do |a|
|
60
|
+
a.use_filesystem = true
|
61
|
+
end
|
39
62
|
|
40
63
|
Custom Analysers
|
41
64
|
----------------
|
42
65
|
|
43
|
-
To register a custom analyser
|
66
|
+
To register a single custom analyser:
|
67
|
+
|
68
|
+
app.analyser.add :wobbliness do |temp_object|
|
69
|
+
# can use temp_object.data, temp_object.path, temp_object.file, etc.
|
70
|
+
SomeLibrary.assess_wobbliness(temp_object.data)
|
71
|
+
end
|
72
|
+
|
73
|
+
image.wobbliness # => 71
|
74
|
+
|
75
|
+
You can create a class like the RMagick one above, in which case all public methods will be counted as analysis methods.
|
44
76
|
Each method takes the temp_object as its argument.
|
45
77
|
|
46
|
-
class MyAnalyser
|
47
|
-
|
78
|
+
class MyAnalyser
|
79
|
+
|
48
80
|
def coolness(temp_object)
|
49
|
-
# use temp_object.data, temp_object.path, etc...
|
50
81
|
temp_object.size / 30
|
51
82
|
end
|
52
83
|
|
53
|
-
|
84
|
+
def uglyness(temp_object)
|
85
|
+
`ugly -i #{temp_object.path}`
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def my_helper_method
|
91
|
+
# do stuff
|
92
|
+
end
|
54
93
|
|
55
94
|
end
|
56
95
|
|
57
|
-
app.
|
58
|
-
|
59
|
-
temp_object = app.create_object(File.new('path/to/image.png'))
|
60
|
-
|
61
|
-
temp_object.coolness # => 2067
|
96
|
+
app.analyser.register(MyAnalyser)
|
62
97
|
|
63
|
-
|
98
|
+
image.coolness # => -4.1
|
99
|
+
image.uglyness # => "VERY"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Caching
|
2
|
+
=======
|
3
|
+
|
4
|
+
Processing and encoding can be an expensive operation. The first time we visit the url,
|
5
|
+
the image is processed, and there might be a short delay and getting the response.
|
6
|
+
|
7
|
+
However, dragonfly apps send `Cache-Control` and `ETag` headers in the response, so we can easily put a caching
|
8
|
+
proxy like {http://varnish.projects.linpro.no Varnish}, {http://www.squid-cache.org Squid},
|
9
|
+
{http://tomayko.com/src/rack-cache/ Rack::Cache}, etc. in front of the app, so that subsequent requests are served
|
10
|
+
super-quickly straight out of the cache.
|
11
|
+
|
12
|
+
The file 'dragonfly/rails/images' puts Rack::Cache in front of Dragonfly by default.
|
13
|
+
|
14
|
+
Given a dragonfly app
|
15
|
+
|
16
|
+
app = Dragonfly[:images]
|
17
|
+
|
18
|
+
You can configure the 'Cache-Control' header with
|
19
|
+
|
20
|
+
app.cache_duration = 3600*24*365*3 # time in seconds
|
21
|
+
|
22
|
+
For a well-written discussion of Cache-Control and ETag headers, see {http://tomayko.com/writings/things-caches-do}.
|
@@ -0,0 +1,116 @@
|
|
1
|
+
Configuration
|
2
|
+
=============
|
3
|
+
|
4
|
+
Given a Dragonfly app
|
5
|
+
|
6
|
+
app = Dragonfly[:app_name]
|
7
|
+
|
8
|
+
Configuration can either be done like so...
|
9
|
+
|
10
|
+
app.configure do |c|
|
11
|
+
c.url_path_prefix = '/media'
|
12
|
+
# ...
|
13
|
+
end
|
14
|
+
|
15
|
+
...or directly like so...
|
16
|
+
|
17
|
+
app.url_path_prefix = '/media'
|
18
|
+
|
19
|
+
The defaults should be fairly sensible, but you can tweak a number of things if you wish.
|
20
|
+
Here is an example of an app with all attributes configured:
|
21
|
+
|
22
|
+
app.configure do |c|
|
23
|
+
c.datastore = SomeCustomDataStore.new :egg => 'head' # defaults to FileDataStore
|
24
|
+
|
25
|
+
c.cache_duration = 3600*24*365*2 # defaults to 1 year # (1 year)
|
26
|
+
c.fallback_mime_type = 'something/mental' # defaults to application/octet-stream
|
27
|
+
c.log = Logger.new($stdout) # defaults to Logger.new('/var/tmp/dragonfly.log')
|
28
|
+
c.infer_mime_type_from_file_ext = false # defaults to true
|
29
|
+
|
30
|
+
c.url_path_prefix = '/images' # defaults to nil
|
31
|
+
c.url_host = 'http://some.domain.com:4000' # defaults to nil
|
32
|
+
|
33
|
+
c.protect_from_dos_attacks = true # defaults to false - adds a SHA parameter on the end of urls
|
34
|
+
c.secret = 'This is my secret yeh!!' # should set this if concerned about DOS attacks
|
35
|
+
|
36
|
+
c.analyser.register(MyAnalyser) # See 'Analysers' for more details
|
37
|
+
c.processor.register(MyProcessor, :type => :fig) # See 'Processing' for more details
|
38
|
+
c.encoder.register(MyEncoder) do |e| # See 'Encoding' for more details
|
39
|
+
e.some_value = 'geg'
|
40
|
+
end
|
41
|
+
c.generator.register(MyGenerator) # See 'Generators' for more details
|
42
|
+
|
43
|
+
c.register_mime_type(:egg, 'fried/egg') # See 'MimeTypes' for more details
|
44
|
+
|
45
|
+
c.job :black_and_white do |size| # Job shortcut - lets you do image.black_and_white('30x30')
|
46
|
+
process :greyscale
|
47
|
+
process :thumb, size
|
48
|
+
encode :gif
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
Where is configuration done?
|
53
|
+
----------------------------
|
54
|
+
In Rails, it should be done in an initializer, e.g. 'config/initializers/dragonfly.rb'.
|
55
|
+
Otherwise it should be done anywhere where general setup is done, early on.
|
56
|
+
|
57
|
+
Saved configurations
|
58
|
+
====================
|
59
|
+
Saved configurations are useful if you often configure the app the same way.
|
60
|
+
There are a number that are provided with Dragonfly:
|
61
|
+
|
62
|
+
RMagick
|
63
|
+
-------
|
64
|
+
|
65
|
+
app.configure_with(:rmagick)
|
66
|
+
|
67
|
+
The {Dragonfly::Config::RMagick RMagick configuration} registers the app with the {Dragonfly::Analysis::RMagickAnalyser RMagickAnalyser}, {Dragonfly::Processing::RMagickProcessor RMagickProcessor},
|
68
|
+
{Dragonfly::Encoding::RMagickEncoder RMagickEncoder} and {Dragonfly::Generation::RMagickGenerator RMagickGenerator}, and adds the 'job shortcuts'
|
69
|
+
`thumb`, `jpg`, `png` and `gif`.
|
70
|
+
|
71
|
+
The file 'dragonfly/rails/images' does this for you.
|
72
|
+
|
73
|
+
Rails
|
74
|
+
-----
|
75
|
+
|
76
|
+
app.configure_with(:rails)
|
77
|
+
|
78
|
+
The {Dragonfly::Config::Rails Rails configuration} points the log to the Rails logger, configures the file data store root path, sets the url_path_prefix to /media, and
|
79
|
+
registers the {Dragonfly::Analysis::FileCommandAnalyser FileCommandAnalyser} for helping with mime_type validations.
|
80
|
+
|
81
|
+
The file 'dragonfly/rails/images' does this for you.
|
82
|
+
|
83
|
+
Heroku
|
84
|
+
------
|
85
|
+
|
86
|
+
app.configure_with(:heroku, 's3_bucket_name')
|
87
|
+
|
88
|
+
The {Dragonfly::Config::Heroku Heroku configuration} configures it to use the {Dragonfly::DataStorage::S3DataStore}, using Heroku's config attributes.
|
89
|
+
See {file:Heroku} for more info.
|
90
|
+
|
91
|
+
Custom Saved Configuration
|
92
|
+
--------------------------
|
93
|
+
You can create your own saved configuration with any object that responds to 'apply_configuration':
|
94
|
+
|
95
|
+
module MyConfiguration
|
96
|
+
|
97
|
+
def self.apply_configuration(app, *args)
|
98
|
+
app.configure do |c|
|
99
|
+
c.url_path_prefix = '/hello/beans'
|
100
|
+
c.processor.register(MyProcessor)
|
101
|
+
# ...
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
Then to configure:
|
108
|
+
|
109
|
+
app.configure_with(MyConfiguration, :any_other => :args) # other args get passed through to apply_configuration
|
110
|
+
|
111
|
+
You can also carry on configuring by passing a block
|
112
|
+
|
113
|
+
app.configure_with(MyConfiguration) do |c|
|
114
|
+
c.any_extra = :config_here
|
115
|
+
# ...
|
116
|
+
end
|
data/extra_docs/DataStorage.md
CHANGED
@@ -1,33 +1,133 @@
|
|
1
1
|
Data Storage
|
2
2
|
============
|
3
3
|
|
4
|
-
Each dragonfly app has a datastore.
|
4
|
+
Each dragonfly app has a key-value datastore to store the content.
|
5
|
+
Lets say we have an app
|
5
6
|
|
6
|
-
Dragonfly
|
7
|
-
|
8
|
-
By default it uses the file data store, but you can configure it to use
|
9
|
-
a custom data store (e.g. S3, SQL, CouchDB, etc.) by registering one with the correct interface, namely
|
10
|
-
having `store`, `retrieve` and `destroy`.
|
7
|
+
app = Dragonfly[:my_app_name]
|
11
8
|
|
12
|
-
|
9
|
+
Then we can store data like so:
|
13
10
|
|
14
|
-
|
15
|
-
|
11
|
+
uid = app.store('SOME CONTENT') # Can pass in a String, File or Tempfile
|
12
|
+
|
13
|
+
We can also save metadata at the same time, and give it a name and format (if you pass in a File object the filename is used by default)
|
14
|
+
|
15
|
+
uid = app.store('SOME CONTENT',
|
16
|
+
:meta => {:time => Time.now},
|
17
|
+
:name => 'great_content.txt',
|
18
|
+
:format => :txt
|
19
|
+
)
|
20
|
+
|
21
|
+
We can get content with
|
22
|
+
|
23
|
+
content = app.fetch(uid)
|
24
|
+
content.data # "SOME CONTENT"
|
25
|
+
|
26
|
+
We can also get the extra saved attributes
|
27
|
+
|
28
|
+
content.meta # {:time => Sat Aug 14 12:04:13 +0100 2010}
|
29
|
+
content.name # 'great_content.txt'
|
30
|
+
content.format # :txt
|
31
|
+
|
32
|
+
We can destroy it with
|
33
|
+
|
34
|
+
app.destroy(uid)
|
35
|
+
|
36
|
+
You can create your own datastore, or use one of the provided ones as outlined below.
|
37
|
+
|
38
|
+
File datastore
|
39
|
+
--------------
|
40
|
+
The {Dragonfly::DataStorage::FileDataStore FileDataStore} stores data on the local filesystem.
|
41
|
+
|
42
|
+
It is used by default.
|
43
|
+
|
44
|
+
If for whatever reason you need to configure it again:
|
45
|
+
|
46
|
+
# shouldn't need this - it is the default
|
47
|
+
app.datastore = Dragonfly::DataStorage::FileDataStore.new
|
48
|
+
|
49
|
+
app.datastore.configure do |d|
|
50
|
+
d.root_path = '/my/custom/path' # defaults to /var/tmp/dragonfly
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
S3 datastore
|
55
|
+
------------
|
56
|
+
To configure with the {Dragonfly::DataStorage::S3DataStore S3DataStore}:
|
57
|
+
|
58
|
+
app.datastore = Dragonfly::DataStorage::S3DataStore.new
|
59
|
+
|
60
|
+
app.datastore.configure do |d|
|
61
|
+
c.bucket_name = 'my_bucket'
|
62
|
+
c.access_key_id = 'salfjasd34u23'
|
63
|
+
c.secret_access_key = '8u2u3rhkhfo23...'
|
64
|
+
end
|
65
|
+
|
66
|
+
You can also pass these options to `S3DataStore.new` as an options hash.
|
67
|
+
|
68
|
+
|
69
|
+
Mongo datastore
|
70
|
+
---------------
|
71
|
+
To configure with the {Dragonfly::DataStorage::MongoDataStore MongoDataStore}:
|
72
|
+
|
73
|
+
app.datastore = Dragonfly::DataStorage::MongoDataStore.new
|
74
|
+
|
75
|
+
It won't normally need configuring, but if you wish to:
|
76
|
+
|
77
|
+
app.datastore.configure do |d|
|
78
|
+
c.host = 'http://egg.heads:5000' # defaults to localhost
|
79
|
+
c.port = '27018' # defaults to mongo default (27017)
|
80
|
+
c.database = 'my_database' # defaults to 'dragonfly'
|
81
|
+
end
|
82
|
+
|
83
|
+
You can also pass these options to `MongoDataStore.new` as an options hash.
|
84
|
+
|
85
|
+
Custom datastore
|
86
|
+
----------------
|
87
|
+
Data stores are key-value in nature, and need to implement 3 methods: `store`, `retrieve` and `destroy`.
|
88
|
+
|
89
|
+
class MyDataStore
|
90
|
+
|
91
|
+
def store(temp_object, opts={})
|
92
|
+
# ... use temp_object.data, temp_object.file, temp_object.path, etc. ...
|
93
|
+
# ... can also make use of temp_object.name, temp_object.format, temp_object.meta
|
94
|
+
# store and return the uid
|
16
95
|
'return_some_unique_uid'
|
17
96
|
end
|
18
97
|
|
19
98
|
def retrieve(uid)
|
20
|
-
#
|
99
|
+
# return an array containing
|
100
|
+
[
|
101
|
+
content, # either a File, String or Tempfile
|
102
|
+
extra_data # Hash with optional keys :meta, :name, :format
|
103
|
+
]
|
21
104
|
end
|
22
|
-
|
105
|
+
|
23
106
|
def destroy(uid)
|
24
107
|
# find the content and destroy
|
25
108
|
end
|
26
109
|
|
27
110
|
end
|
28
111
|
|
29
|
-
You can now configure the app to use
|
112
|
+
You can now configure the app to use your datastore:
|
113
|
+
|
114
|
+
Dragonfly[:my_app_name].datastore = MyDataStore.new
|
30
115
|
|
31
|
-
|
116
|
+
Notice that `store` takes a second `opts` argument.
|
117
|
+
Any options other than `meta`, `name` and `format` get passed through to here, so calling
|
118
|
+
|
119
|
+
uid = app.store('SOME CONTENT',
|
120
|
+
:name => 'great_content.txt',
|
121
|
+
:some_other => :option
|
122
|
+
)
|
123
|
+
|
124
|
+
will be split inside `store` like so:
|
125
|
+
|
126
|
+
def store(temp_object, opts={})
|
127
|
+
temp_object.data # "SOME CONTENT"
|
128
|
+
temp_object.name # 'great_content.txt'
|
129
|
+
opts # {:some_other => :option}
|
130
|
+
# ...
|
131
|
+
end
|
32
132
|
|
33
|
-
|
133
|
+
# ...
|
data/extra_docs/Encoding.md
CHANGED
@@ -1,58 +1,83 @@
|
|
1
1
|
Encoding
|
2
2
|
========
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
Changing the format of data, but not changing the data itself,
|
5
|
+
e.g. converting to gif format, comes under the banner of Encoding.
|
6
6
|
|
7
|
-
|
8
|
-
the mime-type is detected by the analyser).
|
7
|
+
You can register as many encoders as you like.
|
9
8
|
|
10
|
-
|
9
|
+
Let's say we have a Dragonfly app
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
app = Dragonfly[:images]
|
12
|
+
|
13
|
+
and an image object (actually a {Dragonfly::Job Job} object)...
|
14
|
+
|
15
|
+
image = app.fetch('some/uid')
|
16
|
+
|
17
|
+
...OR a Dragonfly model accessor...
|
18
|
+
|
19
|
+
image = @album.cover_image
|
20
|
+
|
21
|
+
We can encode it to any format registered with the encoder.
|
15
22
|
|
16
|
-
|
23
|
+
RMagickEncoder
|
24
|
+
----------------
|
25
|
+
The {Dragonfly::Encoding::RMagickEncoder RMagickEncoder} is registered by default by
|
26
|
+
the {Dragonfly::Config::RMagick RMagick configuration} used by 'dragonfly/rails/images'.
|
17
27
|
|
18
|
-
|
19
|
-
app.register_encoder(Dragonfly::Encoding::RMagickEncoder)
|
28
|
+
If not already registered:
|
20
29
|
|
21
|
-
|
30
|
+
app.encoder.register(Dragonfly::Encoding::RMagickEncoder)
|
31
|
+
|
32
|
+
gives us:
|
33
|
+
|
34
|
+
image.encode(:jpg)
|
35
|
+
image.encode(:gif)
|
36
|
+
image.encode(:png)
|
37
|
+
image.encode(:tiff)
|
38
|
+
|
39
|
+
and various other formats (see {Dragonfly::Encoding::RMagickEncoder RMagickEncoder})
|
40
|
+
|
41
|
+
Lazy evaluation
|
42
|
+
---------------
|
22
43
|
|
23
|
-
|
44
|
+
gif_image = image.encode(:gif)
|
24
45
|
|
25
|
-
|
26
|
-
temp_object.encode!(:gif) # => encodes its own data as a 'png'
|
46
|
+
doesn't actually do anything until you call something on the returned {Dragonfly::Job Job} object, like `url`, `data`, etc.
|
27
47
|
|
28
|
-
|
48
|
+
Bang method
|
49
|
+
-----------
|
29
50
|
|
30
|
-
|
51
|
+
image.encode!(:gif)
|
52
|
+
|
53
|
+
modifies the image object itself, rather than returning a new object.
|
31
54
|
|
32
55
|
Custom Encoders
|
33
56
|
---------------
|
34
57
|
|
35
|
-
To register a custom encoder,
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
def encode(temp_object, format, encoding={})
|
43
|
-
if format.to_s == 'yo'
|
44
|
-
#... encode and return a String, File, Tempfile or TempObject
|
45
|
-
else
|
46
|
-
throw :unable_to_handle
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
58
|
+
To register a custom encoder, for e.g. pdf format:
|
59
|
+
|
60
|
+
app.encoder.add do |temp_object, format|
|
61
|
+
throw :unable_to_handle unless format == :pdf
|
62
|
+
# use temp_object.data, temp_object.path, temp_object.file, etc.
|
63
|
+
SomeLibrary.convert_to_pdf(temp_object.data)
|
64
|
+
# return a String, File or Tempfile
|
50
65
|
end
|
51
|
-
|
52
|
-
app.register_encoder(MyEncoder)
|
53
66
|
|
54
|
-
|
67
|
+
pdf_image = image.encode(:pdf)
|
68
|
+
|
69
|
+
If `:unable_to_handle` is thrown, the next most recently registered encoder is used, and so on.
|
70
|
+
|
71
|
+
Alternatively you can create a class like the RMagick one above, which implements the method `encode`, and register this.
|
72
|
+
|
73
|
+
class MyEncoder
|
74
|
+
|
75
|
+
def encode(temp_object, format, *args)
|
76
|
+
SomeLib.encode(temp_object.data, format, *args)
|
77
|
+
end
|
55
78
|
|
56
|
-
app.register_encoder(MyEncoder) do |e|
|
57
|
-
e.some_attribute = 'hello'
|
58
79
|
end
|
80
|
+
|
81
|
+
app.encoder.register(MyEncoder)
|
82
|
+
|
83
|
+
pdf_image = image.encode(:pdf, :some => :args)
|