rack-gridfs 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ rdoc
2
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Blake Carlson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,54 @@
1
+ = Rack::GridFS
2
+
3
+ Rack:GridFS is a Rack middleware for creating HTTP endpoints for files
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 create a key for looking
6
+ up the file in the GridFS store.
7
+
8
+ For example,
9
+
10
+ GET '/gridfs/images/foo.jpg'
11
+
12
+ If the prefix is "gridfs", then the key will be be "images/foo.jpg".
13
+
14
+ == Dependencies
15
+
16
+ * ActiveSupport (activesupport)
17
+ * Mongo Ruby Driver v0.15.1+ (mongo)
18
+
19
+ == Installation
20
+
21
+ sudo gem install skinandbones-rack-gridfs --source=http://gems.github.com
22
+
23
+ == Usage
24
+
25
+ require 'rack/gridfs'
26
+ use Rack::GridFS, :hostname => 'localhost', :port => 27017, :database => 'test', :prefix => 'gridfs'
27
+
28
+ You must specify MongoDB database details:
29
+ - hostname: the hostname/IP where the MongoDB server is running. Default 'localhost'.
30
+ - port: the port of the MongoDB server. Default 27017.
31
+ - database: the MongoDB database to connect to.
32
+ - prefix: a string used to match against incoming paths and route to through the middleware. Default 'gridfs'.
33
+
34
+ == Caveats
35
+
36
+ This is an experimental project. The Ruby GridFS adaptor is still pretty new and the performance
37
+ is known to be slow. I wouldn't recommend using this middleware for anything high-volume in
38
+ production.
39
+
40
+ == Sinatra Example
41
+
42
+ require 'rubygems'
43
+ require 'sinatra'
44
+
45
+ require 'rack/gridfs'
46
+ use Rack::GridFS, :hostname => 'localhost', :port => 27017, :database => 'test', :prefix => 'gridfs'
47
+
48
+ get /.*/ do
49
+ "Whatchya talking about?"
50
+ end
51
+
52
+ == Copyright
53
+
54
+ Copyright (c) 2009 Blake Carlson. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,66 @@
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('activesupport')
16
+ gem.add_dependency('mongo', '0.15.1')
17
+
18
+ gem.add_development_dependency('mocha', '0.9.4')
19
+ gem.add_development_dependency('rack-test')
20
+ gem.add_development_dependency('thoughtbot-shoulda')
21
+ end
22
+ Jeweler::GemcutterTasks.new
23
+ Jeweler::RubyforgeTasks.new do |rubyforge|
24
+ rubyforge.doc_task = "rdoc"
25
+ end
26
+ rescue LoadError
27
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
28
+ end
29
+
30
+ require 'rake/testtask'
31
+ Rake::TestTask.new(:test) do |test|
32
+ test.libs << 'lib' << 'test'
33
+ test.pattern = 'test/**/*_test.rb'
34
+ test.verbose = true
35
+ end
36
+
37
+ begin
38
+ require 'rcov/rcovtask'
39
+ Rcov::RcovTask.new do |test|
40
+ test.libs << 'test'
41
+ test.pattern = 'test/**/*_test.rb'
42
+ test.verbose = true
43
+ end
44
+ rescue LoadError
45
+ task :rcov do
46
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
47
+ end
48
+ end
49
+
50
+ task :test => :check_dependencies
51
+
52
+ task :default => :test
53
+
54
+ require 'rake/rdoctask'
55
+ Rake::RDocTask.new do |rdoc|
56
+ if File.exist?('VERSION')
57
+ version = File.read('VERSION')
58
+ else
59
+ version = ""
60
+ end
61
+
62
+ rdoc.rdoc_dir = 'rdoc'
63
+ rdoc.title = "Rack::GridFS #{version}"
64
+ rdoc.rdoc_files.include('README*')
65
+ rdoc.rdoc_files.include('lib/**/*.rb')
66
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,9 @@
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
@@ -0,0 +1,66 @@
1
+ require 'timeout'
2
+ require 'mongo'
3
+ require 'mongo/gridfs'
4
+ require 'active_support/core_ext'
5
+
6
+ module Rack
7
+
8
+ class GridFSConnectonError < StandardError ; end
9
+
10
+ class GridFS
11
+
12
+ attr_reader :hostname, :port, :database, :prefix, :connection
13
+
14
+ def initialize(app, options = {})
15
+ options.reverse_merge!(
16
+ :hostname => 'localhost',
17
+ :port => Mongo::Connection::DEFAULT_PORT,
18
+ :prefix => 'gridfs'
19
+ )
20
+
21
+ @app = app
22
+ @hostname = options[:hostname]
23
+ @port = options[:port]
24
+ @database = options[:database]
25
+ @prefix = options[:prefix]
26
+ @connection = nil
27
+
28
+ connect!
29
+ end
30
+
31
+ def call(env)
32
+ request = Rack::Request.new(env)
33
+ if request.path_info =~ /^\/#{prefix}\/(.+)$/
34
+ gridfs_request($1)
35
+ else
36
+ @app.call(env)
37
+ end
38
+ end
39
+
40
+ def not_found
41
+ [404, {'Content-Type' => 'text/plain'}, ['File not found.']]
42
+ end
43
+
44
+ def gridfs_request(key)
45
+ if ::GridFS::GridStore.exist?(connection, key)
46
+ ::GridFS::GridStore.open(connection, key, 'r') do |file|
47
+ [200, {'Content-Type' => file.content_type}, [file.read]]
48
+ end
49
+ else
50
+ not_found
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def connect!
57
+ Timeout::timeout(5) do
58
+ @connection = Mongo::Connection.new(hostname).db(database)
59
+ end
60
+ rescue Exception => e
61
+ raise Rack::GridFSConnectonError, "Unable to connect to the MongoDB server (#{e.to_s})"
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -0,0 +1,72 @@
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.2.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{2009-10-19}
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<activesupport>, [">= 0"])
51
+ s.add_runtime_dependency(%q<mongo>, ["= 0.15.1"])
52
+ s.add_development_dependency(%q<mocha>, ["= 0.9.4"])
53
+ s.add_development_dependency(%q<rack-test>, [">= 0"])
54
+ s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
55
+ else
56
+ s.add_dependency(%q<rack>, [">= 0"])
57
+ s.add_dependency(%q<activesupport>, [">= 0"])
58
+ s.add_dependency(%q<mongo>, ["= 0.15.1"])
59
+ s.add_dependency(%q<mocha>, ["= 0.9.4"])
60
+ s.add_dependency(%q<rack-test>, [">= 0"])
61
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
62
+ end
63
+ else
64
+ s.add_dependency(%q<rack>, [">= 0"])
65
+ s.add_dependency(%q<activesupport>, [">= 0"])
66
+ s.add_dependency(%q<mongo>, ["= 0.15.1"])
67
+ s.add_dependency(%q<mocha>, ["= 0.9.4"])
68
+ s.add_dependency(%q<rack-test>, [">= 0"])
69
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
70
+ end
71
+ end
72
+
Binary file
@@ -0,0 +1,15 @@
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>
@@ -0,0 +1 @@
1
+ Lorem ipsum dolor sit amet.
@@ -0,0 +1,149 @@
1
+ require 'test_helper'
2
+
3
+ class Rack::GridFSTest < Test::Unit::TestCase
4
+ include Rack::Test::Methods
5
+
6
+ def options_for_gridfs
7
+ { :hostname => 'myhostname.mydomain', :port => 8765, :database => 'mydatabase', :prefix => 'myprefix' }
8
+ end
9
+
10
+ def stub_mongodb_connection
11
+ Rack::GridFS.any_instance.stubs(:connect!).returns(true)
12
+ end
13
+
14
+ def test_database_options
15
+ { :hostname => 'localhost', :port => 27017, :database => 'test', :prefix => 'gridfs' }
16
+ end
17
+
18
+ def db
19
+ @db ||= Mongo::Connection.new(test_database_options[:hostname], test_database_options[:port]).db(test_database_options[:database])
20
+ end
21
+
22
+ def app
23
+ Rack::Builder.new do
24
+ use Rack::GridFS, :hostname => 'localhost', :port => 27017, :database => 'test', :prefix => 'gridfs'
25
+ run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
26
+ end
27
+ end
28
+
29
+ def load_artifact(filename, key, content_type)
30
+ GridFS::GridStore.unlink(db, key)
31
+ GridFS::GridStore.open(db, key, 'w', :content_type => content_type) do |dest|
32
+ File.open(File.join(File.dirname(__FILE__), 'artifacts', filename), 'r') do |orig|
33
+ dest.puts orig.read
34
+ end
35
+ end
36
+ end
37
+
38
+ context "Rack::GridFS" do
39
+
40
+ context "on initialization" do
41
+
42
+ setup do
43
+ stub_mongodb_connection
44
+ end
45
+
46
+ should "have a hostname option" do
47
+ mware = Rack::GridFS.new(nil, options_for_gridfs)
48
+ assert_equal options_for_gridfs[:hostname], mware.hostname
49
+ end
50
+
51
+ should "have a default hostname" do
52
+ mware = Rack::GridFS.new(nil, options_for_gridfs.except(:hostname))
53
+ assert_equal 'localhost', mware.hostname
54
+ end
55
+
56
+ should "have a port option" do
57
+ mware = Rack::GridFS.new(nil, options_for_gridfs)
58
+ assert_equal options_for_gridfs[:port], mware.port
59
+ end
60
+
61
+ should "have a default port" do
62
+ mware = Rack::GridFS.new(nil, options_for_gridfs.except(:port))
63
+ assert_equal Mongo::Connection::DEFAULT_PORT, mware.port
64
+ end
65
+
66
+ should "have a database option" do
67
+ mware = Rack::GridFS.new(nil, options_for_gridfs)
68
+ assert_equal options_for_gridfs[:database], mware.database
69
+ end
70
+
71
+ should "not have a default database" do
72
+ mware = Rack::GridFS.new(nil, options_for_gridfs.except(:database))
73
+ assert_nil mware.database
74
+ end
75
+
76
+ should "have a prefix option" do
77
+ mware = Rack::GridFS.new(nil, options_for_gridfs)
78
+ assert_equal mware.prefix, options_for_gridfs[:prefix]
79
+ end
80
+
81
+ should "have a default prefix" do
82
+ mware = Rack::GridFS.new(nil, options_for_gridfs.except(:prefix))
83
+ assert_equal mware.prefix, 'gridfs'
84
+ end
85
+
86
+ should "connect to the MongoDB server" do
87
+ Rack::GridFS.any_instance.expects(:connect!).returns(true).once
88
+ Rack::GridFS.new(nil, options_for_gridfs)
89
+ end
90
+
91
+ end
92
+
93
+ should "delegate requests with a non-matching prefix" do
94
+ %w( / /posts /posts/1 /posts/1/comments ).each do |path|
95
+ get path
96
+ assert last_response.ok?
97
+ assert 'Hello, World!', last_response.body
98
+ end
99
+ end
100
+
101
+ context "with a files in GridFS" do
102
+ setup do
103
+ load_artifact('test.txt', 'test.txt', 'text/plain')
104
+ load_artifact('test.html', 'test.html', 'text/html')
105
+ end
106
+
107
+ should "return TXT files stored in GridFS" do
108
+ get '/gridfs/test.txt'
109
+ assert_equal "Lorem ipsum dolor sit amet.\n", last_response.body
110
+ end
111
+
112
+ should "return the proper content type for TXT files" do
113
+ get '/gridfs/test.txt'
114
+ assert_equal 'text/plain', last_response.content_type
115
+ end
116
+
117
+ should "return HTML files stored in GridFS" do
118
+ get '/gridfs/test.html'
119
+ assert_match /html.*?body.*Test/m, last_response.body
120
+ end
121
+
122
+ should "return the proper content type for HTML files" do
123
+ get '/gridfs/test.html'
124
+ assert_equal 'text/html', last_response.content_type
125
+ end
126
+
127
+ should "return a not found for a unknown path" do
128
+ get '/gridfs/unknown'
129
+ assert last_response.not_found?
130
+ end
131
+
132
+ should "handle complex file paths" do
133
+ load_artifact('test.html', 'stuff/187d/foo.html', 'text/html')
134
+ get '/gridfs/stuff/187d/foo.html'
135
+ assert_equal 'text/html', last_response.content_type
136
+ end
137
+
138
+ should "work for small images" do
139
+ load_artifact('3wolfmoon.jpg', 'images/3wolfmoon.jpg', 'image/jpeg')
140
+ get '/gridfs/images/3wolfmoon.jpg'
141
+ assert last_response.ok?
142
+ assert_equal 'image/jpeg', last_response.content_type
143
+ end
144
+ end
145
+
146
+ end
147
+
148
+ end
149
+
@@ -0,0 +1,14 @@
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
+ gem 'mongo', '>= 0.15.1'
11
+
12
+ require 'mongo'
13
+ require 'mongo/gridfs'
14
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'rack', 'gridfs')
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-gridfs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Blake Carlson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-19 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rack
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: activesupport
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: mongo
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.15.1
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: mocha
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "="
52
+ - !ruby/object:Gem::Version
53
+ version: 0.9.4
54
+ version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: rack-test
57
+ type: :development
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ - !ruby/object:Gem::Dependency
66
+ name: thoughtbot-shoulda
67
+ type: :development
68
+ version_requirement:
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ version:
75
+ description:
76
+ email: blake@coin-operated.net
77
+ executables: []
78
+
79
+ extensions: []
80
+
81
+ extra_rdoc_files:
82
+ - LICENSE
83
+ - README.rdoc
84
+ files:
85
+ - .gitignore
86
+ - LICENSE
87
+ - README.rdoc
88
+ - Rakefile
89
+ - VERSION
90
+ - example/gridfs_server.rb
91
+ - lib/rack/gridfs.rb
92
+ - rack-gridfs.gemspec
93
+ - test/artifacts/3wolfmoon.jpg
94
+ - test/artifacts/test.html
95
+ - test/artifacts/test.txt
96
+ - test/gridfs_test.rb
97
+ - test/test_helper.rb
98
+ has_rdoc: true
99
+ homepage: http://github.com/skinandbones/rack-gridfs
100
+ licenses: []
101
+
102
+ post_install_message:
103
+ rdoc_options:
104
+ - --charset=UTF-8
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: "0"
112
+ version:
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: "0"
118
+ version:
119
+ requirements: []
120
+
121
+ rubyforge_project: rack-gridfs
122
+ rubygems_version: 1.3.5
123
+ signing_key:
124
+ specification_version: 3
125
+ summary: Rack middleware for creating HTTP endpoints for files stored in MongoDB's GridFS
126
+ test_files:
127
+ - test/gridfs_test.rb
128
+ - test/test_helper.rb