useless 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/lib/useless.rb +11 -1
  2. data/lib/useless/rack.rb +18 -26
  3. data/lib/useless/rack/authentication/access_token.rb +39 -0
  4. data/lib/useless/rack/authentication/query_string.rb +19 -0
  5. data/lib/useless/rack/authentication/request_header.rb +19 -0
  6. data/lib/useless/rack/exceptions.rb +28 -0
  7. data/lib/useless/rack/files.rb +37 -0
  8. data/lib/useless/rack/fs.rb +17 -0
  9. data/lib/useless/rack/mongo.rb +16 -0
  10. data/lib/useless/version.rb +1 -1
  11. data/spec/spec_helper.rb +4 -3
  12. data/spec/useless/fs_spec.rb +1 -0
  13. data/spec/useless/mongo_spec.rb +1 -0
  14. data/spec/useless/rack/{middleware/authentication → authentication}/query_string_spec.rb +8 -7
  15. data/spec/useless/rack/{middleware/authentication → authentication}/request_header_spec.rb +8 -7
  16. data/spec/useless/rack/exceptions_spec.rb +31 -0
  17. data/spec/useless/rack/files_spec.rb +49 -0
  18. data/spec/useless/rack/fs_spec.rb +18 -0
  19. data/spec/useless/rack/mongo_spec.rb +18 -0
  20. data/spec/useless/rack_spec.rb +77 -0
  21. data/useless.gemspec +7 -7
  22. metadata +49 -50
  23. data/assets/DOC.html +0 -39
  24. data/assets/application.css +0 -134
  25. data/lib/useless/logger.rb +0 -48
  26. data/lib/useless/rack/base.rb +0 -26
  27. data/lib/useless/rack/base/files.rb +0 -33
  28. data/lib/useless/rack/middleware/assets.rb +0 -38
  29. data/lib/useless/rack/middleware/authentication/access_token.rb +0 -41
  30. data/lib/useless/rack/middleware/authentication/query_string.rb +0 -21
  31. data/lib/useless/rack/middleware/authentication/request_header.rb +0 -21
  32. data/lib/useless/rack/middleware/exceptions.rb +0 -41
  33. data/lib/useless/rack/middleware/fs.rb +0 -17
  34. data/lib/useless/rack/middleware/mongo.rb +0 -18
  35. data/spec/useless/logger_spec.rb +0 -87
  36. data/spec/useless/rack/base/files_spec.rb +0 -42
  37. data/spec/useless/rack/middleware/exceptions_spec.rb +0 -47
@@ -1,48 +0,0 @@
1
- require 'logger'
2
-
3
- module Useless
4
- # Useless::Logger is a wrapper around Logger for the purposes of decorating.
5
- class Logger
6
- attr_accessor :request_id
7
-
8
- def initialize(io = $stdout)
9
- @logger = ::Logger.new(io)
10
- end
11
-
12
- def level=(level)
13
- @logger.level = level
14
- end
15
-
16
- def level
17
- @logger.level
18
- end
19
-
20
- def fatal(message)
21
- add ::Logger::FATAL, message
22
- end
23
-
24
- def error(message)
25
- add ::Logger::ERROR, message
26
- end
27
-
28
- def warn(message)
29
- add ::Logger::WARN, message
30
- end
31
-
32
- def info(message)
33
- add ::Logger::INFO, message
34
- end
35
-
36
- def debug(message)
37
- add ::Logger::DEBUG, message
38
- end
39
-
40
- private
41
-
42
- def add(level, message)
43
- formatted_message = message
44
- formatted_message = "[#{@request_id}] #{formatted_message}" if @request_id
45
- @logger.add level, formatted_message
46
- end
47
- end
48
- end
@@ -1,26 +0,0 @@
1
- require 'useless/rack/base/files'
2
-
3
- module Useless
4
- class Rack
5
- # Useless::Base is the Rack endpoint for useless.io proper. It has two
6
- # responsibilties: show documentation, and serve file from 'useless.fs'.
7
- class Base
8
- def call(env)
9
- # Show platform documentation at root
10
- app = ::Rack::URLMap.new '/' => platform_documentation,
11
-
12
- # serve files out of /files/* via the Files Rack endpoint.
13
- '/files/' => Files.new
14
-
15
- app.call(env)
16
- end
17
-
18
- def platform_documentation
19
- @root_app ||= begin
20
- file = File.expand_path('../../../../assets/DOC.html', __FILE__)
21
- [200, {'Content-Type' => 'text/html'}, file]
22
- end
23
- end
24
- end
25
- end
26
- end
@@ -1,33 +0,0 @@
1
- require 'useless/fs'
2
-
3
- module Useless
4
- class Rack
5
- class Base
6
- # Useless::Base::Files simply retrieves files from Useless::FS and serves
7
- # them up.
8
- class Files
9
- # Provide a helper method for file URLs to keep things consistent.
10
- def self.url_for(id)
11
- "http://useless.io/files/#{id}"
12
- end
13
-
14
- def call(env)
15
- # The file ID is everything after the initial '/' in the path
16
- id = env['PATH_INFO'][1..-1]
17
-
18
- # Retrieve the file from FS
19
- file = env['useless.fs'].get(BSON::ObjectId(id))
20
-
21
- # and serve it up with the associated content type
22
- return [200, {'Content-Type' => file.content_type}, file.read]
23
-
24
- # Two things can go wrong, and they'll both raise an error:
25
- # * the specified ID is not a valid object ID
26
- # * there is no file corresponding to the ID in the FS
27
- rescue BSON::InvalidObjectId, Useless::FS::FileNotFound
28
- [404, {'Content-Type' => 'text/plain'}, "File not found: #{id}"]
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,38 +0,0 @@
1
- module Useless
2
- class Rack
3
- module Middleware
4
- # `Assets` maps requests to files in the assets directory.
5
- class Assets
6
- def initialize(app)
7
- @app = app
8
- end
9
-
10
- def call(env)
11
- # If the path couldn't be a file in assets, just proxy the request.
12
- unless env['PATH_INFO'] =~ /\/\w+/
13
- return @app.call(env)
14
- end
15
-
16
- # The path is relative to the assets directory in the gem root
17
- path = File.expand_path("../../../../assets#{env['PATH_INFO']}", __FILE__)
18
-
19
- # If there's a corresponding file:
20
- if File.exists?(path) and !File.directory?(path)
21
- # Try to infer the type from the extension, resorting to 'plain'
22
- # if we can't.
23
- type = path[/\.(\w+)$/, 1] || 'plain'
24
-
25
- # Read the file,
26
- response = File.read(path)
27
-
28
- # and serve it up
29
- [200, {'Content-Type' => "text/#{type}"}, [response]]
30
- else
31
- # Otherwise, just pass the request along
32
- @app.call(env)
33
- end
34
- end
35
- end
36
- end
37
- end
38
- end
@@ -1,41 +0,0 @@
1
- module Useless
2
- class Rack
3
- module Middleware
4
- module Authentication
5
- # The `Authentication::AccessToken` module defines the behavior for access-
6
- # token-based authentication middleware. The middlewares are responsible
7
- # only for providing the access token via the `#access_token_for_env`
8
- # method.
9
- module AccessToken
10
- def initialize(app)
11
- @app = app
12
- end
13
-
14
- def call(env)
15
- # If we don't already have a user set in the environment,
16
- unless env['useless.user']
17
- # check to see if an access token was specified.
18
- if access_token = access_token_for_env(env)
19
- # If so, and a corresponding user can be found,
20
- if user = env['useless.mongo']['users'].find_one('access_token' => access_token)
21
- # set 'useless.user' in the environment.
22
- env['useless.user'] = user
23
- else
24
- # Otherwise, return a 401 Unauthorized.
25
- return [401, {'Content-Type' => 'text/plain'}, ["Invalid access token: #{access_token}"]]
26
- end
27
- end
28
- end
29
-
30
- @app.call(env)
31
- end
32
-
33
- private
34
-
35
- def access_token_for_env(env)
36
- end
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,21 +0,0 @@
1
- require 'useless/rack/middleware/authentication/access_token'
2
-
3
- module Useless
4
- class Rack
5
- module Middleware
6
- module Authentication
7
- # The `Authentication::QueryString` middleware attempt to retrieve the
8
- # access token from the query string.
9
- class QueryString
10
- include AccessToken
11
-
12
- private
13
-
14
- def access_token_for_env(env)
15
- ::Rack::Utils.parse_query(env['QUERY_STRING'])['access_token']
16
- end
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,21 +0,0 @@
1
- require 'useless/rack/middleware/authentication/access_token'
2
-
3
- module Useless
4
- class Rack
5
- module Middleware
6
- module Authentication
7
- # The `Authentication::RequestHeader` middleware attempts to retrieve the
8
- # access token from the `Authorization` request header.
9
- class RequestHeader
10
- include AccessToken
11
-
12
- private
13
-
14
- def access_token_for_env(env)
15
- env['HTTP_AUTHORIZATION']
16
- end
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,41 +0,0 @@
1
- module Useless
2
- class Rack
3
- module Middleware
4
- # `Exceptions` is a Rack middleware that handles any exceptions raised by
5
- # it's app. It has two responsibilities:
6
- # 1. log the exception trace, if a logger is available, and
7
- # 2. return a 500 response with the appropriate message
8
- class Exceptions
9
- def initialize(app)
10
- @app = app
11
- end
12
-
13
- def call(env)
14
- @app.call(env)
15
- rescue => exception
16
- # First, format the exception trace
17
- trace = exception.message + "\n" + exception.backtrace.join("\n")
18
-
19
- # If a logger is available,
20
- if env['useless.logger']
21
- # log the trace as fatal.
22
- env['useless.logger'].fatal trace
23
- end
24
-
25
- # Next, if the request is authenticated by an admin or we are in development or test,
26
- if (env['useless.user'] and env['useless.user']['admin']) or
27
- ENV['RACK_ENV'] == 'development'
28
- # we will return the trace;
29
- message = trace
30
- else
31
- # otherwise, return a generic message.
32
- message = 'An internal server error occurred. Please try again later.'
33
- end
34
-
35
- # Finally, return the 500 error.
36
- [500, {'Content-Type' => 'text/plain'}, [message]]
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,17 +0,0 @@
1
- module Useless
2
- class Rack
3
- module Middleware
4
- # `FS` simply adds the Useless.fs instance to env as 'useless.fs'.
5
- class FS
6
- def initialize(app)
7
- @app = app
8
- end
9
-
10
- def call(env)
11
- env['useless.fs'] = Useless::Rack.fs
12
- @app.call(env)
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,18 +0,0 @@
1
- module Useless
2
- class Rack
3
- module Middleware
4
- # `Useless::Mongo` simply adds the Useless.mongo instance to env as
5
- # 'useless.mongo'.
6
- class Mongo
7
- def initialize(app)
8
- @app = app
9
- end
10
-
11
- def call(env)
12
- env['useless.mongo'] = Useless::Rack.mongo
13
- @app.call(env)
14
- end
15
- end
16
- end
17
- end
18
- end
@@ -1,87 +0,0 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
2
- require 'useless/logger'
3
-
4
- describe Useless::Logger do
5
- describe '#fatal' do
6
- it 'should emit a fatal message' do
7
- io = StringIO.new
8
- logger = Useless::Logger.new(io)
9
- logger.fatal 'Oh noes!'
10
-
11
- io.rewind; message = io.read
12
- message.should =~ /FATAL/
13
- message.should =~ /Oh noes!$/
14
- end
15
- end
16
-
17
- describe '#error' do
18
- it 'should emit an error message' do
19
- io = StringIO.new
20
- logger = Useless::Logger.new(io)
21
- logger.error 'Wrong!'
22
-
23
- io.rewind; message = io.read
24
- message.should =~ /ERROR/
25
- message.should =~ /Wrong!$/
26
- end
27
- end
28
-
29
- describe '#warn' do
30
- it 'should emit a warn message' do
31
- io = StringIO.new
32
- logger = Useless::Logger.new(io)
33
- logger.warn 'Watchout!'
34
-
35
- io.rewind; message = io.read
36
- message.should =~ /WARN/
37
- message.should =~ /Watchout!$/
38
- end
39
- end
40
-
41
- describe '#info' do
42
- it 'should emit an info message' do
43
- io = StringIO.new
44
- logger = Useless::Logger.new(io)
45
- logger.info 'Such and such'
46
-
47
- io.rewind; message = io.read
48
- message.should =~ /INFO/
49
- message.should =~ /Such and such$/
50
- end
51
- end
52
-
53
- describe '#debug' do
54
- it 'should emit a debug message' do
55
- io = StringIO.new
56
- logger = Useless::Logger.new(io)
57
- logger.debug '101011'
58
-
59
- io.rewind; message = io.read
60
- message.should =~ /DEBUG/
61
- message.should =~ /101011$/
62
- end
63
-
64
- it 'should emit nothing if the level is too high' do
65
- io = StringIO.new
66
- logger = Useless::Logger.new(io)
67
- logger.level = ::Logger::INFO
68
- logger.debug '101011'
69
-
70
- io.rewind; message = io.read
71
- message.should == ''
72
- end
73
- end
74
-
75
- describe '#request_id' do
76
- it 'should append the specified ID to all messages' do
77
- io = StringIO.new
78
- logger = Useless::Logger.new(io)
79
- logger.request_id = 'abc123'
80
- logger.info 'Yadda'
81
-
82
- io.rewind; message = io.read
83
- message.should =~ /abc123/
84
- message.should =~ /Yadda$/
85
- end
86
- end
87
- end
@@ -1,42 +0,0 @@
1
- require File.dirname(__FILE__) + '/../../../spec_helper'
2
- require 'useless/rack/base/files'
3
-
4
- describe 'useless.io/files' do
5
- include Rack::Test::Methods
6
-
7
- def app
8
- Useless::Rack.new
9
- end
10
-
11
- describe 'GET /files/:id' do
12
- it 'should return a file if one exists for the specified ID' do
13
- file = File.open(asset_path('muffin-milk.jpg'))
14
- id = Useless::Rack.fs.put(file)
15
-
16
- get Useless::Rack::Base::Files.url_for(id)
17
- last_response.should be_ok
18
-
19
- # See spec/useless/fs_spec.rb
20
- file.rewind
21
- blob = file.read
22
- blob.force_encoding('BINARY')
23
- blob.should == last_response.body
24
- end
25
-
26
- it 'should return a 404 if the file does not exits' do
27
- get Useless::Rack::Base::Files.url_for(BSON::ObjectId.new)
28
- last_response.should be_not_found
29
- end
30
-
31
- it 'should return a 404 if the specified ID is invalid' do
32
- get Useless::Rack::Base::Files.url_for('invalid-id')
33
- last_response.should be_not_found
34
- end
35
- end
36
-
37
- describe '.url_for' do
38
- it 'should return the appropriate URL for the specified file ID' do
39
- Useless::Rack::Base::Files.url_for('abc123').should == 'http://useless.io/files/abc123'
40
- end
41
- end
42
- end