useless 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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