fog-dragonfly 0.8.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of fog-dragonfly might be problematic. Click here for more details.

Files changed (155) hide show
  1. data/.specopts +2 -0
  2. data/.yardopts +23 -0
  3. data/Gemfile +23 -0
  4. data/Gemfile.rails.2.3.5 +14 -0
  5. data/History.md +266 -0
  6. data/LICENSE +20 -0
  7. data/README.md +88 -0
  8. data/Rakefile +92 -0
  9. data/VERSION +1 -0
  10. data/config.ru +13 -0
  11. data/docs.watchr +1 -0
  12. data/dragonfly.gemspec +293 -0
  13. data/extra_docs/Analysers.md +108 -0
  14. data/extra_docs/Caching.md +23 -0
  15. data/extra_docs/Configuration.md +138 -0
  16. data/extra_docs/DataStorage.md +136 -0
  17. data/extra_docs/Encoding.md +96 -0
  18. data/extra_docs/GeneralUsage.md +121 -0
  19. data/extra_docs/Generators.md +102 -0
  20. data/extra_docs/Heroku.md +50 -0
  21. data/extra_docs/Index.md +36 -0
  22. data/extra_docs/MimeTypes.md +40 -0
  23. data/extra_docs/Models.md +266 -0
  24. data/extra_docs/Mongo.md +45 -0
  25. data/extra_docs/Processing.md +130 -0
  26. data/extra_docs/Rack.md +52 -0
  27. data/extra_docs/Rails2.md +55 -0
  28. data/extra_docs/Rails3.md +62 -0
  29. data/extra_docs/Sinatra.md +25 -0
  30. data/extra_docs/URLs.md +169 -0
  31. data/features/3.0.3.feature +8 -0
  32. data/features/images.feature +47 -0
  33. data/features/no_processing.feature +14 -0
  34. data/features/rails_2.3.5.feature +7 -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 +39 -0
  38. data/features/support/env.rb +40 -0
  39. data/fixtures/files/app/models/album.rb +3 -0
  40. data/fixtures/files/app/views/albums/new.html.erb +4 -0
  41. data/fixtures/files/app/views/albums/show.html.erb +4 -0
  42. data/fixtures/files/config/initializers/dragonfly.rb +4 -0
  43. data/fixtures/files/features/manage_album_images.feature +12 -0
  44. data/fixtures/files/features/step_definitions/image_steps.rb +15 -0
  45. data/fixtures/files/features/support/paths.rb +15 -0
  46. data/fixtures/files/features/text_images.feature +7 -0
  47. data/fixtures/rails_2.3.5/template.rb +10 -0
  48. data/fixtures/rails_3.0.3/template.rb +20 -0
  49. data/irbrc.rb +17 -0
  50. data/lib/dragonfly.rb +45 -0
  51. data/lib/dragonfly/active_model_extensions.rb +13 -0
  52. data/lib/dragonfly/active_model_extensions/attachment.rb +169 -0
  53. data/lib/dragonfly/active_model_extensions/class_methods.rb +45 -0
  54. data/lib/dragonfly/active_model_extensions/instance_methods.rb +28 -0
  55. data/lib/dragonfly/active_model_extensions/validations.rb +37 -0
  56. data/lib/dragonfly/analyser.rb +59 -0
  57. data/lib/dragonfly/analysis/file_command_analyser.rb +32 -0
  58. data/lib/dragonfly/analysis/image_magick_analyser.rb +47 -0
  59. data/lib/dragonfly/analysis/r_magick_analyser.rb +63 -0
  60. data/lib/dragonfly/app.rb +182 -0
  61. data/lib/dragonfly/config/heroku.rb +19 -0
  62. data/lib/dragonfly/config/image_magick.rb +41 -0
  63. data/lib/dragonfly/config/r_magick.rb +46 -0
  64. data/lib/dragonfly/config/rails.rb +17 -0
  65. data/lib/dragonfly/configurable.rb +119 -0
  66. data/lib/dragonfly/core_ext/object.rb +8 -0
  67. data/lib/dragonfly/core_ext/string.rb +9 -0
  68. data/lib/dragonfly/core_ext/symbol.rb +9 -0
  69. data/lib/dragonfly/data_storage.rb +9 -0
  70. data/lib/dragonfly/data_storage/file_data_store.rb +114 -0
  71. data/lib/dragonfly/data_storage/mongo_data_store.rb +82 -0
  72. data/lib/dragonfly/data_storage/s3data_store.rb +115 -0
  73. data/lib/dragonfly/encoder.rb +13 -0
  74. data/lib/dragonfly/encoding/image_magick_encoder.rb +57 -0
  75. data/lib/dragonfly/encoding/r_magick_encoder.rb +61 -0
  76. data/lib/dragonfly/function_manager.rb +69 -0
  77. data/lib/dragonfly/generation/hash_with_css_style_keys.rb +23 -0
  78. data/lib/dragonfly/generation/image_magick_generator.rb +140 -0
  79. data/lib/dragonfly/generation/r_magick_generator.rb +155 -0
  80. data/lib/dragonfly/generator.rb +9 -0
  81. data/lib/dragonfly/image_magick_utils.rb +81 -0
  82. data/lib/dragonfly/job.rb +371 -0
  83. data/lib/dragonfly/job_builder.rb +39 -0
  84. data/lib/dragonfly/job_definitions.rb +26 -0
  85. data/lib/dragonfly/job_endpoint.rb +15 -0
  86. data/lib/dragonfly/loggable.rb +28 -0
  87. data/lib/dragonfly/middleware.rb +34 -0
  88. data/lib/dragonfly/processing/image_magick_processor.rb +99 -0
  89. data/lib/dragonfly/processing/r_magick_processor.rb +126 -0
  90. data/lib/dragonfly/processor.rb +9 -0
  91. data/lib/dragonfly/r_magick_utils.rb +48 -0
  92. data/lib/dragonfly/rails/images.rb +22 -0
  93. data/lib/dragonfly/response.rb +82 -0
  94. data/lib/dragonfly/routed_endpoint.rb +40 -0
  95. data/lib/dragonfly/serializer.rb +32 -0
  96. data/lib/dragonfly/simple_cache.rb +23 -0
  97. data/lib/dragonfly/simple_endpoint.rb +63 -0
  98. data/lib/dragonfly/temp_object.rb +220 -0
  99. data/samples/beach.png +0 -0
  100. data/samples/egg.png +0 -0
  101. data/samples/round.gif +0 -0
  102. data/samples/sample.docx +0 -0
  103. data/samples/taj.jpg +0 -0
  104. data/spec/argument_matchers.rb +19 -0
  105. data/spec/dragonfly/active_model_extensions/active_model_setup.rb +97 -0
  106. data/spec/dragonfly/active_model_extensions/active_record_setup.rb +85 -0
  107. data/spec/dragonfly/active_model_extensions/model_spec.rb +723 -0
  108. data/spec/dragonfly/active_model_extensions/spec_helper.rb +11 -0
  109. data/spec/dragonfly/analyser_spec.rb +123 -0
  110. data/spec/dragonfly/analysis/file_command_analyser_spec.rb +57 -0
  111. data/spec/dragonfly/analysis/image_magick_analyser_spec.rb +15 -0
  112. data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +27 -0
  113. data/spec/dragonfly/analysis/shared_analyser_spec.rb +51 -0
  114. data/spec/dragonfly/app_spec.rb +280 -0
  115. data/spec/dragonfly/config/r_magick_spec.rb +25 -0
  116. data/spec/dragonfly/configurable_spec.rb +220 -0
  117. data/spec/dragonfly/core_ext/string_spec.rb +17 -0
  118. data/spec/dragonfly/core_ext/symbol_spec.rb +17 -0
  119. data/spec/dragonfly/data_storage/data_store_spec.rb +76 -0
  120. data/spec/dragonfly/data_storage/file_data_store_spec.rb +169 -0
  121. data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +38 -0
  122. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +94 -0
  123. data/spec/dragonfly/deprecation_spec.rb +20 -0
  124. data/spec/dragonfly/encoding/image_magick_encoder_spec.rb +41 -0
  125. data/spec/dragonfly/encoding/r_magick_encoder_spec.rb +37 -0
  126. data/spec/dragonfly/function_manager_spec.rb +154 -0
  127. data/spec/dragonfly/generation/hash_with_css_style_keys_spec.rb +24 -0
  128. data/spec/dragonfly/generation/image_magick_generator_spec.rb +12 -0
  129. data/spec/dragonfly/generation/r_magick_generator_spec.rb +24 -0
  130. data/spec/dragonfly/generation/shared_generator_spec.rb +91 -0
  131. data/spec/dragonfly/image_magick_utils_spec.rb +16 -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 +120 -0
  135. data/spec/dragonfly/job_spec.rb +773 -0
  136. data/spec/dragonfly/loggable_spec.rb +80 -0
  137. data/spec/dragonfly/middleware_spec.rb +68 -0
  138. data/spec/dragonfly/processing/image_magick_processor_spec.rb +29 -0
  139. data/spec/dragonfly/processing/r_magick_processor_spec.rb +26 -0
  140. data/spec/dragonfly/processing/shared_processing_spec.rb +215 -0
  141. data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
  142. data/spec/dragonfly/serializer_spec.rb +61 -0
  143. data/spec/dragonfly/simple_cache_spec.rb +27 -0
  144. data/spec/dragonfly/simple_endpoint_spec.rb +89 -0
  145. data/spec/dragonfly/temp_object_spec.rb +352 -0
  146. data/spec/image_matchers.rb +47 -0
  147. data/spec/simple_matchers.rb +44 -0
  148. data/spec/spec_helper.rb +58 -0
  149. data/yard/handlers/configurable_attr_handler.rb +38 -0
  150. data/yard/setup.rb +15 -0
  151. data/yard/templates/default/fulldoc/html/css/common.css +107 -0
  152. data/yard/templates/default/layout/html/layout.erb +87 -0
  153. data/yard/templates/default/module/html/configuration_summary.erb +31 -0
  154. data/yard/templates/default/module/setup.rb +17 -0
  155. metadata +550 -0
@@ -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 = Dragonfly::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,41 @@
1
+ module Dragonfly
2
+ module Config
3
+
4
+ # ImageMagick is a saved configuration for Dragonfly apps, which does the following:
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
40
+ end
41
+ end
@@ -0,0 +1,46 @@
1
+ module Dragonfly
2
+ module Config
3
+
4
+ # RMagick is a saved configuration for Dragonfly apps, which does the following:
5
+ # - registers an rmagick analyser
6
+ # - registers an rmagick processor
7
+ # - registers an rmagick 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 RMagick
11
+
12
+ def self.apply_configuration(app, opts={})
13
+ use_filesystem = opts.has_key?(:use_filesystem) ? opts[:use_filesystem] : true
14
+ app.configure do |c|
15
+ c.analyser.register(Analysis::RMagickAnalyser) do |a|
16
+ a.use_filesystem = use_filesystem
17
+ end
18
+ c.processor.register(Processing::RMagickProcessor) do |p|
19
+ p.use_filesystem = use_filesystem
20
+ end
21
+ c.encoder.register(Encoding::RMagickEncoder) do |e|
22
+ e.use_filesystem = use_filesystem
23
+ end
24
+ c.generator.register(Generation::RMagickGenerator) do |g|
25
+ g.use_filesystem = use_filesystem
26
+ end
27
+ c.job :thumb do |geometry, format|
28
+ process :thumb, geometry
29
+ encode format if format
30
+ end
31
+ c.job :gif do
32
+ encode :gif
33
+ end
34
+ c.job :jpg do
35
+ encode :jpg
36
+ end
37
+ c.job :png do
38
+ encode :png
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,17 @@
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
+ c.datastore.root_path = "#{::Rails.root}/public/system/dragonfly/#{::Rails.env}" if c.datastore.is_a?(DataStorage::FileDataStore)
10
+ c.url_path_prefix = '/media'
11
+ c.analyser.register(Analysis::FileCommandAnalyser)
12
+ end
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,119 @@
1
+ module Dragonfly
2
+ module Configurable
3
+
4
+ # Exceptions
5
+ class BadConfigAttribute < StandardError; end
6
+
7
+ def self.included(klass)
8
+ klass.class_eval do
9
+ include Configurable::InstanceMethods
10
+ extend Configurable::ClassMethods
11
+
12
+ # These aren't included in InstanceMethods because we need access to 'klass'
13
+ # We can't just put them into InstanceMethods and use 'self.class' because
14
+ # this won't always point to the class in which we've included Configurable,
15
+ # e.g. if we've included it in an eigenclasse
16
+ define_method :configuration_hash do
17
+ @configuration_hash ||= klass.default_configuration.dup
18
+ end
19
+ private :configuration_hash
20
+
21
+ define_method :configuration_methods do
22
+ klass.configuration_methods
23
+ end
24
+
25
+ end
26
+ end
27
+
28
+ class DeferredBlock < Proc; end
29
+
30
+ module InstanceMethods
31
+
32
+ def configure(&block)
33
+ yield ConfigurationProxy.new(self)
34
+ self
35
+ end
36
+
37
+ def configure_with(configurer, *args, &block)
38
+ configurer = configurer_for(configurer) if configurer.is_a?(Symbol)
39
+ configurer.apply_configuration(self, *args)
40
+ configure(&block) if block
41
+ self
42
+ end
43
+
44
+ def configuration
45
+ configuration_hash.dup
46
+ end
47
+
48
+ def has_configuration_method?(method_name)
49
+ configuration_methods.include?(method_name.to_sym)
50
+ end
51
+
52
+ end
53
+
54
+ module ClassMethods
55
+
56
+ def default_configuration
57
+ @default_configuration ||= {}
58
+ end
59
+
60
+ def configuration_methods
61
+ @configuration_methods ||= []
62
+ end
63
+
64
+ private
65
+
66
+ def configurable_attr attribute, default=nil, &blk
67
+ default_configuration[attribute] = blk ? DeferredBlock.new(&blk) : default
68
+
69
+ # Define the reader
70
+ define_method(attribute) do
71
+ if configuration_hash[attribute].is_a?(DeferredBlock)
72
+ configuration_hash[attribute] = configuration_hash[attribute].call
73
+ end
74
+ configuration_hash[attribute]
75
+ end
76
+
77
+ # Define the writer
78
+ define_method("#{attribute}=") do |value|
79
+ configuration_hash[attribute] = value
80
+ end
81
+
82
+ configuration_method attribute
83
+ configuration_method "#{attribute}="
84
+ end
85
+
86
+ def configuration_method(*method_names)
87
+ configuration_methods.push(*method_names.map{|n| n.to_sym })
88
+ end
89
+
90
+ end
91
+
92
+ class ConfigurationProxy
93
+
94
+ def initialize(owner)
95
+ @owner = owner
96
+ end
97
+
98
+ def method_missing(method_name, *args, &block)
99
+ if owner.has_configuration_method?(method_name)
100
+ owner.send(method_name, *args, &block)
101
+ elsif nested_configurable?(method_name, *args)
102
+ owner.send(method_name, *args)
103
+ else
104
+ raise BadConfigAttribute, "You tried to configure using '#{method_name.inspect}', but the valid config attributes are #{owner.configuration_methods.map{|a| %('#{a.inspect}') }.sort.join(', ')}"
105
+ end
106
+ end
107
+
108
+ private
109
+
110
+ attr_reader :owner
111
+
112
+ def nested_configurable?(method, *args)
113
+ owner.respond_to?(method) && owner.send(method, *args).is_a?(Configurable)
114
+ end
115
+
116
+ end
117
+
118
+ end
119
+ end
@@ -0,0 +1,8 @@
1
+ class Object
2
+
3
+ # Will eventually get this by cherry-picking from activesupport
4
+ def blank?
5
+ respond_to?(:empty?) ? empty? : !self
6
+ end
7
+
8
+ 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,114 @@
1
+ require 'pathname'
2
+
3
+ module Dragonfly
4
+ module DataStorage
5
+
6
+ class FileDataStore
7
+
8
+ include Configurable
9
+
10
+ configurable_attr :root_path, '/var/tmp/dragonfly'
11
+
12
+ def store(temp_object, opts={})
13
+ relative_path = if opts[:path]
14
+ opts[:path]
15
+ else
16
+ filename = temp_object.name || 'file'
17
+ relative_path = relative_path_for(filename)
18
+ end
19
+
20
+ begin
21
+ path = absolute(relative_path)
22
+ until !File.exist?(path)
23
+ path = disambiguate(path)
24
+ end
25
+ prepare_path(path)
26
+ temp_object.to_file(path).close
27
+ store_extra_data(path, temp_object)
28
+ rescue Errno::EACCES => e
29
+ raise UnableToStore, e.message
30
+ end
31
+
32
+ relative(path)
33
+ end
34
+
35
+ def retrieve(relative_path)
36
+ path = absolute(relative_path)
37
+ file = File.new(path)
38
+ file.close
39
+ [
40
+ file,
41
+ retrieve_extra_data(path)
42
+ ]
43
+ rescue Errno::ENOENT => e
44
+ raise DataNotFound, e.message
45
+ end
46
+
47
+ def destroy(relative_path)
48
+ path = absolute(relative_path)
49
+ FileUtils.rm path
50
+ FileUtils.rm extra_data_path(path)
51
+ purge_empty_directories(relative_path)
52
+ rescue Errno::ENOENT => e
53
+ raise DataNotFound, e.message
54
+ end
55
+
56
+ def disambiguate(path)
57
+ dirname = File.dirname(path)
58
+ basename = File.basename(path, '.*')
59
+ extname = File.extname(path)
60
+ "#{dirname}/#{basename}_#{Time.now.usec.to_s(32)}#{extname}"
61
+ end
62
+
63
+ private
64
+
65
+ def absolute(relative_path)
66
+ File.join(root_path, relative_path)
67
+ end
68
+
69
+ def relative(absolute_path)
70
+ absolute_path[/^#{root_path}\/?(.*)$/, 1]
71
+ end
72
+
73
+ def directory_empty?(path)
74
+ Dir.entries(path) == ['.','..']
75
+ end
76
+
77
+ def extra_data_path(data_path)
78
+ "#{data_path}.extra"
79
+ end
80
+
81
+ def relative_path_for(filename)
82
+ time = Time.now
83
+ msec = time.usec / 1000
84
+ "#{time.strftime '%Y/%m/%d/%H_%M_%S'}_#{msec}_#{filename.gsub(/[^\w.]+/,'_')}"
85
+ end
86
+
87
+ def store_extra_data(data_path, temp_object)
88
+ File.open(extra_data_path(data_path), 'wb') do |f|
89
+ f.write Marshal.dump(temp_object.attributes)
90
+ end
91
+ end
92
+
93
+ def retrieve_extra_data(data_path)
94
+ path = extra_data_path(data_path)
95
+ File.exist?(path) ? File.open(path,'rb'){|f| Marshal.load(f.read) } : {}
96
+ end
97
+
98
+ def prepare_path(path)
99
+ dir = File.dirname(path)
100
+ FileUtils.mkdir_p(dir) unless File.exist?(dir)
101
+ end
102
+
103
+ def purge_empty_directories(path)
104
+ containing_directory = Pathname.new(path).dirname
105
+ containing_directory.ascend do |relative_dir|
106
+ dir = absolute(relative_dir)
107
+ FileUtils.rmdir dir if directory_empty?(dir)
108
+ end
109
+ end
110
+
111
+ end
112
+
113
+ end
114
+ end
@@ -0,0 +1,82 @@
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
+
16
+ # Mongo gem deprecated ObjectID in favour of ObjectId
17
+ OBJECT_ID = defined?(BSON::ObjectId) ? BSON::ObjectId : BSON::ObjectID
18
+ INVALID_OBJECT_ID = defined?(BSON::InvalidObjectId) ? BSON::InvalidObjectId : BSON::InvalidObjectID
19
+
20
+ def initialize(opts={})
21
+ self.host = opts[:host]
22
+ self.port = opts[:port]
23
+ self.database = opts[:database] if opts[:database]
24
+ self.username = opts[:username]
25
+ self.password = opts[:password]
26
+ end
27
+
28
+ def store(temp_object, opts={})
29
+ ensure_authenticated!
30
+ temp_object.file do |f|
31
+ mongo_id = grid.put(f, :metadata => marshal_encode(temp_object.attributes))
32
+ mongo_id.to_s
33
+ end
34
+ end
35
+
36
+ def retrieve(uid)
37
+ ensure_authenticated!
38
+ grid_io = grid.get(bson_id(uid))
39
+ extra = marshal_decode(grid_io.metadata)
40
+ extra[:meta].merge!(:stored_at => grid_io.upload_date)
41
+ [
42
+ grid_io.read,
43
+ extra
44
+ ]
45
+ rescue Mongo::GridFileNotFound, INVALID_OBJECT_ID => e
46
+ raise DataNotFound, "#{e} - #{uid}"
47
+ end
48
+
49
+ def destroy(uid)
50
+ ensure_authenticated!
51
+ grid.delete(bson_id(uid))
52
+ rescue Mongo::GridFileNotFound, INVALID_OBJECT_ID => e
53
+ raise DataNotFound, "#{e} - #{uid}"
54
+ end
55
+
56
+ def connection
57
+ @connection ||= Mongo::Connection.new(host, port)
58
+ end
59
+
60
+ def db
61
+ @db ||= connection.db(database)
62
+ end
63
+
64
+ def grid
65
+ @grid ||= Mongo::Grid.new(db)
66
+ end
67
+
68
+ private
69
+
70
+ def ensure_authenticated!
71
+ if username
72
+ @authenticated ||= db.authenticate(username, password)
73
+ end
74
+ end
75
+
76
+ def bson_id(uid)
77
+ OBJECT_ID.from_string(uid)
78
+ end
79
+
80
+ end
81
+ end
82
+ end