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.

Files changed (157) hide show
  1. data/.gitignore +2 -0
  2. data/.specopts +2 -0
  3. data/.yardopts +11 -5
  4. data/Gemfile +22 -0
  5. data/Gemfile.rails.2.3.5 +13 -0
  6. data/History.md +49 -0
  7. data/README.md +18 -28
  8. data/Rakefile +24 -36
  9. data/VERSION +1 -1
  10. data/config.ru +4 -1
  11. data/dragonfly.gemspec +85 -99
  12. data/extra_docs/Analysers.md +66 -30
  13. data/extra_docs/Caching.md +22 -0
  14. data/extra_docs/Configuration.md +116 -0
  15. data/extra_docs/DataStorage.md +114 -14
  16. data/extra_docs/Encoding.md +62 -37
  17. data/extra_docs/GeneralUsage.md +118 -0
  18. data/extra_docs/Generators.md +92 -0
  19. data/extra_docs/Heroku.md +51 -0
  20. data/extra_docs/Index.md +8 -9
  21. data/extra_docs/MimeTypes.md +18 -17
  22. data/extra_docs/Models.md +251 -0
  23. data/extra_docs/Processing.md +94 -70
  24. data/extra_docs/Rack.md +53 -0
  25. data/extra_docs/Rails2.md +44 -0
  26. data/extra_docs/Rails3.md +51 -0
  27. data/extra_docs/Sinatra.md +21 -0
  28. data/extra_docs/URLs.md +114 -0
  29. data/features/images.feature +6 -7
  30. data/features/no_processing.feature +0 -6
  31. data/features/rails_2.3.5.feature +1 -1
  32. data/features/rails_3.0.0.rc.feature +8 -0
  33. data/features/steps/dragonfly_steps.rb +14 -12
  34. data/features/steps/rails_steps.rb +20 -9
  35. data/features/support/env.rb +10 -11
  36. data/fixtures/files/app/views/albums/new.html.erb +4 -4
  37. data/fixtures/files/app/views/albums/show.html.erb +1 -1
  38. data/fixtures/files/features/manage_album_images.feature +1 -1
  39. data/fixtures/files/features/step_definitions/{album_steps.rb → image_steps.rb} +4 -3
  40. data/fixtures/files/features/support/paths.rb +2 -0
  41. data/fixtures/files/features/text_images.feature +7 -0
  42. data/fixtures/rails_3.0.0.rc/template.rb +21 -0
  43. data/irbrc.rb +2 -1
  44. data/lib/dragonfly.rb +4 -16
  45. data/lib/dragonfly/{active_record_extensions.rb → active_model_extensions.rb} +1 -1
  46. data/lib/dragonfly/active_model_extensions/attachment.rb +146 -0
  47. data/lib/dragonfly/{active_record_extensions → active_model_extensions}/class_methods.rb +5 -6
  48. data/lib/dragonfly/{active_record_extensions → active_model_extensions}/instance_methods.rb +1 -1
  49. data/lib/dragonfly/{active_record_extensions → active_model_extensions}/validations.rb +5 -9
  50. data/lib/dragonfly/analyser.rb +59 -0
  51. data/lib/dragonfly/analysis/file_command_analyser.rb +1 -1
  52. data/lib/dragonfly/analysis/r_magick_analyser.rb +46 -31
  53. data/lib/dragonfly/app.rb +138 -173
  54. data/lib/dragonfly/config/heroku.rb +19 -0
  55. data/lib/dragonfly/config/r_magick.rb +37 -0
  56. data/lib/dragonfly/config/{rails_defaults.rb → rails.rb} +6 -7
  57. data/lib/dragonfly/configurable.rb +30 -27
  58. data/lib/dragonfly/core_ext/object.rb +1 -1
  59. data/lib/dragonfly/data_storage/file_data_store.rb +59 -26
  60. data/lib/dragonfly/data_storage/mongo_data_store.rb +65 -0
  61. data/lib/dragonfly/data_storage/s3data_store.rb +31 -12
  62. data/lib/dragonfly/encoder.rb +13 -0
  63. data/lib/dragonfly/encoding/r_magick_encoder.rb +10 -19
  64. data/lib/dragonfly/endpoint.rb +43 -0
  65. data/lib/dragonfly/function_manager.rb +65 -0
  66. data/lib/dragonfly/{processing/r_magick_text_processor.rb → generation/r_magick_generator.rb} +25 -11
  67. data/lib/dragonfly/generator.rb +9 -0
  68. data/lib/dragonfly/job.rb +290 -0
  69. data/lib/dragonfly/job_builder.rb +39 -0
  70. data/lib/dragonfly/job_definitions.rb +26 -0
  71. data/lib/dragonfly/job_endpoint.rb +17 -0
  72. data/lib/dragonfly/loggable.rb +28 -0
  73. data/lib/dragonfly/middleware.rb +21 -14
  74. data/lib/dragonfly/processing/r_magick_processor.rb +71 -48
  75. data/lib/dragonfly/processor.rb +9 -0
  76. data/lib/dragonfly/r_magick_utils.rb +24 -0
  77. data/lib/dragonfly/rails/images.rb +10 -7
  78. data/lib/dragonfly/routed_endpoint.rb +42 -0
  79. data/lib/dragonfly/serializer.rb +32 -0
  80. data/lib/dragonfly/simple_cache.rb +23 -0
  81. data/lib/dragonfly/simple_endpoint.rb +64 -0
  82. data/lib/dragonfly/temp_object.rb +77 -45
  83. data/spec/argument_matchers.rb +7 -17
  84. data/spec/dragonfly/active_model_extensions/active_model_setup.rb +97 -0
  85. data/spec/dragonfly/active_model_extensions/active_record_setup.rb +85 -0
  86. data/spec/dragonfly/{active_record_extensions → active_model_extensions}/model_spec.rb +282 -244
  87. data/spec/dragonfly/active_model_extensions/spec_helper.rb +11 -0
  88. data/spec/dragonfly/analyser_spec.rb +123 -0
  89. data/spec/dragonfly/analysis/file_command_analyser_spec.rb +2 -2
  90. data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +10 -1
  91. data/spec/dragonfly/app_spec.rb +175 -69
  92. data/spec/dragonfly/configurable_spec.rb +14 -0
  93. data/spec/dragonfly/data_storage/data_store_spec.rb +36 -9
  94. data/spec/dragonfly/data_storage/file_data_store_spec.rb +61 -38
  95. data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +18 -0
  96. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +34 -39
  97. data/spec/dragonfly/deprecation_spec.rb +20 -0
  98. data/spec/dragonfly/function_manager_spec.rb +154 -0
  99. data/spec/dragonfly/generation/r_magick_generator_spec.rb +119 -0
  100. data/spec/dragonfly/job_builder_spec.rb +37 -0
  101. data/spec/dragonfly/job_definitions_spec.rb +35 -0
  102. data/spec/dragonfly/job_endpoint_spec.rb +66 -0
  103. data/spec/dragonfly/job_spec.rb +605 -0
  104. data/spec/dragonfly/loggable_spec.rb +80 -0
  105. data/spec/dragonfly/middleware_spec.rb +37 -17
  106. data/spec/dragonfly/processing/r_magick_processor_spec.rb +182 -166
  107. data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
  108. data/spec/dragonfly/serializer_spec.rb +61 -0
  109. data/spec/dragonfly/simple_cache_spec.rb +27 -0
  110. data/spec/dragonfly/simple_endpoint_spec.rb +78 -0
  111. data/spec/dragonfly/temp_object_spec.rb +154 -119
  112. data/spec/simple_matchers.rb +22 -0
  113. data/spec/spec_helper.rb +28 -4
  114. data/yard/templates/default/layout/html/layout.erb +18 -11
  115. metadata +89 -190
  116. data/config.rb +0 -5
  117. data/extra_docs/ActiveRecord.md +0 -196
  118. data/extra_docs/ExampleUseCases.md +0 -189
  119. data/extra_docs/GettingStarted.md +0 -114
  120. data/extra_docs/Shortcuts.md +0 -118
  121. data/extra_docs/UsingWithRails.md +0 -81
  122. data/features/rails_3.0.0.beta3.feature +0 -7
  123. data/fixtures/rails_3.0.0.beta3/template.rb +0 -16
  124. data/lib/dragonfly/active_record_extensions/attachment.rb +0 -170
  125. data/lib/dragonfly/analyser_list.rb +0 -9
  126. data/lib/dragonfly/analysis/base.rb +0 -10
  127. data/lib/dragonfly/belongs_to_app.rb +0 -24
  128. data/lib/dragonfly/config/heroku_rails_images.rb +0 -23
  129. data/lib/dragonfly/config/r_magick_images.rb +0 -69
  130. data/lib/dragonfly/config/r_magick_text.rb +0 -25
  131. data/lib/dragonfly/config/rails_images.rb +0 -13
  132. data/lib/dragonfly/data_storage/base.rb +0 -21
  133. data/lib/dragonfly/data_storage/base64_data_store.rb +0 -23
  134. data/lib/dragonfly/data_storage/transparent_data_store.rb +0 -21
  135. data/lib/dragonfly/delegatable.rb +0 -14
  136. data/lib/dragonfly/delegator.rb +0 -62
  137. data/lib/dragonfly/encoder_list.rb +0 -9
  138. data/lib/dragonfly/encoding/base.rb +0 -14
  139. data/lib/dragonfly/encoding/transparent_encoder.rb +0 -14
  140. data/lib/dragonfly/extended_temp_object.rb +0 -120
  141. data/lib/dragonfly/parameters.rb +0 -163
  142. data/lib/dragonfly/processing/base.rb +0 -10
  143. data/lib/dragonfly/processor_list.rb +0 -9
  144. data/lib/dragonfly/url_handler.rb +0 -147
  145. data/spec/dragonfly/active_record_extensions/attachment_spec.rb +0 -8
  146. data/spec/dragonfly/active_record_extensions/migration.rb +0 -42
  147. data/spec/dragonfly/active_record_extensions/models.rb +0 -6
  148. data/spec/dragonfly/active_record_extensions/spec_helper.rb +0 -24
  149. data/spec/dragonfly/belongs_to_app_spec.rb +0 -55
  150. data/spec/dragonfly/delegatable_spec.rb +0 -32
  151. data/spec/dragonfly/delegator_spec.rb +0 -145
  152. data/spec/dragonfly/extended_temp_object_spec.rb +0 -71
  153. data/spec/dragonfly/parameters_spec.rb +0 -298
  154. data/spec/dragonfly/processing/r_magick_text_processor_spec.rb +0 -84
  155. data/spec/dragonfly/url_handler_spec.rb +0 -247
  156. data/spec/dragonfly_spec.rb +0 -16
  157. data/spec/ginger_scenarios.rb +0 -13
@@ -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
- Let's say we have a dragonfly app called 'images'
6
+ You can register as many analysers as you like.
7
7
 
8
- app = Dragonfly::App[:images]
8
+ Let's say we have a Dragonfly app
9
9
 
10
- Data gets passed around between the datastore, processor, analyser, etc. in the form of an {Dragonfly::ExtendedTempObject ExtendedTempObject}.
10
+ app = Dragonfly[:images]
11
11
 
12
- temp_object = app.create_object(File.new('path/to/image.png'))
12
+ and an image object (actually a {Dragonfly::Job Job} object)...
13
13
 
14
- This object will have any methods which have been registered with the analyser. For example, registering
15
- the {Dragonfly::Analysis::RMagickAnalyser rmagick analyser}
14
+ image = app.fetch('some/uid')
16
15
 
17
- app.register_analyser(Dragonfly::Analysis::RMagickAnalyser)
16
+ ...OR a Dragonfly model accessor...
18
17
 
19
- give us the methods `width`, `height`, `depth` and `number_of_colours` (or `number_of_colors`).
18
+ image = @album.cover_image
20
19
 
21
- temp_object.width # => 280
22
- # ...etc.
20
+ We can analyse it using any analysis methods that have been registered with the analyser.
23
21
 
24
- Registering the {Dragonfly::Analysis::FileCommandAnalyser 'file' command analyser}
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
- app.register_analyser(Dragonfly::Analysis::FileCommandAnalyser)
27
+ If not already registered:
27
28
 
28
- gives us the method `mime_type`, which is necessary for the app to serve the file properly.
29
+ app.analyser.register(Dragonfly::Analysis::RMagickAnalyser)
29
30
 
30
- temp_object.mime_type # => 'image/png'
31
+ gives us these methods:
31
32
 
32
- As the file command analyser is {Dragonfly::Configurable configurable}, we can configure it as we register it if we need to
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
- app.register_analyser(Dragonfly::Analysis::FileCommandAnalyser) do |a|
35
- a.file_command = '/usr/bin/file'
36
- end
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
- The saved configuration {Dragonfly::Config::RMagickImages RMagickImages} registers the above two analysers automatically.
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, derive from {Dragonfly::Analysis::Base Analysis::Base} and register.
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 < Dragonfly::Analysis::Base
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
- # ... add as many methods as you wish
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.register_analyser(MyAnalyser)
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
- You can register multiple analysers.
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
@@ -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::App[:my_app_name].datastore
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
- class MyDataStore < Dragonfly::DataStorage::Base
9
+ Then we can store data like so:
13
10
 
14
- def store(temp_object)
15
- # ... use temp_object.data, temp_object.file, or temp_object.path and store
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
- # find the content and return either a data string, a file, a tempfile or a Dragonfly::TempObject
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 this datastore like so
112
+ You can now configure the app to use your datastore:
113
+
114
+ Dragonfly[:my_app_name].datastore = MyDataStore.new
30
115
 
31
- Dragonfly::App[:my_app_name].datastore = MyDataStore.new
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
- If you want your datastore to be configurable, you can include the {Dragonfly::Configurable Configurable} module.
133
+ # ...
@@ -1,58 +1,83 @@
1
1
  Encoding
2
2
  ========
3
3
 
4
- 'Encoding' encapsulates the idea of a format (e.g. 'png', 'jpeg', 'doc', 'txt', etc.), and any encoding options
5
- (e.g. bit_rate, etc.).
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
- It is up to the encoder to modify the data according to the requested format (note the format is not the same as the mime-type;
8
- the mime-type is detected by the analyser).
7
+ You can register as many encoders as you like.
9
8
 
10
- The encoder needs to implement a single method, `encode`, which takes a {Dragonfly::ExtendedTempObject temp_object}, a format, and encoding options as arguments.
9
+ Let's say we have a Dragonfly app
11
10
 
12
- def encode(temp_object, format, encoding={})
13
- #... encode and return a String, File, Tempfile or TempObject
14
- end
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
- Let's say we register the {Dragonfly::Encoding::RMagickEncoder rmagick encoder} to our dragonfly app called 'images'
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
- app = Dragonfly::App[:images]
19
- app.register_encoder(Dragonfly::Encoding::RMagickEncoder)
28
+ If not already registered:
20
29
 
21
- Then we can encode {Dragonfly::ExtendedTempObject temp_objects} to formats recognised by the RMagickEncoder
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
- temp_object = app.create_object(File.new('path/to/image.png'))
44
+ gif_image = image.encode(:gif)
24
45
 
25
- temp_object.encode(:png) # => returns a new temp_object with data encoded as 'png'
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
- temp_object.encode(:doc) # => throws :unable_to_handle
48
+ Bang method
49
+ -----------
29
50
 
30
- The saved configuration {Dragonfly::Config::RMagickImages RMagickImages} registers the above encoder automatically.
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, derive from {Dragonfly::Encoding::Base Encoding::Base} and register.
36
- As described above, you need to implement the `encode` method.
37
- If the encoder can't handle a format, it should throw `:unable_to_handle`, and control will pass to the previously
38
- registered encoder, and so on.
39
-
40
- class MyEncoder < Dragonfly::Encoding::Base
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
- If the encoder is {Dragonfly::Configurable configurable}, we can configure it as we register it if we need to
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)