dragonfly 0.8.6 → 0.9.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/{.specopts → .rspec} +0 -1
- data/.yardopts +6 -2
- data/Gemfile +14 -13
- data/History.md +47 -9
- data/README.md +25 -5
- data/Rakefile +37 -79
- data/VERSION +1 -1
- data/dragonfly.gemspec +140 -89
- data/extra_docs/Analysers.md +8 -48
- data/extra_docs/Configuration.md +40 -25
- data/extra_docs/Couch.md +49 -0
- data/extra_docs/DataStorage.md +94 -24
- data/extra_docs/Encoding.md +6 -35
- data/extra_docs/ExampleUseCases.md +113 -0
- data/extra_docs/GeneralUsage.md +7 -23
- data/extra_docs/Generators.md +15 -49
- data/extra_docs/Heroku.md +7 -8
- data/extra_docs/ImageMagick.md +126 -0
- data/extra_docs/MimeTypes.md +3 -3
- data/extra_docs/Models.md +163 -0
- data/extra_docs/Mongo.md +1 -4
- data/extra_docs/Processing.md +7 -60
- data/extra_docs/Rails2.md +3 -1
- data/extra_docs/Rails3.md +2 -10
- data/extra_docs/ServingRemotely.md +83 -0
- data/extra_docs/Sinatra.md +3 -3
- data/extra_docs/URLs.md +60 -33
- data/features/rails_3.0.5.feature +8 -0
- data/features/steps/rails_steps.rb +7 -18
- data/features/support/env.rb +10 -37
- data/features/support/setup.rb +32 -0
- data/fixtures/rails_3.0.5/files/app/models/album.rb +5 -0
- data/fixtures/rails_3.0.5/files/app/views/albums/new.html.erb +7 -0
- data/fixtures/{files → rails_3.0.5/files}/app/views/albums/show.html.erb +2 -0
- data/fixtures/{files → rails_3.0.5/files}/config/initializers/dragonfly.rb +0 -0
- data/fixtures/rails_3.0.5/files/features/manage_album_images.feature +38 -0
- data/fixtures/rails_3.0.5/files/features/step_definitions/helper_steps.rb +7 -0
- data/fixtures/{files → rails_3.0.5/files}/features/step_definitions/image_steps.rb +11 -1
- data/fixtures/{files → rails_3.0.5/files}/features/support/paths.rb +2 -0
- data/fixtures/{files → rails_3.0.5/files}/features/text_images.feature +0 -0
- data/fixtures/{rails_3.0.3 → rails_3.0.5}/template.rb +2 -2
- data/irbrc.rb +2 -1
- data/lib/dragonfly.rb +7 -0
- data/lib/dragonfly/active_model_extensions/attachment.rb +134 -46
- data/lib/dragonfly/active_model_extensions/attachment_class_methods.rb +144 -0
- data/lib/dragonfly/active_model_extensions/class_methods.rb +62 -9
- data/lib/dragonfly/active_model_extensions/instance_methods.rb +2 -2
- data/lib/dragonfly/active_model_extensions/validations.rb +10 -6
- data/lib/dragonfly/analyser.rb +0 -1
- data/lib/dragonfly/analysis/file_command_analyser.rb +1 -1
- data/lib/dragonfly/analysis/image_magick_analyser.rb +2 -43
- data/lib/dragonfly/app.rb +64 -55
- data/lib/dragonfly/config/heroku.rb +1 -1
- data/lib/dragonfly/config/image_magick.rb +2 -37
- data/lib/dragonfly/config/rails.rb +5 -2
- data/lib/dragonfly/configurable.rb +115 -35
- data/lib/dragonfly/core_ext/object.rb +1 -1
- data/lib/dragonfly/core_ext/string.rb +1 -1
- data/lib/dragonfly/data_storage/couch_data_store.rb +84 -0
- data/lib/dragonfly/data_storage/file_data_store.rb +43 -18
- data/lib/dragonfly/data_storage/mongo_data_store.rb +8 -4
- data/lib/dragonfly/data_storage/s3data_store.rb +82 -38
- data/lib/dragonfly/encoding/image_magick_encoder.rb +2 -53
- data/lib/dragonfly/function_manager.rb +4 -2
- data/lib/dragonfly/generation/image_magick_generator.rb +2 -136
- data/lib/dragonfly/hash_with_css_style_keys.rb +21 -0
- data/lib/dragonfly/image_magick/analyser.rb +51 -0
- data/lib/dragonfly/image_magick/config.rb +44 -0
- data/lib/dragonfly/{encoding/r_magick_encoder.rb → image_magick/encoder.rb} +10 -14
- data/lib/dragonfly/image_magick/generator.rb +145 -0
- data/lib/dragonfly/image_magick/processor.rb +104 -0
- data/lib/dragonfly/image_magick/utils.rb +72 -0
- data/lib/dragonfly/image_magick_utils.rb +2 -79
- data/lib/dragonfly/job.rb +152 -90
- data/lib/dragonfly/middleware.rb +5 -19
- data/lib/dragonfly/processing/image_magick_processor.rb +2 -95
- data/lib/dragonfly/rails/images.rb +15 -10
- data/lib/dragonfly/response.rb +26 -12
- data/lib/dragonfly/serializer.rb +1 -4
- data/lib/dragonfly/server.rb +103 -0
- data/lib/dragonfly/temp_object.rb +56 -101
- data/lib/dragonfly/url_mapper.rb +78 -0
- data/spec/dragonfly/active_model_extensions/model_spec.rb +772 -65
- data/spec/dragonfly/active_model_extensions/spec_helper.rb +90 -10
- data/spec/dragonfly/analyser_spec.rb +1 -1
- data/spec/dragonfly/analysis/file_command_analyser_spec.rb +5 -14
- data/spec/dragonfly/app_spec.rb +35 -180
- data/spec/dragonfly/configurable_spec.rb +259 -18
- data/spec/dragonfly/core_ext/string_spec.rb +2 -2
- data/spec/dragonfly/core_ext/symbol_spec.rb +1 -1
- data/spec/dragonfly/data_storage/couch_data_store_spec.rb +84 -0
- data/spec/dragonfly/data_storage/file_data_store_spec.rb +149 -22
- data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +21 -2
- data/spec/dragonfly/data_storage/s3_data_store_spec.rb +207 -43
- data/spec/dragonfly/data_storage/{data_store_spec.rb → shared_data_store_examples.rb} +16 -15
- data/spec/dragonfly/function_manager_spec.rb +2 -2
- data/spec/dragonfly/{generation/hash_with_css_style_keys_spec.rb → hash_with_css_style_keys_spec.rb} +2 -2
- data/spec/dragonfly/{analysis/shared_analyser_spec.rb → image_magick/analyser_spec.rb} +19 -6
- data/spec/dragonfly/{encoding/image_magick_encoder_spec.rb → image_magick/encoder_spec.rb} +2 -2
- data/spec/dragonfly/image_magick/generator_spec.rb +172 -0
- data/spec/dragonfly/{processing/shared_processing_spec.rb → image_magick/processor_spec.rb} +55 -6
- data/spec/dragonfly/image_magick/utils_spec.rb +18 -0
- data/spec/dragonfly/job_builder_spec.rb +1 -1
- data/spec/dragonfly/job_definitions_spec.rb +1 -1
- data/spec/dragonfly/job_endpoint_spec.rb +26 -3
- data/spec/dragonfly/job_spec.rb +426 -208
- data/spec/dragonfly/loggable_spec.rb +2 -2
- data/spec/dragonfly/middleware_spec.rb +5 -26
- data/spec/dragonfly/routed_endpoint_spec.rb +1 -1
- data/spec/dragonfly/serializer_spec.rb +1 -14
- data/spec/dragonfly/server_spec.rb +261 -0
- data/spec/dragonfly/simple_cache_spec.rb +1 -1
- data/spec/dragonfly/temp_object_spec.rb +84 -130
- data/spec/dragonfly/url_mapper_spec.rb +130 -0
- data/spec/functional/deprecations_spec.rb +51 -0
- data/spec/functional/image_magick_app_spec.rb +27 -0
- data/spec/functional/model_urls_spec.rb +85 -0
- data/spec/functional/remote_on_the_fly_spec.rb +51 -0
- data/spec/functional/to_response_spec.rb +31 -0
- data/spec/spec_helper.rb +12 -22
- data/spec/{argument_matchers.rb → support/argument_matchers.rb} +0 -0
- data/spec/{image_matchers.rb → support/image_matchers.rb} +4 -4
- data/spec/support/simple_matchers.rb +53 -0
- data/yard/handlers/configurable_attr_handler.rb +2 -2
- data/yard/templates/default/fulldoc/html/css/common.css +12 -10
- data/yard/templates/default/layout/html/layout.erb +6 -0
- metadata +267 -308
- data/Gemfile.rails.2.3.5 +0 -20
- data/features/3.0.3.feature +0 -8
- data/features/rails_2.3.5.feature +0 -7
- data/fixtures/files/app/models/album.rb +0 -3
- data/fixtures/files/app/views/albums/new.html.erb +0 -4
- data/fixtures/files/features/manage_album_images.feature +0 -12
- data/fixtures/rails_2.3.5/template.rb +0 -10
- data/lib/dragonfly/analysis/r_magick_analyser.rb +0 -63
- data/lib/dragonfly/config/r_magick.rb +0 -46
- data/lib/dragonfly/generation/hash_with_css_style_keys.rb +0 -23
- data/lib/dragonfly/generation/r_magick_generator.rb +0 -155
- data/lib/dragonfly/processing/r_magick_processor.rb +0 -126
- data/lib/dragonfly/r_magick_utils.rb +0 -48
- data/lib/dragonfly/simple_endpoint.rb +0 -76
- data/spec/dragonfly/active_model_extensions/active_model_setup.rb +0 -97
- data/spec/dragonfly/active_model_extensions/active_record_setup.rb +0 -85
- data/spec/dragonfly/analysis/image_magick_analyser_spec.rb +0 -15
- data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +0 -31
- data/spec/dragonfly/config/r_magick_spec.rb +0 -29
- data/spec/dragonfly/encoding/r_magick_encoder_spec.rb +0 -41
- data/spec/dragonfly/generation/image_magick_generator_spec.rb +0 -12
- data/spec/dragonfly/generation/r_magick_generator_spec.rb +0 -28
- data/spec/dragonfly/generation/shared_generator_spec.rb +0 -91
- data/spec/dragonfly/image_magick_utils_spec.rb +0 -16
- data/spec/dragonfly/processing/image_magick_processor_spec.rb +0 -29
- data/spec/dragonfly/processing/r_magick_processor_spec.rb +0 -30
- data/spec/dragonfly/simple_endpoint_spec.rb +0 -97
- data/spec/simple_matchers.rb +0 -44
@@ -5,7 +5,7 @@ module Dragonfly
|
|
5
5
|
|
6
6
|
def self.apply_configuration(app, bucket_name)
|
7
7
|
app.configure do |c|
|
8
|
-
c.datastore =
|
8
|
+
c.datastore = DataStorage::S3DataStore.new
|
9
9
|
c.datastore.configure do |d|
|
10
10
|
d.bucket_name = bucket_name
|
11
11
|
d.access_key_id = ENV['S3_KEY'] || raise("ENV variable 'S3_KEY' needs to be set - use\n\theroku config:add S3_KEY=XXXXXXXXX")
|
@@ -1,41 +1,6 @@
|
|
1
1
|
module Dragonfly
|
2
2
|
module Config
|
3
|
-
|
4
|
-
|
5
|
-
# - registers an imagemagick analyser
|
6
|
-
# - registers an imagemagick processor
|
7
|
-
# - registers an imagemagick encoder
|
8
|
-
# - adds thumb shortcuts like '280x140!', etc.
|
9
|
-
# Look at the source code for apply_configuration to see exactly how it configures the app.
|
10
|
-
module ImageMagick
|
11
|
-
|
12
|
-
def self.apply_configuration(app, opts={})
|
13
|
-
app.configure do |c|
|
14
|
-
c.analyser.register(Analysis::ImageMagickAnalyser)
|
15
|
-
c.processor.register(Processing::ImageMagickProcessor)
|
16
|
-
c.encoder.register(Encoding::ImageMagickEncoder)
|
17
|
-
c.generator.register(Generation::ImageMagickGenerator)
|
18
|
-
|
19
|
-
c.job :thumb do |geometry, format|
|
20
|
-
process :thumb, geometry
|
21
|
-
encode format if format
|
22
|
-
end
|
23
|
-
c.job :gif do
|
24
|
-
encode :gif
|
25
|
-
end
|
26
|
-
c.job :jpg do
|
27
|
-
encode :jpg
|
28
|
-
end
|
29
|
-
c.job :png do
|
30
|
-
encode :png
|
31
|
-
end
|
32
|
-
c.job :convert do |args, format|
|
33
|
-
process :convert, args, format
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
3
|
+
puts "WARNING: Dragonfly::Config::ImageMagick is DEPRECATED and will soon be removed. Please use Dragonfly::ImageMagick::Config instead."
|
4
|
+
ImageMagick = Dragonfly::ImageMagick::Config
|
40
5
|
end
|
41
6
|
end
|
@@ -6,8 +6,11 @@ module Dragonfly
|
|
6
6
|
def self.apply_configuration(app)
|
7
7
|
app.configure do |c|
|
8
8
|
c.log = ::Rails.logger
|
9
|
-
|
10
|
-
|
9
|
+
if c.datastore.is_a?(DataStorage::FileDataStore)
|
10
|
+
c.datastore.root_path = ::Rails.root.join('public/system/dragonfly', ::Rails.env).to_s
|
11
|
+
c.datastore.server_root = ::Rails.root.join('public').to_s
|
12
|
+
end
|
13
|
+
c.url_format = '/media/:job/:basename.:format'
|
11
14
|
c.analyser.register(Analysis::FileCommandAnalyser)
|
12
15
|
end
|
13
16
|
end
|
@@ -2,26 +2,20 @@ module Dragonfly
|
|
2
2
|
module Configurable
|
3
3
|
|
4
4
|
# Exceptions
|
5
|
-
class
|
5
|
+
class NotConfigured < RuntimeError; end
|
6
|
+
class BadConfigAttribute < RuntimeError; end
|
6
7
|
|
7
8
|
def self.included(klass)
|
8
9
|
klass.class_eval do
|
9
10
|
include Configurable::InstanceMethods
|
10
11
|
extend Configurable::ClassMethods
|
11
12
|
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
@configuration_hash ||= klass.default_configuration.dup
|
13
|
+
# We should use configured_class rather than self.class
|
14
|
+
# because sometimes this will be the eigenclass of an object
|
15
|
+
# e.g. if we configure a module, etc.
|
16
|
+
define_method :configured_class do
|
17
|
+
klass
|
18
18
|
end
|
19
|
-
private :configuration_hash
|
20
|
-
|
21
|
-
define_method :configuration_methods do
|
22
|
-
klass.configuration_methods
|
23
|
-
end
|
24
|
-
|
25
19
|
end
|
26
20
|
end
|
27
21
|
|
@@ -42,19 +36,86 @@ module Dragonfly
|
|
42
36
|
self
|
43
37
|
end
|
44
38
|
|
45
|
-
def configure_with(
|
46
|
-
|
47
|
-
|
39
|
+
def configure_with(config, *args, &block)
|
40
|
+
config = saved_config_for(config) if config.is_a?(Symbol)
|
41
|
+
config.apply_configuration(self, *args)
|
48
42
|
configure(&block) if block
|
49
43
|
self
|
50
44
|
end
|
51
45
|
|
46
|
+
def has_config_method?(method_name)
|
47
|
+
config_methods.include?(method_name.to_sym)
|
48
|
+
end
|
49
|
+
|
50
|
+
def config_methods
|
51
|
+
@config_methods ||= configured_class.config_methods.dup
|
52
|
+
end
|
53
|
+
|
52
54
|
def configuration
|
53
|
-
|
55
|
+
@configuration ||= {}
|
56
|
+
end
|
57
|
+
|
58
|
+
def default_configuration
|
59
|
+
# Merge the default configuration of all ancestor classes/modules which are configurable
|
60
|
+
@default_configuration ||= [self.class, configured_class, *configured_class.ancestors].reverse.inject({}) do |default_config, klass|
|
61
|
+
default_config.merge!(klass.default_configuration) if klass.respond_to? :default_configuration
|
62
|
+
default_config
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def set_config_value(key, value)
|
67
|
+
configuration[key] = value
|
68
|
+
child_configurables.each{|c| c.set_if_unset(key, value) }
|
69
|
+
value
|
70
|
+
end
|
71
|
+
|
72
|
+
def use_as_fallback_config(other_configurable)
|
73
|
+
other_configurable.add_child_configurable(self)
|
74
|
+
self.fallback_configurable = other_configurable
|
75
|
+
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
|
79
|
+
def add_child_configurable(obj)
|
80
|
+
child_configurables << obj
|
81
|
+
config_methods.push(*obj.config_methods)
|
82
|
+
fallback_configurable.config_methods.push(*obj.config_methods) if fallback_configurable
|
83
|
+
end
|
84
|
+
|
85
|
+
def set_if_unset(key, value)
|
86
|
+
set_config_value(key, value) unless set_locally?(key)
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
attr_accessor :fallback_configurable
|
92
|
+
|
93
|
+
def child_configurables
|
94
|
+
@child_configurables ||= []
|
95
|
+
end
|
96
|
+
|
97
|
+
def set_locally?(key)
|
98
|
+
instance_variable_defined?("@#{key}")
|
99
|
+
end
|
100
|
+
|
101
|
+
def default_value(key)
|
102
|
+
if default_configuration[key].is_a?(DeferredBlock)
|
103
|
+
default_configuration[key] = default_configuration[key].call
|
104
|
+
end
|
105
|
+
default_configuration[key]
|
54
106
|
end
|
55
107
|
|
56
|
-
def
|
57
|
-
|
108
|
+
def saved_configs
|
109
|
+
configured_class.saved_configs
|
110
|
+
end
|
111
|
+
|
112
|
+
def saved_config_for(symbol)
|
113
|
+
config = saved_configs[symbol]
|
114
|
+
if config.nil?
|
115
|
+
raise ArgumentError, "#{symbol.inspect} is not a known configuration - try one of #{saved_configs.keys.join(', ')}"
|
116
|
+
end
|
117
|
+
config = config.call if config.respond_to?(:call)
|
118
|
+
config
|
58
119
|
end
|
59
120
|
|
60
121
|
end
|
@@ -65,8 +126,20 @@ module Dragonfly
|
|
65
126
|
@default_configuration ||= {}
|
66
127
|
end
|
67
128
|
|
68
|
-
def
|
69
|
-
@
|
129
|
+
def config_methods
|
130
|
+
@config_methods ||= []
|
131
|
+
end
|
132
|
+
|
133
|
+
def nested_configurables
|
134
|
+
@nested_configurables ||= []
|
135
|
+
end
|
136
|
+
|
137
|
+
def register_configuration(name, config=nil, &config_in_block)
|
138
|
+
saved_configs[name] = config_in_block || config
|
139
|
+
end
|
140
|
+
|
141
|
+
def saved_configs
|
142
|
+
@saved_configs ||= {}
|
70
143
|
end
|
71
144
|
|
72
145
|
private
|
@@ -76,15 +149,13 @@ module Dragonfly
|
|
76
149
|
|
77
150
|
# Define the reader
|
78
151
|
define_method(attribute) do
|
79
|
-
|
80
|
-
configuration_hash[attribute] = configuration_hash[attribute].call
|
81
|
-
end
|
82
|
-
configuration_hash[attribute]
|
152
|
+
configuration.has_key?(attribute) ? configuration[attribute] : default_value(attribute)
|
83
153
|
end
|
84
154
|
|
85
155
|
# Define the writer
|
86
156
|
define_method("#{attribute}=") do |value|
|
87
|
-
|
157
|
+
instance_variable_set("@#{attribute}", value)
|
158
|
+
set_config_value(attribute, value)
|
88
159
|
end
|
89
160
|
|
90
161
|
configuration_method attribute
|
@@ -92,7 +163,11 @@ module Dragonfly
|
|
92
163
|
end
|
93
164
|
|
94
165
|
def configuration_method(*method_names)
|
95
|
-
|
166
|
+
config_methods.push(*method_names.map{|n| n.to_sym }).uniq!
|
167
|
+
end
|
168
|
+
|
169
|
+
def nested_configurable(*method_names)
|
170
|
+
nested_configurables.push(*method_names)
|
96
171
|
end
|
97
172
|
|
98
173
|
end
|
@@ -104,12 +179,17 @@ module Dragonfly
|
|
104
179
|
end
|
105
180
|
|
106
181
|
def method_missing(method_name, *args, &block)
|
107
|
-
if owner.
|
108
|
-
|
109
|
-
|
110
|
-
|
182
|
+
if owner.has_config_method?(method_name)
|
183
|
+
attribute = method_name.to_s.tr('=','').to_sym
|
184
|
+
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
|
185
|
+
owner.set_config_value(attribute, args.first)
|
186
|
+
else
|
187
|
+
owner.send(method_name, *args, &block)
|
188
|
+
end
|
189
|
+
elsif nested_configurable?(method_name)
|
190
|
+
owner.send(method_name)
|
111
191
|
else
|
112
|
-
raise BadConfigAttribute, "You tried to configure using '#{method_name.inspect}', but the valid config attributes are #{owner.
|
192
|
+
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(', ')}"
|
113
193
|
end
|
114
194
|
end
|
115
195
|
|
@@ -117,11 +197,11 @@ module Dragonfly
|
|
117
197
|
|
118
198
|
attr_reader :owner
|
119
199
|
|
120
|
-
def nested_configurable?(method
|
121
|
-
owner.
|
200
|
+
def nested_configurable?(method)
|
201
|
+
owner.configured_class.nested_configurables.include?(method.to_sym)
|
122
202
|
end
|
123
203
|
|
124
204
|
end
|
125
205
|
|
126
206
|
end
|
127
|
-
end
|
207
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'couchrest'
|
2
|
+
|
3
|
+
module Dragonfly
|
4
|
+
module DataStorage
|
5
|
+
class CouchDataStore
|
6
|
+
|
7
|
+
include Configurable
|
8
|
+
include Serializer
|
9
|
+
|
10
|
+
configurable_attr :host, 'localhost'
|
11
|
+
configurable_attr :port, '5984'
|
12
|
+
configurable_attr :database, 'dragonfly'
|
13
|
+
configurable_attr :username
|
14
|
+
configurable_attr :password
|
15
|
+
|
16
|
+
def initialize(opts={})
|
17
|
+
self.host = opts[:host] if opts[:host]
|
18
|
+
self.port = opts[:port] if opts[:port]
|
19
|
+
self.database = opts[:database] if opts[:database]
|
20
|
+
self.username = opts[:username]
|
21
|
+
self.password = opts[:password]
|
22
|
+
end
|
23
|
+
|
24
|
+
def store(temp_object, opts={})
|
25
|
+
meta = opts[:meta] || {}
|
26
|
+
name = meta[:name] || temp_object.original_filename || 'file'
|
27
|
+
content_type = opts[:content_type] || opts[:mime_type] || 'application/octet-stream'
|
28
|
+
|
29
|
+
temp_object.file do |f|
|
30
|
+
doc = CouchRest::Document.new(:meta => marshal_encode(meta))
|
31
|
+
response = db.save_doc(doc)
|
32
|
+
doc.put_attachment(name, f, {:content_type => content_type})
|
33
|
+
form_uid(response['id'], name)
|
34
|
+
end
|
35
|
+
rescue RuntimeError => e
|
36
|
+
raise UnableToStore, "#{e} - #{temp_object.inspect}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def retrieve(uid)
|
40
|
+
doc_id, attachment = parse_uid(uid)
|
41
|
+
doc = db.get(doc_id)
|
42
|
+
[doc.fetch_attachment(attachment), marshal_decode(doc['meta'])]
|
43
|
+
rescue RestClient::ResourceNotFound => e
|
44
|
+
raise DataNotFound, "#{e} - #{uid}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def destroy(uid)
|
48
|
+
doc_id, attachment = parse_uid(uid)
|
49
|
+
doc = db.get(doc_id)
|
50
|
+
db.delete_doc(doc)
|
51
|
+
rescue RestClient::ResourceNotFound => e
|
52
|
+
raise DataNotFound, "#{e} - #{uid}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def db
|
56
|
+
@db ||= begin
|
57
|
+
url = "http://#{auth}#{host}:#{port}"
|
58
|
+
CouchRest.new(url).database!(database)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def url_for(uid, opts={})
|
63
|
+
doc_id, attachment = parse_uid(uid)
|
64
|
+
"http://#{host}:#{port}/#{database}/#{doc_id}/#{attachment}"
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def auth
|
70
|
+
username.blank? ? nil : "#{username}:#{password}@"
|
71
|
+
end
|
72
|
+
|
73
|
+
def form_uid(doc_id, attachment)
|
74
|
+
"#{doc_id}/#{attachment}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def parse_uid(uid)
|
78
|
+
doc_id, attachment = uid.split('/')
|
79
|
+
[doc_id, (attachment || 'file')]
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -7,16 +7,20 @@ module Dragonfly
|
|
7
7
|
|
8
8
|
# Exceptions
|
9
9
|
class BadUID < RuntimeError; end
|
10
|
+
class UnableToFormUrl < RuntimeError; end
|
10
11
|
|
11
12
|
include Configurable
|
12
13
|
|
13
14
|
configurable_attr :root_path, '/var/tmp/dragonfly'
|
15
|
+
configurable_attr :server_root
|
16
|
+
configurable_attr :store_meta, true
|
14
17
|
|
15
18
|
def store(temp_object, opts={})
|
19
|
+
meta = opts[:meta] || {}
|
16
20
|
relative_path = if opts[:path]
|
17
21
|
opts[:path]
|
18
22
|
else
|
19
|
-
filename = temp_object.
|
23
|
+
filename = meta[:name] || temp_object.original_filename || 'file'
|
20
24
|
relative_path = relative_path_for(filename)
|
21
25
|
end
|
22
26
|
|
@@ -27,7 +31,7 @@ module Dragonfly
|
|
27
31
|
end
|
28
32
|
prepare_path(path)
|
29
33
|
temp_object.to_file(path).close
|
30
|
-
|
34
|
+
store_meta_data(path, meta) if store_meta
|
31
35
|
rescue Errno::EACCES => e
|
32
36
|
raise UnableToStore, e.message
|
33
37
|
end
|
@@ -38,26 +42,38 @@ module Dragonfly
|
|
38
42
|
def retrieve(relative_path)
|
39
43
|
validate_uid!(relative_path)
|
40
44
|
path = absolute(relative_path)
|
41
|
-
|
42
|
-
file.
|
45
|
+
pathname = Pathname.new(path)
|
46
|
+
raise DataNotFound, "couldn't find file #{path}" unless pathname.exist?
|
43
47
|
[
|
44
|
-
|
45
|
-
|
48
|
+
pathname,
|
49
|
+
(store_meta ? retrieve_meta_data(path) : {})
|
46
50
|
]
|
47
|
-
rescue Errno::ENOENT => e
|
48
|
-
raise DataNotFound, e.message
|
49
51
|
end
|
50
52
|
|
51
53
|
def destroy(relative_path)
|
52
54
|
validate_uid!(relative_path)
|
53
55
|
path = absolute(relative_path)
|
54
56
|
FileUtils.rm path
|
55
|
-
FileUtils.
|
57
|
+
FileUtils.rm_f meta_data_path(path)
|
58
|
+
FileUtils.rm_f deprecated_meta_data_path(path)
|
56
59
|
purge_empty_directories(relative_path)
|
57
60
|
rescue Errno::ENOENT => e
|
58
61
|
raise DataNotFound, e.message
|
59
62
|
end
|
60
63
|
|
64
|
+
def url_for(relative_path, opts={})
|
65
|
+
if server_root.nil?
|
66
|
+
raise NotConfigured, "you need to configure server_root for #{self.class.name} in order to form urls"
|
67
|
+
else
|
68
|
+
_, __, path = absolute(relative_path).partition(server_root)
|
69
|
+
if path.empty?
|
70
|
+
raise UnableToFormUrl, "couldn't form url for uid #{relative_path.inspect} with root_path #{root_path.inspect} and server_root #{server_root.inspect}"
|
71
|
+
else
|
72
|
+
path
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
61
77
|
def disambiguate(path)
|
62
78
|
dirname = File.dirname(path)
|
63
79
|
basename = File.basename(path, '.*')
|
@@ -72,14 +88,18 @@ module Dragonfly
|
|
72
88
|
end
|
73
89
|
|
74
90
|
def relative(absolute_path)
|
75
|
-
absolute_path[/^#{root_path}\/?(.*)$/, 1]
|
91
|
+
absolute_path[/^#{Regexp.escape root_path}\/?(.*)$/, 1]
|
76
92
|
end
|
77
93
|
|
78
94
|
def directory_empty?(path)
|
79
95
|
Dir.entries(path) == ['.','..']
|
80
96
|
end
|
81
97
|
|
82
|
-
def
|
98
|
+
def meta_data_path(data_path)
|
99
|
+
"#{data_path}.meta"
|
100
|
+
end
|
101
|
+
|
102
|
+
def deprecated_meta_data_path(data_path)
|
83
103
|
"#{data_path}.extra"
|
84
104
|
end
|
85
105
|
|
@@ -89,15 +109,20 @@ module Dragonfly
|
|
89
109
|
"#{time.strftime '%Y/%m/%d/%H_%M_%S'}_#{msec}_#{filename.gsub(/[^\w.]+/,'_')}"
|
90
110
|
end
|
91
111
|
|
92
|
-
def
|
93
|
-
File.open(
|
94
|
-
f.write Marshal.dump(
|
112
|
+
def store_meta_data(data_path, meta)
|
113
|
+
File.open(meta_data_path(data_path), 'wb') do |f|
|
114
|
+
f.write Marshal.dump(meta)
|
95
115
|
end
|
96
116
|
end
|
97
117
|
|
98
|
-
def
|
99
|
-
path =
|
100
|
-
File.exist?(path)
|
118
|
+
def retrieve_meta_data(data_path)
|
119
|
+
path = meta_data_path(data_path)
|
120
|
+
if File.exist?(path)
|
121
|
+
File.open(path,'rb'){|f| Marshal.load(f.read) }
|
122
|
+
else
|
123
|
+
deprecated_path = deprecated_meta_data_path(data_path)
|
124
|
+
File.exist?(deprecated_path) ? File.open(deprecated_path,'rb'){|f| Marshal.load(f.read) } : {}
|
125
|
+
end
|
101
126
|
end
|
102
127
|
|
103
128
|
def prepare_path(path)
|
@@ -114,7 +139,7 @@ module Dragonfly
|
|
114
139
|
end
|
115
140
|
|
116
141
|
def validate_uid!(uid)
|
117
|
-
raise BadUID, "tried to fetch uid #{uid.inspect} - perhaps due to a malicious user" if uid['
|
142
|
+
raise BadUID, "tried to fetch uid #{uid.inspect} - perhaps due to a malicious user" if uid['..']
|
118
143
|
end
|
119
144
|
|
120
145
|
end
|