eldr 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +28 -0
- data/.rubocop_todo.yml +15 -0
- data/.travis.yml +3 -0
- data/DUCK.md +15 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +89 -0
- data/LICENSE +20 -0
- data/README.md +876 -0
- data/Rakefile +9 -0
- data/TODOS +3 -0
- data/eldr.gemspec +36 -0
- data/examples/README.md +7 -0
- data/examples/action_objects.ru +28 -0
- data/examples/app.ru +75 -0
- data/examples/builder.ru +24 -0
- data/examples/custom_response.ru +23 -0
- data/examples/errors.ru +16 -0
- data/examples/hello_world.ru +8 -0
- data/examples/inheritance.ru +22 -0
- data/examples/multiple_apps.ru +30 -0
- data/examples/rails_style_routing.ru +14 -0
- data/examples/rendering_templates.ru +38 -0
- data/examples/views/cats.slim +1 -0
- data/lib/eldr/app.rb +146 -0
- data/lib/eldr/builder.rb +60 -0
- data/lib/eldr/configuration.rb +37 -0
- data/lib/eldr/matcher.rb +36 -0
- data/lib/eldr/recognizer.rb +35 -0
- data/lib/eldr/route.rb +92 -0
- data/lib/eldr/version.rb +3 -0
- data/lib/eldr.rb +1 -0
- data/spec/app_spec.rb +194 -0
- data/spec/builder_spec.rb +11 -0
- data/spec/configuration_spec.rb +29 -0
- data/spec/examples/action_objects_spec.rb +18 -0
- data/spec/examples/builder_spec.rb +16 -0
- data/spec/examples/custom_response_spec.rb +17 -0
- data/spec/examples/errors_spec.rb +18 -0
- data/spec/examples/example_app_spec.rb +98 -0
- data/spec/examples/hello_world_spec.rb +17 -0
- data/spec/examples/inheritance_spec.rb +23 -0
- data/spec/examples/multiple_apps_spec.rb +31 -0
- data/spec/examples/rails_style_routing_spec.rb +17 -0
- data/spec/examples/rendering_templates_spec.rb +26 -0
- data/spec/matcher_spec.rb +21 -0
- data/spec/readme_definitions.yml +28 -0
- data/spec/readme_spec.rb +117 -0
- data/spec/recognizer_spec.rb +32 -0
- data/spec/route_spec.rb +131 -0
- data/spec/spec_helper.rb +14 -0
- metadata +252 -0
data/Rakefile
ADDED
data/TODOS
ADDED
data/eldr.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/eldr/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'eldr'
|
6
|
+
s.version = Eldr::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ['K-2052']
|
9
|
+
s.email = ['k@2052.me']
|
10
|
+
s.homepage = 'https://github.com/eldr-rb/eldr'
|
11
|
+
s.summary = 'A minimal framework that lights a fire in your development'
|
12
|
+
s.description = 'A minimal framework that lights a fire in your development.
|
13
|
+
Built close to Rack and the metal.'
|
14
|
+
s.licenses = ['MIT']
|
15
|
+
|
16
|
+
s.required_rubygems_version = '~> 1.3.6'
|
17
|
+
s.required_ruby_version = '~> 2.0'
|
18
|
+
s.rubyforge_project = 'eldr'
|
19
|
+
|
20
|
+
s.add_dependency 'rack', '~> 1.5'
|
21
|
+
s.add_dependency 'mustermann', '0.4.0'
|
22
|
+
s.add_dependency 'fast_blank', '0.0.2'
|
23
|
+
|
24
|
+
s.add_development_dependency 'bundler', '~> 1.7'
|
25
|
+
s.add_development_dependency 'rake', '10.4.2'
|
26
|
+
s.add_development_dependency 'rspec', '3.1.0'
|
27
|
+
s.add_development_dependency 'rubocop', '0.28.0'
|
28
|
+
s.add_development_dependency 'rack-test', '0.6.2'
|
29
|
+
s.add_development_dependency 'tilt', '2.0.1'
|
30
|
+
s.add_development_dependency 'slim', '3.0.1'
|
31
|
+
s.add_development_dependency 'coveralls', '~> 0.7'
|
32
|
+
|
33
|
+
s.files = `git ls-files`.split("\n")
|
34
|
+
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
35
|
+
s.require_path = 'lib'
|
36
|
+
end
|
data/examples/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'eldr'
|
3
|
+
|
4
|
+
class Show
|
5
|
+
attr_accessor :env
|
6
|
+
|
7
|
+
def helper_logic
|
8
|
+
# do things here
|
9
|
+
end
|
10
|
+
|
11
|
+
def params
|
12
|
+
env['eldr.params']
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
@env = env
|
17
|
+
|
18
|
+
helper_logic
|
19
|
+
# @cat = Cat.find params[:id]
|
20
|
+
Rack::Response.new "Found cat named #{params['name'].capitalize}!"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class CatsController < Eldr::App
|
25
|
+
get '/cats/:name', Show.new
|
26
|
+
end
|
27
|
+
|
28
|
+
run CatsController.new
|
data/examples/app.ru
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
class ExampleApp < Eldr::App
|
2
|
+
class NotFound < StandardError
|
3
|
+
def call(env)
|
4
|
+
[404, {}, ['']]
|
5
|
+
end
|
6
|
+
end
|
7
|
+
attr_accessor :cats
|
8
|
+
|
9
|
+
before :before do
|
10
|
+
@thing1 = "Thing1"
|
11
|
+
end
|
12
|
+
|
13
|
+
before do
|
14
|
+
@thing2 = "Thing2"
|
15
|
+
end
|
16
|
+
|
17
|
+
after :cats do
|
18
|
+
@cats == 'Cats!'
|
19
|
+
end
|
20
|
+
|
21
|
+
get '/posts' do |params|
|
22
|
+
Rack::Response.new "posts", 200
|
23
|
+
end
|
24
|
+
|
25
|
+
post '/posts' do
|
26
|
+
Rack::Response.new "posts", 201
|
27
|
+
end
|
28
|
+
|
29
|
+
put '/posts' do
|
30
|
+
Rack::Response.new "posts", 200
|
31
|
+
end
|
32
|
+
|
33
|
+
delete '/posts' do
|
34
|
+
Rack::Response.new "posts", 201
|
35
|
+
end
|
36
|
+
|
37
|
+
get '/deferred' do
|
38
|
+
throw :pass
|
39
|
+
end
|
40
|
+
|
41
|
+
get '/deferred' do
|
42
|
+
Rack::Response.new "Deferred!", 200
|
43
|
+
end
|
44
|
+
|
45
|
+
get '/raises-an-error' do
|
46
|
+
raise NotFound, 'Not Found'
|
47
|
+
end
|
48
|
+
|
49
|
+
get '/state' do
|
50
|
+
@state = 1 + @state.to_i
|
51
|
+
[200, {}, [@state]]
|
52
|
+
end
|
53
|
+
|
54
|
+
get '/state-2' do
|
55
|
+
[200, {}, [@state ||= 0]]
|
56
|
+
end
|
57
|
+
|
58
|
+
get '/before', name: :before do
|
59
|
+
[200, {}, [@thing1]]
|
60
|
+
end
|
61
|
+
|
62
|
+
get '/before-all', name: :before do
|
63
|
+
[200, {}, [@thing2]]
|
64
|
+
end
|
65
|
+
|
66
|
+
get '/after' do
|
67
|
+
[200, {}, ["Cats!"]]
|
68
|
+
end
|
69
|
+
|
70
|
+
get '/posts/:id' do
|
71
|
+
[200, {}, [params['id']]]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
run ExampleApp
|
data/examples/builder.ru
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'eldr'
|
3
|
+
|
4
|
+
class SimpleCounterMiddleware
|
5
|
+
def initialize(app)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env['eldr.simple_counter'] ||= 0
|
11
|
+
env['eldr.simple_counter'] += 1
|
12
|
+
@app.call(env)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class BuilderExample < Eldr::App
|
17
|
+
use SimpleCounterMiddleware
|
18
|
+
|
19
|
+
get '/' do |env|
|
20
|
+
Rack::Response.new env['eldr.simple_counter'].to_s
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
run BuilderExample
|
@@ -0,0 +1,23 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'eldr'
|
3
|
+
|
4
|
+
class Response
|
5
|
+
attr_accessor :status, :headers, :body
|
6
|
+
|
7
|
+
def initialize(body, status=200, headers={})
|
8
|
+
@body, @status, @headers = body, status, headers
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_a
|
12
|
+
[@status, @headers, [@body]]
|
13
|
+
end
|
14
|
+
alias_method :to_ary, :to_a
|
15
|
+
end
|
16
|
+
|
17
|
+
class CustomResponseExample < Eldr::App
|
18
|
+
get '/' do
|
19
|
+
Response.new("Hello World Custom!")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
run CustomResponseExample
|
data/examples/errors.ru
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'eldr'
|
3
|
+
|
4
|
+
class ErrorResponse < StandardError
|
5
|
+
def call(env)
|
6
|
+
Rack::Response.new message, 500
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class ErrorsExample < Eldr::App
|
11
|
+
get '/' do
|
12
|
+
raise ErrorResponse, "Bad Data"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
run ErrorsExample
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class SimpleMiddleware
|
2
|
+
def initialize(app)
|
3
|
+
@app = app
|
4
|
+
end
|
5
|
+
|
6
|
+
def call(env)
|
7
|
+
env['eldr.simple_counter'] ||= 0
|
8
|
+
env['eldr.simple_counter'] += 1
|
9
|
+
@app.call(env)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class TestInheritanceApp < Eldr::App
|
14
|
+
use SimpleCounterMiddleware
|
15
|
+
set :bob, 'what about him?'
|
16
|
+
end
|
17
|
+
|
18
|
+
class InheritedApp < TestInheritanceApp
|
19
|
+
get '/', proc { [200, {}, [env['eldr.simple_counter']]]}
|
20
|
+
end
|
21
|
+
|
22
|
+
run InheritedApp
|
@@ -0,0 +1,30 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'eldr'
|
3
|
+
|
4
|
+
class HelloWorldExample < Eldr::App
|
5
|
+
get '/' do
|
6
|
+
Rack::Response.new "Hello World EXAMPLE!"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class CatsExample < Eldr::App
|
11
|
+
get '/' do
|
12
|
+
Rack::Response.new "Hello Cats!"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class DogsExample < Eldr::App
|
17
|
+
get '/', proc { Rack::Response.new "Hello Dogs!" }
|
18
|
+
end
|
19
|
+
|
20
|
+
map '/' do
|
21
|
+
run HelloWorldExample
|
22
|
+
end
|
23
|
+
|
24
|
+
map '/cats' do
|
25
|
+
run CatsExample
|
26
|
+
end
|
27
|
+
|
28
|
+
map '/dogs' do
|
29
|
+
run DogsExample
|
30
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'eldr'
|
3
|
+
|
4
|
+
class Cats
|
5
|
+
def index env
|
6
|
+
Rack::Response.new "Hello from all the Cats!"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class RailsStyle < Eldr::App
|
11
|
+
get '/cats', to: 'Cats#index'
|
12
|
+
end
|
13
|
+
|
14
|
+
run RailsStyle
|
@@ -0,0 +1,38 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'eldr'
|
3
|
+
require 'tilt'
|
4
|
+
require 'slim'
|
5
|
+
|
6
|
+
module RenderingResponses
|
7
|
+
class NotFound < StandardError
|
8
|
+
def call(env)
|
9
|
+
Rack::Response.new message, 404
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module RenderingHelpers
|
15
|
+
def render(path, resp_code=200)
|
16
|
+
Rack::Response.new Tilt.new(find_template(path)).render(self), resp_code
|
17
|
+
end
|
18
|
+
|
19
|
+
def find_template(path)
|
20
|
+
template = File.join(__dir__, 'views', path)
|
21
|
+
raise RenderingResponses::NotFound, 'Template Not Found' unless File.exists? template
|
22
|
+
template
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class RenderingTemplatesExample < Eldr::App
|
27
|
+
include RenderingHelpers
|
28
|
+
|
29
|
+
get '/cats' do
|
30
|
+
render 'cats.slim'
|
31
|
+
end
|
32
|
+
|
33
|
+
get '/no-template' do
|
34
|
+
render 'template.slim'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
run RenderingTemplatesExample
|
@@ -0,0 +1 @@
|
|
1
|
+
h1 Cats!
|
data/lib/eldr/app.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'rack/request'
|
3
|
+
|
4
|
+
require_relative 'route'
|
5
|
+
require_relative 'matcher'
|
6
|
+
require_relative 'recognizer'
|
7
|
+
require_relative 'configuration'
|
8
|
+
require_relative 'builder'
|
9
|
+
|
10
|
+
###
|
11
|
+
# Eldr is a minimal Ruby framework
|
12
|
+
###
|
13
|
+
module Eldr
|
14
|
+
###
|
15
|
+
# The main class all Eldr apps extend
|
16
|
+
###
|
17
|
+
class App # rubocop:disable Metrics/ClassLength
|
18
|
+
attr_accessor :env, :configuration
|
19
|
+
HTTP_VERBS = %w(DELETE GET HEAD OPTIONS PATCH POST PUT)
|
20
|
+
|
21
|
+
class << self
|
22
|
+
attr_accessor :routes, :recognizer, :builder, :before_filters, :after_filters, :configuration
|
23
|
+
extend Forwardable
|
24
|
+
def_delegators :builder, :map, :use
|
25
|
+
|
26
|
+
alias_method :_new, :new
|
27
|
+
def new(*args, &block)
|
28
|
+
builder.run _new(*args, &block)
|
29
|
+
builder
|
30
|
+
end
|
31
|
+
|
32
|
+
def call(env)
|
33
|
+
new.call env
|
34
|
+
end
|
35
|
+
|
36
|
+
def inherited(base)
|
37
|
+
base.builder.use builder.middleware
|
38
|
+
base.configuration.merge!(configuration)
|
39
|
+
end
|
40
|
+
|
41
|
+
def builder
|
42
|
+
@builder ||= Builder.new
|
43
|
+
end
|
44
|
+
|
45
|
+
def configuration
|
46
|
+
@configuration ||= Configuration.new
|
47
|
+
end
|
48
|
+
alias_method :config, :configuration
|
49
|
+
|
50
|
+
def set(key, value)
|
51
|
+
configuration.set(key, value)
|
52
|
+
end
|
53
|
+
|
54
|
+
def before_filters
|
55
|
+
@before_filters ||= { all: [] }
|
56
|
+
end
|
57
|
+
|
58
|
+
def after_filters
|
59
|
+
@after_filters ||= { all: [] }
|
60
|
+
end
|
61
|
+
|
62
|
+
def before(*keys, &block)
|
63
|
+
*keys = [:all] if keys.empty?
|
64
|
+
keys.each do |key|
|
65
|
+
before_filters[key] ||= []
|
66
|
+
before_filters[key] << block
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def after(*keys, &block)
|
71
|
+
*keys = [:all] if keys.empty?
|
72
|
+
keys.each do |key|
|
73
|
+
after_filters[key] ||= []
|
74
|
+
after_filters[key] << block
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def routes
|
79
|
+
@routes ||= { delete: [], get: [], head: [], options: [], patch: [], post: [], put: [] }
|
80
|
+
end
|
81
|
+
|
82
|
+
def recognizer
|
83
|
+
@recognizer ||= Recognizer.new(routes)
|
84
|
+
end
|
85
|
+
|
86
|
+
HTTP_VERBS.each do |verb|
|
87
|
+
define_method verb.downcase.to_sym do |path, *args, &block|
|
88
|
+
handler = Proc.new(&block) if block
|
89
|
+
handler ||= args.pop if args.last.respond_to?(:call)
|
90
|
+
options ||= args.pop if args.last.is_a?(Hash)
|
91
|
+
options ||= {}
|
92
|
+
add(verb: verb.downcase.to_sym, path: path, handler: handler, options: options)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def add(verb: :get, path: '/', options: {}, handler: nil)
|
97
|
+
handler = Proc.new if block_given?
|
98
|
+
route = Route.new(verb: verb, path: path, options: options, handler: handler)
|
99
|
+
|
100
|
+
route.before_filters.push(*before_filters[route.name]) if before_filters.include? route.name
|
101
|
+
route.after_filters.push(*after_filters[route.name]) if after_filters.include? route.name
|
102
|
+
|
103
|
+
routes[verb] << route
|
104
|
+
route
|
105
|
+
end
|
106
|
+
alias_method :<<, :add
|
107
|
+
end
|
108
|
+
|
109
|
+
def initialize(configuration = nil)
|
110
|
+
configuration ||= self.class.configuration
|
111
|
+
@configuration = configuration
|
112
|
+
end
|
113
|
+
|
114
|
+
def call(env)
|
115
|
+
dup.call!(env)
|
116
|
+
end
|
117
|
+
|
118
|
+
def call!(env)
|
119
|
+
@env = env
|
120
|
+
|
121
|
+
recognize(env).each do |route|
|
122
|
+
env['eldr.route'] = route
|
123
|
+
params.merge!(route.params(env['PATH_INFO']))
|
124
|
+
catch(:pass) { return route.call(env, app: self) }
|
125
|
+
end
|
126
|
+
rescue => error
|
127
|
+
if error.respond_to? :call
|
128
|
+
error.call(env)
|
129
|
+
else
|
130
|
+
raise error
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def request
|
135
|
+
env['eldr.request'] ||= Rack::Request.new(env)
|
136
|
+
end
|
137
|
+
|
138
|
+
def params
|
139
|
+
env['eldr.params'] ||= request.params
|
140
|
+
end
|
141
|
+
|
142
|
+
def recognize(env)
|
143
|
+
self.class.recognizer.call(env)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
data/lib/eldr/builder.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rack/builder'
|
2
|
+
|
3
|
+
module Eldr
|
4
|
+
class Builder < Rack::Builder
|
5
|
+
attr_accessor :middleware
|
6
|
+
def initialize(default_app = nil, &block)
|
7
|
+
@middleware, @map, @run, @warmup = [], nil, default_app, nil
|
8
|
+
instance_eval(&block) if block_given?
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.app(default_app = nil, &block)
|
12
|
+
new(default_app, &block).to_app
|
13
|
+
end
|
14
|
+
|
15
|
+
def use(middleware, *args, &block)
|
16
|
+
if middleware.is_a? Array
|
17
|
+
@middleware.push(*middleware)
|
18
|
+
else
|
19
|
+
if @map
|
20
|
+
mapping, @map = @map, nil
|
21
|
+
@middleware << proc { |app| generate_map app, mapping }
|
22
|
+
end
|
23
|
+
@middleware << proc { |app| middleware.new(app, *args, &block) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def run(app) # rubocop:disable Style/TrivialAccessors
|
28
|
+
@run = app
|
29
|
+
end
|
30
|
+
|
31
|
+
def warmup(prc = nil, &block)
|
32
|
+
@warmup = prc || block
|
33
|
+
end
|
34
|
+
|
35
|
+
def map(path, &block)
|
36
|
+
@map ||= {}
|
37
|
+
@map[path] = block
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_app
|
41
|
+
app = @map ? generate_map(@run, @map) : @run
|
42
|
+
fail 'missing run or map statement' unless app
|
43
|
+
app = @middleware.reverse.inject(app) { |a, e| e[a] }
|
44
|
+
@warmup.call(app) if @warmup
|
45
|
+
app
|
46
|
+
end
|
47
|
+
|
48
|
+
def call(env)
|
49
|
+
to_app.call(env)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def generate_map(default_app, mapping)
|
55
|
+
mapped = default_app ? { '/' => default_app } : {}
|
56
|
+
mapping.each { |r, b| mapped[r] = self.class.new(default_app, &b).to_app }
|
57
|
+
URLMap.new(mapped)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Eldr
|
2
|
+
###
|
3
|
+
# This a OpenStruct like class.
|
4
|
+
# It wraps a hash and when you hit a method that doesn't exist it tries to pull it from the hash
|
5
|
+
# Probably can break in 100 ways an is dumb, but it works.
|
6
|
+
# And it performs astromnomically better than stuff like Hashie::Mash
|
7
|
+
###
|
8
|
+
class Configuration
|
9
|
+
attr_accessor :table
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
defaults = { lock: false }
|
13
|
+
table.merge!(defaults)
|
14
|
+
end
|
15
|
+
|
16
|
+
def set(key, value)
|
17
|
+
@table[key] = value
|
18
|
+
end
|
19
|
+
|
20
|
+
def table
|
21
|
+
@table ||= {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def merge!(hash)
|
25
|
+
hash = hash.table unless hash.is_a? Hash
|
26
|
+
@table.merge!(hash)
|
27
|
+
end
|
28
|
+
|
29
|
+
def method_missing(method, *args)
|
30
|
+
if !args.empty? # we assume we are setting something
|
31
|
+
set(method.to_s.gsub(/\=$/, '').to_sym, args.pop)
|
32
|
+
else
|
33
|
+
@table[method.to_s.gsub(/\?$/, '').to_sym]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/eldr/matcher.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'mustermann'
|
2
|
+
|
3
|
+
module Eldr
|
4
|
+
class Matcher
|
5
|
+
PATH_DELIMITER = '/'.freeze
|
6
|
+
QUERY_PREFIX = '?'.freeze
|
7
|
+
QUERY_DELIMITER = '&'.freeze
|
8
|
+
|
9
|
+
def initialize(path, options = {})
|
10
|
+
@path = path.is_a?(String) && path.empty? ? PATH_DELIMITER : path
|
11
|
+
@capture = options.delete(:capture)
|
12
|
+
@default_values = options.delete(:default_values)
|
13
|
+
end
|
14
|
+
|
15
|
+
def match(pattern)
|
16
|
+
match_data = handler.match(pattern)
|
17
|
+
return match_data if match_data
|
18
|
+
pattern = pattern[0..-2] if mustermann? && pattern != PATH_DELIMITER && pattern.end_with?(PATH_DELIMITER)
|
19
|
+
handler.match(pattern)
|
20
|
+
end
|
21
|
+
|
22
|
+
def mustermann?
|
23
|
+
handler.instance_of?(Mustermann)
|
24
|
+
end
|
25
|
+
|
26
|
+
def handler
|
27
|
+
@handler ||=
|
28
|
+
case @path
|
29
|
+
when String
|
30
|
+
Mustermann.new(@path, capture: @capture)
|
31
|
+
when Regexp
|
32
|
+
/^(?:#{@path})$/
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'fast_blank'
|
2
|
+
|
3
|
+
module Eldr
|
4
|
+
class Recognizer
|
5
|
+
class NotFound < StandardError
|
6
|
+
def call(_env)
|
7
|
+
[404, {}, ['']]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_accessor :app, :env, :routes, :pattern
|
12
|
+
|
13
|
+
def initialize(routes)
|
14
|
+
@routes = routes
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
@env = env
|
19
|
+
|
20
|
+
ret_routes = routes[verb].select { |route| !route.match(pattern).nil? }
|
21
|
+
raise NotFound if ret_routes.empty?
|
22
|
+
ret_routes
|
23
|
+
end
|
24
|
+
|
25
|
+
def pattern
|
26
|
+
@pattern = env['PATH_INFO']
|
27
|
+
@pattern = '/' if @pattern.blank?
|
28
|
+
@pattern
|
29
|
+
end
|
30
|
+
|
31
|
+
def verb
|
32
|
+
env['REQUEST_METHOD'].downcase.to_sym
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|