oahu-dragonfly 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. data/.rspec +1 -0
  2. data/.yardopts +24 -0
  3. data/Gemfile +30 -0
  4. data/History.md +323 -0
  5. data/LICENSE +20 -0
  6. data/README.md +88 -0
  7. data/Rakefile +50 -0
  8. data/VERSION +1 -0
  9. data/config.ru +14 -0
  10. data/docs.watchr +1 -0
  11. data/dragonfly.gemspec +297 -0
  12. data/extra_docs/Analysers.md +66 -0
  13. data/extra_docs/Caching.md +23 -0
  14. data/extra_docs/Configuration.md +124 -0
  15. data/extra_docs/Couch.md +49 -0
  16. data/extra_docs/DataStorage.md +153 -0
  17. data/extra_docs/Encoding.md +67 -0
  18. data/extra_docs/GeneralUsage.md +121 -0
  19. data/extra_docs/Generators.md +60 -0
  20. data/extra_docs/Heroku.md +50 -0
  21. data/extra_docs/ImageMagick.md +125 -0
  22. data/extra_docs/Index.md +33 -0
  23. data/extra_docs/MimeTypes.md +40 -0
  24. data/extra_docs/Models.md +272 -0
  25. data/extra_docs/Mongo.md +45 -0
  26. data/extra_docs/Processing.md +77 -0
  27. data/extra_docs/Rack.md +52 -0
  28. data/extra_docs/Rails2.md +57 -0
  29. data/extra_docs/Rails3.md +62 -0
  30. data/extra_docs/Sinatra.md +25 -0
  31. data/extra_docs/URLs.md +169 -0
  32. data/features/images.feature +47 -0
  33. data/features/no_processing.feature +14 -0
  34. data/features/rails_3.0.5.feature +8 -0
  35. data/features/steps/common_steps.rb +8 -0
  36. data/features/steps/dragonfly_steps.rb +66 -0
  37. data/features/steps/rails_steps.rb +28 -0
  38. data/features/support/env.rb +13 -0
  39. data/features/support/setup.rb +32 -0
  40. data/fixtures/rails_3.0.5/files/app/models/album.rb +7 -0
  41. data/fixtures/rails_3.0.5/files/app/views/albums/new.html.erb +7 -0
  42. data/fixtures/rails_3.0.5/files/app/views/albums/show.html.erb +6 -0
  43. data/fixtures/rails_3.0.5/files/config/initializers/dragonfly.rb +4 -0
  44. data/fixtures/rails_3.0.5/files/features/manage_album_images.feature +38 -0
  45. data/fixtures/rails_3.0.5/files/features/step_definitions/helper_steps.rb +7 -0
  46. data/fixtures/rails_3.0.5/files/features/step_definitions/image_steps.rb +25 -0
  47. data/fixtures/rails_3.0.5/files/features/support/paths.rb +17 -0
  48. data/fixtures/rails_3.0.5/files/features/text_images.feature +7 -0
  49. data/fixtures/rails_3.0.5/template.rb +20 -0
  50. data/irbrc.rb +18 -0
  51. data/lib/dragonfly.rb +55 -0
  52. data/lib/dragonfly/active_model_extensions.rb +13 -0
  53. data/lib/dragonfly/active_model_extensions/attachment.rb +250 -0
  54. data/lib/dragonfly/active_model_extensions/attachment_class_methods.rb +148 -0
  55. data/lib/dragonfly/active_model_extensions/class_methods.rb +95 -0
  56. data/lib/dragonfly/active_model_extensions/instance_methods.rb +28 -0
  57. data/lib/dragonfly/active_model_extensions/validations.rb +41 -0
  58. data/lib/dragonfly/analyser.rb +58 -0
  59. data/lib/dragonfly/analysis/file_command_analyser.rb +32 -0
  60. data/lib/dragonfly/analysis/image_magick_analyser.rb +6 -0
  61. data/lib/dragonfly/app.rb +172 -0
  62. data/lib/dragonfly/config/heroku.rb +19 -0
  63. data/lib/dragonfly/config/image_magick.rb +6 -0
  64. data/lib/dragonfly/config/rails.rb +20 -0
  65. data/lib/dragonfly/configurable.rb +207 -0
  66. data/lib/dragonfly/core_ext/array.rb +7 -0
  67. data/lib/dragonfly/core_ext/hash.rb +7 -0
  68. data/lib/dragonfly/core_ext/object.rb +12 -0
  69. data/lib/dragonfly/core_ext/string.rb +9 -0
  70. data/lib/dragonfly/core_ext/symbol.rb +9 -0
  71. data/lib/dragonfly/data_storage.rb +9 -0
  72. data/lib/dragonfly/data_storage/couch_data_store.rb +64 -0
  73. data/lib/dragonfly/data_storage/file_data_store.rb +141 -0
  74. data/lib/dragonfly/data_storage/mongo_data_store.rb +86 -0
  75. data/lib/dragonfly/data_storage/s3data_store.rb +145 -0
  76. data/lib/dragonfly/encoder.rb +13 -0
  77. data/lib/dragonfly/encoding/image_magick_encoder.rb +6 -0
  78. data/lib/dragonfly/function_manager.rb +71 -0
  79. data/lib/dragonfly/generation/image_magick_generator.rb +6 -0
  80. data/lib/dragonfly/generator.rb +9 -0
  81. data/lib/dragonfly/hash_with_css_style_keys.rb +21 -0
  82. data/lib/dragonfly/image_magick/analyser.rb +51 -0
  83. data/lib/dragonfly/image_magick/config.rb +41 -0
  84. data/lib/dragonfly/image_magick/encoder.rb +57 -0
  85. data/lib/dragonfly/image_magick/generator.rb +145 -0
  86. data/lib/dragonfly/image_magick/processor.rb +99 -0
  87. data/lib/dragonfly/image_magick/utils.rb +72 -0
  88. data/lib/dragonfly/image_magick_utils.rb +4 -0
  89. data/lib/dragonfly/job.rb +451 -0
  90. data/lib/dragonfly/job_builder.rb +39 -0
  91. data/lib/dragonfly/job_definitions.rb +26 -0
  92. data/lib/dragonfly/job_endpoint.rb +15 -0
  93. data/lib/dragonfly/loggable.rb +28 -0
  94. data/lib/dragonfly/middleware.rb +20 -0
  95. data/lib/dragonfly/processing/image_magick_processor.rb +6 -0
  96. data/lib/dragonfly/processor.rb +9 -0
  97. data/lib/dragonfly/rails/images.rb +27 -0
  98. data/lib/dragonfly/response.rb +97 -0
  99. data/lib/dragonfly/routed_endpoint.rb +40 -0
  100. data/lib/dragonfly/serializer.rb +32 -0
  101. data/lib/dragonfly/server.rb +113 -0
  102. data/lib/dragonfly/simple_cache.rb +23 -0
  103. data/lib/dragonfly/temp_object.rb +175 -0
  104. data/lib/dragonfly/url_mapper.rb +78 -0
  105. data/samples/beach.png +0 -0
  106. data/samples/egg.png +0 -0
  107. data/samples/round.gif +0 -0
  108. data/samples/sample.docx +0 -0
  109. data/samples/taj.jpg +0 -0
  110. data/spec/dragonfly/active_model_extensions/model_spec.rb +1426 -0
  111. data/spec/dragonfly/active_model_extensions/spec_helper.rb +91 -0
  112. data/spec/dragonfly/analyser_spec.rb +123 -0
  113. data/spec/dragonfly/analysis/file_command_analyser_spec.rb +48 -0
  114. data/spec/dragonfly/app_spec.rb +135 -0
  115. data/spec/dragonfly/configurable_spec.rb +461 -0
  116. data/spec/dragonfly/core_ext/array_spec.rb +19 -0
  117. data/spec/dragonfly/core_ext/hash_spec.rb +19 -0
  118. data/spec/dragonfly/core_ext/string_spec.rb +17 -0
  119. data/spec/dragonfly/core_ext/symbol_spec.rb +17 -0
  120. data/spec/dragonfly/data_storage/couch_data_store_spec.rb +76 -0
  121. data/spec/dragonfly/data_storage/file_data_store_spec.rb +296 -0
  122. data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +57 -0
  123. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +258 -0
  124. data/spec/dragonfly/data_storage/shared_data_store_examples.rb +77 -0
  125. data/spec/dragonfly/function_manager_spec.rb +154 -0
  126. data/spec/dragonfly/hash_with_css_style_keys_spec.rb +24 -0
  127. data/spec/dragonfly/image_magick/analyser_spec.rb +64 -0
  128. data/spec/dragonfly/image_magick/encoder_spec.rb +41 -0
  129. data/spec/dragonfly/image_magick/generator_spec.rb +172 -0
  130. data/spec/dragonfly/image_magick/processor_spec.rb +233 -0
  131. data/spec/dragonfly/image_magick/utils_spec.rb +18 -0
  132. data/spec/dragonfly/job_builder_spec.rb +37 -0
  133. data/spec/dragonfly/job_definitions_spec.rb +35 -0
  134. data/spec/dragonfly/job_endpoint_spec.rb +173 -0
  135. data/spec/dragonfly/job_spec.rb +1046 -0
  136. data/spec/dragonfly/loggable_spec.rb +80 -0
  137. data/spec/dragonfly/middleware_spec.rb +47 -0
  138. data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
  139. data/spec/dragonfly/serializer_spec.rb +61 -0
  140. data/spec/dragonfly/server_spec.rb +278 -0
  141. data/spec/dragonfly/simple_cache_spec.rb +27 -0
  142. data/spec/dragonfly/temp_object_spec.rb +306 -0
  143. data/spec/dragonfly/url_mapper_spec.rb +126 -0
  144. data/spec/functional/deprecations_spec.rb +51 -0
  145. data/spec/functional/image_magick_app_spec.rb +27 -0
  146. data/spec/functional/model_urls_spec.rb +85 -0
  147. data/spec/functional/remote_on_the_fly_spec.rb +51 -0
  148. data/spec/functional/to_response_spec.rb +31 -0
  149. data/spec/spec_helper.rb +51 -0
  150. data/spec/support/argument_matchers.rb +19 -0
  151. data/spec/support/image_matchers.rb +47 -0
  152. data/spec/support/simple_matchers.rb +53 -0
  153. data/yard/handlers/configurable_attr_handler.rb +38 -0
  154. data/yard/setup.rb +15 -0
  155. data/yard/templates/default/fulldoc/html/css/common.css +107 -0
  156. data/yard/templates/default/layout/html/layout.erb +89 -0
  157. data/yard/templates/default/module/html/configuration_summary.erb +31 -0
  158. data/yard/templates/default/module/setup.rb +17 -0
  159. metadata +544 -0
@@ -0,0 +1,7 @@
1
+ class Array
2
+
3
+ def to_dragonfly_unique_s
4
+ map{|item| item.to_dragonfly_unique_s }.join
5
+ end
6
+
7
+ end
@@ -0,0 +1,7 @@
1
+ class Hash
2
+
3
+ def to_dragonfly_unique_s
4
+ sort_by{|k, v| k.to_dragonfly_unique_s }.to_dragonfly_unique_s
5
+ end
6
+
7
+ end
@@ -0,0 +1,12 @@
1
+ class Object
2
+
3
+ # Don't want to depend on activesupport for this
4
+ def blank?
5
+ respond_to?(:empty?) ? empty? : !self
6
+ end
7
+
8
+ def to_dragonfly_unique_s
9
+ to_s
10
+ end
11
+
12
+ end
@@ -0,0 +1,9 @@
1
+ class String
2
+
3
+ # Ruby 1.8 reports methods as strings,
4
+ # whereas 1.9 reports them as symbols
5
+ def to_method_name
6
+ RUBY_VERSION =~ /^1.8/ ? self : to_sym
7
+ end
8
+
9
+ end
@@ -0,0 +1,9 @@
1
+ class Symbol
2
+
3
+ # Ruby 1.8 reports methods as strings,
4
+ # whereas 1.9 reports them as symbols
5
+ def to_method_name
6
+ RUBY_VERSION =~ /^1.8/ ? to_s : self
7
+ end
8
+
9
+ end
@@ -0,0 +1,9 @@
1
+ module Dragonfly
2
+ module DataStorage
3
+
4
+ # Exceptions
5
+ class DataNotFound < StandardError; end
6
+ class UnableToStore < StandardError; end
7
+
8
+ end
9
+ end
@@ -0,0 +1,64 @@
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]
18
+ self.port = 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
+ response['id']
34
+ end
35
+ rescue RuntimeError => e
36
+ raise UnableToStore, "#{e} - #{temp_object.inspect}"
37
+ end
38
+
39
+ def retrieve(uid)
40
+ doc = db.get(uid)
41
+ name = doc['_attachments'].keys.first
42
+ [doc.fetch_attachment(name), marshal_decode(doc['meta'])]
43
+ rescue RestClient::ResourceNotFound => e
44
+ raise DataNotFound, "#{e} - #{uid}"
45
+ end
46
+
47
+ def destroy(uid)
48
+ doc = db.get(uid)
49
+ db.delete_doc(doc)
50
+ rescue RestClient::ResourceNotFound => e
51
+ raise DataNotFound, "#{e} - #{uid}"
52
+ end
53
+
54
+ def db
55
+ @db ||= begin
56
+ auth = username.blank? ? nil : "#{username}:#{password}@"
57
+ url = "http://#{auth}#{host}:#{port}"
58
+ CouchRest.new(url).database!(database)
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,141 @@
1
+ require 'pathname'
2
+
3
+ module Dragonfly
4
+ module DataStorage
5
+
6
+ class FileDataStore
7
+
8
+ # Exceptions
9
+ class UnableToFormUrl < RuntimeError; end
10
+
11
+ include Configurable
12
+
13
+ configurable_attr :root_path, '/var/tmp/dragonfly'
14
+ configurable_attr :server_root
15
+ configurable_attr :store_meta, true
16
+
17
+ def store(temp_object, opts={})
18
+ meta = opts[:meta] || {}
19
+ relative_path = if opts[:path]
20
+ opts[:path]
21
+ else
22
+ filename = meta[:name] || temp_object.original_filename || 'file'
23
+ relative_path = relative_path_for(filename)
24
+ end
25
+
26
+ begin
27
+ path = absolute(relative_path)
28
+ until !File.exist?(path)
29
+ path = disambiguate(path)
30
+ end
31
+ prepare_path(path)
32
+ temp_object.to_file(path).close
33
+ store_meta_data(path, meta) if store_meta
34
+ rescue Errno::EACCES => e
35
+ raise UnableToStore, e.message
36
+ end
37
+
38
+ relative(path)
39
+ end
40
+
41
+ def retrieve(relative_path)
42
+ path = absolute(relative_path)
43
+ pathname = Pathname.new(path)
44
+ raise DataNotFound, "couldn't find file #{path}" unless pathname.exist?
45
+ [
46
+ pathname,
47
+ (store_meta ? retrieve_meta_data(path) : {})
48
+ ]
49
+ end
50
+
51
+ def destroy(relative_path)
52
+ path = absolute(relative_path)
53
+ FileUtils.rm path
54
+ FileUtils.rm_f meta_data_path(path)
55
+ FileUtils.rm_f deprecated_meta_data_path(path)
56
+ purge_empty_directories(relative_path)
57
+ rescue Errno::ENOENT => e
58
+ raise DataNotFound, e.message
59
+ end
60
+
61
+ def url_for(relative_path, opts={})
62
+ if server_root.nil?
63
+ raise NotConfigured, "you need to configure server_root for #{self.class.name} in order to form urls"
64
+ else
65
+ _, __, path = absolute(relative_path).partition(server_root)
66
+ if path.empty?
67
+ raise UnableToFormUrl, "couldn't form url for uid #{relative_path.inspect} with root_path #{root_path.inspect} and server_root #{server_root.inspect}"
68
+ else
69
+ path
70
+ end
71
+ end
72
+ end
73
+
74
+ def disambiguate(path)
75
+ dirname = File.dirname(path)
76
+ basename = File.basename(path, '.*')
77
+ extname = File.extname(path)
78
+ "#{dirname}/#{basename}_#{(Time.now.usec*10 + rand(100)).to_s(32)}#{extname}"
79
+ end
80
+
81
+ private
82
+
83
+ def absolute(relative_path)
84
+ File.join(root_path, relative_path)
85
+ end
86
+
87
+ def relative(absolute_path)
88
+ absolute_path[/^#{Regexp.escape root_path}\/?(.*)$/, 1]
89
+ end
90
+
91
+ def directory_empty?(path)
92
+ Dir.entries(path) == ['.','..']
93
+ end
94
+
95
+ def meta_data_path(data_path)
96
+ "#{data_path}.meta"
97
+ end
98
+
99
+ def deprecated_meta_data_path(data_path)
100
+ "#{data_path}.extra"
101
+ end
102
+
103
+ def relative_path_for(filename)
104
+ time = Time.now
105
+ msec = time.usec / 1000
106
+ "#{time.strftime '%Y/%m/%d/%H_%M_%S'}_#{msec}_#{filename.gsub(/[^\w.]+/,'_')}"
107
+ end
108
+
109
+ def store_meta_data(data_path, meta)
110
+ File.open(meta_data_path(data_path), 'wb') do |f|
111
+ f.write Marshal.dump(meta)
112
+ end
113
+ end
114
+
115
+ def retrieve_meta_data(data_path)
116
+ path = meta_data_path(data_path)
117
+ if File.exist?(path)
118
+ File.open(path,'rb'){|f| Marshal.load(f.read) }
119
+ else
120
+ deprecated_path = deprecated_meta_data_path(data_path)
121
+ File.exist?(deprecated_path) ? File.open(deprecated_path,'rb'){|f| Marshal.load(f.read) } : {}
122
+ end
123
+ end
124
+
125
+ def prepare_path(path)
126
+ dir = File.dirname(path)
127
+ FileUtils.mkdir_p(dir) unless File.exist?(dir)
128
+ end
129
+
130
+ def purge_empty_directories(path)
131
+ containing_directory = Pathname.new(path).dirname
132
+ containing_directory.ascend do |relative_dir|
133
+ dir = absolute(relative_dir)
134
+ FileUtils.rmdir dir if directory_empty?(dir)
135
+ end
136
+ end
137
+
138
+ end
139
+
140
+ end
141
+ end
@@ -0,0 +1,86 @@
1
+ require 'mongo'
2
+
3
+ module Dragonfly
4
+ module DataStorage
5
+ class MongoDataStore
6
+
7
+ include Configurable
8
+ include Serializer
9
+
10
+ configurable_attr :host
11
+ configurable_attr :port
12
+ configurable_attr :database, 'dragonfly'
13
+ configurable_attr :username
14
+ configurable_attr :password
15
+ configurable_attr :connection
16
+ configurable_attr :db
17
+
18
+ # Mongo gem deprecated ObjectID in favour of ObjectId
19
+ OBJECT_ID = defined?(BSON::ObjectId) ? BSON::ObjectId : BSON::ObjectID
20
+ INVALID_OBJECT_ID = defined?(BSON::InvalidObjectId) ? BSON::InvalidObjectId : BSON::InvalidObjectID
21
+
22
+ def initialize(opts={})
23
+ self.host = opts[:host]
24
+ self.port = opts[:port]
25
+ self.database = opts[:database] if opts[:database]
26
+ self.username = opts[:username]
27
+ self.password = opts[:password]
28
+ self.connection = opts[:connection]
29
+ self.db = opts[:db]
30
+ end
31
+
32
+ def store(temp_object, opts={})
33
+ ensure_authenticated!
34
+ temp_object.file do |f|
35
+ mongo_id = grid.put(f, :metadata => marshal_encode(opts[:meta] || {}))
36
+ mongo_id.to_s
37
+ end
38
+ end
39
+
40
+ def retrieve(uid)
41
+ ensure_authenticated!
42
+ grid_io = grid.get(bson_id(uid))
43
+ meta = marshal_decode(grid_io.metadata)
44
+ meta.merge!(:stored_at => grid_io.upload_date)
45
+ [
46
+ grid_io.read,
47
+ meta
48
+ ]
49
+ rescue Mongo::GridFileNotFound, INVALID_OBJECT_ID => e
50
+ raise DataNotFound, "#{e} - #{uid}"
51
+ end
52
+
53
+ def destroy(uid)
54
+ ensure_authenticated!
55
+ grid.delete(bson_id(uid))
56
+ rescue Mongo::GridFileNotFound, INVALID_OBJECT_ID => e
57
+ raise DataNotFound, "#{e} - #{uid}"
58
+ end
59
+
60
+ def connection
61
+ @connection ||= Mongo::Connection.new(host, port)
62
+ end
63
+
64
+ def db
65
+ @db ||= connection.db(database)
66
+ end
67
+
68
+ def grid
69
+ @grid ||= Mongo::Grid.new(db)
70
+ end
71
+
72
+ private
73
+
74
+ def ensure_authenticated!
75
+ if username
76
+ @authenticated ||= db.authenticate(username, password)
77
+ end
78
+ end
79
+
80
+ def bson_id(uid)
81
+ OBJECT_ID.from_string(uid)
82
+ end
83
+
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,145 @@
1
+ require 'fog'
2
+
3
+ module Dragonfly
4
+ module DataStorage
5
+
6
+ class S3DataStore
7
+
8
+ include Configurable
9
+ include Serializer
10
+
11
+ configurable_attr :bucket_name
12
+ configurable_attr :access_key_id
13
+ configurable_attr :secret_access_key
14
+ configurable_attr :use_filesystem, true
15
+ configurable_attr :region
16
+ configurable_attr :storage_headers, {'x-amz-acl' => 'public-read'}
17
+ configurable_attr :specific_uid
18
+
19
+ REGIONS = {
20
+ 'us-east-1' => 's3.amazonaws.com', #default
21
+ 'eu-west-1' => 's3-eu-west-1.amazonaws.com',
22
+ 'ap-southeast-1' => 's3-ap-southeast-1.amazonaws.com',
23
+ 'us-west-1' => 's3-us-west-1.amazonaws.com'
24
+ }
25
+
26
+ def initialize(opts={})
27
+ self.bucket_name = opts[:bucket_name]
28
+ self.access_key_id = opts[:access_key_id]
29
+ self.secret_access_key = opts[:secret_access_key]
30
+ self.region = opts[:region]
31
+ end
32
+
33
+ def store(temp_object, opts={})
34
+ ensure_configured
35
+ ensure_bucket_initialized
36
+
37
+ meta = opts[:meta] || {}
38
+ headers = opts[:headers] || {}
39
+ uid = opts[:path] || generate_uid(meta[:name] || temp_object.original_filename || 'file')
40
+
41
+ if use_filesystem
42
+ temp_object.file do |f|
43
+ storage.put_object(bucket_name, uid, f, full_storage_headers(headers, meta))
44
+ end
45
+ else
46
+ storage.put_object(bucket_name, uid, temp_object.data, full_storage_headers(headers, meta))
47
+ end
48
+
49
+ uid
50
+ end
51
+
52
+ def retrieve(uid)
53
+ ensure_configured
54
+ response = storage.get_object(bucket_name, uid)
55
+ [
56
+ response.body,
57
+ parse_s3_metadata(response.headers)
58
+ ]
59
+ rescue Excon::Errors::NotFound => e
60
+ raise DataNotFound, "#{e} - #{uid}"
61
+ end
62
+
63
+ def destroy(uid)
64
+ storage.delete_object(bucket_name, uid)
65
+ rescue Excon::Errors::NotFound => e
66
+ raise DataNotFound, "#{e} - #{uid}"
67
+ end
68
+
69
+ def url_for(uid, opts={})
70
+ if opts && opts[:expires]
71
+ storage.get_object_url(bucket_name, uid, opts[:expires])
72
+ else
73
+ "http://#{bucket_name}.s3.amazonaws.com/#{uid}"
74
+ end
75
+ end
76
+
77
+ def domain
78
+ REGIONS[get_region]
79
+ end
80
+
81
+ def storage
82
+ @storage ||= Fog::Storage.new(
83
+ :provider => 'AWS',
84
+ :aws_access_key_id => access_key_id,
85
+ :aws_secret_access_key => secret_access_key,
86
+ :region => region
87
+ )
88
+ end
89
+
90
+ def bucket_exists?
91
+ storage.get_bucket_location(bucket_name)
92
+ true
93
+ rescue Excon::Errors::NotFound => e
94
+ false
95
+ end
96
+
97
+ private
98
+
99
+ def ensure_configured
100
+ unless @configured
101
+ [:bucket_name, :access_key_id, :secret_access_key].each do |attr|
102
+ raise NotConfigured, "You need to configure #{self.class.name} with #{attr}" if send(attr).nil?
103
+ end
104
+ @configured = true
105
+ end
106
+ end
107
+
108
+ def ensure_bucket_initialized
109
+ unless @bucket_initialized
110
+ storage.put_bucket(bucket_name, 'LocationConstraint' => region) unless bucket_exists?
111
+ @bucket_initialized = true
112
+ end
113
+ end
114
+
115
+ def get_region
116
+ reg = region || 'us-east-1'
117
+ raise "Invalid region #{reg} - should be one of #{valid_regions.join(', ')}" unless valid_regions.include?(reg)
118
+ reg
119
+ end
120
+
121
+ def generate_uid(name)
122
+ if self.specific_uid.is_a?(Proc)
123
+ self.specific_uid.call(name)
124
+ else
125
+ "#{Time.now.strftime '%Y/%m/%d/%H/%M/%S'}/#{rand(1000)}/#{name.gsub(/[^\w.]+/, '_')}"
126
+ end
127
+ end
128
+
129
+ def full_storage_headers(headers, meta)
130
+ {'x-amz-meta-extra' => marshal_encode(meta)}.merge(storage_headers).merge(headers)
131
+ end
132
+
133
+ def parse_s3_metadata(headers)
134
+ encoded_meta = headers['x-amz-meta-extra']
135
+ (marshal_decode(encoded_meta) if encoded_meta) || {}
136
+ end
137
+
138
+ def valid_regions
139
+ REGIONS.keys
140
+ end
141
+
142
+ end
143
+
144
+ end
145
+ end