track 0.3.0 → 0.4.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.
- 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: []
|