roy 0.5.2 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/LICENSE +1 -1
- data/lib/roy/after.rb +26 -0
- data/lib/roy/base.rb +8 -0
- data/lib/roy/basic_auth.rb +68 -12
- data/lib/roy/before.rb +29 -0
- data/lib/roy/context.rb +30 -1
- data/lib/roy/halt.rb +31 -4
- data/lib/roy/render.rb +88 -13
- data/lib/roy/version.rb +3 -1
- data/test/plugins/basic_auth_test.rb +1 -1
- metadata +11 -11
data/Gemfile.lock
CHANGED
data/LICENSE
CHANGED
data/lib/roy/after.rb
CHANGED
@@ -1,4 +1,30 @@
|
|
1
1
|
module Roy
|
2
|
+
# This module allows you to modify the response before it is sent to the
|
3
|
+
# client. It does this by overriding the {Roy#call} method.
|
4
|
+
#
|
5
|
+
# == Configuration:
|
6
|
+
# roy.conf.after::
|
7
|
+
# A proc object that will be called with the response as argument.
|
8
|
+
# Defaults to identity if not set.
|
9
|
+
#
|
10
|
+
# @example Forcing a custom content-type
|
11
|
+
#
|
12
|
+
# class SetContentType
|
13
|
+
# include Roy
|
14
|
+
#
|
15
|
+
# roy use: [:after],
|
16
|
+
# after: ->(resp) { resp.headers['Content-Type'] = 'text/x-foo' }
|
17
|
+
#
|
18
|
+
# def get(_)
|
19
|
+
# "Hello, world\n"
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# @example Demo
|
24
|
+
#
|
25
|
+
# $ curl -i localhost:9292
|
26
|
+
# HTTP/1.1 200 OK
|
27
|
+
# Content-Type: text/x-foo
|
2
28
|
module After
|
3
29
|
def call(env)
|
4
30
|
status, header, body = super
|
data/lib/roy/base.rb
CHANGED
@@ -9,17 +9,23 @@ require 'ostruct'
|
|
9
9
|
require 'roy/version'
|
10
10
|
require 'roy/context'
|
11
11
|
|
12
|
+
# This is the main module that applications should include.
|
12
13
|
module Roy
|
14
|
+
|
15
|
+
# Default options.
|
13
16
|
Defaults = {allow: [:get], prefix: :'', use: [:halt]}
|
14
17
|
|
18
|
+
# Extend the class with the ClassMethods module.
|
15
19
|
def self.included(base)
|
16
20
|
base.send(:extend, ClassMethods)
|
17
21
|
end
|
18
22
|
|
23
|
+
# Returns the application context or initialize it
|
19
24
|
def roy
|
20
25
|
@roy ||= Context.new(self)
|
21
26
|
end
|
22
27
|
|
28
|
+
# A Rack-compliant #call method.
|
23
29
|
def call(env)
|
24
30
|
roy.prepare!(env)
|
25
31
|
|
@@ -41,6 +47,7 @@ module Roy
|
|
41
47
|
module ClassMethods
|
42
48
|
attr_reader :conf
|
43
49
|
|
50
|
+
# Setup default configuration for the application.
|
44
51
|
def self.extended(base)
|
45
52
|
base.instance_eval do
|
46
53
|
@conf ||= OpenStruct.new
|
@@ -48,6 +55,7 @@ module Roy
|
|
48
55
|
end
|
49
56
|
end
|
50
57
|
|
58
|
+
# Set options for the application
|
51
59
|
def roy(options={})
|
52
60
|
options.each do |key,value|
|
53
61
|
case key
|
data/lib/roy/basic_auth.rb
CHANGED
@@ -1,20 +1,76 @@
|
|
1
1
|
module Roy
|
2
|
+
# This module provides helpers for using the HTTP basic authentication system.
|
3
|
+
#
|
4
|
+
# == Configuration:
|
5
|
+
# roy.conf.auth [:realm]::
|
6
|
+
# The authentication realm to use.
|
7
|
+
# roy.conf.auth [:logic]::
|
8
|
+
# A proc that checks if an user is authorized. See #authorized? in
|
9
|
+
# InstanceMethods.
|
10
|
+
#
|
11
|
+
# @example Simple auth example
|
12
|
+
#
|
13
|
+
# class AuthApp
|
14
|
+
# include Roy
|
15
|
+
# roy use: [:basic_auth],
|
16
|
+
# auth: {
|
17
|
+
# realm: "My Realm",
|
18
|
+
# logic: ->(_, u, p) { %w(admin foobar) == [u, p] }
|
19
|
+
# }
|
20
|
+
#
|
21
|
+
# def get(_)
|
22
|
+
# roy.protected!
|
23
|
+
# "Protected zone"
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# @example Using user data
|
28
|
+
#
|
29
|
+
# class AuthUserDataApp
|
30
|
+
# include Roy
|
31
|
+
# roy use: [:basic_auth],
|
32
|
+
# auth: {
|
33
|
+
# realm: "My Realm",
|
34
|
+
# logic: ->(override, u, p) {
|
35
|
+
# override || (%w(admin foobar) == [u, p])
|
36
|
+
# }
|
37
|
+
# }
|
38
|
+
#
|
39
|
+
# def get(path)
|
40
|
+
# roy.protected!(path =~ /private/)
|
41
|
+
# "Protected if path contains private"
|
42
|
+
# end
|
43
|
+
# end
|
2
44
|
module BasicAuth
|
3
|
-
def
|
4
|
-
|
5
|
-
realm = roy.conf.auth && roy.conf.auth[:realm] || 'Realm'
|
6
|
-
roy.response['WWW-Authenticate'] = %(Basic realm="#{realm}")
|
7
|
-
roy.halt 401
|
8
|
-
end
|
45
|
+
def self.setup(roy)
|
46
|
+
roy.send(:extend, InstanceMethods)
|
9
47
|
end
|
10
48
|
|
11
|
-
|
12
|
-
|
49
|
+
module InstanceMethods
|
50
|
+
|
51
|
+
# Protect all subsequent code using HTTP Basic Authentication.
|
52
|
+
#
|
53
|
+
# @param data user data to pass to #authorized?
|
54
|
+
def protected!(data=nil)
|
55
|
+
unless authorized?(data)
|
56
|
+
realm = conf.auth && conf.auth[:realm] || 'Realm'
|
57
|
+
response['WWW-Authenticate'] = %(Basic realm="#{realm}")
|
58
|
+
halt 401
|
59
|
+
end
|
60
|
+
end
|
13
61
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
62
|
+
# Runs the authentication logic against the user and passord given in the
|
63
|
+
# request, using custom additional data.
|
64
|
+
#
|
65
|
+
# @param data user data to pass to the authentication logic
|
66
|
+
def authorized?(data=nil)
|
67
|
+
auth = Rack::Auth::Basic::Request.new(request.env)
|
68
|
+
|
69
|
+
auth.provided? && auth.basic? && auth.credentials &&
|
70
|
+
(conf.auth[:logic] || ->(data, u, p) {
|
71
|
+
%w(admin password) == [u, p]
|
72
|
+
}).(data, *auth.credentials)
|
73
|
+
end
|
18
74
|
end
|
19
75
|
end
|
20
76
|
end
|
data/lib/roy/before.rb
CHANGED
@@ -1,4 +1,33 @@
|
|
1
1
|
module Roy
|
2
|
+
# This module allows you to modify the environment before it is handled by the
|
3
|
+
# application. It does this by overriding the {Roy#call} method.
|
4
|
+
#
|
5
|
+
# == Configuration:
|
6
|
+
# roy.conf.before::
|
7
|
+
# A proc object that will be called with the environment as argument.
|
8
|
+
# Defaults to identity if not set.
|
9
|
+
#
|
10
|
+
# @example Forcing a method
|
11
|
+
#
|
12
|
+
# class AlwaysGet
|
13
|
+
# include Roy
|
14
|
+
#
|
15
|
+
# roy allow: [:put, :post], use: [:before],
|
16
|
+
# before: ->(env) { env['REQUEST_METHOD'] = 'GET' }
|
17
|
+
#
|
18
|
+
# def get(_)
|
19
|
+
# "Hello, world\n"
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# @example Demo
|
24
|
+
#
|
25
|
+
# $ curl -i localhost:9292
|
26
|
+
# HTTP/1.1 200 OK
|
27
|
+
# $ curl -X POST -i localhost:9292
|
28
|
+
# HTTP/1.1 200 OK
|
29
|
+
# $ curl -X PUT -i localhost:9292
|
30
|
+
# HTTP/1.1 200 OK
|
2
31
|
module Before
|
3
32
|
def call(env)
|
4
33
|
(roy.conf.before || lambda {|x| x }).(env)
|
data/lib/roy/context.rb
CHANGED
@@ -1,7 +1,33 @@
|
|
1
1
|
module Roy
|
2
|
+
# Application context for Roy applications.
|
3
|
+
#
|
4
|
+
# Everything must be namespaced in this context to avoid any clashes and to
|
5
|
+
# make the code cleaner.
|
2
6
|
class Context
|
3
|
-
|
7
|
+
# Returns the current application
|
8
|
+
attr_reader :app
|
4
9
|
|
10
|
+
# Returns the application's configuration
|
11
|
+
attr_reader :conf
|
12
|
+
|
13
|
+
# Returns the environment passed to #call
|
14
|
+
attr_reader :env
|
15
|
+
|
16
|
+
# Returns the current request
|
17
|
+
attr_reader :request
|
18
|
+
|
19
|
+
# Returns the current response
|
20
|
+
attr_reader :response
|
21
|
+
|
22
|
+
# Returns the current response's headers
|
23
|
+
attr_reader :headers
|
24
|
+
|
25
|
+
# Returns the current request's params
|
26
|
+
attr_reader :params
|
27
|
+
|
28
|
+
# Creates a new Context object.
|
29
|
+
#
|
30
|
+
# @param app the context's application
|
5
31
|
def initialize(app)
|
6
32
|
@app = app
|
7
33
|
@conf = app.class.conf
|
@@ -11,6 +37,9 @@ module Roy
|
|
11
37
|
end
|
12
38
|
end
|
13
39
|
|
40
|
+
# Initializes the attributes based on an environment.
|
41
|
+
#
|
42
|
+
# @param env the environment to use
|
14
43
|
def prepare!(env)
|
15
44
|
@env = env
|
16
45
|
@request = Rack::Request.new(env)
|
data/lib/roy/halt.rb
CHANGED
@@ -1,11 +1,38 @@
|
|
1
1
|
module Roy
|
2
|
+
# This module adds a +halt+ method to the application context that allows you
|
3
|
+
# to break during a handler and immediately return a status code and a body.
|
4
|
+
#
|
5
|
+
# Included by default.
|
6
|
+
#
|
7
|
+
# @example A Not Found application
|
8
|
+
#
|
9
|
+
# class NotFoundApp
|
10
|
+
# include Roy
|
11
|
+
#
|
12
|
+
# def get(_)
|
13
|
+
# halt 404
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# @example Test
|
18
|
+
#
|
19
|
+
# $ curl -i localhost:9292
|
20
|
+
# HTTP/1.1 404 Not Found
|
2
21
|
module Halt
|
3
22
|
|
4
23
|
def self.setup(roy)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
24
|
+
roy.send(:extend, InstanceMethods)
|
25
|
+
end
|
26
|
+
|
27
|
+
module InstanceMethods
|
28
|
+
# Break from the current +catch(:halt)+ block
|
29
|
+
#
|
30
|
+
# @param [Integer] code the response status code.
|
31
|
+
# @param [String] message the response body.
|
32
|
+
# @return [Integer, String] the status and the given message or a default
|
33
|
+
# one.
|
34
|
+
def halt(code, message=nil)
|
35
|
+
throw :halt, [code, message || Rack::Utils::HTTP_STATUS_CODES[code]]
|
9
36
|
end
|
10
37
|
end
|
11
38
|
|
data/lib/roy/render.rb
CHANGED
@@ -1,24 +1,99 @@
|
|
1
1
|
require 'tilt'
|
2
2
|
|
3
3
|
module Roy
|
4
|
+
# A simple template rendering mechanism based on Tilt.
|
5
|
+
#
|
6
|
+
# == Configuration:
|
7
|
+
# roy.conf.render::
|
8
|
+
# A hash of options to pass to Tilt.
|
9
|
+
# roy.conf.views::
|
10
|
+
# The directory where views are kept. Defaults to +views/+
|
11
|
+
#
|
12
|
+
# @example Using <tt>roy.render</tt>
|
13
|
+
#
|
14
|
+
# class ErbApp
|
15
|
+
# include Roy
|
16
|
+
#
|
17
|
+
# roy use: [:render]
|
18
|
+
#
|
19
|
+
# def get(path)
|
20
|
+
# case path
|
21
|
+
# when /\/hello/
|
22
|
+
# roy.render :erb, "Hello, <%= roy.params[:p] || \"world\" %>!\n"
|
23
|
+
# else
|
24
|
+
# roy.render :erb, :index
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# @example Test
|
30
|
+
#
|
31
|
+
# $ cat views/index.erb
|
32
|
+
# Let me <a href="/hello">greet</a> you.
|
33
|
+
# $ curl -i localhost:9292
|
34
|
+
# Let me <a href="/hello">greet</a> you.
|
35
|
+
# $ curl -i localhost:9292/hello?p=blah
|
36
|
+
# Hello, blah!
|
37
|
+
#
|
38
|
+
# @example Haml renderer with partials support
|
39
|
+
#
|
40
|
+
# module HamlRenderWithPartial
|
41
|
+
# def self.setup(roy)
|
42
|
+
# roy.send(:extend, InstanceMethods)
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# module InstanceMethods
|
46
|
+
# def render(tpl_or_string, params={})
|
47
|
+
# case layout = params.delete(:layout)
|
48
|
+
# when false
|
49
|
+
# super(:haml, tpl_or_string, params)
|
50
|
+
# else
|
51
|
+
# super(:haml, :layout, params do
|
52
|
+
# super(:haml, tpl_or_string, params)
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
# end
|
57
|
+
# end
|
4
58
|
module Render
|
5
59
|
|
6
60
|
def self.setup(roy)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
when Symbol
|
12
|
-
file = [view_or_string.to_s, engine].map(&:to_s).join('.')
|
13
|
-
dir = conf.views || 'views'
|
14
|
-
Tilt.new(File.join(dir, file), nil, options)
|
15
|
-
else
|
16
|
-
Tilt[engine].new(nil, nil, options) { view_or_string.to_s }
|
17
|
-
end
|
61
|
+
roy.send(:extend, InstanceMethods)
|
62
|
+
end
|
63
|
+
|
64
|
+
module InstanceMethods
|
18
65
|
|
19
|
-
|
20
|
-
|
66
|
+
# Render the given template or string with the selected engine.
|
67
|
+
#
|
68
|
+
# Views are looked for inside the +roy.conf.views+ directory.
|
69
|
+
# Files should have an extension matching the selected engine.
|
70
|
+
# If you want to use sub-directories, you have to use the
|
71
|
+
# +:"subdir/file.ext"+ syntax.
|
72
|
+
#
|
73
|
+
# @see https://github.com/rtomayko/tilt/blob/master/README.md
|
74
|
+
# @see https://github.com/rtomayko/tilt/blob/master/TEMPLATES.md
|
75
|
+
#
|
76
|
+
# @param [Symbol] engine the name of the rendering engine. Must be
|
77
|
+
# supported by Tilt.
|
78
|
+
# @param [Symbol] view_or_string a template file.
|
79
|
+
# @param [String] view_or_string a template string.
|
80
|
+
# @param [Hash] params locals for Tilt::Template#render.
|
81
|
+
# @param [Proc] block a block to execute when using +yield+ in the
|
82
|
+
# template.
|
83
|
+
def render(engine, view_or_string, params={}, &block)
|
84
|
+
options = conf.render || {}
|
85
|
+
template = case view_or_string
|
86
|
+
when Symbol
|
87
|
+
file = [view_or_string.to_s, engine].map(&:to_s).join('.')
|
88
|
+
dir = conf.views || 'views'
|
89
|
+
Tilt.new(File.join(dir, file), nil, options)
|
90
|
+
else
|
91
|
+
Tilt[engine].new(nil, nil, options) { view_or_string.to_s }
|
92
|
+
end
|
93
|
+
|
94
|
+
template.render(app, params, &block)
|
21
95
|
end
|
96
|
+
|
22
97
|
end
|
23
98
|
|
24
99
|
end
|
data/lib/roy/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-02-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
16
|
-
requirement: &
|
16
|
+
requirement: &13775240 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *13775240
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: minitest
|
27
|
-
requirement: &
|
27
|
+
requirement: &13774520 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *13774520
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rack-test
|
38
|
-
requirement: &
|
38
|
+
requirement: &13792140 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *13792140
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: tilt
|
49
|
-
requirement: &
|
49
|
+
requirement: &13791400 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *13791400
|
58
58
|
description: ! 'roy is a small library which allows every Ruby object to be used
|
59
59
|
|
60
60
|
as a Rack application.'
|
@@ -111,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
111
|
version: '0'
|
112
112
|
requirements: []
|
113
113
|
rubyforge_project: roy
|
114
|
-
rubygems_version: 1.8.
|
114
|
+
rubygems_version: 1.8.15
|
115
115
|
signing_key:
|
116
116
|
specification_version: 3
|
117
117
|
summary: make your objects REST-friendly
|