flame 3.4.0 → 3.5.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.
- checksums.yaml +4 -4
- data/lib/flame/application.rb +18 -5
- data/lib/flame/controller.rb +8 -8
- data/lib/flame/cookies.rb +18 -0
- data/lib/flame/dispatcher.rb +57 -77
- data/lib/flame/errors.rb +4 -4
- data/lib/flame/render.rb +21 -11
- data/lib/flame/response.rb +11 -0
- data/lib/flame/route.rb +63 -15
- data/lib/flame/router.rb +38 -32
- data/lib/flame/static.rb +32 -0
- data/lib/flame/validators.rb +20 -6
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: edd8f37ca2180414b5428f5d5bbb5cf146daa356
|
4
|
+
data.tar.gz: 1f79bd46b74f82ac879c470dc2df4d59d2120adc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 907034532dbbd46fad3ecb8963579a4ec92f161b0aad1c798a663aea55b46e38efa1b6a4e549d6a1706b5cd42973fb130878ac7b56d96e491ff0e027ec742a87
|
7
|
+
data.tar.gz: 19b1337d223b707b2ed27b692d718746f895fc7d439ee3bf296742889dcc19525ffe49b1f5a46943b2cadeb6e5d285d82bb80ca7fb9cf703d46ec6a6e01d9340
|
data/lib/flame/application.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require_relative 'router'
|
2
|
-
require_relative 'request'
|
3
2
|
require_relative 'dispatcher'
|
4
3
|
|
5
4
|
module Flame
|
@@ -25,22 +24,32 @@ module Flame
|
|
25
24
|
)
|
26
25
|
end
|
27
26
|
|
28
|
-
def
|
29
|
-
@app
|
30
|
-
|
27
|
+
def initialize(app = nil)
|
28
|
+
@app = app
|
29
|
+
router.routes.map! do |route|
|
30
|
+
route[:hooks] = router.find_hooks(route)
|
31
|
+
route.freeze
|
32
|
+
end
|
33
|
+
router.freeze
|
31
34
|
end
|
32
35
|
|
33
36
|
## Init function
|
34
37
|
def call(env)
|
38
|
+
@app.call(env) if @app.respond_to? :call
|
35
39
|
Flame::Dispatcher.new(self, env).run!
|
36
40
|
end
|
37
41
|
|
42
|
+
def self.call(env)
|
43
|
+
@app ||= new
|
44
|
+
@app.call env
|
45
|
+
end
|
46
|
+
|
38
47
|
def self.mount(ctrl, path = nil, &block)
|
39
48
|
router.add_controller(ctrl, path, block)
|
40
49
|
end
|
41
50
|
|
42
51
|
def self.helpers(*modules)
|
43
|
-
modules.empty? ? (@helpers ||= []) :
|
52
|
+
modules.empty? ? (@helpers ||= []) : helpers.concat(modules).uniq!
|
44
53
|
end
|
45
54
|
|
46
55
|
## Router for routing
|
@@ -48,6 +57,10 @@ module Flame
|
|
48
57
|
@router ||= Flame::Router.new(self)
|
49
58
|
end
|
50
59
|
|
60
|
+
def router
|
61
|
+
self.class.router
|
62
|
+
end
|
63
|
+
|
51
64
|
def self.default_config_dirs(root_dir:)
|
52
65
|
{
|
53
66
|
root_dir: File.realpath(root_dir),
|
data/lib/flame/controller.rb
CHANGED
@@ -29,7 +29,7 @@ module Flame
|
|
29
29
|
)
|
30
30
|
template.render(cache: config[:environment] == 'production')
|
31
31
|
end
|
32
|
-
|
32
|
+
alias render view
|
33
33
|
|
34
34
|
## Helpers from Flame::Dispatcher
|
35
35
|
def method_missing(m, *args, &block)
|
@@ -37,14 +37,14 @@ module Flame
|
|
37
37
|
@dispatcher.send(m, *args, &block)
|
38
38
|
end
|
39
39
|
|
40
|
-
|
40
|
+
class << self
|
41
|
+
using GorillaPatch::StringExt
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
.unshift(nil)[(last ? -1 : 0)..-1].join('/')
|
43
|
+
def default_path(last = false)
|
44
|
+
(name.split('::').last.underscore.split('_') - %w(index controller ctrl))
|
45
|
+
.join('/').split('/')
|
46
|
+
.unshift(nil)[(last ? -1 : 0)..-1].join('/')
|
47
|
+
end
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Flame
|
2
|
+
## Helper class for cookies
|
3
|
+
class Cookies
|
4
|
+
def initialize(request_cookies, response)
|
5
|
+
@request_cookies = request_cookies
|
6
|
+
@response = response
|
7
|
+
end
|
8
|
+
|
9
|
+
def [](key)
|
10
|
+
@request_cookies[key.to_s]
|
11
|
+
end
|
12
|
+
|
13
|
+
def []=(key, new_value)
|
14
|
+
return @response.delete_cookie(key.to_s, path: '/') if new_value.nil?
|
15
|
+
@response.set_cookie(key.to_s, value: new_value, path: '/')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/flame/dispatcher.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
require 'gorilla-patch/hash'
|
2
2
|
|
3
|
+
require_relative 'cookies'
|
4
|
+
require_relative 'request'
|
5
|
+
require_relative 'response'
|
6
|
+
require_relative 'static'
|
7
|
+
|
3
8
|
module Flame
|
4
9
|
## Helpers for dispatch Flame::Application#call
|
5
10
|
class Dispatcher
|
@@ -7,26 +12,28 @@ module Flame
|
|
7
12
|
|
8
13
|
using GorillaPatch::HashExt
|
9
14
|
|
15
|
+
include Flame::Dispatcher::Static
|
16
|
+
|
10
17
|
def initialize(app, env)
|
11
18
|
@app = app
|
19
|
+
@env = env
|
12
20
|
@request = Flame::Request.new(env)
|
13
|
-
@response =
|
21
|
+
@response = Flame::Response.new
|
14
22
|
end
|
15
23
|
|
16
24
|
def run!
|
17
|
-
|
25
|
+
catch :halt do
|
18
26
|
try_route ||
|
19
|
-
|
20
|
-
|
21
|
-
|
27
|
+
try_static ||
|
28
|
+
try_static(File.join(__dir__, '..', '..', 'public')) ||
|
29
|
+
try_error(404)
|
22
30
|
end
|
23
|
-
# p body
|
24
|
-
response.write body
|
25
31
|
response.finish
|
26
32
|
end
|
27
33
|
|
28
34
|
def status(value = nil)
|
29
35
|
response.status ||= 200
|
36
|
+
response.headers['X-Cascade'] = 'pass' if value == 404
|
30
37
|
value ? response.status = value : response.status
|
31
38
|
end
|
32
39
|
|
@@ -53,26 +60,37 @@ module Flame
|
|
53
60
|
path.empty? ? '/' : path
|
54
61
|
end
|
55
62
|
|
56
|
-
def halt(new_status, body = nil, new_headers = {})
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
if body.nil? &&
|
61
|
-
!Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status)
|
62
|
-
body = Rack::Utils::HTTP_STATUS_CODES[status]
|
63
|
+
def halt(new_status = nil, body = nil, new_headers = {})
|
64
|
+
case new_status
|
65
|
+
when String then body = new_status
|
66
|
+
when Integer then status new_status
|
63
67
|
end
|
64
|
-
|
68
|
+
# new_status.is_a?(String) ? () : (status new_status)
|
69
|
+
body = default_body if body.nil? && response.body.empty?
|
70
|
+
response.body = body if body
|
71
|
+
response.headers.merge!(new_headers)
|
72
|
+
throw :halt
|
65
73
|
end
|
66
74
|
|
67
75
|
private
|
68
76
|
|
77
|
+
## Generate default body of error page
|
78
|
+
def default_body
|
79
|
+
return if Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status)
|
80
|
+
"<h1>#{Rack::Utils::HTTP_STATUS_CODES[status]}</h1>"
|
81
|
+
end
|
82
|
+
|
83
|
+
## Find nearest route
|
84
|
+
def nearest_route_for_request
|
85
|
+
@app.router.find_nearest_route(request.path_parts)
|
86
|
+
end
|
87
|
+
|
69
88
|
## Find route and try execute it
|
70
89
|
def try_route
|
71
90
|
route = @app.class.router.find_route(
|
72
91
|
method: request.http_method,
|
73
92
|
path_parts: request.path_parts
|
74
93
|
)
|
75
|
-
# p route
|
76
94
|
return nil unless route
|
77
95
|
status 200
|
78
96
|
params.merge!(route.arguments(request.path_parts))
|
@@ -81,67 +99,29 @@ module Flame
|
|
81
99
|
end
|
82
100
|
|
83
101
|
def execute_route(route)
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
return nil unless File.exist?(file) && File.file?(file)
|
108
|
-
return_static(file)
|
109
|
-
end
|
110
|
-
|
111
|
-
def static_cached?(file_time)
|
112
|
-
since = request.env['HTTP_IF_MODIFIED_SINCE']
|
113
|
-
since && Time.httpdate(since).to_i >= file_time.to_i
|
114
|
-
end
|
115
|
-
|
116
|
-
def return_static(file)
|
117
|
-
file_time = File.mtime(file)
|
118
|
-
halt 304 if static_cached?(file_time)
|
119
|
-
mime_type = Rack::Mime.mime_type(File.extname(file))
|
120
|
-
response.headers.merge!(
|
121
|
-
'Content-Type' => mime_type,
|
122
|
-
'Last-Modified' => file_time.httpdate
|
123
|
-
# 'Content-Disposition' => 'attachment;' \
|
124
|
-
# "filename=\"#{File.basename(static_file)}\"",
|
125
|
-
# 'Content-Length' => File.size?(static_file).to_s
|
126
|
-
)
|
127
|
-
halt 200, File.read(file)
|
128
|
-
end
|
129
|
-
|
130
|
-
## Helper class for cookies
|
131
|
-
class Cookies
|
132
|
-
def initialize(request_cookies, response)
|
133
|
-
@request_cookies = request_cookies
|
134
|
-
@response = response
|
135
|
-
end
|
136
|
-
|
137
|
-
def [](key)
|
138
|
-
@request_cookies[key.to_s]
|
139
|
-
end
|
140
|
-
|
141
|
-
def []=(key, new_value)
|
142
|
-
return @response.delete_cookie(key.to_s, path: '/') if new_value.nil?
|
143
|
-
@response.set_cookie(key.to_s, value: new_value, path: '/')
|
144
|
-
end
|
102
|
+
exec_route = route.executable
|
103
|
+
response.body = exec_route.run!(self)
|
104
|
+
rescue => exception
|
105
|
+
dump_error(exception)
|
106
|
+
# status 500
|
107
|
+
# exec_route.execute_errors(status)
|
108
|
+
try_error(500, exec_route)
|
109
|
+
end
|
110
|
+
|
111
|
+
def try_error(error_status = nil, exec_route = nil)
|
112
|
+
exec_route = nearest_route_for_request.executable unless exec_route
|
113
|
+
status error_status if error_status
|
114
|
+
exec_route.execute_errors(status)
|
115
|
+
halt
|
116
|
+
end
|
117
|
+
|
118
|
+
def dump_error(error)
|
119
|
+
msg = [
|
120
|
+
"#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} - " \
|
121
|
+
"#{error.class} - #{error.message}:",
|
122
|
+
*error.backtrace
|
123
|
+
].join("\n\t")
|
124
|
+
@env['rack.errors'].puts(msg)
|
145
125
|
end
|
146
126
|
end
|
147
127
|
end
|
data/lib/flame/errors.rb
CHANGED
@@ -79,14 +79,14 @@ module Flame
|
|
79
79
|
end
|
80
80
|
|
81
81
|
## Error for Flame::Router.find_path
|
82
|
-
class
|
83
|
-
def initialize(
|
84
|
-
@
|
82
|
+
class UnexpectedTypeOfHookError < StandardError
|
83
|
+
def initialize(hook, route)
|
84
|
+
@hook = hook
|
85
85
|
@route = route
|
86
86
|
end
|
87
87
|
|
88
88
|
def message
|
89
|
-
"Unexpected
|
89
|
+
"Unexpected hook-block class '#{@hook.class}'" \
|
90
90
|
" in route '#{@route}'"
|
91
91
|
end
|
92
92
|
end
|
data/lib/flame/render.rb
CHANGED
@@ -16,6 +16,7 @@ module Flame
|
|
16
16
|
@locals = options.merge(options.delete(:locals) || {})
|
17
17
|
## Find filename
|
18
18
|
@filename = find_file(path)
|
19
|
+
@ctrl.instance_exec { halt 404 } unless @filename
|
19
20
|
@layout = nil if File.basename(@filename)[0] == '_'
|
20
21
|
end
|
21
22
|
|
@@ -26,7 +27,15 @@ module Flame
|
|
26
27
|
layout_render tilt.render(@scope, @locals), cache: cache
|
27
28
|
end
|
28
29
|
|
29
|
-
|
30
|
+
private
|
31
|
+
|
32
|
+
class << self
|
33
|
+
private
|
34
|
+
|
35
|
+
def tilts
|
36
|
+
@tilts ||= {}
|
37
|
+
end
|
38
|
+
end
|
30
39
|
|
31
40
|
using GorillaPatch::StringExt
|
32
41
|
|
@@ -34,19 +43,20 @@ module Flame
|
|
34
43
|
Tilt.new(filename)
|
35
44
|
end
|
36
45
|
|
37
|
-
def self.tilts
|
38
|
-
@tilts ||= {}
|
39
|
-
end
|
40
|
-
|
41
46
|
## TODO: Add `views_dir` for Application and Controller
|
42
47
|
## TODO: Add `layout` method for Controller
|
43
48
|
def find_file(path)
|
44
49
|
## Get full filename
|
50
|
+
# p Dir[File.join(
|
51
|
+
# @ctrl.config[:views_dir],
|
52
|
+
# "{#{controller_dirs.join(',')},}",
|
53
|
+
# "#{path}.*"
|
54
|
+
# )].uniq
|
45
55
|
Dir[File.join(
|
46
56
|
@ctrl.config[:views_dir],
|
47
57
|
"{#{controller_dirs.join(',')},}",
|
48
58
|
"#{path}.*"
|
49
|
-
)].find do |file|
|
59
|
+
)].uniq.find do |file|
|
50
60
|
Tilt[file]
|
51
61
|
end
|
52
62
|
end
|
@@ -68,11 +78,11 @@ module Flame
|
|
68
78
|
## Compile layout to hash
|
69
79
|
return result unless layout_file
|
70
80
|
layout =
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
81
|
+
if cache
|
82
|
+
self.class.tilts[layout_file] ||= compile(layout_file)
|
83
|
+
else
|
84
|
+
compile(layout_file)
|
85
|
+
end
|
76
86
|
return result unless layout
|
77
87
|
layout.render(@scope, @locals) { result }
|
78
88
|
end
|
data/lib/flame/route.rb
CHANGED
@@ -9,13 +9,17 @@ module Flame
|
|
9
9
|
)
|
10
10
|
end
|
11
11
|
|
12
|
-
def [](
|
13
|
-
@attributes[
|
12
|
+
def [](key)
|
13
|
+
@attributes[key]
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
16
|
+
def []=(key, value)
|
17
|
+
@attributes[key] = value
|
18
|
+
end
|
19
|
+
|
20
|
+
## Create Executable object (route)
|
21
|
+
def executable
|
22
|
+
Executable.new(self)
|
19
23
|
end
|
20
24
|
|
21
25
|
## Compare attributes for `Router.find_route`
|
@@ -46,16 +50,6 @@ module Flame
|
|
46
50
|
end
|
47
51
|
end
|
48
52
|
|
49
|
-
## Arguments in order as parameters of method of controller
|
50
|
-
def arranged_params(params)
|
51
|
-
self[:controller].instance_method(self[:action]).parameters
|
52
|
-
.each_with_object([]) do |par, arr|
|
53
|
-
arr << params[par[1]] if par[0] == :req || params[par[1]]
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
53
|
## Helpers for `compare_attributes`
|
60
54
|
def compare_attribute(name, value)
|
61
55
|
case name
|
@@ -99,5 +93,59 @@ module Flame
|
|
99
93
|
## All is ok
|
100
94
|
param
|
101
95
|
end
|
96
|
+
|
97
|
+
## Class for Route execution
|
98
|
+
class Executable
|
99
|
+
def initialize(route)
|
100
|
+
@route = route
|
101
|
+
end
|
102
|
+
|
103
|
+
## Execute route from Dispatcher
|
104
|
+
def run!(dispatcher)
|
105
|
+
@ctrl = @route[:controller].new(dispatcher)
|
106
|
+
execute_hooks(:before)
|
107
|
+
result = @ctrl.send(@route[:action], *arranged_params)
|
108
|
+
execute_hooks(:after)
|
109
|
+
result
|
110
|
+
end
|
111
|
+
|
112
|
+
def execute_errors(status = 500)
|
113
|
+
execute_hooks(:error, status)
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
## Arguments in order as parameters of method of controller
|
119
|
+
def arranged_params
|
120
|
+
# action_parameters.each_with_object([]) do |par, arr|
|
121
|
+
# arr << @ctrl.params[par[1]] if par[0] == :req || @ctrl.params[par[1]]
|
122
|
+
# end
|
123
|
+
@ctrl.params.values_at(*action_parameters.map { |par| par[1] })
|
124
|
+
end
|
125
|
+
|
126
|
+
## Method parameters of route controller#action
|
127
|
+
def action_parameters
|
128
|
+
@route[:controller].instance_method(@route[:action]).parameters
|
129
|
+
end
|
130
|
+
|
131
|
+
## Execute before, after or error hook of Symbol, String or Proc
|
132
|
+
def execute_hook(hook)
|
133
|
+
case hook
|
134
|
+
when Symbol, String
|
135
|
+
@ctrl.send(hook.to_sym)
|
136
|
+
when Proc
|
137
|
+
@ctrl.instance_exec(&hook)
|
138
|
+
else
|
139
|
+
fail UnexpectedTypeOfHookError.new(hook, @route)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
## Execute before, after or error hooks
|
144
|
+
def execute_hooks(*keys)
|
145
|
+
hooks = @route[:hooks].dig(*keys)
|
146
|
+
# p hooks
|
147
|
+
hooks.each { |hook| execute_hook(hook) } if hooks
|
148
|
+
end
|
149
|
+
end
|
102
150
|
end
|
103
151
|
end
|
data/lib/flame/router.rb
CHANGED
@@ -4,12 +4,12 @@ require_relative 'validators'
|
|
4
4
|
module Flame
|
5
5
|
## Router class for routing
|
6
6
|
class Router
|
7
|
-
attr_reader :app, :routes, :
|
7
|
+
attr_reader :app, :routes, :hooks
|
8
8
|
|
9
9
|
def initialize(app)
|
10
10
|
@app = app
|
11
11
|
@routes = []
|
12
|
-
@
|
12
|
+
@hooks = {}
|
13
13
|
end
|
14
14
|
|
15
15
|
def add_controller(ctrl, path, block = nil)
|
@@ -22,39 +22,48 @@ module Flame
|
|
22
22
|
end
|
23
23
|
|
24
24
|
## Find route by any attributes
|
25
|
-
def find_route(attrs
|
25
|
+
def find_route(attrs)
|
26
26
|
route = routes.find { |r| r.compare_attributes(attrs) }
|
27
|
-
|
28
|
-
route.merge(
|
29
|
-
befores: find_befores(route),
|
30
|
-
afters: find_afters(route)
|
31
|
-
)
|
27
|
+
route.dup if route
|
32
28
|
end
|
33
29
|
|
34
|
-
## Find
|
35
|
-
def
|
36
|
-
|
37
|
-
|
30
|
+
## Find the nearest route by path parts
|
31
|
+
def find_nearest_route(path_parts)
|
32
|
+
while path_parts.size >= 0
|
33
|
+
route = find_route(path_parts: path_parts)
|
34
|
+
break if route || path_parts.empty?
|
35
|
+
path_parts.pop
|
36
|
+
end
|
37
|
+
route
|
38
38
|
end
|
39
39
|
|
40
|
-
## Find
|
41
|
-
def
|
42
|
-
|
43
|
-
|
40
|
+
## Find hooks by Route
|
41
|
+
def find_hooks(route)
|
42
|
+
result = {}
|
43
|
+
hooks[route[:controller]].each do |type, hash|
|
44
|
+
if type == :error
|
45
|
+
result[type] = hash
|
46
|
+
else
|
47
|
+
result[type] = (hash[route[:action]] || []) | (hash[:*] || [])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
# p result
|
51
|
+
result
|
44
52
|
end
|
45
53
|
|
46
54
|
private
|
47
55
|
|
48
56
|
def concat_routes(route_refine)
|
49
57
|
routes.concat(route_refine.routes)
|
50
|
-
|
51
|
-
afters[route_refine.ctrl] = route_refine.afters
|
58
|
+
hooks[route_refine.ctrl] = route_refine.hooks
|
52
59
|
end
|
53
60
|
|
54
61
|
## Helper module for routing refine
|
55
62
|
class RouteRefine
|
56
63
|
attr_accessor :rest_routes
|
57
|
-
attr_reader :ctrl, :routes, :
|
64
|
+
attr_reader :ctrl, :routes, :hooks
|
65
|
+
|
66
|
+
HOOK_TYPES = [:before, :after, :error].freeze
|
58
67
|
|
59
68
|
def self.http_methods
|
60
69
|
[:GET, :POST, :PUT, :DELETE]
|
@@ -75,7 +84,7 @@ module Flame
|
|
75
84
|
@ctrl = ctrl
|
76
85
|
@path = path || @ctrl.default_path
|
77
86
|
@routes = []
|
78
|
-
@
|
87
|
+
@hooks = HOOK_TYPES.each_with_object({}) { |type, hash| hash[type] = {} }
|
79
88
|
execute(&block)
|
80
89
|
end
|
81
90
|
|
@@ -90,14 +99,12 @@ module Flame
|
|
90
99
|
end
|
91
100
|
end
|
92
101
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
actions = [actions] unless actions.is_a?(Array)
|
100
|
-
actions.each { |a| (@afters[a] ||= []).push(action || block) }
|
102
|
+
HOOK_TYPES.each do |type|
|
103
|
+
default_actions = (type == :error ? 500 : :*)
|
104
|
+
define_method(type) do |actions = default_actions, action = nil, &block|
|
105
|
+
actions = [actions] unless actions.is_a?(Array)
|
106
|
+
actions.each { |a| (@hooks[type][a] ||= []).push(action || block) }
|
107
|
+
end
|
101
108
|
end
|
102
109
|
|
103
110
|
def defaults
|
@@ -141,10 +148,9 @@ module Flame
|
|
141
148
|
## TODO: Add :arg:type support (:id:num, :name:str, etc.)
|
142
149
|
unshifted = force_params ? path : action_path(action)
|
143
150
|
if path.nil? || force_params
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
.join('/')
|
151
|
+
parameters = @ctrl.instance_method(action).parameters
|
152
|
+
parameters.map! { |par| ":#{par[0] == :req ? '' : '?'}#{par[1]}" }
|
153
|
+
path = parameters.unshift(unshifted).join('/')
|
148
154
|
end
|
149
155
|
path_merge(@path, path)
|
150
156
|
end
|
data/lib/flame/static.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Flame
|
2
|
+
class Dispatcher
|
3
|
+
## Module for working with static files
|
4
|
+
module Static
|
5
|
+
## Find static files and try return it
|
6
|
+
def try_static(dir = config[:public_dir])
|
7
|
+
file = File.join(dir, request.path_info)
|
8
|
+
return nil unless File.exist?(file) && File.file?(file)
|
9
|
+
return_static(file)
|
10
|
+
end
|
11
|
+
|
12
|
+
def static_cached?(file_time)
|
13
|
+
since = request.env['HTTP_IF_MODIFIED_SINCE']
|
14
|
+
since && Time.httpdate(since).to_i >= file_time.to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
def return_static(file)
|
18
|
+
file_time = File.mtime(file)
|
19
|
+
halt 304 if static_cached?(file_time)
|
20
|
+
mime_type = Rack::Mime.mime_type(File.extname(file))
|
21
|
+
response.headers.merge!(
|
22
|
+
'Content-Type' => mime_type,
|
23
|
+
'Last-Modified' => file_time.httpdate
|
24
|
+
# 'Content-Disposition' => 'attachment;' \
|
25
|
+
# "filename=\"#{File.basename(static_file)}\"",
|
26
|
+
# 'Content-Length' => File.size?(static_file).to_s
|
27
|
+
)
|
28
|
+
halt 200, File.read(file)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/flame/validators.rb
CHANGED
@@ -58,28 +58,42 @@ module Flame
|
|
58
58
|
## Compare actions from routes and from controller
|
59
59
|
class ActionsValidator
|
60
60
|
def initialize(route_refine)
|
61
|
-
@
|
61
|
+
@routes_actions = route_refine.routes.map { |route| route[:action] }
|
62
|
+
@hooks_actions = route_refine.hooks.values.map(&:values).flatten
|
63
|
+
@hooks_actions.select! { |action| action.is_a? Symbol }
|
62
64
|
@ctrl = route_refine.ctrl
|
65
|
+
@ctrl_actions = {
|
66
|
+
public: @ctrl.public_instance_methods(false),
|
67
|
+
all: @ctrl.instance_methods + @ctrl.private_instance_methods
|
68
|
+
}
|
63
69
|
end
|
64
70
|
|
65
71
|
def valid?
|
66
|
-
|
67
|
-
|
68
|
-
|
72
|
+
no_extra_routes_actions? &&
|
73
|
+
no_extra_hooks_actions? &&
|
74
|
+
no_extra_controller_actions?
|
69
75
|
end
|
70
76
|
|
71
77
|
private
|
72
78
|
|
73
79
|
def no_extra_routes_actions?
|
74
|
-
extra_routes_actions = @routes_actions - @ctrl_actions
|
80
|
+
extra_routes_actions = @routes_actions - @ctrl_actions[:public]
|
75
81
|
return true if extra_routes_actions.empty?
|
76
82
|
fail RouterError::ExtraRoutesActionsError.new(
|
77
83
|
@ctrl, extra_routes_actions
|
78
84
|
)
|
79
85
|
end
|
80
86
|
|
87
|
+
def no_extra_hooks_actions?
|
88
|
+
extra_hooks_actions = @hooks_actions - @ctrl_actions[:all]
|
89
|
+
return true if extra_hooks_actions.empty?
|
90
|
+
fail RouterError::ExtraRoutesActionsError.new(
|
91
|
+
@ctrl, extra_hooks_actions
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
81
95
|
def no_extra_controller_actions?
|
82
|
-
extra_ctrl_actions = @ctrl_actions - @routes_actions
|
96
|
+
extra_ctrl_actions = @ctrl_actions[:public] - @routes_actions
|
83
97
|
return true if extra_ctrl_actions.empty?
|
84
98
|
fail RouterError::ExtraControllerActionsError.new(
|
85
99
|
@ctrl, extra_ctrl_actions
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flame
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Popov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -75,12 +75,15 @@ files:
|
|
75
75
|
- lib/flame.rb
|
76
76
|
- lib/flame/application.rb
|
77
77
|
- lib/flame/controller.rb
|
78
|
+
- lib/flame/cookies.rb
|
78
79
|
- lib/flame/dispatcher.rb
|
79
80
|
- lib/flame/errors.rb
|
80
81
|
- lib/flame/render.rb
|
81
82
|
- lib/flame/request.rb
|
83
|
+
- lib/flame/response.rb
|
82
84
|
- lib/flame/route.rb
|
83
85
|
- lib/flame/router.rb
|
86
|
+
- lib/flame/static.rb
|
84
87
|
- lib/flame/validators.rb
|
85
88
|
- public/favicon.ico
|
86
89
|
homepage: https://gitlab.com/AlexWayfer/flame
|