rack-gridfs 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.rdoc ADDED
@@ -0,0 +1,31 @@
1
+ == CHANGE LOG
2
+
3
+ === 0.4.0 / May 12, 2011
4
+
5
+ Major refactoring and loads of new features! Thanks to {Ben Marini}[https://github.com/bmarini]
6
+ for his substantial contributions to this release.
7
+
8
+ {full commit log}[https://github.com/skinandbones/rack-gridfs/compare/v0.2.0...v0.4.0]
9
+
10
+ ==== Features
11
+
12
+ - Allow configuration of MongoDB authentication (Steve Sloan)
13
+ - Allow option to look up objects by GridFS filename instead of +ObjectId+
14
+ (SHIBATA Hiroshi)
15
+ - Return iterable GridIO object instead of file contents, so Rack can stream in
16
+ chunks (Ches Martin)
17
+ - <tt>Rack::GridFS::Endpoint</tt>: support for mounting as a Rack endpoint in
18
+ addition to middleware (Ben Marini)
19
+ - Cache headers: set <tt>Last-Modified</tt> and +Etag+ so that
20
+ <tt>Rack::ConditionalGet</tt> sends 304s. +expires+ option to set
21
+ <tt>Cache-Control</tt> (Alexander Gräfe & Ben Marini)
22
+ - <tt>mime-types</tt> dependency so GridFS lib can determine content types
23
+ (Ben Marini)
24
+ - You can now pass a <tt>Mongo::DB</tt> instance instead of discrete database
25
+ configuration parameters. Connections are retried so we take advantage of a
26
+ +ReplSetConnection+ in high-availability architectures (Ben Marini)
27
+
28
+ ==== Bug Fixes
29
+
30
+ - <tt>BSON::ObjectID</tt> renamed to +ObjectId+, and other changes supporting
31
+ current versions of Mongo libraries
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009 Blake Carlson
1
+ Copyright (c) 2009-2011 Blake Carlson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.rdoc CHANGED
@@ -2,53 +2,149 @@
2
2
 
3
3
  Rack:GridFS is a Rack middleware for creating HTTP endpoints for files
4
4
  stored in MongoDB's GridFS. You can configure a prefix string which
5
- will be used to match the path of a request and supply an id for looking
6
- up the file in the GridFS store.
5
+ will be used to match the path of a request, and further look up GridFS
6
+ files based on either their +ObjectId+ or +filename+ field.
7
7
 
8
8
  For example,
9
9
 
10
10
  GET '/gridfs/someobjectid'
11
-
11
+
12
12
  If the prefix is "gridfs", then the id will be be "someobjectid".
13
13
 
14
- == Mongo Driver Compatibility Notes
14
+ You can also use Rack::GridFS::Endpoint as a rack endpoint if you want to
15
+ handle routing another way
15
16
 
16
- This version is currently based off of mongo-0.20.1.
17
+ == Mongo Driver Compatibility Notes
17
18
 
18
- As of mongo-0.19.1, there have been significant changes to GridFS. I do
19
- not plan to support versions of the mongo driver prior to 0.19. There are
20
- some compatibility issues with mongo-0.19 vs. mongo-0.20 (Mongo::ObjectID
21
- vs. BSON::ObjectID). For now, I am choosing to support mongo-0.20.
19
+ This version is currently based on mongo-1.2+. As there were significant changes
20
+ to the GridFS API prior to v1.0, you may have luck with the git-tagged version
21
+ 0.2.0 of this library with earlier versions of the driver.
22
22
 
23
23
  == Installation
24
24
 
25
- sudo gem install skinandbones-rack-gridfs --source=http://gems.github.com
25
+ gem install rack-gridfs
26
+
27
+ == Features
28
+ - Use as rack middleware or mount as a rack endpoint
29
+ - File lookup using a path or object id
30
+ - Chunked transfer encoding, keeps memory usage low
31
+ - Content-Type header set using 'mime-types' gem
32
+ - Last-Modified and Etag headers set automatically for conditional get support
33
+ - Cache-Control header support
34
+ - High availability when using replication sets
26
35
 
27
36
  == Usage
28
37
 
29
38
  require 'rack/gridfs'
30
- use Rack::GridFS, :hostname => 'localhost', :port => 27017, :database => 'test', :prefix => 'gridfs'
39
+ use Rack::GridFS, :prefix => 'gridfs', :hostname => 'localhost', :port => 27017, :database => 'test'
31
40
 
32
- You must specify MongoDB database details:
33
- - hostname: the hostname/IP where the MongoDB server is running. Default 'localhost'.
34
- - port: the port of the MongoDB server. Default 27017.
35
- - database: the MongoDB database to connect to.
36
- - prefix: a string used to match against incoming paths and route to through the middleware. Default 'gridfs'.
41
+ Options:
42
+ - +prefix+: a string used to match against incoming paths and route to through
43
+ the middleware. Default 'gridfs'.
44
+ - +lookup+: whether to look up a file based on <tt>:id</tt> or <tt>:path</tt>
45
+ (example below). Default is <tt>:id</tt>.
37
46
 
38
- == Sinatra Example
47
+ You must also specify MongoDB database details:
48
+ - +hostname+: the hostname/IP where the MongoDB server is running. Default 'localhost'.
49
+ - +port+: the port of the MongoDB server. Default 27017.
50
+ - +database+: the name of the MongoDB database to connect to.
51
+ - +username+ and +password+: if you need to authenticate to MongoDB.
39
52
 
40
- # TODO: THIS COULD USE A LOT MORE EXPLANATION!
53
+ Alternatively you can pass in a <tt>Mongo::DB</tt> instance instead:
54
+ - +db+: MongoMapper.database, or Mongoid.database for example.
55
+
56
+ === Simple Sinatra Example
41
57
 
42
58
  require 'rubygems'
43
59
  require 'sinatra'
44
60
 
45
61
  require 'rack/gridfs'
46
- use Rack::GridFS, :hostname => 'localhost', :port => 27017, :database => 'test', :prefix => 'gridfs'
62
+ use Rack::GridFS, :database => 'test', :prefix => 'gridfs'
47
63
 
48
64
  get /.*/ do
49
65
  "The URL did not match a file in GridFS."
50
66
  end
51
67
 
68
+ === Usage with Rails 2
69
+
70
+ To use <tt>Rack::GridFS</tt> in a Rails application, add it as middleware in
71
+ <tt>application.rb</tt> or <tt>config/environments/*</tt>with something like this:
72
+
73
+ config.middleware.insert_after Rack::Runtime, Rack::GridFS,
74
+ :prefix => 'uploads', :database => "my_app_#{Rails.env}"
75
+
76
+ Run <tt>rake middleware</tt> to decide for yourself where to best place it in
77
+ the middleware stack for your app using {the Rails convenience methods}[http://guides.rubyonrails.org/rails_on_rack.html#configuring-middleware-stack],
78
+ taking into consideration that it can probably be near the top since it simply
79
+ returns a "static" file or a 404.
80
+
81
+ === Usage with Rails 3
82
+
83
+ To use in Rails 3, you can insert into the middleware stack as above, or mount
84
+ the app directly in your routes (recommended). In <tt>config/routes.rb</tt>:
85
+
86
+ mount Rack::GridFS::Endpoint.new(:db => Mongoid.database), :at => "gridfs"
87
+
88
+ This allows for much more straightforward and sensible configuration, if you do
89
+ not require other middleware in front of GridFS (Rack-based authorization, for
90
+ instance).
91
+
92
+ === Path (filename) Lookup
93
+
94
+ The <tt>:lookup => :path</tt> option causes files to be looked up from the GridFS
95
+ store based on their +filename+ field (which can be a full file path) rather than
96
+ +ObjectId+ (requests still need to match the +prefix+ you've set). This allows
97
+ you to find files based on essentially arbitrary URLs such as:
98
+
99
+ GET '/prefix/media/images/jane_avatar.jpg'
100
+
101
+ How filenames are set is specific to your application. We'll look at an example
102
+ with Carrierwave below.
103
+
104
+ *NOTE*: The Mongo Ruby driver will try to create an index on the +filename+
105
+ field for you automatically, but if you are using filename lookup you'll want to
106
+ double-check that it is created appropriately (on slaves only if you have a
107
+ master-slave architecture, etc.).
108
+
109
+ === Carrierwave Example
110
+
111
+ Path lookup works well for usage with Carrierwave[https://github.com/jnicklas/carrierwave].
112
+ As a minimal example with Mongoid:
113
+
114
+ # config/initializers/carrierwave.rb
115
+ CarrierWave.configure do |config|
116
+ config.storage = :grid_fs
117
+ config.grid_fs_connection = Mongoid.database
118
+ config.grid_fs_access_url = "/uploads"
119
+ end
120
+
121
+ # app/uploaders/avatar_uploader.rb
122
+ class AvatarUploader < CarrierWave::Uploader::Base
123
+ # (Virtual) path where uploaded files will be stored, appended to the
124
+ # gridfs_access_url by methods used with view helpers
125
+ def store_dir
126
+ "#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
127
+ end
128
+ end
129
+
130
+ # app/models/user.rb
131
+ class User
132
+ include Mongoid::Document
133
+ mount_uploader :avatar, AvatarUploader
134
+ end
135
+
136
+ # app/views/user/show.html.erb
137
+ <%= image_tag(@user.avatar.url) if @user.avatar? %>
138
+
139
+ This will result in URL paths like <tt>/uploads/user/avatar/4d250d04a8f41c0a31000006/original_filename.jpg</tt>
140
+ being generated for the view helpers, and Carrierwave will store
141
+ <tt>user/avatar/4d250d04a8f41c0a31000006/original_filename.jpg</tt> as the
142
+ +filename+ in GridFS. Thus, you can configure <tt>Rack::GridFS</tt> to serve
143
+ these files as such:
144
+
145
+ config.middleware.insert_after Rack::Runtime, Rack::GridFS,
146
+ :prefix => 'uploads', :lookup => :path, :database => "my_app_#{Rails.env}"
147
+
52
148
  == Copyright
53
149
 
54
- Copyright (c) 2010 Blake Carlson. See LICENSE for details.
150
+ Copyright (c) 2010-2011 Blake Carlson. See LICENSE for details.
data/Rakefile CHANGED
@@ -1,30 +1,5 @@
1
- require 'rubygems'
2
- require 'rake'
3
-
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = "rack-gridfs"
8
- gem.summary = "Rack middleware for creating HTTP endpoints for files stored in MongoDB's GridFS"
9
- gem.email = "blake@coin-operated.net"
10
- gem.homepage = "http://github.com/skinandbones/rack-gridfs"
11
- gem.authors = ["Blake Carlson"]
12
- gem.rubyforge_project = "rack-gridfs"
13
-
14
- gem.add_dependency('rack')
15
- gem.add_dependency('mongo', '>=0.20.1')
16
-
17
- gem.add_development_dependency('mocha', '0.9.4')
18
- gem.add_development_dependency('rack-test')
19
- gem.add_development_dependency('shoulda')
20
- end
21
- Jeweler::GemcutterTasks.new
22
- Jeweler::RubyforgeTasks.new do |rubyforge|
23
- rubyforge.doc_task = "rdoc"
24
- end
25
- rescue LoadError
26
- puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
27
- end
1
+ require 'bundler/setup'
2
+ Bundler::GemHelper.install_tasks
28
3
 
29
4
  require 'rake/testtask'
30
5
  Rake::TestTask.new(:test) do |test|
@@ -37,29 +12,24 @@ begin
37
12
  require 'rcov/rcovtask'
38
13
  Rcov::RcovTask.new do |test|
39
14
  test.libs << 'test'
40
- test.pattern = 'test/**/*_test.rb'
15
+ test.test_files = FileList['test/**/*_test.rb']
41
16
  test.verbose = true
17
+ test.rcov_opts << '--exclude /gems/,/Library/,/usr/,spec,lib/tasks'
42
18
  end
43
19
  rescue LoadError
44
20
  task :rcov do
45
- abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
21
+ abort "RCov is not available. In order to run rcov, you must: gem install rcov"
46
22
  end
47
23
  end
48
24
 
49
- task :test => :check_dependencies
50
-
51
25
  task :default => :test
52
26
 
53
27
  require 'rake/rdoctask'
54
28
  Rake::RDocTask.new do |rdoc|
55
- if File.exist?('VERSION')
56
- version = File.read('VERSION')
57
- else
58
- version = ""
59
- end
29
+ require File.expand_path("../lib/rack/gridfs/version", __FILE__)
60
30
 
61
31
  rdoc.rdoc_dir = 'rdoc'
62
- rdoc.title = "Rack::GridFS #{version}"
63
- rdoc.rdoc_files.include('README*')
32
+ rdoc.title = "Rack::GridFS #{Rack::GridFS::VERSION}"
33
+ rdoc.rdoc_files.include(%w[ README* CHANGES* ])
64
34
  rdoc.rdoc_files.include('lib/**/*.rb')
65
35
  end
data/lib/rack/gridfs.rb CHANGED
@@ -1,57 +1,52 @@
1
- require 'timeout'
2
1
  require 'mongo'
2
+ require 'mime/types'
3
3
 
4
4
  module Rack
5
-
6
5
  class GridFSConnectionError < StandardError ; end
7
-
6
+
7
+ # Rack middleware that will serve GridFS files from a specified path prefix.
8
+ # By default the prefix is stripped from the path before file lookup in
9
+ # GridFS occurs.
10
+ #
11
+ # For example:
12
+ #
13
+ # "/gridfs/filename.png" -> "filename.png"
14
+ #
15
+ # If you are using Rails you can mount the endpoint directly.
16
+ #
17
+ # For example (in config/routes.rb):
18
+ #
19
+ # mount Rack::GridFS::Endpoint, :at => "gridfs"
20
+
8
21
  class GridFS
22
+ autoload :Endpoint, "rack/gridfs/endpoint"
9
23
 
10
- attr_reader :hostname, :port, :database, :prefix, :db
11
-
12
- def initialize(app, options = {})
13
- options = {
14
- :hostname => 'localhost',
15
- :prefix => 'gridfs',
16
- :port => Mongo::Connection::DEFAULT_PORT
17
- }.merge(options)
18
-
19
- @app = app
20
- @hostname = options[:hostname]
21
- @port = options[:port]
22
- @database = options[:database]
23
- @prefix = options[:prefix]
24
- @db = nil
25
-
26
- connect!
24
+ def initialize(app, options={})
25
+ @app = app
26
+ @options = normalize_options(options)
27
27
  end
28
28
 
29
29
  def call(env)
30
- request = Rack::Request.new(env)
31
- if request.path_info =~ /^\/#{prefix}\/(.+)$/
32
- gridfs_request($1)
30
+ if env['PATH_INFO'] =~ %r{^/#{@options[:prefix]}/*}
31
+ endpoint.call(env)
33
32
  else
34
33
  @app.call(env)
35
34
  end
36
35
  end
37
36
 
38
- def gridfs_request(id)
39
- file = Mongo::Grid.new(db).get(BSON::ObjectID.from_string(id))
40
- [200, {'Content-Type' => file.content_type}, [file.read]]
41
- rescue Mongo::GridError, BSON::InvalidObjectID
42
- [404, {'Content-Type' => 'text/plain'}, ['File not found.']]
43
- end
44
-
45
37
  private
46
-
47
- def connect!
48
- Timeout::timeout(5) do
49
- @db = Mongo::Connection.new(hostname).db(database)
38
+
39
+ # TODO: doc explanation/example of custom mapper
40
+ def normalize_options(options)
41
+ options.tap do |opts|
42
+ opts[:prefix] ||= "gridfs"
43
+ opts[:prefix].gsub!(/^\//, '')
44
+ opts[:mapper] ||= lambda { |path| %r!^/#{options[:prefix]}/(.+)!.match(path)[1] }
50
45
  end
51
- rescue Exception => e
52
- raise Rack::GridFSConnectionError, "Unable to connect to the MongoDB server (#{e.to_s})"
53
46
  end
54
-
47
+
48
+ def endpoint
49
+ @endpoint ||= Endpoint.new(@options)
50
+ end
55
51
  end
56
-
57
52
  end
@@ -0,0 +1,13 @@
1
+ require 'rack/gridfs/endpoint/base'
2
+ require 'rack/gridfs/endpoint/caching'
3
+ require 'rack/gridfs/endpoint/connection'
4
+
5
+ module Rack
6
+ class GridFS
7
+ class Endpoint
8
+ include Base
9
+ include Connection
10
+ include Caching
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,76 @@
1
+ module Rack
2
+ class GridFS
3
+ class Endpoint
4
+ module Base
5
+ attr_reader :db
6
+
7
+ def initialize(options = {})
8
+ @options = default_options.merge(options)
9
+
10
+ @db = @options[:db]
11
+ @lookup = @options[:lookup]
12
+ @mapper = @options[:mapper]
13
+ end
14
+
15
+ def call(env)
16
+ with_rescues do
17
+ request = Rack::Request.new(env)
18
+ key = key_for_path(request.path_info)
19
+ file = find_file(key)
20
+
21
+ response_for(file, request)
22
+ end
23
+ end
24
+
25
+ def key_for_path(path)
26
+ @mapper.respond_to?(:call) ? @mapper.call(path) : path
27
+ end
28
+
29
+ protected
30
+
31
+ def default_options
32
+ {
33
+ :lookup => :id,
34
+ :mapper => lambda { |path| %r!/(.+)!.match(path)[1] }
35
+ }
36
+ end
37
+
38
+ def with_rescues
39
+ rescue_connection_failure { yield }
40
+ rescue Mongo::GridFileNotFound, BSON::InvalidObjectId => e
41
+ [ 404, {'Content-Type' => 'text/plain'}, ["File not found. #{e}"] ]
42
+ rescue Mongo::GridError => e
43
+ [ 500, {'Content-Type' => 'text/plain'}, ["An error occured. #{e}"] ]
44
+ end
45
+
46
+ def rescue_connection_failure(max_retries=60)
47
+ retries = 0
48
+ begin
49
+ yield
50
+ rescue Mongo::ConnectionFailure => e
51
+ retries += 1
52
+ raise e if retries > max_retries
53
+ sleep(0.5)
54
+ retry
55
+ end
56
+ end
57
+
58
+ def response_for(file, request)
59
+ [ 200, headers(file), file ]
60
+ end
61
+
62
+ def find_file(id_or_path)
63
+ case @lookup.to_sym
64
+ when :id then Mongo::Grid.new(db).get(BSON::ObjectId.from_string(id_or_path))
65
+ when :path then Mongo::GridFileSystem.new(db).open(id_or_path, "r")
66
+ end
67
+ end
68
+
69
+ def headers(file)
70
+ { 'Content-Type' => file.content_type }
71
+ end
72
+
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,34 @@
1
+ module Rack
2
+ class GridFS
3
+ class Endpoint
4
+
5
+ module Caching
6
+ def initialize(*)
7
+ super
8
+ @options[:expires] ||= false
9
+ end
10
+
11
+ protected
12
+
13
+ def headers(file)
14
+ super.merge(
15
+ 'Last-Modified' => file.upload_date.httpdate,
16
+ 'Etag' => file.files_id.to_s
17
+ ).merge(cache_control_header)
18
+ end
19
+
20
+ private
21
+
22
+ def cache_control_header
23
+ if @options[:expires]
24
+ { "Cache-Control" => "max-age=#{@options[:expires]}, public" }
25
+ else
26
+ {}
27
+ end
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,43 @@
1
+ require 'timeout'
2
+
3
+ module Rack
4
+ class GridFS
5
+ class Endpoint
6
+
7
+ module Connection
8
+ def initialize(*)
9
+ super
10
+
11
+ @hostname, @port, @database, @username, @password =
12
+ @options.values_at(:hostname, :port, :database, :username, :password)
13
+ end
14
+
15
+ def default_options
16
+ super.merge({
17
+ :hostname => 'localhost',
18
+ :port => Mongo::Connection::DEFAULT_PORT
19
+ })
20
+ end
21
+
22
+ def db
23
+ @db ||= (super || connect!)
24
+ end
25
+
26
+ protected
27
+
28
+ def connect!
29
+ database = nil
30
+
31
+ Timeout::timeout(5) do
32
+ database = Mongo::Connection.new(@hostname, @port).db(@database)
33
+ database.authenticate(@username, @password) if @username
34
+ end
35
+
36
+ return database
37
+ rescue Exception => e
38
+ raise Rack::GridFSConnectionError, "Unable to connect to the MongoDB server (#{e.to_s})"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,5 @@
1
+ module Rack
2
+ class GridFS
3
+ VERSION = "0.4.0"
4
+ end
5
+ end
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-gridfs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ hash: 15
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 4
9
+ - 0
10
+ version: 0.4.0
5
11
  platform: ruby
6
12
  authors:
7
13
  - Blake Carlson
@@ -9,110 +15,183 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2010-05-11 00:00:00 -04:00
18
+ date: 2011-05-13 00:00:00 +07:00
13
19
  default_executable:
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
- name: rack
22
+ prerelease: false
17
23
  type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
20
26
  requirements:
21
27
  - - ">="
22
28
  - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
23
32
  version: "0"
24
- version:
33
+ version_requirements: *id001
34
+ name: rack
25
35
  - !ruby/object:Gem::Dependency
36
+ prerelease: false
37
+ type: :runtime
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ hash: 11
44
+ segments:
45
+ - 1
46
+ - 2
47
+ version: "1.2"
48
+ version_requirements: *id002
26
49
  name: mongo
50
+ - !ruby/object:Gem::Dependency
51
+ prerelease: false
27
52
  type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ version_requirements: *id003
63
+ name: mime-types
64
+ - !ruby/object:Gem::Dependency
65
+ prerelease: false
66
+ type: :development
67
+ requirement: &id004 !ruby/object:Gem::Requirement
68
+ none: false
30
69
  requirements:
31
70
  - - ">="
32
71
  - !ruby/object:Gem::Version
33
- version: 0.20.1
34
- version:
72
+ hash: 23
73
+ segments:
74
+ - 1
75
+ - 0
76
+ - 0
77
+ version: 1.0.0
78
+ version_requirements: *id004
79
+ name: bundler
35
80
  - !ruby/object:Gem::Dependency
36
- name: mocha
81
+ prerelease: false
37
82
  type: :development
38
- version_requirement:
39
- version_requirements: !ruby/object:Gem::Requirement
83
+ requirement: &id005 !ruby/object:Gem::Requirement
84
+ none: false
40
85
  requirements:
41
86
  - - "="
42
87
  - !ruby/object:Gem::Version
43
- version: 0.9.4
44
- version:
88
+ hash: 35
89
+ segments:
90
+ - 0
91
+ - 9
92
+ - 12
93
+ version: 0.9.12
94
+ version_requirements: *id005
95
+ name: mocha
45
96
  - !ruby/object:Gem::Dependency
97
+ prerelease: false
98
+ type: :development
99
+ requirement: &id006 !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ hash: 3
105
+ segments:
106
+ - 0
107
+ version: "0"
108
+ version_requirements: *id006
46
109
  name: rack-test
110
+ - !ruby/object:Gem::Dependency
111
+ prerelease: false
47
112
  type: :development
48
- version_requirement:
49
- version_requirements: !ruby/object:Gem::Requirement
113
+ requirement: &id007 !ruby/object:Gem::Requirement
114
+ none: false
50
115
  requirements:
51
116
  - - ">="
52
117
  - !ruby/object:Gem::Version
118
+ hash: 3
119
+ segments:
120
+ - 0
53
121
  version: "0"
54
- version:
122
+ version_requirements: *id007
123
+ name: rake
55
124
  - !ruby/object:Gem::Dependency
56
- name: shoulda
125
+ prerelease: false
57
126
  type: :development
58
- version_requirement:
59
- version_requirements: !ruby/object:Gem::Requirement
127
+ requirement: &id008 !ruby/object:Gem::Requirement
128
+ none: false
60
129
  requirements:
61
130
  - - ">="
62
131
  - !ruby/object:Gem::Version
132
+ hash: 3
133
+ segments:
134
+ - 0
63
135
  version: "0"
64
- version:
65
- description:
66
- email: blake@coin-operated.net
136
+ version_requirements: *id008
137
+ name: shoulda
138
+ description: Rack middleware for creating HTTP endpoints for files stored in MongoDB's GridFS
139
+ email:
140
+ - blake@coin-operated.net
67
141
  executables: []
68
142
 
69
143
  extensions: []
70
144
 
71
145
  extra_rdoc_files:
146
+ - CHANGES.rdoc
72
147
  - LICENSE
73
148
  - README.rdoc
74
149
  files:
75
- - .gitignore
150
+ - lib/rack/gridfs/endpoint/base.rb
151
+ - lib/rack/gridfs/endpoint/caching.rb
152
+ - lib/rack/gridfs/endpoint/connection.rb
153
+ - lib/rack/gridfs/endpoint.rb
154
+ - lib/rack/gridfs/version.rb
155
+ - lib/rack/gridfs.rb
76
156
  - LICENSE
77
157
  - README.rdoc
78
158
  - Rakefile
79
- - VERSION
80
- - example/gridfs_server.rb
81
- - lib/rack/gridfs.rb
82
- - rack-gridfs.gemspec
83
- - test/artifacts/3wolfmoon.jpg
84
- - test/artifacts/test.html
85
- - test/artifacts/test.txt
86
- - test/gridfs_test.rb
87
- - test/test_helper.rb
159
+ - CHANGES.rdoc
88
160
  has_rdoc: true
89
161
  homepage: http://github.com/skinandbones/rack-gridfs
90
162
  licenses: []
91
163
 
92
164
  post_install_message:
93
- rdoc_options:
94
- - --charset=UTF-8
165
+ rdoc_options: []
166
+
95
167
  require_paths:
96
168
  - lib
97
169
  required_ruby_version: !ruby/object:Gem::Requirement
170
+ none: false
98
171
  requirements:
99
172
  - - ">="
100
173
  - !ruby/object:Gem::Version
174
+ hash: 3
175
+ segments:
176
+ - 0
101
177
  version: "0"
102
- version:
103
178
  required_rubygems_version: !ruby/object:Gem::Requirement
179
+ none: false
104
180
  requirements:
105
181
  - - ">="
106
182
  - !ruby/object:Gem::Version
107
- version: "0"
108
- version:
183
+ hash: 23
184
+ segments:
185
+ - 1
186
+ - 3
187
+ - 6
188
+ version: 1.3.6
109
189
  requirements: []
110
190
 
111
191
  rubyforge_project: rack-gridfs
112
- rubygems_version: 1.3.5
192
+ rubygems_version: 1.5.2
113
193
  signing_key:
114
194
  specification_version: 3
115
- summary: Rack middleware for creating HTTP endpoints for files stored in MongoDB's GridFS
116
- test_files:
117
- - test/gridfs_test.rb
118
- - test/test_helper.rb
195
+ summary: Serve MongoDB GridFS files from Rack
196
+ test_files: []
197
+
data/.gitignore DELETED
@@ -1,2 +0,0 @@
1
- rdoc
2
- pkg
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.3.0
@@ -1,9 +0,0 @@
1
- require 'rubygems'
2
- require 'sinatra'
3
-
4
- require File.join(File.dirname(__FILE__), '..', 'lib', 'rack', 'gridfs')
5
- use Rack::GridFS, :hostname => 'localhost', :port => 27017, :database => 'test', :prefix => 'gridfs'
6
-
7
- get /.*/ do
8
- "Whatchya talking about?"
9
- end
data/rack-gridfs.gemspec DELETED
@@ -1,69 +0,0 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
- # -*- encoding: utf-8 -*-
5
-
6
- Gem::Specification.new do |s|
7
- s.name = %q{rack-gridfs}
8
- s.version = "0.3.0"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Blake Carlson"]
12
- s.date = %q{2010-05-11}
13
- s.email = %q{blake@coin-operated.net}
14
- s.extra_rdoc_files = [
15
- "LICENSE",
16
- "README.rdoc"
17
- ]
18
- s.files = [
19
- ".gitignore",
20
- "LICENSE",
21
- "README.rdoc",
22
- "Rakefile",
23
- "VERSION",
24
- "example/gridfs_server.rb",
25
- "lib/rack/gridfs.rb",
26
- "rack-gridfs.gemspec",
27
- "test/artifacts/3wolfmoon.jpg",
28
- "test/artifacts/test.html",
29
- "test/artifacts/test.txt",
30
- "test/gridfs_test.rb",
31
- "test/test_helper.rb"
32
- ]
33
- s.homepage = %q{http://github.com/skinandbones/rack-gridfs}
34
- s.rdoc_options = ["--charset=UTF-8"]
35
- s.require_paths = ["lib"]
36
- s.rubyforge_project = %q{rack-gridfs}
37
- s.rubygems_version = %q{1.3.5}
38
- s.summary = %q{Rack middleware for creating HTTP endpoints for files stored in MongoDB's GridFS}
39
- s.test_files = [
40
- "test/gridfs_test.rb",
41
- "test/test_helper.rb"
42
- ]
43
-
44
- if s.respond_to? :specification_version then
45
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
46
- s.specification_version = 3
47
-
48
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
49
- s.add_runtime_dependency(%q<rack>, [">= 0"])
50
- s.add_runtime_dependency(%q<mongo>, [">= 0.20.1"])
51
- s.add_development_dependency(%q<mocha>, ["= 0.9.4"])
52
- s.add_development_dependency(%q<rack-test>, [">= 0"])
53
- s.add_development_dependency(%q<shoulda>, [">= 0"])
54
- else
55
- s.add_dependency(%q<rack>, [">= 0"])
56
- s.add_dependency(%q<mongo>, [">= 0.20.1"])
57
- s.add_dependency(%q<mocha>, ["= 0.9.4"])
58
- s.add_dependency(%q<rack-test>, [">= 0"])
59
- s.add_dependency(%q<shoulda>, [">= 0"])
60
- end
61
- else
62
- s.add_dependency(%q<rack>, [">= 0"])
63
- s.add_dependency(%q<mongo>, [">= 0.20.1"])
64
- s.add_dependency(%q<mocha>, ["= 0.9.4"])
65
- s.add_dependency(%q<rack-test>, [">= 0"])
66
- s.add_dependency(%q<shoulda>, [">= 0"])
67
- end
68
- end
69
-
Binary file
@@ -1,15 +0,0 @@
1
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
2
- "http://www.w3.org/TR/html4/strict.dtd">
3
-
4
- <html lang="en">
5
- <head>
6
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
7
- <title>test</title>
8
- <meta name="generator" content="TextMate http://macromates.com/">
9
- <meta name="author" content="Blake Carlson">
10
- <!-- Date: 2009-09-20 -->
11
- </head>
12
- <body>
13
- Test
14
- </body>
15
- </html>
@@ -1 +0,0 @@
1
- Lorem ipsum dolor sit amet.
data/test/gridfs_test.rb DELETED
@@ -1,141 +0,0 @@
1
- require 'test_helper'
2
-
3
- class Rack::GridFSTest < Test::Unit::TestCase
4
- include Rack::Test::Methods
5
-
6
- def stub_mongodb_connection
7
- Rack::GridFS.any_instance.stubs(:connect!).returns(true)
8
- end
9
-
10
- def test_database_options
11
- { :hostname => 'localhost', :port => 27017, :database => 'test', :prefix => 'gridfs' }
12
- end
13
-
14
- def db
15
- @db ||= Mongo::Connection.new(test_database_options[:hostname], test_database_options[:port]).db(test_database_options[:database])
16
- end
17
-
18
- def app
19
- gridfs_opts = test_database_options
20
- Rack::Builder.new do
21
- use Rack::GridFS, gridfs_opts
22
- run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
23
- end
24
- end
25
-
26
- def load_artifact(filename, content_type)
27
- contents = File.read(File.join(File.dirname(__FILE__), 'artifacts', filename))
28
- Mongo::Grid.new(db).put(contents, :filename => filename, :content_type => content_type)
29
- end
30
-
31
- context "Rack::GridFS" do
32
-
33
- context "on initialization" do
34
-
35
- setup do
36
- stub_mongodb_connection
37
- @options = { :hostname => 'myhostname.mydomain', :port => 8765, :database => 'mydatabase', :prefix => 'myprefix' }
38
- end
39
-
40
- should "have a hostname option" do
41
- mware = Rack::GridFS.new(nil, @options)
42
- assert_equal @options[:hostname], mware.hostname
43
- end
44
-
45
- should "have a default hostname" do
46
- mware = Rack::GridFS.new(nil, @options.except(:hostname))
47
- assert_equal 'localhost', mware.hostname
48
- end
49
-
50
- should "have a port option" do
51
- mware = Rack::GridFS.new(nil, @options)
52
- assert_equal @options[:port], mware.port
53
- end
54
-
55
- should "have a default port" do
56
- mware = Rack::GridFS.new(nil, @options.except(:port))
57
- assert_equal Mongo::Connection::DEFAULT_PORT, mware.port
58
- end
59
-
60
- should "have a database option" do
61
- mware = Rack::GridFS.new(nil, @options)
62
- assert_equal @options[:database], mware.database
63
- end
64
-
65
- should "not have a default database" do
66
- mware = Rack::GridFS.new(nil, @options.except(:database))
67
- assert_nil mware.database
68
- end
69
-
70
- should "have a prefix option" do
71
- mware = Rack::GridFS.new(nil, @options)
72
- assert_equal mware.prefix, @options[:prefix]
73
- end
74
-
75
- should "have a default prefix" do
76
- mware = Rack::GridFS.new(nil, @options.except(:prefix))
77
- assert_equal mware.prefix, 'gridfs'
78
- end
79
-
80
- should "connect to the MongoDB server" do
81
- Rack::GridFS.any_instance.expects(:connect!).returns(true).once
82
- Rack::GridFS.new(nil, @options)
83
- end
84
-
85
- end
86
-
87
- should "delegate requests with a non-matching prefix" do
88
- %w( / /posts /posts/1 /posts/1/comments ).each do |path|
89
- get path
90
- assert last_response.ok?
91
- assert 'Hello, World!', last_response.body
92
- end
93
- end
94
-
95
- context "with files in GridFS" do
96
- setup do
97
- @text_id = load_artifact('test.txt', 'text/plain')
98
- @html_id = load_artifact('test.html', 'text/html')
99
- end
100
-
101
- teardown do
102
- db.collection('fs.files').remove
103
- end
104
-
105
- should "return TXT files stored in GridFS" do
106
- get "/gridfs/#{@text_id}"
107
- assert_equal "Lorem ipsum dolor sit amet.", last_response.body
108
- end
109
-
110
- should "return the proper content type for TXT files" do
111
- get "/gridfs/#{@text_id}"
112
- assert_equal 'text/plain', last_response.content_type
113
- end
114
-
115
- should "return HTML files stored in GridFS" do
116
- get "/gridfs/#{@html_id}"
117
- assert_match /html.*?body.*Test/m, last_response.body
118
- end
119
-
120
- should "return the proper content type for HTML files" do
121
- get "/gridfs/#{@html_id}"
122
- assert_equal 'text/html', last_response.content_type
123
- end
124
-
125
- should "return a not found for a unknown path" do
126
- get '/gridfs/unknown'
127
- assert last_response.not_found?
128
- end
129
-
130
- should "work for small images" do
131
- image_id = load_artifact('3wolfmoon.jpg', 'image/jpeg')
132
- get "/gridfs/#{image_id}"
133
- assert last_response.ok?
134
- assert_equal 'image/jpeg', last_response.content_type
135
- end
136
- end
137
-
138
- end
139
-
140
- end
141
-
data/test/test_helper.rb DELETED
@@ -1,19 +0,0 @@
1
- require 'rubygems'
2
- require 'test/unit'
3
- require 'shoulda'
4
- require 'mocha'
5
-
6
- require 'rack/builder'
7
- require 'rack/mock'
8
- require 'rack/test'
9
-
10
- require 'mongo'
11
- require File.join(File.dirname(__FILE__), '..', 'lib', 'rack', 'gridfs')
12
-
13
-
14
- class Hash
15
- def except(*keys)
16
- rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
17
- reject { |key,| rejected.include?(key) }
18
- end
19
- end