dragonfly 0.9.15 → 1.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 (203) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -8
  3. data/.travis.yml +11 -0
  4. data/Gemfile +1 -0
  5. data/History.md +52 -2
  6. data/LICENSE +1 -1
  7. data/README.md +38 -95
  8. data/dev/grid.jpg +0 -0
  9. data/dev/irbrc.rb +27 -0
  10. data/dev/rails_template.rb +38 -0
  11. data/dev/test.ru +56 -0
  12. data/dev/test_rails +19 -0
  13. data/dragonfly.gemspec +3 -21
  14. data/lib/dragonfly.rb +45 -44
  15. data/lib/dragonfly/app.rb +175 -96
  16. data/lib/dragonfly/configurable.rb +71 -170
  17. data/lib/dragonfly/content.rb +211 -0
  18. data/lib/dragonfly/core_ext/object.rb +1 -6
  19. data/lib/dragonfly/file_data_store.rb +197 -0
  20. data/lib/dragonfly/image_magick/analysers/image_properties.rb +23 -0
  21. data/lib/dragonfly/image_magick/generators/convert.rb +19 -0
  22. data/lib/dragonfly/image_magick/generators/plain.rb +26 -0
  23. data/lib/dragonfly/image_magick/generators/plasma.rb +25 -0
  24. data/lib/dragonfly/image_magick/generators/text.rb +127 -0
  25. data/lib/dragonfly/image_magick/plugin.rb +83 -0
  26. data/lib/dragonfly/image_magick/processors/convert.rb +29 -0
  27. data/lib/dragonfly/image_magick/processors/encode.rb +18 -0
  28. data/lib/dragonfly/image_magick/processors/thumb.rb +76 -0
  29. data/lib/dragonfly/job.rb +118 -134
  30. data/lib/dragonfly/job_endpoint.rb +2 -0
  31. data/lib/dragonfly/memory_data_store.rb +34 -0
  32. data/lib/dragonfly/middleware.rb +5 -3
  33. data/lib/dragonfly/{active_model_extensions.rb → model.rb} +5 -3
  34. data/lib/dragonfly/{active_model_extensions → model}/attachment.rb +40 -35
  35. data/lib/dragonfly/{active_model_extensions → model}/attachment_class_methods.rb +36 -40
  36. data/lib/dragonfly/model/class_methods.rb +109 -0
  37. data/lib/dragonfly/{active_model_extensions → model}/instance_methods.rb +2 -2
  38. data/lib/dragonfly/{active_model_extensions → model}/validations.rb +17 -12
  39. data/lib/dragonfly/railtie.rb +8 -6
  40. data/lib/dragonfly/register.rb +27 -0
  41. data/lib/dragonfly/response.rb +47 -52
  42. data/lib/dragonfly/routed_endpoint.rb +4 -0
  43. data/lib/dragonfly/serializer.rb +15 -5
  44. data/lib/dragonfly/server.rb +56 -29
  45. data/lib/dragonfly/shell.rb +12 -23
  46. data/lib/dragonfly/spec/data_store_examples.rb +64 -0
  47. data/lib/dragonfly/temp_object.rb +32 -47
  48. data/lib/dragonfly/url_attributes.rb +19 -22
  49. data/lib/dragonfly/url_mapper.rb +3 -0
  50. data/lib/dragonfly/utils.rb +12 -0
  51. data/lib/dragonfly/version.rb +1 -1
  52. data/lib/dragonfly/whitelist.rb +19 -0
  53. data/lib/rails/generators/dragonfly/USAGE +8 -0
  54. data/lib/rails/generators/dragonfly/dragonfly_generator.rb +24 -0
  55. data/lib/rails/generators/dragonfly/templates/initializer.rb.erb +27 -0
  56. data/samples/gif.gif +0 -0
  57. data/spec/dragonfly/app_spec.rb +270 -64
  58. data/spec/dragonfly/configurable_spec.rb +142 -418
  59. data/spec/dragonfly/content_spec.rb +353 -0
  60. data/spec/dragonfly/cookie_monster_spec.rb +2 -1
  61. data/spec/dragonfly/file_data_store_spec.rb +301 -0
  62. data/spec/dragonfly/image_magick/analysers/image_properties_spec.rb +20 -0
  63. data/spec/dragonfly/image_magick/generators/convert_spec.rb +19 -0
  64. data/spec/dragonfly/image_magick/generators/plain_spec.rb +50 -0
  65. data/spec/dragonfly/image_magick/generators/plasma_spec.rb +32 -0
  66. data/spec/dragonfly/image_magick/generators/text_spec.rb +77 -0
  67. data/spec/dragonfly/image_magick/plugin_spec.rb +131 -0
  68. data/spec/dragonfly/image_magick/processors/convert_spec.rb +56 -0
  69. data/spec/dragonfly/image_magick/processors/thumb_spec.rb +173 -0
  70. data/spec/dragonfly/job_endpoint_spec.rb +30 -73
  71. data/spec/dragonfly/job_spec.rb +280 -608
  72. data/spec/dragonfly/memory_data_store_spec.rb +20 -0
  73. data/spec/dragonfly/middleware_spec.rb +47 -27
  74. data/spec/dragonfly/{active_model_extensions → model}/model_spec.rb +331 -555
  75. data/spec/dragonfly/model/validations_spec.rb +196 -0
  76. data/spec/dragonfly/register_spec.rb +35 -0
  77. data/spec/dragonfly/routed_endpoint_spec.rb +6 -6
  78. data/spec/dragonfly/serializer_spec.rb +13 -15
  79. data/spec/dragonfly/server_spec.rb +122 -46
  80. data/spec/dragonfly/shell_spec.rb +43 -24
  81. data/spec/dragonfly/temp_object_spec.rb +69 -94
  82. data/spec/dragonfly/url_attributes_spec.rb +49 -0
  83. data/spec/dragonfly/utils_spec.rb +32 -0
  84. data/spec/dragonfly/whitelist_spec.rb +30 -0
  85. data/spec/dragonfly_spec.rb +43 -0
  86. data/spec/fixtures/deprecated_stored_content/eggs.bonus +1 -0
  87. data/spec/fixtures/deprecated_stored_content/eggs.bonus.meta +1 -0
  88. data/spec/functional/configuration_spec.rb +19 -0
  89. data/spec/functional/model_urls_spec.rb +43 -41
  90. data/spec/functional/remote_on_the_fly_spec.rb +14 -16
  91. data/spec/functional/shell_commands_spec.rb +24 -14
  92. data/spec/functional/to_response_spec.rb +10 -10
  93. data/spec/functional/urls_spec.rb +5 -3
  94. data/spec/spec_helper.rb +23 -28
  95. data/spec/support/argument_matchers.rb +7 -8
  96. data/spec/support/image_matchers.rb +14 -36
  97. data/spec/support/model_helpers.rb +97 -0
  98. data/spec/support/simple_matchers.rb +12 -0
  99. metadata +92 -393
  100. data/.yardopts +0 -29
  101. data/Rakefile +0 -36
  102. data/config.ru +0 -14
  103. data/docs.watchr +0 -1
  104. data/extra_docs/Analysers.md +0 -68
  105. data/extra_docs/Caching.md +0 -23
  106. data/extra_docs/Configuration.md +0 -149
  107. data/extra_docs/Couch.md +0 -49
  108. data/extra_docs/DataStorage.md +0 -226
  109. data/extra_docs/Encoding.md +0 -67
  110. data/extra_docs/ExampleUseCases.md +0 -116
  111. data/extra_docs/GeneralUsage.md +0 -105
  112. data/extra_docs/Generators.md +0 -68
  113. data/extra_docs/Heroku.md +0 -50
  114. data/extra_docs/ImageMagick.md +0 -136
  115. data/extra_docs/Index.md +0 -33
  116. data/extra_docs/MimeTypes.md +0 -40
  117. data/extra_docs/Models.md +0 -441
  118. data/extra_docs/Mongo.md +0 -42
  119. data/extra_docs/Processing.md +0 -77
  120. data/extra_docs/Rack.md +0 -52
  121. data/extra_docs/Rails2.md +0 -57
  122. data/extra_docs/Rails3.md +0 -56
  123. data/extra_docs/ServingRemotely.md +0 -104
  124. data/extra_docs/Sinatra.md +0 -25
  125. data/extra_docs/URLs.md +0 -203
  126. data/features/images.feature +0 -47
  127. data/features/no_processing.feature +0 -14
  128. data/features/rails.feature +0 -8
  129. data/features/steps/common_steps.rb +0 -8
  130. data/features/steps/dragonfly_steps.rb +0 -66
  131. data/features/steps/rails_steps.rb +0 -40
  132. data/features/support/env.rb +0 -13
  133. data/features/support/setup.rb +0 -41
  134. data/fixtures/rails/files/app/models/album.rb +0 -6
  135. data/fixtures/rails/files/app/views/albums/new.html.erb +0 -7
  136. data/fixtures/rails/files/app/views/albums/show.html.erb +0 -6
  137. data/fixtures/rails/files/config/initializers/dragonfly.rb +0 -4
  138. data/fixtures/rails/files/features/manage_album_images.feature +0 -38
  139. data/fixtures/rails/files/features/step_definitions/helper_steps.rb +0 -7
  140. data/fixtures/rails/files/features/step_definitions/image_steps.rb +0 -25
  141. data/fixtures/rails/files/features/step_definitions/web_steps.rb +0 -189
  142. data/fixtures/rails/files/features/support/paths.rb +0 -17
  143. data/fixtures/rails/files/features/text_images.feature +0 -7
  144. data/fixtures/rails/template.rb +0 -20
  145. data/irbrc.rb +0 -19
  146. data/lib/dragonfly/active_model_extensions/class_methods.rb +0 -98
  147. data/lib/dragonfly/analyser.rb +0 -58
  148. data/lib/dragonfly/analysis/file_command_analyser.rb +0 -33
  149. data/lib/dragonfly/analysis/image_magick_analyser.rb +0 -6
  150. data/lib/dragonfly/config/heroku.rb +0 -26
  151. data/lib/dragonfly/config/image_magick.rb +0 -6
  152. data/lib/dragonfly/config/rails.rb +0 -20
  153. data/lib/dragonfly/data_storage.rb +0 -11
  154. data/lib/dragonfly/data_storage/couch_data_store.rb +0 -83
  155. data/lib/dragonfly/data_storage/file_data_store.rb +0 -144
  156. data/lib/dragonfly/data_storage/mongo_data_store.rb +0 -96
  157. data/lib/dragonfly/data_storage/s3data_store.rb +0 -168
  158. data/lib/dragonfly/encoder.rb +0 -13
  159. data/lib/dragonfly/encoding/image_magick_encoder.rb +0 -6
  160. data/lib/dragonfly/function_manager.rb +0 -67
  161. data/lib/dragonfly/generation/image_magick_generator.rb +0 -6
  162. data/lib/dragonfly/generator.rb +0 -9
  163. data/lib/dragonfly/image_magick/analyser.rb +0 -53
  164. data/lib/dragonfly/image_magick/config.rb +0 -44
  165. data/lib/dragonfly/image_magick/encoder.rb +0 -57
  166. data/lib/dragonfly/image_magick/generator.rb +0 -147
  167. data/lib/dragonfly/image_magick/processor.rb +0 -114
  168. data/lib/dragonfly/image_magick/utils.rb +0 -46
  169. data/lib/dragonfly/image_magick_utils.rb +0 -4
  170. data/lib/dragonfly/job_builder.rb +0 -39
  171. data/lib/dragonfly/job_definitions.rb +0 -30
  172. data/lib/dragonfly/loggable.rb +0 -28
  173. data/lib/dragonfly/processing/image_magick_processor.rb +0 -6
  174. data/lib/dragonfly/processor.rb +0 -9
  175. data/lib/dragonfly/rails/images.rb +0 -32
  176. data/lib/dragonfly/simple_cache.rb +0 -23
  177. data/spec/dragonfly/active_model_extensions/spec_helper.rb +0 -95
  178. data/spec/dragonfly/analyser_spec.rb +0 -123
  179. data/spec/dragonfly/analysis/file_command_analyser_spec.rb +0 -49
  180. data/spec/dragonfly/data_storage/couch_data_store_spec.rb +0 -84
  181. data/spec/dragonfly/data_storage/file_data_store_spec.rb +0 -308
  182. data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +0 -81
  183. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +0 -277
  184. data/spec/dragonfly/data_storage/shared_data_store_examples.rb +0 -77
  185. data/spec/dragonfly/function_manager_spec.rb +0 -154
  186. data/spec/dragonfly/image_magick/analyser_spec.rb +0 -73
  187. data/spec/dragonfly/image_magick/encoder_spec.rb +0 -46
  188. data/spec/dragonfly/image_magick/generator_spec.rb +0 -178
  189. data/spec/dragonfly/image_magick/processor_spec.rb +0 -293
  190. data/spec/dragonfly/job_builder_spec.rb +0 -37
  191. data/spec/dragonfly/job_definitions_spec.rb +0 -57
  192. data/spec/dragonfly/loggable_spec.rb +0 -80
  193. data/spec/dragonfly/simple_cache_spec.rb +0 -27
  194. data/spec/dragonfly/url_attributes.rb +0 -47
  195. data/spec/functional/deprecations_spec.rb +0 -51
  196. data/spec/functional/image_magick_app_spec.rb +0 -27
  197. data/spec/test_imagemagick.ru +0 -49
  198. data/yard/handlers/configurable_attr_handler.rb +0 -38
  199. data/yard/setup.rb +0 -15
  200. data/yard/templates/default/fulldoc/html/css/common.css +0 -109
  201. data/yard/templates/default/layout/html/layout.erb +0 -93
  202. data/yard/templates/default/module/html/configuration_summary.erb +0 -31
  203. data/yard/templates/default/module/setup.rb +0 -17
@@ -2,205 +2,106 @@ module Dragonfly
2
2
  module Configurable
3
3
 
4
4
  # Exceptions
5
- class NotConfigured < RuntimeError; end
6
- class BadConfigAttribute < RuntimeError; end
7
-
8
- def self.included(klass)
9
- klass.class_eval do
10
- include Configurable::InstanceMethods
11
- extend Configurable::ClassMethods
12
- end
13
- end
14
-
15
- class DeferredBlock # Inheriting from Proc causes errors in some versions of Ruby
16
- def initialize(blk)
17
- @blk = blk
18
- end
19
-
20
- def call
21
- @blk.call
22
- end
23
- end
24
-
25
- module InstanceMethods
26
-
27
- def configure(&block)
28
- yield ConfigurationProxy.new(self)
29
- self
30
- end
31
-
32
- def configure_with(config, *args, &block)
33
- config = saved_config_for(config) if config.is_a?(Symbol)
34
- config.apply_configuration(self, *args)
35
- configure(&block) if block
36
- self
37
- end
38
-
39
- def has_config_method?(method_name)
40
- config_methods.include?(method_name.to_sym)
41
- end
42
-
43
- def configuration
44
- @configuration ||= {}
45
- end
46
-
47
- def config_methods
48
- @config_methods ||= self.class.config_methods.dup
49
- end
50
-
51
- def default_configuration
52
- @default_configuration ||= self.class.default_configuration.dup
53
- end
54
-
55
- def set_config_value(key, value)
56
- configuration[key] = value
57
- child_configurables.each{|c| c.set_if_unset(key, value) }
58
- value
59
- end
60
-
61
- def use_as_fallback_config(other_configurable)
62
- other_configurable.add_child_configurable(self)
63
- self.fallback_configurable = other_configurable
64
- end
65
-
66
- protected
67
-
68
- def add_child_configurable(obj)
69
- child_configurables << obj
70
- config_methods.push(*obj.config_methods)
71
- fallback_configurable.config_methods.push(*obj.config_methods) if fallback_configurable
72
- end
73
-
74
- def set_if_unset(key, value)
75
- set_config_value(key, value) unless set_locally?(key)
76
- end
77
-
78
- private
79
-
80
- attr_accessor :fallback_configurable
81
-
82
- def child_configurables
83
- @child_configurables ||= []
84
- end
85
-
86
- def set_locally?(key)
87
- instance_variable_defined?("@#{key}")
88
- end
89
-
90
- def default_value(key)
91
- if default_configuration[key].is_a?(DeferredBlock)
92
- default_configuration[key] = default_configuration[key].call
5
+ class UnregisteredPlugin < RuntimeError; end
6
+
7
+ class Configurer
8
+
9
+ class << self
10
+ private
11
+
12
+ def writer(*args)
13
+ names, opts = extract_options(args)
14
+ names.each do |name|
15
+ define_method name do |value|
16
+ if opts[:for]
17
+ obj.send(opts[:for]).send("#{name}=", value)
18
+ else
19
+ obj.send("#{name}=", value)
20
+ end
21
+ end
22
+ end
93
23
  end
94
- default_configuration[key]
95
- end
96
-
97
- def saved_configs
98
- self.class.saved_configs
99
- end
100
24
 
101
- def saved_config_for(symbol)
102
- config = saved_configs[symbol]
103
- if config.nil?
104
- raise ArgumentError, "#{symbol.inspect} is not a known configuration - try one of #{saved_configs.keys.join(', ')}"
25
+ def meth(*args)
26
+ names, opts = extract_options(args)
27
+ names.each do |name|
28
+ define_method name do |*args, &block|
29
+ if opts[:for]
30
+ obj.send(opts[:for]).send(name, *args, &block)
31
+ else
32
+ obj.send(name, *args, &block)
33
+ end
34
+ end
35
+ end
105
36
  end
106
- config = config.call if config.respond_to?(:call)
107
- config
108
- end
109
-
110
- end
111
37
 
112
- module ClassMethods
113
-
114
- def default_configuration
115
- @default_configuration ||= configurable_ancestors.reverse.inject({}) do |default_config, klass|
116
- default_config.merge!(klass.default_configuration)
117
- default_config
38
+ def extract_options(args)
39
+ opts = args.last.is_a?(Hash) ? args.pop : {}
40
+ [args, opts]
118
41
  end
119
42
  end
120
43
 
121
- def config_methods
122
- @config_methods ||= configurable_ancestors.inject([]) do |conf_methods, klass|
123
- conf_methods |= klass.config_methods
124
- conf_methods
125
- end
44
+ def initialize(&block)
45
+ (class << self; self; end).class_eval(&block)
126
46
  end
127
47
 
128
- def nested_configurables
129
- @nested_configurables ||= []
48
+ def configure(obj, &block)
49
+ previous_obj = @obj
50
+ @obj = obj
51
+ instance_eval(&block)
52
+ @obj = previous_obj
130
53
  end
131
54
 
132
- def register_configuration(name, config=nil, &config_in_block)
133
- saved_configs[name] = config_in_block || config
55
+ def configure_with_plugin(obj, plugin, *args, &block)
56
+ if plugin.is_a?(Symbol)
57
+ symbol = plugin
58
+ raise(UnregisteredPlugin, "plugin #{symbol.inspect} is not registered") unless registered_plugins[symbol]
59
+ plugin = registered_plugins[symbol].call
60
+ obj.plugins[symbol] = plugin if obj.respond_to?(:plugins)
61
+ end
62
+ plugin.call(obj, *args, &block)
63
+ plugin
134
64
  end
135
65
 
136
- def saved_configs
137
- @saved_configs ||= {}
66
+ def register_plugin(name, &block)
67
+ registered_plugins[name] = block
138
68
  end
139
69
 
140
- def configurable_ancestors
141
- @configurable_ancestors ||= ancestors.select{|a| a.included_modules.include?(Configurable) } - [self]
70
+ def plugin(plugin, *args, &block)
71
+ configure_with_plugin(obj, plugin, *args, &block)
142
72
  end
143
73
 
144
74
  private
145
75
 
146
- def configurable_attr attribute, default=nil, &blk
147
- default_configuration[attribute] = blk ? DeferredBlock.new(blk) : default
148
-
149
- # Define the reader
150
- define_method(attribute) do
151
- configuration.has_key?(attribute) ? configuration[attribute] : default_value(attribute)
152
- end
153
-
154
- # Define the writer
155
- define_method("#{attribute}=") do |value|
156
- instance_variable_set("@#{attribute}", value)
157
- set_config_value(attribute, value)
158
- end
76
+ attr_reader :obj
159
77
 
160
- configuration_method attribute
161
- configuration_method "#{attribute}="
78
+ def registered_plugins
79
+ @registered_plugins ||= {}
162
80
  end
163
-
164
- def configuration_method(*method_names)
165
- config_methods.push(*method_names.map{|n| n.to_sym }).uniq!
166
- end
167
-
168
- def nested_configurable(*method_names)
169
- nested_configurables.push(*method_names)
170
- end
171
-
172
81
  end
173
82
 
174
- class ConfigurationProxy
83
+ #######
175
84
 
176
- def initialize(owner)
177
- @owner = owner
178
- end
179
-
180
- def method_missing(method_name, *args, &block)
181
- if owner.has_config_method?(method_name)
182
- attribute = method_name.to_s.tr('=','').to_sym
183
- if method_name.to_s =~ /=$/ && owner.has_config_method?(attribute) # a bit hacky - if it has both getter and setter, assume it's a configurable_attr
184
- owner.set_config_value(attribute, args.first)
185
- else
186
- owner.send(method_name, *args, &block)
187
- end
188
- elsif nested_configurable?(method_name)
189
- owner.send(method_name)
190
- else
191
- raise BadConfigAttribute, "You tried to configure using '#{method_name.inspect}', but the valid config attributes are #{owner.config_methods.map{|a| %('#{a.inspect}') }.sort.join(', ')}"
85
+ def set_up_config(&setup_block)
86
+ self.configurer = Configurer.new(&setup_block)
87
+ class_eval do
88
+ def configure(&block)
89
+ self.class.configurer.configure(self, &block)
90
+ self
192
91
  end
193
- end
194
-
195
- private
196
92
 
197
- attr_reader :owner
93
+ def configure_with(plugin, *args, &block)
94
+ self.class.configurer.configure_with_plugin(self, plugin, *args, &block)
95
+ self
96
+ end
198
97
 
199
- def nested_configurable?(method)
200
- owner.class.nested_configurables.include?(method.to_sym)
98
+ def plugins
99
+ @plugins ||= {}
100
+ end
201
101
  end
202
-
203
102
  end
204
103
 
104
+ attr_accessor :configurer
105
+
205
106
  end
206
107
  end
@@ -0,0 +1,211 @@
1
+ require 'base64'
2
+ require 'forwardable'
3
+ require 'dragonfly/has_filename'
4
+ require 'dragonfly/temp_object'
5
+ require 'dragonfly/utils'
6
+
7
+ module Dragonfly
8
+
9
+ # A Dragonfly::Content object is responsible for holding
10
+ # 1. content (in the form of a data string, file, tempfile, or path)
11
+ # 2. metadata about the content (i.e. name, etc.)
12
+ # Furthermore, it belongs to a Dragonfly app, so has access to its already registered generators, processors, analysers and datastore.
13
+ # It provides convenience methods for updating its content, and though the original data may have been in the form of a String, or a Pathname, etc.
14
+ # methods like "path", "data" and "file" will always work regardless.
15
+ #
16
+ # It is acted upon in generator, processor, analyser and datastore methods and provides a standard interface for updating content,
17
+ # no matter how that content first got there (whether in the form of a String/Pathname/File/etc.)
18
+ class Content
19
+
20
+ include HasFilename
21
+ extend Forwardable
22
+
23
+ def initialize(app, obj="", meta=nil)
24
+ @app = app
25
+ @meta = {}
26
+ @previous_temp_objects = []
27
+ update(obj, meta)
28
+ end
29
+
30
+ attr_reader :app
31
+ def_delegators :app,
32
+ :analyser, :generator, :processor, :shell, :datastore, :env
33
+
34
+ attr_reader :temp_object
35
+
36
+ # @return [Hash]
37
+ attr_accessor :meta
38
+
39
+ # @!method data
40
+ # @return [String] the content data as a string (even if it was initialized with a file)
41
+ # @!method file
42
+ # @example
43
+ # content.file
44
+ # @example With a block (it closes the file at the end)
45
+ # content.file do |f|
46
+ # # do something with f
47
+ # end
48
+ # @return [File] the content as a readable file (even if it was initialized with data)
49
+ # @!method path
50
+ # @return [String] a file path for the content (even if it was initialized with data)
51
+ # @!method size
52
+ # @return [Fixnum] the size in bytes
53
+ # @!method to_file
54
+ # @param [String] path
55
+ # @return [File] a new file
56
+ # @!method to_tempfile
57
+ # @return [Tempfile] a new tempfile
58
+ def_delegators :temp_object,
59
+ :data, :file, :tempfile, :path, :size, :each, :to_file, :to_tempfile
60
+
61
+ # @example "beach.jpg"
62
+ # @return [String]
63
+ def name
64
+ meta["name"] || temp_object.original_filename
65
+ end
66
+
67
+ # @example
68
+ # content.name = "beach.jpg"
69
+ def name=(name)
70
+ meta["name"] = name
71
+ end
72
+
73
+ # The mime-type taken from the name's file extension
74
+ # @example "image/jpeg"
75
+ # @return [String]
76
+ def mime_type
77
+ app.mime_type_for(ext)
78
+ end
79
+
80
+ # Set the content using a pre-registered generator
81
+ # @example
82
+ # content.generate!(:text, "some text")
83
+ # @return [Content] self
84
+ def generate!(name, *args)
85
+ app.get_generator(name).call(self, *args)
86
+ self
87
+ end
88
+
89
+ # Update the content using a pre-registered processor
90
+ # @example
91
+ # content.process!(:convert, "-resize 300x300")
92
+ # @return [Content] self
93
+ def process!(name, *args)
94
+ app.get_processor(name).call(self, *args)
95
+ self
96
+ end
97
+
98
+ # Analyse the content using a pre-registered analyser
99
+ # @example
100
+ # content.analyse(:width) # ===> 280
101
+ def analyse(name)
102
+ analyser_cache[name.to_s] ||= app.get_analyser(name).call(self)
103
+ end
104
+
105
+ # Update the content
106
+ # @param obj [String, Pathname, Tempfile, File, Content, TempObject] can be any of these types
107
+ # @param meta [Hash] - should be json-like, i.e. contain no types other than String, Number, Boolean
108
+ # @return [Content] self
109
+ def update(obj, meta=nil)
110
+ self.temp_object = TempObject.new(obj)
111
+ original_filename = temp_object.original_filename
112
+ self.meta['name'] ||= original_filename if original_filename
113
+ self.meta.delete("analyser_cache")
114
+ add_meta(obj.meta) if obj.respond_to?(:meta)
115
+ add_meta(meta) if meta
116
+ self
117
+ end
118
+
119
+ # Add to the meta (merge)
120
+ # @param meta [Hash] - should be json-like, i.e. contain no types other than String, Number, Boolean
121
+ def add_meta(meta)
122
+ self.meta.merge!(meta)
123
+ self
124
+ end
125
+
126
+ # Analyse the content using a shell command
127
+ # @param opts [Hash] passing :escape => false doesn't shell-escape each word
128
+ # @example
129
+ # content.shell_eval do |path|
130
+ # "file --mime-type #{path}"
131
+ # end
132
+ # # ===> "beach.jpg: image/jpeg"
133
+ def shell_eval(opts={})
134
+ should_escape = opts[:escape] != false
135
+ command = yield(should_escape ? shell.quote(path) : path)
136
+ run command, :escape => should_escape
137
+ end
138
+
139
+ # Set the content using a shell command
140
+ # @param opts [Hash] :ext sets the file extension of the new path and :escape => false doesn't shell-escape each word
141
+ # @example
142
+ # content.shell_generate do |path|
143
+ # "/usr/local/bin/generate_text gumfry -o #{path}"
144
+ # end
145
+ # @return [Content] self
146
+ def shell_generate(opts={})
147
+ ext = opts[:ext] || self.ext
148
+ should_escape = opts[:escape] != false
149
+ tempfile = Utils.new_tempfile(ext)
150
+ new_path = should_escape ? shell.quote(tempfile.path) : tempfile.path
151
+ command = yield(new_path)
152
+ run(command, :escape => should_escape)
153
+ update(tempfile)
154
+ end
155
+
156
+ # Update the content using a shell command
157
+ # @param opts [Hash] :ext sets the file extension of the new path and :escape => false doesn't shell-escape each word
158
+ # @example
159
+ # content.shell_update do |old_path, new_path|
160
+ # "convert -resize 20x10 #{old_path} #{new_path}"
161
+ # end
162
+ # @return [Content] self
163
+ def shell_update(opts={})
164
+ ext = opts[:ext] || self.ext
165
+ should_escape = opts[:escape] != false
166
+ tempfile = Utils.new_tempfile(ext)
167
+ old_path = should_escape ? shell.quote(path) : path
168
+ new_path = should_escape ? shell.quote(tempfile.path) : tempfile.path
169
+ command = yield(old_path, new_path)
170
+ run(command, :escape => should_escape)
171
+ update(tempfile)
172
+ end
173
+
174
+ def store(opts={})
175
+ datastore.write(self, opts)
176
+ end
177
+
178
+ # @example
179
+ # "data:image/jpeg;base64,IGSsdhfsoi..."
180
+ # @return [String] A data url representation of the data
181
+ def b64_data
182
+ "data:#{mime_type};base64,#{Base64.encode64(data)}"
183
+ end
184
+
185
+ def close
186
+ previous_temp_objects.each{|temp_object| temp_object.close }
187
+ temp_object.close
188
+ end
189
+
190
+ def inspect
191
+ "<#{self.class.name} temp_object=#{temp_object.inspect}>"
192
+ end
193
+
194
+ private
195
+
196
+ attr_reader :previous_temp_objects
197
+ def temp_object=(temp_object)
198
+ previous_temp_objects.push(@temp_object) if @temp_object
199
+ @temp_object = temp_object
200
+ end
201
+
202
+ def analyser_cache
203
+ meta["analyser_cache"] ||= {}
204
+ end
205
+
206
+ def run(command, opts)
207
+ shell.run(command, opts)
208
+ end
209
+
210
+ end
211
+ end