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.
@@ -1 +1,6 @@
1
+ # Changelog
2
+
3
+ ## v 0.4.0
4
+
5
+ - complete rewrite
1
6
 
data/README.md CHANGED
@@ -1,17 +1,17 @@
1
1
  # Track
2
2
 
3
- A nano framework for server applications based on rack and ruby 1.9 named capture groups.
3
+ A nano framework for server applications based on rack.
4
4
 
5
5
  ## What Track does
6
6
 
7
- - modularize your rack app through controllers
8
- - routes paths to methods inside of your controllers via the `route` method
9
- - define before filters via the `pre` method
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
- ## Install example application
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
@@ -0,0 +1,8 @@
1
+ # Track
2
+
3
+ - add logging
4
+
5
+ # FilterMap
6
+
7
+ - add controller/action cache
8
+
@@ -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 use(plugin)
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
- begin
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
@@ -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
- @@route_map = RouteMap.new
9
- @@filter_map = FilterMap.new
7
+ @@filters = FilterMap.new
10
8
 
11
- attr_accessor :params
9
+ attr_reader :env, :params
12
10
 
13
- def initialize
14
- @params = {}
11
+ def initialize(env, params)
12
+ @env = env
13
+ @params = params
15
14
  end
16
15
 
17
- def call(env)
18
- req = Rack::Request.new(env)
19
- @params.merge!(req.params)
20
- if route = @@route_map.scan(self.class.name, req)
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
- protected
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
- def self.route(pattern, action, methods = nil)
49
- @@route_map.add self.name, pattern, action, methods
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
@@ -1,23 +1,36 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Track
4
- class FilterMap < Hash
4
+ class FilterMap
5
5
 
6
- def add(key, method, actions)
7
- self[key] ||= {}
8
- actions = actions.is_a?(Array) ? actions.map(&:to_sym) : [actions.to_sym]
9
- actions.each do |action|
10
- self[key][action.to_sym] ||= []
11
- self[key][action.to_sym] << method.to_sym
12
- end
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(key, action)
16
- if self[key]
17
- self[key][action.to_sym] ? self[key][action.to_sym] : []
18
- else
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
@@ -1,25 +1,36 @@
1
- # encoding: utf-8
2
1
 
3
2
  module Track
4
- class RouteMap < Hash
3
+ class RouteMap
5
4
 
6
- def add(clazz, pattern, action, methods)
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
- self[clazz] ||= []
9
- self[clazz].push(
10
- :pattern => compile_regexp(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(clazz, req)
17
- method = req.request_method.downcase.to_sym
18
- self[clazz].each do |route|
19
- md = req.path_info.match(route[:pattern])
20
- return route.merge(:matches => match_hash(md)) if md && allowed_method?(route, method)
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
- false
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
- pattern.gsub!(/:([^\/]+)/i, '(?<\1> [^/]+)')
42
- Regexp.new('\A'+pattern+'\z', Regexp::EXTENDED)
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Track
2
- VERSION = '0.3.0'
2
+ VERSION = '0.4.0'
3
3
  end
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.3.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: 2011-12-10 00:00:00.000000000Z
12
+ date: 2012-01-03 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
16
- requirement: &70223625727700 !ruby/object:Gem::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: *70223625727700
24
+ version_requirements: *70210397017080
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &70223625725260 !ruby/object:Gem::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: *70223625725260
35
+ version_requirements: *70210397015520
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rack-test
38
- requirement: &70223625719580 !ruby/object:Gem::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: *70223625719580
47
- - !ruby/object:Gem::Dependency
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: '1.9'
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 and ruby
112
- 1.9
90
+ summary: Nano framework to build small server applications based on rack
113
91
  test_files: []