oahu-dragonfly 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.rspec +1 -0
- data/.yardopts +24 -0
- data/Gemfile +30 -0
- data/History.md +323 -0
- data/LICENSE +20 -0
- data/README.md +88 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/config.ru +14 -0
- data/docs.watchr +1 -0
- data/dragonfly.gemspec +297 -0
- data/extra_docs/Analysers.md +66 -0
- data/extra_docs/Caching.md +23 -0
- data/extra_docs/Configuration.md +124 -0
- data/extra_docs/Couch.md +49 -0
- data/extra_docs/DataStorage.md +153 -0
- data/extra_docs/Encoding.md +67 -0
- data/extra_docs/GeneralUsage.md +121 -0
- data/extra_docs/Generators.md +60 -0
- data/extra_docs/Heroku.md +50 -0
- data/extra_docs/ImageMagick.md +125 -0
- data/extra_docs/Index.md +33 -0
- data/extra_docs/MimeTypes.md +40 -0
- data/extra_docs/Models.md +272 -0
- data/extra_docs/Mongo.md +45 -0
- data/extra_docs/Processing.md +77 -0
- data/extra_docs/Rack.md +52 -0
- data/extra_docs/Rails2.md +57 -0
- data/extra_docs/Rails3.md +62 -0
- data/extra_docs/Sinatra.md +25 -0
- data/extra_docs/URLs.md +169 -0
- data/features/images.feature +47 -0
- data/features/no_processing.feature +14 -0
- data/features/rails_3.0.5.feature +8 -0
- data/features/steps/common_steps.rb +8 -0
- data/features/steps/dragonfly_steps.rb +66 -0
- data/features/steps/rails_steps.rb +28 -0
- data/features/support/env.rb +13 -0
- data/features/support/setup.rb +32 -0
- data/fixtures/rails_3.0.5/files/app/models/album.rb +7 -0
- data/fixtures/rails_3.0.5/files/app/views/albums/new.html.erb +7 -0
- data/fixtures/rails_3.0.5/files/app/views/albums/show.html.erb +6 -0
- data/fixtures/rails_3.0.5/files/config/initializers/dragonfly.rb +4 -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/rails_3.0.5/files/features/step_definitions/image_steps.rb +25 -0
- data/fixtures/rails_3.0.5/files/features/support/paths.rb +17 -0
- data/fixtures/rails_3.0.5/files/features/text_images.feature +7 -0
- data/fixtures/rails_3.0.5/template.rb +20 -0
- data/irbrc.rb +18 -0
- data/lib/dragonfly.rb +55 -0
- data/lib/dragonfly/active_model_extensions.rb +13 -0
- data/lib/dragonfly/active_model_extensions/attachment.rb +250 -0
- data/lib/dragonfly/active_model_extensions/attachment_class_methods.rb +148 -0
- data/lib/dragonfly/active_model_extensions/class_methods.rb +95 -0
- data/lib/dragonfly/active_model_extensions/instance_methods.rb +28 -0
- data/lib/dragonfly/active_model_extensions/validations.rb +41 -0
- data/lib/dragonfly/analyser.rb +58 -0
- data/lib/dragonfly/analysis/file_command_analyser.rb +32 -0
- data/lib/dragonfly/analysis/image_magick_analyser.rb +6 -0
- data/lib/dragonfly/app.rb +172 -0
- data/lib/dragonfly/config/heroku.rb +19 -0
- data/lib/dragonfly/config/image_magick.rb +6 -0
- data/lib/dragonfly/config/rails.rb +20 -0
- data/lib/dragonfly/configurable.rb +207 -0
- data/lib/dragonfly/core_ext/array.rb +7 -0
- data/lib/dragonfly/core_ext/hash.rb +7 -0
- data/lib/dragonfly/core_ext/object.rb +12 -0
- data/lib/dragonfly/core_ext/string.rb +9 -0
- data/lib/dragonfly/core_ext/symbol.rb +9 -0
- data/lib/dragonfly/data_storage.rb +9 -0
- data/lib/dragonfly/data_storage/couch_data_store.rb +64 -0
- data/lib/dragonfly/data_storage/file_data_store.rb +141 -0
- data/lib/dragonfly/data_storage/mongo_data_store.rb +86 -0
- data/lib/dragonfly/data_storage/s3data_store.rb +145 -0
- data/lib/dragonfly/encoder.rb +13 -0
- data/lib/dragonfly/encoding/image_magick_encoder.rb +6 -0
- data/lib/dragonfly/function_manager.rb +71 -0
- data/lib/dragonfly/generation/image_magick_generator.rb +6 -0
- data/lib/dragonfly/generator.rb +9 -0
- 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 +41 -0
- data/lib/dragonfly/image_magick/encoder.rb +57 -0
- data/lib/dragonfly/image_magick/generator.rb +145 -0
- data/lib/dragonfly/image_magick/processor.rb +99 -0
- data/lib/dragonfly/image_magick/utils.rb +72 -0
- data/lib/dragonfly/image_magick_utils.rb +4 -0
- data/lib/dragonfly/job.rb +451 -0
- data/lib/dragonfly/job_builder.rb +39 -0
- data/lib/dragonfly/job_definitions.rb +26 -0
- data/lib/dragonfly/job_endpoint.rb +15 -0
- data/lib/dragonfly/loggable.rb +28 -0
- data/lib/dragonfly/middleware.rb +20 -0
- data/lib/dragonfly/processing/image_magick_processor.rb +6 -0
- data/lib/dragonfly/processor.rb +9 -0
- data/lib/dragonfly/rails/images.rb +27 -0
- data/lib/dragonfly/response.rb +97 -0
- data/lib/dragonfly/routed_endpoint.rb +40 -0
- data/lib/dragonfly/serializer.rb +32 -0
- data/lib/dragonfly/server.rb +113 -0
- data/lib/dragonfly/simple_cache.rb +23 -0
- data/lib/dragonfly/temp_object.rb +175 -0
- data/lib/dragonfly/url_mapper.rb +78 -0
- data/samples/beach.png +0 -0
- data/samples/egg.png +0 -0
- data/samples/round.gif +0 -0
- data/samples/sample.docx +0 -0
- data/samples/taj.jpg +0 -0
- data/spec/dragonfly/active_model_extensions/model_spec.rb +1426 -0
- data/spec/dragonfly/active_model_extensions/spec_helper.rb +91 -0
- data/spec/dragonfly/analyser_spec.rb +123 -0
- data/spec/dragonfly/analysis/file_command_analyser_spec.rb +48 -0
- data/spec/dragonfly/app_spec.rb +135 -0
- data/spec/dragonfly/configurable_spec.rb +461 -0
- data/spec/dragonfly/core_ext/array_spec.rb +19 -0
- data/spec/dragonfly/core_ext/hash_spec.rb +19 -0
- data/spec/dragonfly/core_ext/string_spec.rb +17 -0
- data/spec/dragonfly/core_ext/symbol_spec.rb +17 -0
- data/spec/dragonfly/data_storage/couch_data_store_spec.rb +76 -0
- data/spec/dragonfly/data_storage/file_data_store_spec.rb +296 -0
- data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +57 -0
- data/spec/dragonfly/data_storage/s3_data_store_spec.rb +258 -0
- data/spec/dragonfly/data_storage/shared_data_store_examples.rb +77 -0
- data/spec/dragonfly/function_manager_spec.rb +154 -0
- data/spec/dragonfly/hash_with_css_style_keys_spec.rb +24 -0
- data/spec/dragonfly/image_magick/analyser_spec.rb +64 -0
- data/spec/dragonfly/image_magick/encoder_spec.rb +41 -0
- data/spec/dragonfly/image_magick/generator_spec.rb +172 -0
- data/spec/dragonfly/image_magick/processor_spec.rb +233 -0
- data/spec/dragonfly/image_magick/utils_spec.rb +18 -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 +173 -0
- data/spec/dragonfly/job_spec.rb +1046 -0
- data/spec/dragonfly/loggable_spec.rb +80 -0
- data/spec/dragonfly/middleware_spec.rb +47 -0
- data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
- data/spec/dragonfly/serializer_spec.rb +61 -0
- data/spec/dragonfly/server_spec.rb +278 -0
- data/spec/dragonfly/simple_cache_spec.rb +27 -0
- data/spec/dragonfly/temp_object_spec.rb +306 -0
- data/spec/dragonfly/url_mapper_spec.rb +126 -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 +51 -0
- data/spec/support/argument_matchers.rb +19 -0
- data/spec/support/image_matchers.rb +47 -0
- data/spec/support/simple_matchers.rb +53 -0
- data/yard/handlers/configurable_attr_handler.rb +38 -0
- data/yard/setup.rb +15 -0
- data/yard/templates/default/fulldoc/html/css/common.css +107 -0
- data/yard/templates/default/layout/html/layout.erb +89 -0
- data/yard/templates/default/module/html/configuration_summary.erb +31 -0
- data/yard/templates/default/module/setup.rb +17 -0
- metadata +544 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Dragonfly
|
|
2
|
+
module ActiveModelExtensions
|
|
3
|
+
module InstanceMethods
|
|
4
|
+
|
|
5
|
+
def dragonfly_attachments
|
|
6
|
+
@dragonfly_attachments ||= self.class.dragonfly_attachment_classes.inject({}) do |hash, klass|
|
|
7
|
+
hash[klass.attribute] = klass.new(self)
|
|
8
|
+
hash
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def save_dragonfly_attachments
|
|
15
|
+
dragonfly_attachments.each do |attribute, attachment|
|
|
16
|
+
attachment.save!
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def destroy_dragonfly_attachments
|
|
21
|
+
dragonfly_attachments.each do |attribute, attachment|
|
|
22
|
+
attachment.destroy!
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Dragonfly
|
|
2
|
+
module ActiveModelExtensions
|
|
3
|
+
module Validations
|
|
4
|
+
|
|
5
|
+
private
|
|
6
|
+
|
|
7
|
+
def validates_property(property_name, opts)
|
|
8
|
+
attrs = opts[:of] or raise ArgumentError, "you need to provide the attribute which has the property, using :of => <attribute_name>"
|
|
9
|
+
attrs = [attrs].flatten #(make sure it's an array)
|
|
10
|
+
|
|
11
|
+
raise ArgumentError, "you must provide either :in => [<value1>, <value2>..] or :as => <value>" unless opts[:in] || opts[:as]
|
|
12
|
+
allowed_values = opts[:in] || [opts[:as]]
|
|
13
|
+
|
|
14
|
+
args = attrs + [opts]
|
|
15
|
+
validates_each(*args) do |model, attr, attachment|
|
|
16
|
+
if attachment
|
|
17
|
+
property = attachment.send(property_name)
|
|
18
|
+
unless allowed_values.include?(property)
|
|
19
|
+
message = opts[:message] ||
|
|
20
|
+
"#{property_name.to_s.humanize.downcase} is incorrect. "+
|
|
21
|
+
"It needs to be #{Validations.expected_values_string(allowed_values)}"+
|
|
22
|
+
(property ? ", but was '#{property}'" : "")
|
|
23
|
+
message = message.call(property, model) if message.respond_to?(:call)
|
|
24
|
+
model.errors.add(attr, message)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.expected_values_string(allowed_values)
|
|
32
|
+
if allowed_values.is_a?(Range)
|
|
33
|
+
"between #{allowed_values.first} and #{allowed_values.last}"
|
|
34
|
+
else
|
|
35
|
+
allowed_values.length > 1 ? "one of '#{allowed_values.join('\', \'')}'" : "'#{allowed_values.first.to_s}'"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module Dragonfly
|
|
2
|
+
class Analyser < FunctionManager
|
|
3
|
+
|
|
4
|
+
configurable_attr :enable_cache, true
|
|
5
|
+
configurable_attr :cache_size, 100
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
super
|
|
9
|
+
analyser = self
|
|
10
|
+
@analysis_methods = Module.new do
|
|
11
|
+
|
|
12
|
+
define_method :analyser do
|
|
13
|
+
analyser
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
@analysis_method_names = []
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
attr_reader :analysis_methods, :analysis_method_names
|
|
21
|
+
|
|
22
|
+
def analyse(temp_object, method, *args)
|
|
23
|
+
if enable_cache
|
|
24
|
+
key = [temp_object.object_id, method, *args]
|
|
25
|
+
cache[key] ||= call_last(method, temp_object, *args)
|
|
26
|
+
else
|
|
27
|
+
call_last(method, temp_object, *args)
|
|
28
|
+
end
|
|
29
|
+
rescue NotDefined, UnableToHandle => e
|
|
30
|
+
log.warn(e.message)
|
|
31
|
+
nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Each time a function is registered with the analyser,
|
|
35
|
+
# add a method to the analysis_methods module.
|
|
36
|
+
# Expects the object that is extended to define 'analyse(method, *args)'
|
|
37
|
+
def add(name, *args, &block)
|
|
38
|
+
analysis_methods.module_eval %(
|
|
39
|
+
def #{name}(*args)
|
|
40
|
+
analyse(:#{name}, *args)
|
|
41
|
+
end
|
|
42
|
+
)
|
|
43
|
+
analysis_method_names << name.to_sym
|
|
44
|
+
super
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def clear_cache!
|
|
48
|
+
@cache = nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def cache
|
|
54
|
+
@cache ||= SimpleCache.new(cache_size)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Dragonfly
|
|
2
|
+
module Analysis
|
|
3
|
+
|
|
4
|
+
class FileCommandAnalyser
|
|
5
|
+
|
|
6
|
+
include Configurable
|
|
7
|
+
|
|
8
|
+
configurable_attr :file_command, "file"
|
|
9
|
+
configurable_attr :use_filesystem, false
|
|
10
|
+
configurable_attr :num_bytes_to_check, 255
|
|
11
|
+
|
|
12
|
+
def mime_type(temp_object)
|
|
13
|
+
content_type = if use_filesystem
|
|
14
|
+
`#{file_command} -b --mime '#{temp_object.path}'`
|
|
15
|
+
else
|
|
16
|
+
IO.popen("#{file_command} -b --mime -", 'r+') do |io|
|
|
17
|
+
if num_bytes_to_check
|
|
18
|
+
io.write temp_object.data[0, num_bytes_to_check]
|
|
19
|
+
else
|
|
20
|
+
io.write temp_object.data
|
|
21
|
+
end
|
|
22
|
+
io.close_write
|
|
23
|
+
io.read
|
|
24
|
+
end
|
|
25
|
+
end.split(';').first
|
|
26
|
+
content_type.strip if content_type
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
require 'logger'
|
|
2
|
+
require 'forwardable'
|
|
3
|
+
require 'rack'
|
|
4
|
+
|
|
5
|
+
module Dragonfly
|
|
6
|
+
class App
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
|
|
10
|
+
private :new # Hide 'new' - need to use 'instance'
|
|
11
|
+
|
|
12
|
+
def instance(name)
|
|
13
|
+
apps[name] ||= new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
alias [] instance
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def apps
|
|
21
|
+
@apps ||= {}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def initialize
|
|
27
|
+
@analyser, @processor, @encoder, @generator = Analyser.new, Processor.new, Encoder.new, Generator.new
|
|
28
|
+
[@analyser, @processor, @encoder, @generator].each do |obj|
|
|
29
|
+
obj.use_same_log_as(self)
|
|
30
|
+
obj.use_as_fallback_config(self)
|
|
31
|
+
end
|
|
32
|
+
@server = Server.new(self)
|
|
33
|
+
@job_definitions = JobDefinitions.new
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
include Configurable
|
|
37
|
+
|
|
38
|
+
extend Forwardable
|
|
39
|
+
def_delegator :datastore, :destroy
|
|
40
|
+
def_delegators :new_job, :fetch, :generate, :fetch_file, :fetch_url
|
|
41
|
+
def_delegators :server, :call
|
|
42
|
+
|
|
43
|
+
configurable_attr :datastore do DataStorage::FileDataStore.new end
|
|
44
|
+
configurable_attr :cache_duration, 3600*24*365 # (1 year)
|
|
45
|
+
configurable_attr :fallback_mime_type, 'application/octet-stream'
|
|
46
|
+
configurable_attr :secret, 'secret yo'
|
|
47
|
+
configurable_attr :log do Logger.new('/var/tmp/dragonfly.log') end
|
|
48
|
+
configurable_attr :trust_file_extensions, true
|
|
49
|
+
configurable_attr :content_disposition
|
|
50
|
+
configurable_attr :content_filename, Response::DEFAULT_FILENAME
|
|
51
|
+
|
|
52
|
+
attr_reader :analyser
|
|
53
|
+
attr_reader :processor
|
|
54
|
+
attr_reader :encoder
|
|
55
|
+
attr_reader :generator
|
|
56
|
+
attr_reader :server
|
|
57
|
+
|
|
58
|
+
nested_configurable :server, :analyser, :processor, :encoder, :generator
|
|
59
|
+
|
|
60
|
+
attr_accessor :job_definitions
|
|
61
|
+
|
|
62
|
+
def new_job(content=nil, meta={})
|
|
63
|
+
job_class.new(self, content, meta)
|
|
64
|
+
end
|
|
65
|
+
alias create new_job
|
|
66
|
+
|
|
67
|
+
def endpoint(job=nil, &block)
|
|
68
|
+
block ? RoutedEndpoint.new(self, &block) : JobEndpoint.new(job)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def job(name, &block)
|
|
72
|
+
job_definitions.add(name, &block)
|
|
73
|
+
end
|
|
74
|
+
configuration_method :job
|
|
75
|
+
|
|
76
|
+
def job_class
|
|
77
|
+
@job_class ||= begin
|
|
78
|
+
app = self
|
|
79
|
+
Class.new(Job).class_eval do
|
|
80
|
+
include app.analyser.analysis_methods
|
|
81
|
+
include app.job_definitions
|
|
82
|
+
include Job::OverrideInstanceMethods
|
|
83
|
+
self
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def store(object, opts={})
|
|
89
|
+
temp_object = object.is_a?(TempObject) ? object : TempObject.new(object)
|
|
90
|
+
datastore.store(temp_object, opts)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def register_mime_type(format, mime_type)
|
|
94
|
+
registered_mime_types[file_ext_string(format)] = mime_type
|
|
95
|
+
end
|
|
96
|
+
configuration_method :register_mime_type
|
|
97
|
+
|
|
98
|
+
def registered_mime_types
|
|
99
|
+
@registered_mime_types ||= Rack::Mime::MIME_TYPES.dup
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def mime_type_for(format)
|
|
103
|
+
registered_mime_types[file_ext_string(format)]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def define_url(&block)
|
|
107
|
+
@url_proc = block
|
|
108
|
+
end
|
|
109
|
+
configuration_method :define_url
|
|
110
|
+
|
|
111
|
+
def url_for(job, opts={})
|
|
112
|
+
if @url_proc
|
|
113
|
+
@url_proc.call(self, job, opts)
|
|
114
|
+
else
|
|
115
|
+
server.url_for(job, opts)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def remote_url_for(uid, opts={})
|
|
120
|
+
datastore.url_for(uid, opts)
|
|
121
|
+
rescue NoMethodError => e
|
|
122
|
+
raise NotImplementedError, "The datastore doesn't support serving content directly - #{datastore.inspect}"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def define_macro(mod, macro_name)
|
|
126
|
+
already_extended = (class << mod; self; end).included_modules.include?(ActiveModelExtensions)
|
|
127
|
+
mod.extend(ActiveModelExtensions) unless already_extended
|
|
128
|
+
mod.register_dragonfly_app(macro_name, self)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def define_macro_on_include(mod, macro_name)
|
|
132
|
+
app = self
|
|
133
|
+
(class << mod; self; end).class_eval do
|
|
134
|
+
alias included_without_dragonfly included
|
|
135
|
+
define_method :included_with_dragonfly do |mod|
|
|
136
|
+
included_without_dragonfly(mod)
|
|
137
|
+
app.define_macro(mod, macro_name)
|
|
138
|
+
end
|
|
139
|
+
alias included included_with_dragonfly
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Deprecated methods
|
|
144
|
+
def url_path_prefix=(thing)
|
|
145
|
+
raise NoMethodError, "url_path_prefix is deprecated - please use url_format, e.g. url_format = '/media/:job/:basename.:format' - see docs for more details"
|
|
146
|
+
end
|
|
147
|
+
configuration_method :url_path_prefix=
|
|
148
|
+
|
|
149
|
+
def url_suffix=(thing)
|
|
150
|
+
raise NoMethodError, "url_suffix is deprecated - please use url_format, e.g. url_format = '/media/:job/:basename.:format' - see docs for more details"
|
|
151
|
+
end
|
|
152
|
+
configuration_method :url_suffix=
|
|
153
|
+
|
|
154
|
+
def infer_mime_type_from_file_ext=(bool)
|
|
155
|
+
raise NoMethodError, "infer_mime_type_from_file_ext is deprecated - please use trust_file_extensions = #{bool.inspect} instead"
|
|
156
|
+
end
|
|
157
|
+
configuration_method :infer_mime_type_from_file_ext=
|
|
158
|
+
|
|
159
|
+
private
|
|
160
|
+
|
|
161
|
+
attr_accessor :get_remote_url
|
|
162
|
+
|
|
163
|
+
def saved_configs
|
|
164
|
+
self.class.saved_configs
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def file_ext_string(format)
|
|
168
|
+
'.' + format.to_s.downcase.sub(/^.*\./,'')
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
end
|
|
172
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Dragonfly
|
|
2
|
+
module Config
|
|
3
|
+
|
|
4
|
+
module Heroku
|
|
5
|
+
|
|
6
|
+
def self.apply_configuration(app, bucket_name)
|
|
7
|
+
app.configure do |c|
|
|
8
|
+
c.datastore = DataStorage::S3DataStore.new
|
|
9
|
+
c.datastore.configure do |d|
|
|
10
|
+
d.bucket_name = bucket_name
|
|
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")
|
|
12
|
+
d.secret_access_key = ENV['S3_SECRET'] || raise("ENV variable 'S3_SECRET' needs to be set - use\n\theroku config:add S3_SECRET=XXXXXXXXX")
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Dragonfly
|
|
2
|
+
module Config
|
|
3
|
+
|
|
4
|
+
module Rails
|
|
5
|
+
|
|
6
|
+
def self.apply_configuration(app)
|
|
7
|
+
app.configure do |c|
|
|
8
|
+
c.log = ::Rails.logger
|
|
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'
|
|
14
|
+
c.analyser.register(Analysis::FileCommandAnalyser)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
module Dragonfly
|
|
2
|
+
module Configurable
|
|
3
|
+
|
|
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
|
+
|
|
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
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class DeferredBlock # Inheriting from Proc causes errors in some versions of Ruby
|
|
23
|
+
def initialize(blk)
|
|
24
|
+
@blk = blk
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def call
|
|
28
|
+
@blk.call
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
module InstanceMethods
|
|
33
|
+
|
|
34
|
+
def configure(&block)
|
|
35
|
+
yield ConfigurationProxy.new(self)
|
|
36
|
+
self
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def configure_with(config, *args, &block)
|
|
40
|
+
config = saved_config_for(config) if config.is_a?(Symbol)
|
|
41
|
+
config.apply_configuration(self, *args)
|
|
42
|
+
configure(&block) if block
|
|
43
|
+
self
|
|
44
|
+
end
|
|
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
|
+
|
|
54
|
+
def configuration
|
|
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]
|
|
106
|
+
end
|
|
107
|
+
|
|
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
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
module ClassMethods
|
|
124
|
+
|
|
125
|
+
def default_configuration
|
|
126
|
+
@default_configuration ||= {}
|
|
127
|
+
end
|
|
128
|
+
|
|
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 ||= {}
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
private
|
|
146
|
+
|
|
147
|
+
def configurable_attr attribute, default=nil, &blk
|
|
148
|
+
default_configuration[attribute] = blk ? DeferredBlock.new(blk) : default
|
|
149
|
+
|
|
150
|
+
# Define the reader
|
|
151
|
+
define_method(attribute) do
|
|
152
|
+
configuration.has_key?(attribute) ? configuration[attribute] : default_value(attribute)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Define the writer
|
|
156
|
+
define_method("#{attribute}=") do |value|
|
|
157
|
+
instance_variable_set("@#{attribute}", value)
|
|
158
|
+
set_config_value(attribute, value)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
configuration_method attribute
|
|
162
|
+
configuration_method "#{attribute}="
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def configuration_method(*method_names)
|
|
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)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
class ConfigurationProxy
|
|
176
|
+
|
|
177
|
+
def initialize(owner)
|
|
178
|
+
@owner = owner
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def method_missing(method_name, *args, &block)
|
|
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)
|
|
191
|
+
else
|
|
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(', ')}"
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
private
|
|
197
|
+
|
|
198
|
+
attr_reader :owner
|
|
199
|
+
|
|
200
|
+
def nested_configurable?(method)
|
|
201
|
+
owner.configured_class.nested_configurables.include?(method.to_sym)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
end
|
|
207
|
+
end
|