expressr 0.0.2 → 0.0.3
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.
- data/README.md +725 -0
- data/lib/expressr.rb +7 -1
- data/lib/expressr/app.rb +108 -0
- data/lib/expressr/json.rb +15 -0
- data/lib/expressr/listeners/request.rb +11 -0
- data/lib/expressr/listeners/response.rb +11 -0
- data/lib/expressr/renderer.rb +39 -0
- data/lib/expressr/renderers.rb +9 -0
- data/lib/expressr/renderers/base.rb +10 -0
- data/lib/expressr/renderers/haml.rb +13 -0
- data/lib/expressr/renderers/slim.rb +12 -0
- data/lib/expressr/request.rb +118 -0
- data/lib/expressr/response.rb +188 -0
- data/lib/expressr/route.rb +33 -0
- data/lib/expressr/route_item.rb +103 -0
- data/lib/expressr/route_node.rb +22 -0
- data/lib/expressr/router.rb +68 -0
- data/lib/expressr/utils.rb +46 -0
- data/lib/expressr/version.rb +1 -1
- metadata +98 -3
- data/Rakefile +0 -12
@@ -0,0 +1,33 @@
|
|
1
|
+
module Expressr
|
2
|
+
class Route
|
3
|
+
def initialize(options={})
|
4
|
+
@router = options[:router] || raise('No router provided')
|
5
|
+
@path = options[:path] || raise('No path provided')
|
6
|
+
end
|
7
|
+
|
8
|
+
def all(&block)
|
9
|
+
@router.add_route(block, path: @path)
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(&block)
|
14
|
+
@router.get(@path, &block)
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def put(&block)
|
19
|
+
@router.put(@path, &block)
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def post(&block)
|
24
|
+
@router.post(@path, &block)
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def delete(&block)
|
29
|
+
@router.delete(@path, &block)
|
30
|
+
self
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Expressr
|
2
|
+
class RouteItem
|
3
|
+
attr_reader :proc, :additional_arguments
|
4
|
+
|
5
|
+
def initialize(proc, options)
|
6
|
+
@proc = proc
|
7
|
+
@path = options[:path]
|
8
|
+
@method = options[:method]
|
9
|
+
@content_type = options[:content_type]
|
10
|
+
@param = options[:param] || []
|
11
|
+
|
12
|
+
@additional_arguments = []
|
13
|
+
set_path_token_and_param_names
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env, continue_method)
|
17
|
+
@env = env
|
18
|
+
@continue = continue_method
|
19
|
+
@env[:request].params.merge!(params)
|
20
|
+
@proc.call(@env[:request], @env[:response], @continue, *@additional_arguments)
|
21
|
+
continue
|
22
|
+
@env
|
23
|
+
end
|
24
|
+
|
25
|
+
def continue
|
26
|
+
@continue.call(@env)
|
27
|
+
end
|
28
|
+
|
29
|
+
def matches_env?(env)
|
30
|
+
matches_request?(env[:request])
|
31
|
+
end
|
32
|
+
|
33
|
+
def matches_request?(request)
|
34
|
+
content_type_matches?(request) &&
|
35
|
+
method_matches?(request.env) &&
|
36
|
+
path_matches?(request.env) &&
|
37
|
+
param_matches?(request)
|
38
|
+
end
|
39
|
+
|
40
|
+
def params
|
41
|
+
if @param_values.empty?
|
42
|
+
{}
|
43
|
+
else
|
44
|
+
if @param_names.empty?
|
45
|
+
@param_names = (0..(@param_values.length - 1)).to_a
|
46
|
+
end
|
47
|
+
Hash[@param_names.zip(@param_values)]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def set_path_token_and_param_names
|
54
|
+
@path_token, @param_names = path_token_and_param_names(@path)
|
55
|
+
@param_values = []
|
56
|
+
end
|
57
|
+
|
58
|
+
def path_token_and_param_names(path)
|
59
|
+
if path.is_a?(String) && path =~ /:[a-z]/i
|
60
|
+
regexp = path.gsub(/:[a-z_]+/i, '([\w_]+)')
|
61
|
+
token = Regexp.new(regexp, Regexp::IGNORECASE)
|
62
|
+
param_names = path.scan(/:([a-z_]+)/i).flatten
|
63
|
+
[token, param_names]
|
64
|
+
else
|
65
|
+
[path, []]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def content_type_matches?(request)
|
70
|
+
return true if @content_type.nil?
|
71
|
+
!!request.accepts([@content_type])
|
72
|
+
end
|
73
|
+
|
74
|
+
def method_matches?(request_env)
|
75
|
+
return true if @method.nil?
|
76
|
+
@method == request_env[:request_method]
|
77
|
+
end
|
78
|
+
|
79
|
+
def path_matches?(request_env)
|
80
|
+
return true if @path.nil?
|
81
|
+
|
82
|
+
token = @path_token
|
83
|
+
request_uri = request_env[:request_uri]
|
84
|
+
if token.is_a?(String) && request_uri.end_with?(token)
|
85
|
+
return true
|
86
|
+
elsif token.is_a?(Regexp) && token =~ request_uri
|
87
|
+
@param_values = $~.to_a.drop(1)
|
88
|
+
return true
|
89
|
+
end
|
90
|
+
false
|
91
|
+
end
|
92
|
+
|
93
|
+
def param_matches?(request)
|
94
|
+
return true if @param.empty?
|
95
|
+
if request.params.keys.include?(@param)
|
96
|
+
@additional_arguments = [request.params[@param]]
|
97
|
+
true
|
98
|
+
else
|
99
|
+
false
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Expressr
|
2
|
+
class RouteNode
|
3
|
+
def initialize(proc, next_node, options={})
|
4
|
+
@proc = proc
|
5
|
+
@next_node = next_node
|
6
|
+
@additional_arguments = options[:additional_arguments] || []
|
7
|
+
@has_continued = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(request, response)
|
11
|
+
@request = request
|
12
|
+
@response = response
|
13
|
+
instance_exec(request, response, &@proc)
|
14
|
+
continue unless @has_continued
|
15
|
+
end
|
16
|
+
|
17
|
+
def continue
|
18
|
+
@has_continued = true
|
19
|
+
@next_node.call(@request, @response, *@additional_arguments)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Expressr
|
2
|
+
class Router
|
3
|
+
attr_accessor :server
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@nodes = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def use(path=nil, &block)
|
10
|
+
add_route(block, path: path)
|
11
|
+
end
|
12
|
+
|
13
|
+
def param(name, &block)
|
14
|
+
add_route(block, param: name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def route(path)
|
18
|
+
Route.new(router: self, path: path)
|
19
|
+
end
|
20
|
+
|
21
|
+
def get(path, &block)
|
22
|
+
add_route(block, method: 'GET', path: path)
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def put(path, &block)
|
27
|
+
add_route(block, method: 'PUT', path: path)
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def post(path, &block)
|
32
|
+
add_route(block, method: 'POST', path: path)
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def delete(path, &block)
|
37
|
+
add_route(block, method: 'DELETE', path: path)
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def run(request, response)
|
42
|
+
env = {
|
43
|
+
request: request,
|
44
|
+
response: response
|
45
|
+
}
|
46
|
+
emit('request', env)
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_route(proc, options={})
|
50
|
+
if options[:path]
|
51
|
+
options[:path] = standardize_path(options[:path])
|
52
|
+
end
|
53
|
+
callback = RouteItem.new(proc, options)
|
54
|
+
server.add_listener('request', callback)
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
def standardize_path(path)
|
60
|
+
if path == '*'
|
61
|
+
path = nil
|
62
|
+
elsif path.is_a?(String) && path.include?('*')
|
63
|
+
path = Regexp.new("^#{path.gsub('*', '.*')}$")
|
64
|
+
end
|
65
|
+
path
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Expressr
|
2
|
+
module Utils
|
3
|
+
# From ActiveSupport
|
4
|
+
def constantize(camel_cased_word)
|
5
|
+
names = camel_cased_word.split('::')
|
6
|
+
|
7
|
+
# Trigger a builtin NameError exception including the ill-formed constant in the message.
|
8
|
+
Object.const_get(camel_cased_word) if names.empty?
|
9
|
+
|
10
|
+
# Remove the first blank element in case of '::ClassName' notation.
|
11
|
+
names.shift if names.size > 1 && names.first.empty?
|
12
|
+
|
13
|
+
names.inject(Object) do |constant, name|
|
14
|
+
if constant == Object
|
15
|
+
constant.const_get(name)
|
16
|
+
else
|
17
|
+
candidate = constant.const_get(name)
|
18
|
+
next candidate if constant.const_defined?(name, false)
|
19
|
+
next candidate unless Object.const_defined?(name)
|
20
|
+
|
21
|
+
# Go down the ancestors to check it it's owned
|
22
|
+
# directly before we reach Object or the end of ancestors.
|
23
|
+
constant = constant.ancestors.inject do |const, ancestor|
|
24
|
+
break const if ancestor == Object
|
25
|
+
break ancestor if ancestor.const_defined?(name, false)
|
26
|
+
const
|
27
|
+
end
|
28
|
+
|
29
|
+
# owner is in Object, so raise
|
30
|
+
constant.const_get(name, false)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
module_function :constantize
|
35
|
+
|
36
|
+
def standardize_content_type(content_type)
|
37
|
+
canonicalized_types = {
|
38
|
+
'text' => 'text/plain',
|
39
|
+
'html' => 'text/html',
|
40
|
+
'json' => 'application/json'
|
41
|
+
}
|
42
|
+
canonicalized_types[content_type] || content_type
|
43
|
+
end
|
44
|
+
module_function :standardize_content_type
|
45
|
+
end
|
46
|
+
end
|
data/lib/expressr/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: expressr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,56 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-05-
|
12
|
+
date: 2014-05-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: noder
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: hashie
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: mime-types
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
14
62
|
- !ruby/object:Gem::Dependency
|
15
63
|
name: rspec
|
16
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -27,6 +75,38 @@ dependencies:
|
|
27
75
|
- - ! '>='
|
28
76
|
- !ruby/object:Gem::Version
|
29
77
|
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: haml
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: slim
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
30
110
|
description: Express.js for Ruby
|
31
111
|
email:
|
32
112
|
- tombenner@gmail.com
|
@@ -34,10 +114,25 @@ executables: []
|
|
34
114
|
extensions: []
|
35
115
|
extra_rdoc_files: []
|
36
116
|
files:
|
117
|
+
- lib/expressr/app.rb
|
118
|
+
- lib/expressr/json.rb
|
119
|
+
- lib/expressr/listeners/request.rb
|
120
|
+
- lib/expressr/listeners/response.rb
|
121
|
+
- lib/expressr/renderer.rb
|
122
|
+
- lib/expressr/renderers/base.rb
|
123
|
+
- lib/expressr/renderers/haml.rb
|
124
|
+
- lib/expressr/renderers/slim.rb
|
125
|
+
- lib/expressr/renderers.rb
|
126
|
+
- lib/expressr/request.rb
|
127
|
+
- lib/expressr/response.rb
|
128
|
+
- lib/expressr/route.rb
|
129
|
+
- lib/expressr/route_item.rb
|
130
|
+
- lib/expressr/route_node.rb
|
131
|
+
- lib/expressr/router.rb
|
132
|
+
- lib/expressr/utils.rb
|
37
133
|
- lib/expressr/version.rb
|
38
134
|
- lib/expressr.rb
|
39
135
|
- MIT-LICENSE
|
40
|
-
- Rakefile
|
41
136
|
- README.md
|
42
137
|
homepage: https://github.com/tombenner/expressr
|
43
138
|
licenses:
|
data/Rakefile
DELETED