track 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +5 -0
- data/README.md +10 -44
- data/ROADMAP.md +8 -0
- data/lib/track.rb +13 -7
- data/lib/track/application.rb +23 -0
- data/lib/track/controller.rb +25 -37
- data/lib/track/filter_map.rb +26 -13
- data/lib/track/route_map.rb +29 -22
- data/lib/track/routes.rb +27 -0
- data/lib/track/version.rb +1 -1
- metadata +13 -35
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
# Track
|
2
2
|
|
3
|
-
A nano framework for server applications based on rack
|
3
|
+
A nano framework for server applications based on rack.
|
4
4
|
|
5
5
|
## What Track does
|
6
6
|
|
7
|
-
- modularize your rack app
|
8
|
-
- routes paths to methods
|
9
|
-
- define before filters
|
10
|
-
- ActiveRecord initializer through `require 'track/orm/active_record'`
|
7
|
+
- modularize your rack app with controllers
|
8
|
+
- routes paths to methods of controllers via `Track::Routes.define` in `config/routes.rb`
|
9
|
+
- lets you define before- and after-filters in your controllers
|
11
10
|
|
12
11
|
## What Track does *not*
|
13
12
|
|
14
13
|
- support any template engines, your actions have to return low level rack responses
|
14
|
+
- no security layer
|
15
15
|
|
16
16
|
## Install
|
17
17
|
|
@@ -23,7 +23,11 @@ or install it via rubygems
|
|
23
23
|
|
24
24
|
`gem install track`
|
25
25
|
|
26
|
-
##
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
Have a look at the example application. I will provide documentation and more examples in the future.
|
29
|
+
|
30
|
+
### Install example application
|
27
31
|
|
28
32
|
Clone the [http://github.com/larskuhnt/track-example](track-example) project:
|
29
33
|
|
@@ -37,44 +41,6 @@ or install it via the gem executable
|
|
37
41
|
track new my_track_project
|
38
42
|
```
|
39
43
|
|
40
|
-
## Usage
|
41
|
-
|
42
|
-
Subclass the `Track::Controller` class to define controllers:
|
43
|
-
|
44
|
-
### Example
|
45
|
-
|
46
|
-
```ruby
|
47
|
-
class UsersController < Track::Controller
|
48
|
-
|
49
|
-
route '/', :index, :get
|
50
|
-
route '/show/:id', :show, :get
|
51
|
-
route '/update/(?<id> [^\/]+)', :show, [:post, :put]
|
52
|
-
|
53
|
-
pre :find_user, :show
|
54
|
-
|
55
|
-
def index
|
56
|
-
[200, { "Content-Type" => 'text/plain' }, StringIO.new('hello from index')]
|
57
|
-
end
|
58
|
-
|
59
|
-
def show
|
60
|
-
[200, { "Content-Type" => 'text/plain' }, StringIO.new(@user.name)]
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
|
65
|
-
def find_user
|
66
|
-
@user = User.find(params['id'])
|
67
|
-
fail [404, { "Content-Type" => 'text/plain' }, StringIO.new('user not found')] unless @user
|
68
|
-
end
|
69
|
-
end
|
70
|
-
```
|
71
|
-
|
72
|
-
The `route` method maps a route to an action in your controller. You can define named parameters by appending a : or by using a named capture group.
|
73
|
-
|
74
|
-
You can build arbitrary path match patterns by using regaular expressions.
|
75
|
-
|
76
|
-
The `pre` method calls a method prior to the action. If `fail` is called in before filter method the action will not get called and the given response will be returned.
|
77
|
-
|
78
44
|
## Plugins
|
79
45
|
|
80
46
|
Currently available:
|
data/ROADMAP.md
CHANGED
data/lib/track.rb
CHANGED
@@ -1,8 +1,14 @@
|
|
1
1
|
require 'rack'
|
2
|
+
require 'track/application'
|
3
|
+
require 'track/routes'
|
2
4
|
require 'track/controller'
|
3
5
|
|
4
6
|
module Track
|
5
7
|
|
8
|
+
@@responses = {
|
9
|
+
:routing_error => [404, { 'Content-Type' => 'text/plain'}, ['Route not found']],
|
10
|
+
:not_found => [404, { 'Content-Type' => 'text/plain'}, ['Resource not found']]
|
11
|
+
}
|
6
12
|
@@env = ENV['RACK_ENV'].to_sym.freeze
|
7
13
|
@@config = nil
|
8
14
|
@@root = nil
|
@@ -13,6 +19,7 @@ module Track
|
|
13
19
|
@@root = root
|
14
20
|
@@config = load_config_file!(:config)
|
15
21
|
boot_plugins!
|
22
|
+
Routes.load! File.join(root, 'config', 'routes')
|
16
23
|
end
|
17
24
|
|
18
25
|
def [](key)
|
@@ -39,17 +46,16 @@ module Track
|
|
39
46
|
VERSION
|
40
47
|
end
|
41
48
|
|
42
|
-
def
|
49
|
+
def plugin(plugin)
|
43
50
|
@@plugins << plugin
|
44
51
|
end
|
45
52
|
|
53
|
+
def responses
|
54
|
+
@@responses
|
55
|
+
end
|
56
|
+
|
46
57
|
def load_config_file!(filename)
|
47
|
-
|
48
|
-
YAML.load(File.open(File.join(root, 'config', "#{filename}.yml")))[env.to_s]
|
49
|
-
rescue
|
50
|
-
raise "Config file config/config.yml is missing!" if env?(:production)
|
51
|
-
YAML.load(File.open(File.join(root, 'config', "#{filename}.example.yml")))[env.to_s]
|
52
|
-
end
|
58
|
+
YAML.load(File.open(File.join(root, 'config', "#{filename}.yml")))[env.to_s]
|
53
59
|
end
|
54
60
|
|
55
61
|
def boot_plugins!
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Track
|
4
|
+
class Application
|
5
|
+
|
6
|
+
def call(env)
|
7
|
+
req = Rack::Request.new(env)
|
8
|
+
if route = Routes.find(req.request_method, req.path_info)
|
9
|
+
controller = route[:class].new(env, req.params.merge(route[:matches]))
|
10
|
+
if response = controller.run_filters(:before, route[:action])
|
11
|
+
return response
|
12
|
+
else
|
13
|
+
response = controller.send(route[:action])
|
14
|
+
controller.run_filters(:after, route[:action])
|
15
|
+
response
|
16
|
+
end
|
17
|
+
else
|
18
|
+
Track.responses[:routing_error]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
data/lib/track/controller.rb
CHANGED
@@ -1,57 +1,45 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require_relative 'route_map'
|
3
2
|
require_relative 'filter_map'
|
4
3
|
|
5
4
|
module Track
|
6
5
|
class Controller
|
7
6
|
|
8
|
-
@@
|
9
|
-
@@filter_map = FilterMap.new
|
7
|
+
@@filters = FilterMap.new
|
10
8
|
|
11
|
-
|
9
|
+
attr_reader :env, :params
|
12
10
|
|
13
|
-
def initialize
|
14
|
-
@
|
11
|
+
def initialize(env, params)
|
12
|
+
@env = env
|
13
|
+
@params = params
|
15
14
|
end
|
16
15
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
@params.merge!(route[:matches])
|
22
|
-
response_for(route)
|
23
|
-
else
|
24
|
-
routing_error
|
16
|
+
def run_filters(kind, action)
|
17
|
+
@@filters.scan(self.class, kind, action).each do |filter_method|
|
18
|
+
self.send(filter_method)
|
19
|
+
return @_response if @_response
|
25
20
|
end
|
21
|
+
nil
|
26
22
|
end
|
27
23
|
|
28
|
-
|
29
|
-
|
30
|
-
def routing_error
|
31
|
-
[404, { 'Content-Type' => 'text/plain' }, ['route not found']]
|
32
|
-
end
|
33
|
-
|
34
|
-
def response_for(route)
|
35
|
-
if filters = @@filter_map.scan(self.class.name, route[:action])
|
36
|
-
filters.each do |m|
|
37
|
-
send(m)
|
38
|
-
return @_response if @_response
|
39
|
-
end
|
40
|
-
end
|
41
|
-
send(route[:action])
|
42
|
-
end
|
43
|
-
|
44
|
-
def fail(response = [404, { 'Content-Type' => 'text/plain' }, ['']])
|
24
|
+
def respond(response)
|
45
25
|
@_response = response
|
46
26
|
end
|
47
27
|
|
48
|
-
|
49
|
-
|
28
|
+
class << self
|
29
|
+
|
30
|
+
def filters
|
31
|
+
@@filters
|
32
|
+
end
|
33
|
+
|
34
|
+
def before_filter(method, options = {})
|
35
|
+
@@filters.add(self, :before, method, options)
|
36
|
+
end
|
37
|
+
|
38
|
+
def after_filter(method, options = {})
|
39
|
+
@@filters.add(self, :after, method, options)
|
40
|
+
end
|
41
|
+
|
50
42
|
end
|
51
43
|
|
52
|
-
def self.pre(method, actions)
|
53
|
-
@@filter_map.add self.name, method, actions
|
54
|
-
end
|
55
|
-
|
56
44
|
end
|
57
45
|
end
|
data/lib/track/filter_map.rb
CHANGED
@@ -1,23 +1,36 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module Track
|
4
|
-
class FilterMap
|
4
|
+
class FilterMap
|
5
5
|
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
def initialize
|
7
|
+
@filters = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def add(klass, kind, method, options = {})
|
11
|
+
@filters[kind] ||= []
|
12
|
+
@filters[kind] << [method, options, klass]
|
13
13
|
end
|
14
14
|
|
15
|
-
def scan(
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
def scan(klass, kind, action)
|
16
|
+
filters = []
|
17
|
+
if @filters[kind]
|
18
|
+
@filters[kind].each do |method, options, k|
|
19
|
+
next if contains?(options[:except], action) || !(klass <= k)
|
20
|
+
filters << method if contains?(options[:only], action) || blank?(options[:only])
|
21
|
+
end
|
20
22
|
end
|
23
|
+
filters
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def contains?(a, k)
|
29
|
+
a == k || (Array === a && a.include?(k)) ? true : false
|
30
|
+
end
|
31
|
+
|
32
|
+
def blank?(a)
|
33
|
+
a.nil? || a.size == 0
|
21
34
|
end
|
22
35
|
|
23
36
|
end
|
data/lib/track/route_map.rb
CHANGED
@@ -1,25 +1,36 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
|
3
2
|
module Track
|
4
|
-
class RouteMap
|
3
|
+
class RouteMap
|
5
4
|
|
6
|
-
def
|
5
|
+
def initialize
|
6
|
+
@routes = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def add(pattern, klass, action, methods = nil)
|
10
|
+
raise "#{klass} is not a subclass of Track::Controller" unless klass <= Track::Controller
|
7
11
|
methods = methods.is_a?(Array) ? methods : [methods] if methods
|
8
|
-
|
9
|
-
|
10
|
-
:pattern =>
|
12
|
+
regex, keys = compile_regexp(pattern)
|
13
|
+
@routes.push(
|
14
|
+
:pattern => regex,
|
15
|
+
:keys => keys,
|
16
|
+
:class => klass,
|
11
17
|
:action => action.to_sym,
|
12
18
|
:methods => methods
|
13
19
|
)
|
14
20
|
end
|
21
|
+
alias_method :route, :add
|
15
22
|
|
16
|
-
def scan(
|
17
|
-
|
18
|
-
|
19
|
-
md
|
20
|
-
|
23
|
+
def scan(path, method)
|
24
|
+
@routes.each do |route|
|
25
|
+
md = path.match(route[:pattern])
|
26
|
+
if md && allowed_method?(route, method)
|
27
|
+
keys = route[:keys]
|
28
|
+
matches = {}
|
29
|
+
(1..md.size-1).each { |i| matches[keys[i-1]] = md[i] }
|
30
|
+
return route.merge(:matches => matches)
|
31
|
+
end
|
21
32
|
end
|
22
|
-
|
33
|
+
nil
|
23
34
|
end
|
24
35
|
|
25
36
|
private
|
@@ -28,18 +39,14 @@ module Track
|
|
28
39
|
route[:methods].nil? ? true : route[:methods].include?(method)
|
29
40
|
end
|
30
41
|
|
31
|
-
def match_hash(md)
|
32
|
-
params = {}
|
33
|
-
md.names.each do |key|
|
34
|
-
params[key.to_s] = md[key]
|
35
|
-
end
|
36
|
-
params
|
37
|
-
end
|
38
|
-
|
39
42
|
def compile_regexp(pattern)
|
40
43
|
pattern = (pattern[-1,1] == '/' ? pattern.chop : pattern) << '/?'
|
41
|
-
|
42
|
-
|
44
|
+
keys = []
|
45
|
+
pattern.gsub!(/:(\w+)/) do |m|
|
46
|
+
keys << $1
|
47
|
+
'([^\/#\?]+)'
|
48
|
+
end
|
49
|
+
[Regexp.new("^#{pattern}$"), keys]
|
43
50
|
end
|
44
51
|
end
|
45
52
|
end
|
data/lib/track/routes.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative 'route_map'
|
2
|
+
|
3
|
+
module Track
|
4
|
+
|
5
|
+
class Routes
|
6
|
+
|
7
|
+
@@route_map = RouteMap.new
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
def load!(route_file)
|
12
|
+
require route_file
|
13
|
+
end
|
14
|
+
|
15
|
+
def define(&block)
|
16
|
+
@@route_map.instance_eval &block
|
17
|
+
end
|
18
|
+
|
19
|
+
def find(method, path)
|
20
|
+
@@route_map.scan(path, method.downcase.to_sym)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/track/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: track
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
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:
|
12
|
+
date: 2012-01-03 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
16
|
-
requirement: &
|
16
|
+
requirement: &70210397017080 !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: *70210397017080
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
requirement: &
|
27
|
+
requirement: &70210397015520 !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: *70210397015520
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rack-test
|
38
|
-
requirement: &
|
38
|
+
requirement: &70210397014500 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,31 +43,8 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
47
|
-
|
48
|
-
name: active_record
|
49
|
-
requirement: &70223625717640 !ruby/object:Gem::Requirement
|
50
|
-
none: false
|
51
|
-
requirements:
|
52
|
-
- - ! '>='
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
type: :development
|
56
|
-
prerelease: false
|
57
|
-
version_requirements: *70223625717640
|
58
|
-
- !ruby/object:Gem::Dependency
|
59
|
-
name: thor
|
60
|
-
requirement: &70223625715720 !ruby/object:Gem::Requirement
|
61
|
-
none: false
|
62
|
-
requirements:
|
63
|
-
- - ! '>='
|
64
|
-
- !ruby/object:Gem::Version
|
65
|
-
version: '0'
|
66
|
-
type: :development
|
67
|
-
prerelease: false
|
68
|
-
version_requirements: *70223625715720
|
69
|
-
description: Nano framework to build small server applications based on rack and ruby
|
70
|
-
1.9
|
46
|
+
version_requirements: *70210397014500
|
47
|
+
description: Nano framework to build small and fast server applications based on rack
|
71
48
|
email:
|
72
49
|
- lars.kuhnt@gmail.com
|
73
50
|
executables:
|
@@ -75,9 +52,11 @@ executables:
|
|
75
52
|
extensions: []
|
76
53
|
extra_rdoc_files: []
|
77
54
|
files:
|
55
|
+
- lib/track/application.rb
|
78
56
|
- lib/track/controller.rb
|
79
57
|
- lib/track/filter_map.rb
|
80
58
|
- lib/track/route_map.rb
|
59
|
+
- lib/track/routes.rb
|
81
60
|
- lib/track/version.rb
|
82
61
|
- lib/track.rb
|
83
62
|
- LICENSE
|
@@ -96,7 +75,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
96
75
|
requirements:
|
97
76
|
- - ! '>='
|
98
77
|
- !ruby/object:Gem::Version
|
99
|
-
version: '
|
78
|
+
version: '0'
|
100
79
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
80
|
none: false
|
102
81
|
requirements:
|
@@ -108,6 +87,5 @@ rubyforge_project:
|
|
108
87
|
rubygems_version: 1.8.10
|
109
88
|
signing_key:
|
110
89
|
specification_version: 3
|
111
|
-
summary: Nano framework to build small server applications based on rack
|
112
|
-
1.9
|
90
|
+
summary: Nano framework to build small server applications based on rack
|
113
91
|
test_files: []
|