nekonote-framework 1.0.0.pre.beta
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 +7 -0
- data/LICENSE +22 -0
- data/README.md +49 -0
- data/bin/nekonote +45 -0
- data/data/structure/Gemfile +25 -0
- data/data/structure/config.ru +14 -0
- data/data/structure/handler/base.rb +21 -0
- data/data/structure/handler/error.rb +35 -0
- data/data/structure/handler/welcome.rb +11 -0
- data/data/structure/lib/.gitkeep +0 -0
- data/data/structure/preference/development/logger.yml +62 -0
- data/data/structure/preference/development/middlewares.rb +152 -0
- data/data/structure/preference/development/public.yml +29 -0
- data/data/structure/preference/development/route.yml +30 -0
- data/data/structure/preference/development/route_error.yml +28 -0
- data/data/structure/preference/development/route_include.yml +22 -0
- data/data/structure/preference/development/server/puma.rb +63 -0
- data/data/structure/preference/development/setting/example.yml +40 -0
- data/data/structure/preference/development/setting/site.yml +3 -0
- data/data/structure/preference/development/setting/welcome.yml +7 -0
- data/data/structure/public/css/layout/common.css +11 -0
- data/data/structure/public/css/layout/default.css +3 -0
- data/data/structure/public/css/layout/error.css +3 -0
- data/data/structure/public/css/welcome.css +47 -0
- data/data/structure/public/favicon.ico +0 -0
- data/data/structure/public/img/.gitkeep +0 -0
- data/data/structure/public/img/logo.png +0 -0
- data/data/structure/public/js/.gitkeep +0 -0
- data/data/structure/static/layout/default.tpl +19 -0
- data/data/structure/static/layout/error.tpl +15 -0
- data/data/structure/static/sass/welcome.scss +52 -0
- data/data/structure/static/template/error.tpl +4 -0
- data/data/structure/static/template/welcome/index.tpl +26 -0
- data/data/structure/tmp/pids/.gitkeep +0 -0
- data/lib/loader.rb +83 -0
- data/lib/nekonote.rb +9 -0
- data/lib/nekonote/cli.rb +702 -0
- data/lib/nekonote/cmd_parser.rb +55 -0
- data/lib/nekonote/core.rb +116 -0
- data/lib/nekonote/env.rb +56 -0
- data/lib/nekonote/exception/cli_error.rb +34 -0
- data/lib/nekonote/exception/error.rb +75 -0
- data/lib/nekonote/exception/handler_error.rb +5 -0
- data/lib/nekonote/exception/logger_error.rb +8 -0
- data/lib/nekonote/exception/page_cache_error.rb +6 -0
- data/lib/nekonote/exception/preference_error.rb +11 -0
- data/lib/nekonote/exception/view_error.rb +7 -0
- data/lib/nekonote/handler.rb +274 -0
- data/lib/nekonote/handler/protected_methods.rb +119 -0
- data/lib/nekonote/liquid/tag_env_get.rb +12 -0
- data/lib/nekonote/liquid/tag_setting_get.rb +12 -0
- data/lib/nekonote/logger.rb +135 -0
- data/lib/nekonote/page_cache.rb +111 -0
- data/lib/nekonote/preference.rb +215 -0
- data/lib/nekonote/puma.rb +131 -0
- data/lib/nekonote/rack/rack_static.rb +17 -0
- data/lib/nekonote/rack/rack_static_file.rb +19 -0
- data/lib/nekonote/rack/url_mapper.rb +193 -0
- data/lib/nekonote/rackup.rb +319 -0
- data/lib/nekonote/request.rb +295 -0
- data/lib/nekonote/setting.rb +59 -0
- data/lib/nekonote/spec.rb +22 -0
- data/lib/nekonote/util/filer.rb +69 -0
- data/lib/nekonote/util/process.rb +43 -0
- data/lib/nekonote/view.rb +398 -0
- data/lib/nekonote/yaml_access.rb +60 -0
- metadata +144 -0
@@ -0,0 +1,131 @@
|
|
1
|
+
module Nekonote
|
2
|
+
class Puma
|
3
|
+
# @param string app_root
|
4
|
+
# @param string env
|
5
|
+
def initialize(app_root, env)
|
6
|
+
@app_root = app_root
|
7
|
+
@env = env
|
8
|
+
end
|
9
|
+
|
10
|
+
# @return string
|
11
|
+
public
|
12
|
+
def get_config_path
|
13
|
+
return get_puma_config_file_path
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param cmd symbol
|
17
|
+
public
|
18
|
+
def ctl_server(cmd)
|
19
|
+
# set pumactl command corresponded with nekonote sub command
|
20
|
+
case cmd
|
21
|
+
when :start
|
22
|
+
puma_cmd = 'start'
|
23
|
+
|
24
|
+
when :status
|
25
|
+
puma_cmd = 'status'
|
26
|
+
|
27
|
+
when :stop
|
28
|
+
puma_cmd = 'stop'
|
29
|
+
|
30
|
+
when :halt
|
31
|
+
puma_cmd = 'halt'
|
32
|
+
|
33
|
+
when :restart
|
34
|
+
puma_cmd = 'restart'
|
35
|
+
|
36
|
+
when :phased_restart
|
37
|
+
puma_cmd = 'phased-restart'
|
38
|
+
end
|
39
|
+
|
40
|
+
# make object
|
41
|
+
argv = ['-F', get_puma_config_file_path, puma_cmd]
|
42
|
+
stdout_buffer = $stdout.clone
|
43
|
+
stderr_buffer = $stderr.clone
|
44
|
+
|
45
|
+
begin
|
46
|
+
if cmd == :start
|
47
|
+
change_exec_file_to_puma_bin # if did't change $0 to puma/bin/puma, restart will be failed
|
48
|
+
end
|
49
|
+
cli = ::Puma::ControlCLI.new argv, STDOUT, STDERR
|
50
|
+
|
51
|
+
# get pid if it exists
|
52
|
+
def cli.get_pid_file_path
|
53
|
+
return @pidfile
|
54
|
+
end
|
55
|
+
pid = Util::Process.get_server_pid cli.get_pid_file_path
|
56
|
+
|
57
|
+
# exit if there's no need to run Puma::ControlCLI
|
58
|
+
nothing_to_do = false
|
59
|
+
case cmd
|
60
|
+
when :start
|
61
|
+
if pid != nil
|
62
|
+
puts %(Already started with pid #{pid})
|
63
|
+
nothing_to_do = true
|
64
|
+
end
|
65
|
+
|
66
|
+
when :status
|
67
|
+
if pid == nil
|
68
|
+
puts %(Server is stopped)
|
69
|
+
else
|
70
|
+
puts %(Server is running with pid #{pid})
|
71
|
+
end
|
72
|
+
nothing_to_do = true
|
73
|
+
|
74
|
+
when :stop, :halt
|
75
|
+
if pid == nil
|
76
|
+
puts %(Already stopped)
|
77
|
+
nothing_to_do = true
|
78
|
+
end
|
79
|
+
|
80
|
+
when :restart, :phased_restart
|
81
|
+
if pid == nil
|
82
|
+
# it have not started!
|
83
|
+
ctl_server :start
|
84
|
+
nothing_to_do = true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# exit if no need to continue task
|
89
|
+
if nothing_to_do
|
90
|
+
$stdout = stdout_buffer
|
91
|
+
$stderr = stderr_buffer
|
92
|
+
exit 0
|
93
|
+
end
|
94
|
+
|
95
|
+
# send signal
|
96
|
+
# when requested 'start' it will exit here
|
97
|
+
cli.run
|
98
|
+
|
99
|
+
ensure
|
100
|
+
# it won't called if script exited
|
101
|
+
$stdout = stdout_buffer
|
102
|
+
$stderr = stderr_buffer
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
def change_exec_file_to_puma_bin
|
108
|
+
puma_bin_path = "#{::Bundler.bundle_path.to_s}/gems/puma-#{::Puma::Const::VERSION}/bin/puma"
|
109
|
+
|
110
|
+
# is it readable?
|
111
|
+
if !Util::Filer.available_file? puma_bin_path
|
112
|
+
raise PreferenceError, Error::MSG_MISSING_FILE% puma_bin_path
|
113
|
+
end
|
114
|
+
|
115
|
+
$0 = puma_bin_path
|
116
|
+
end
|
117
|
+
|
118
|
+
# @return string
|
119
|
+
private
|
120
|
+
def get_puma_config_file_path
|
121
|
+
file_path = "#{@app_root}/preference/#{@env}/server/puma.rb"
|
122
|
+
|
123
|
+
# is it readable?
|
124
|
+
if !Util::Filer.available_file? file_path
|
125
|
+
raise PreferenceError, Error::MSG_MISSING_FILE% file_path
|
126
|
+
end
|
127
|
+
|
128
|
+
return file_path
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Nekonote
|
2
|
+
class RackStatic < ::Rack::Static
|
3
|
+
def initialize(app, options={})
|
4
|
+
if options[:root] == nil
|
5
|
+
raise Error, self.class.to_s + ' require key :root'
|
6
|
+
end
|
7
|
+
|
8
|
+
super
|
9
|
+
|
10
|
+
# Overwrite property for using Nekonote::RackStaticFile instead of Rack::File.
|
11
|
+
# This for handling the error case that file requested was not found.
|
12
|
+
@file_server = RackStaticFile.new options[:root]
|
13
|
+
|
14
|
+
# @file_server = Rack::File.new(root)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Nekonote
|
2
|
+
class RackStaticFile < ::Rack::File
|
3
|
+
def fail(status, body, headers = {})
|
4
|
+
if Preference.instance.has_error_route? Preference::FIELD_ROUTE_ERR_NOT_FOUND
|
5
|
+
begin
|
6
|
+
# display custom error response
|
7
|
+
return ::Nekonote::Handler.call_error_handler Preference::FIELD_ROUTE_ERR_NOT_FOUND, Env.get_all
|
8
|
+
rescue => e
|
9
|
+
Error.logging_error e
|
10
|
+
# error, default behavior
|
11
|
+
super
|
12
|
+
end
|
13
|
+
else
|
14
|
+
# no error route, default behavior
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
# This class is forked from rack/urlmap.rb
|
2
|
+
# Constant values in core source must be prefixed namespace.
|
3
|
+
# Allows using 2-space indentation in this class because of Rack using 2-space indentation
|
4
|
+
module Nekonote
|
5
|
+
class URLMapper < ::Rack::URLMap
|
6
|
+
# =========================================================================
|
7
|
+
# Start adding source code for Nekonote Framework
|
8
|
+
# =========================================================================
|
9
|
+
# @param string pattern
|
10
|
+
# @returns hash, string
|
11
|
+
def parse_url_path_params(pattern)
|
12
|
+
url_path_params_mapper = {}
|
13
|
+
# change variables in path to wild card
|
14
|
+
if /:.+/ =~ pattern
|
15
|
+
pattern.split('/').each_with_index do |inspection, index|
|
16
|
+
inspection.scan(/(?<=:).+/).each do |v|
|
17
|
+
url_path_params_mapper[v] = index
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# replace variable with wildcard
|
22
|
+
url_path_params_mapper.each_key do |name|
|
23
|
+
pattern.sub! (':' + name), '.+'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
return url_path_params_mapper, pattern
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param string pattern
|
31
|
+
# @returns regexp, hash, string
|
32
|
+
def get_route_regexp(pattern)
|
33
|
+
# if home page
|
34
|
+
pattern = '/' if pattern == ''
|
35
|
+
|
36
|
+
# escape special meaning characters in regexp
|
37
|
+
pattern = Regexp.quote pattern
|
38
|
+
|
39
|
+
# parse path for url path parameters
|
40
|
+
url_path_params_mapper, pattern = parse_url_path_params pattern
|
41
|
+
|
42
|
+
pattern = %(^#{pattern}$)
|
43
|
+
|
44
|
+
# If duplocate slashes are allowed change regexp a little bit for it
|
45
|
+
if Preference.instance.is_allow_dup_slash?
|
46
|
+
pattern.gsub! '/', '/+'
|
47
|
+
end
|
48
|
+
|
49
|
+
match = Regexp.new pattern, nil, 'n'
|
50
|
+
|
51
|
+
return match, url_path_params_mapper, pattern
|
52
|
+
end
|
53
|
+
|
54
|
+
# @param string pattern
|
55
|
+
# @returns regexp, hash, string
|
56
|
+
def get_route_regexp_custom(pattern)
|
57
|
+
option = nil
|
58
|
+
code = nil
|
59
|
+
|
60
|
+
# parse path for url path parameters
|
61
|
+
url_path_params_mapper, pattern = parse_url_path_params pattern
|
62
|
+
|
63
|
+
if pattern == ''
|
64
|
+
# home page
|
65
|
+
pattern = '/$'
|
66
|
+
|
67
|
+
elsif /\/[ixmn]+$/ =~ pattern
|
68
|
+
# there is regexp option
|
69
|
+
matched_str = $&.delete '/'
|
70
|
+
pattern = pattern.sub /\/[ixmn]+$/, ''
|
71
|
+
option = 0
|
72
|
+
matched_str.each_char do |char|
|
73
|
+
case char
|
74
|
+
when 'i'
|
75
|
+
option = option | Regexp::IGNORECASE
|
76
|
+
when 'm'
|
77
|
+
option = option | Regexp::MULTILINE
|
78
|
+
when 'x'
|
79
|
+
option = option | Regexp::EXTENDED
|
80
|
+
when 'n'
|
81
|
+
code = 'n'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
pattern = '^' + pattern
|
87
|
+
|
88
|
+
# If duplocate slashes are allowed change regexp a little bit for it
|
89
|
+
if Preference.instance.is_allow_dup_slash?
|
90
|
+
pattern.gsub! '/', '/+'
|
91
|
+
end
|
92
|
+
|
93
|
+
match = Regexp.new pattern, option, code
|
94
|
+
|
95
|
+
return match, url_path_params_mapper, pattern
|
96
|
+
end
|
97
|
+
# =========================================================================
|
98
|
+
# End adding source code
|
99
|
+
# =========================================================================
|
100
|
+
|
101
|
+
def remap(map)
|
102
|
+
@mapping = map.map { |location, app|
|
103
|
+
if location =~ %r{\Ahttps?://(.*?)(/.*)}
|
104
|
+
host, location = $1, $2
|
105
|
+
else
|
106
|
+
host = nil
|
107
|
+
end
|
108
|
+
|
109
|
+
unless location[0] == ?/
|
110
|
+
raise ArgumentError, "paths need to start with /"
|
111
|
+
end
|
112
|
+
|
113
|
+
location = location.chomp('/')
|
114
|
+
#match = Regexp.new("^#{Regexp.quote(location).gsub('/', '/+')}(.*)", nil, 'n') # comment out of original source
|
115
|
+
# =========================================================================
|
116
|
+
# Start adding source code for Nekonote Framework
|
117
|
+
# =========================================================================
|
118
|
+
# get regexp for matching URL
|
119
|
+
if Preference.instance.is_path_regexp?
|
120
|
+
match, url_path_params_mapper, location = get_route_regexp_custom location # path will be evaluated as regexp
|
121
|
+
else
|
122
|
+
match, url_path_params_mapper, location = get_route_regexp location
|
123
|
+
end
|
124
|
+
|
125
|
+
# set the values to Nekonote::Handler class
|
126
|
+
app.route_regexp = match
|
127
|
+
app.url_path_params_mapper = url_path_params_mapper
|
128
|
+
# =========================================================================
|
129
|
+
# End adding source code
|
130
|
+
# =========================================================================
|
131
|
+
|
132
|
+
[host, location, match, app]
|
133
|
+
}.sort_by do |(host, location, _, _)|
|
134
|
+
[host ? -host.size : ::Rack::URLMap::INFINITY, -location.size]
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def call(env)
|
139
|
+
path = env[::Rack::PATH_INFO]
|
140
|
+
script_name = env[::Rack::SCRIPT_NAME]
|
141
|
+
http_host = env[::Rack::HTTP_HOST]
|
142
|
+
server_name = env[::Rack::SERVER_NAME]
|
143
|
+
server_port = env[::Rack::SERVER_PORT]
|
144
|
+
|
145
|
+
is_same_server = casecmp?(http_host, server_name) ||
|
146
|
+
casecmp?(http_host, "#{server_name}:#{server_port}")
|
147
|
+
|
148
|
+
@mapping.each do |host, location, match, app|
|
149
|
+
unless casecmp?(http_host, host) \
|
150
|
+
|| casecmp?(server_name, host) \
|
151
|
+
|| (!host && is_same_server)
|
152
|
+
next
|
153
|
+
end
|
154
|
+
|
155
|
+
next unless m = match.match(path.to_s)
|
156
|
+
|
157
|
+
rest = m[1]
|
158
|
+
next unless !rest || rest.empty? || rest[0] == ?/
|
159
|
+
env[::Rack::SCRIPT_NAME] = (script_name + location)
|
160
|
+
env[::Rack::PATH_INFO] = rest
|
161
|
+
|
162
|
+
return app.call(env)
|
163
|
+
end
|
164
|
+
|
165
|
+
# [404, {::Rack::CONTENT_TYPE => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path}"]] comment out of original source
|
166
|
+
# =========================================================================
|
167
|
+
# Start adding source code for Nekonote Framework
|
168
|
+
# =========================================================================
|
169
|
+
if Preference.instance.has_error_route? Preference::FIELD_ROUTE_ERR_MISSING_ROUTE
|
170
|
+
# "missing_route" route has been defined
|
171
|
+
begin
|
172
|
+
# display custom error response
|
173
|
+
return ::Nekonote::Handler.call_error_handler Preference::FIELD_ROUTE_ERR_MISSING_ROUTE, env
|
174
|
+
rescue => e
|
175
|
+
Error.logging_error e
|
176
|
+
# error, default behavior
|
177
|
+
[404, {::Rack::CONTENT_TYPE => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path}"]]
|
178
|
+
end
|
179
|
+
|
180
|
+
else
|
181
|
+
# no error route, default behavior
|
182
|
+
[404, {::Rack::CONTENT_TYPE => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path}"]]
|
183
|
+
end
|
184
|
+
# =========================================================================
|
185
|
+
# End adding source code for Nekonote Framework
|
186
|
+
# =========================================================================
|
187
|
+
|
188
|
+
ensure
|
189
|
+
env[::Rack::PATH_INFO] = path
|
190
|
+
env[::Rack::SCRIPT_NAME] = script_name
|
191
|
+
end
|
192
|
+
end # class URLMapper
|
193
|
+
end # module Nekonote
|
@@ -0,0 +1,319 @@
|
|
1
|
+
module Nekonote
|
2
|
+
class Rackup
|
3
|
+
include Singleton
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
begin
|
7
|
+
# initialize Logger
|
8
|
+
Nekonote.init_logger
|
9
|
+
|
10
|
+
# initialize Setting
|
11
|
+
Setting.init
|
12
|
+
rescue => e
|
13
|
+
Error.abort e
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param mixed info
|
18
|
+
# @return hash
|
19
|
+
def self.get_header_rules_field(info)
|
20
|
+
headers = {}
|
21
|
+
if info.is_a? Hash
|
22
|
+
# just one header
|
23
|
+
headers = {info['name'] => info['value']}
|
24
|
+
|
25
|
+
elsif info.is_a? Array
|
26
|
+
# plural headers
|
27
|
+
headers = {}
|
28
|
+
info.each do |pair|
|
29
|
+
headers[pair['name']] = pair['value']
|
30
|
+
end
|
31
|
+
end
|
32
|
+
return headers
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param mixed info
|
36
|
+
# @param proc get_rule
|
37
|
+
# @return hash
|
38
|
+
def self.get_header_rules_field_having_target(info, get_rule)
|
39
|
+
rules = []
|
40
|
+
if info.is_a?(Array)
|
41
|
+
# multiple
|
42
|
+
stack = []
|
43
|
+
info.each do |each_ext|
|
44
|
+
rule = get_rule.call each_ext
|
45
|
+
stack << rule if rule != nil
|
46
|
+
end
|
47
|
+
stack.each do |rule|
|
48
|
+
rules << rule
|
49
|
+
end
|
50
|
+
else
|
51
|
+
rule = get_rule.call info
|
52
|
+
rules << rule if rule != nil
|
53
|
+
end
|
54
|
+
return rules
|
55
|
+
end
|
56
|
+
|
57
|
+
# make data for header rules option
|
58
|
+
# @param hash info
|
59
|
+
# @return array
|
60
|
+
def self.get_header_rules(info)
|
61
|
+
rules = []
|
62
|
+
|
63
|
+
# for :all
|
64
|
+
headers = get_header_rules_field info['all']
|
65
|
+
rules << [:all, headers] if headers.size > 0
|
66
|
+
|
67
|
+
# for :directory
|
68
|
+
if info['directory'] != nil
|
69
|
+
get_rule = lambda do |data|
|
70
|
+
rule = nil
|
71
|
+
if data.is_a?(Hash) && data.has_key?('target')
|
72
|
+
dir = data.delete 'target'
|
73
|
+
dir = "/#{dir}" if !dir.start_with? '/'
|
74
|
+
headers = get_header_rules_field data
|
75
|
+
rule = [dir, headers] if headers.size > 0
|
76
|
+
end
|
77
|
+
return rule
|
78
|
+
end
|
79
|
+
rules_for_dir = get_header_rules_field_having_target info['directory'], get_rule
|
80
|
+
rules_for_dir.each do |rule|
|
81
|
+
rules << rule
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# for :extension
|
86
|
+
if info['extension'] != nil
|
87
|
+
get_rule = lambda do |data|
|
88
|
+
rule = nil
|
89
|
+
if data.is_a?(Hash) && data.has_key?('target')
|
90
|
+
target = data.delete 'target'
|
91
|
+
ext = target.split(',')
|
92
|
+
ext.map! do |v| v.strip end
|
93
|
+
headers = get_header_rules_field data
|
94
|
+
rule = [ext, headers] if headers.size > 0
|
95
|
+
end
|
96
|
+
return rule
|
97
|
+
end
|
98
|
+
rules_for_dir = get_header_rules_field_having_target info['extension'], get_rule
|
99
|
+
rules_for_dir.each do |rule|
|
100
|
+
rules << rule
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# for :regexp
|
105
|
+
if info['regexp'] != nil
|
106
|
+
get_rule = lambda do |data|
|
107
|
+
rule = nil
|
108
|
+
if data.is_a?(Hash) && data.has_key?('target')
|
109
|
+
target = data.delete 'target'
|
110
|
+
if data['ignore_case'] == true
|
111
|
+
regexp = Regexp.new target, Regexp::IGNORECASE
|
112
|
+
else
|
113
|
+
regexp = Regexp.new target
|
114
|
+
end
|
115
|
+
headers = get_header_rules_field data
|
116
|
+
rule = [regexp, headers] if headers.size > 0
|
117
|
+
end
|
118
|
+
return rule
|
119
|
+
end
|
120
|
+
rules_for_dir = get_header_rules_field_having_target info['regexp'], get_rule
|
121
|
+
rules_for_dir.each do |rule|
|
122
|
+
rules << rule
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# for :fonts
|
127
|
+
headers = get_header_rules_field info['fonts']
|
128
|
+
rules << [:fonts, headers] if headers.size > 0
|
129
|
+
|
130
|
+
return rules
|
131
|
+
end
|
132
|
+
|
133
|
+
# @return proc
|
134
|
+
public
|
135
|
+
def use_middlewares
|
136
|
+
return Proc.new do
|
137
|
+
# overwrite the core method of lib/rack/builder.rb
|
138
|
+
def self.use(middleware, *args, &block)
|
139
|
+
@nekonote_middlewares = [] if !defined? @nekonote_middlewares
|
140
|
+
@nekonote_middlewares << middleware.to_s
|
141
|
+
super
|
142
|
+
end
|
143
|
+
|
144
|
+
# add the individual method
|
145
|
+
def self.get_nekonote_middlewares
|
146
|
+
return @nekonote_middlewares
|
147
|
+
end
|
148
|
+
|
149
|
+
# evaluate middlewares.rb as Ruby codes
|
150
|
+
path = Preference.instance.path_middlewares_rb
|
151
|
+
begin
|
152
|
+
instance_eval IO.read path
|
153
|
+
rescue => e
|
154
|
+
warn <<EOS
|
155
|
+
#{PreferenceError::MSG_EVAL_MIDDLEWARES% path}
|
156
|
+
|
157
|
+
#{e.class}:
|
158
|
+
#{e.message}
|
159
|
+
|
160
|
+
#{e.backtrace.join($/)}
|
161
|
+
EOS
|
162
|
+
exit 1
|
163
|
+
end
|
164
|
+
|
165
|
+
# display middleware list
|
166
|
+
is_enabled_show_exceptions = false
|
167
|
+
get_nekonote_middlewares.each do |middleware_name|
|
168
|
+
if middleware_name == 'Rack::ShowExceptions'
|
169
|
+
is_enabled_show_exceptions = true
|
170
|
+
end
|
171
|
+
puts " + Use -> #{middleware_name}"
|
172
|
+
end
|
173
|
+
|
174
|
+
Preference.instance.is_enabled_show_exceptions = is_enabled_show_exceptions
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# publishing for static files
|
179
|
+
public
|
180
|
+
def define_public_dir
|
181
|
+
return Proc.new do |pref_public|
|
182
|
+
# expected Hash only
|
183
|
+
pref_public = {} if !pref_public.is_a? Hash
|
184
|
+
|
185
|
+
options = {
|
186
|
+
:root => Nekonote.get_root_path + 'public'
|
187
|
+
}
|
188
|
+
|
189
|
+
# publish specific files only
|
190
|
+
# define published directories under 'public'
|
191
|
+
pub_dirs = []
|
192
|
+
if pref_public['published_directory'].is_a? Array
|
193
|
+
pub_dirs = pref_public['published_directory']
|
194
|
+
pub_dirs.map! do |val|
|
195
|
+
if val.start_with? '/'
|
196
|
+
val
|
197
|
+
else
|
198
|
+
'/' + val
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
if pub_dirs.count > 0
|
203
|
+
options[:urls] = pub_dirs
|
204
|
+
end
|
205
|
+
|
206
|
+
# define published files under 'public'
|
207
|
+
pub_files = []
|
208
|
+
if pref_public['published_file'].is_a? Array
|
209
|
+
pub_files = pref_public['published_file']
|
210
|
+
pub_files.map! do |val|
|
211
|
+
if val.start_with? '/'
|
212
|
+
val
|
213
|
+
else
|
214
|
+
'/' + val
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
if pub_files.count > 0
|
219
|
+
if options[:urls].is_a? Array
|
220
|
+
options[:urls] = options[:urls] + pub_files
|
221
|
+
else
|
222
|
+
options[:urls] = pub_files
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
# add custom headers
|
227
|
+
if pref_public['custom_header'].is_a? Hash
|
228
|
+
rules = ::Nekonote::Rackup.get_header_rules pref_public['custom_header']
|
229
|
+
if rules.size > 0
|
230
|
+
options[:header_rules] = rules
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# register published static files
|
235
|
+
use RackStatic, options
|
236
|
+
end # end proc
|
237
|
+
end
|
238
|
+
|
239
|
+
# @return proc
|
240
|
+
public
|
241
|
+
def define_route
|
242
|
+
return Proc.new do |pref_route|
|
243
|
+
# load the common handler
|
244
|
+
Nekonote.load_base_handler
|
245
|
+
|
246
|
+
# load files under 'handler' direcotry
|
247
|
+
Dir[File.expand_path('handler', Nekonote.get_root_path) + '/**/*.rb'].each do |file|
|
248
|
+
require file # TODO need auto loading
|
249
|
+
end
|
250
|
+
|
251
|
+
# get preferences for include
|
252
|
+
pref_common = Preference.instance.get_route_include
|
253
|
+
|
254
|
+
# define the routes
|
255
|
+
routes = {} # instance list of app
|
256
|
+
paths = [] # for duplicate check
|
257
|
+
pref_route.each do |info|
|
258
|
+
# if include directive has been set, convert it to the directives and missing directives will be filled
|
259
|
+
if info[Preference::FIELD_ROUTE_INCLUDE].is_a? String
|
260
|
+
# include directive has been set in the route
|
261
|
+
if pref_common[info[Preference::FIELD_ROUTE_INCLUDE]].is_a? Hash
|
262
|
+
pref_common[info[Preference::FIELD_ROUTE_INCLUDE]].each_pair do |k, v|
|
263
|
+
if info[k] == nil
|
264
|
+
info[k] = v
|
265
|
+
else
|
266
|
+
# directive name is duplicate between route.yml and route_include.yml
|
267
|
+
# values in route.yml takes precedence over values in route_include.yml that without method or params
|
268
|
+
info[k] += ',' + v if k == Preference::FIELD_ROUTE_PARAMS || k == Preference::FIELD_ROUTE_ALLOW_METHODS
|
269
|
+
end
|
270
|
+
end
|
271
|
+
info.delete Preference::FIELD_ROUTE_INCLUDE
|
272
|
+
else
|
273
|
+
# no such field in route_include.yml
|
274
|
+
raise PreferenceError, PreferenceError::MSG_MISSING_INCLUDE% [info[Preference::FIELD_ROUTE_INCLUDE], Preference.instance.path_route_include_yml]
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# difined path field?
|
279
|
+
path = info[Preference::FIELD_ROUTE_PATH]
|
280
|
+
if !path.is_a? String
|
281
|
+
raise PreferenceError, PreferenceError::MSG_MISSING_FIELD% [Preference::FIELD_ROUTE_PATH, Preference.instance.path_route_yml]
|
282
|
+
end
|
283
|
+
|
284
|
+
# having handler?
|
285
|
+
handler = info[Preference::FIELD_ROUTE_HANDLER]
|
286
|
+
if !handler.is_a? String
|
287
|
+
raise PreferenceError, PreferenceError::MSG_INVALID_HANDLER_NAME% "#{handler}"
|
288
|
+
end
|
289
|
+
|
290
|
+
# validation for the field 'page_cache_time'
|
291
|
+
if info[Preference::FIELD_ROUTE_PAGE_CACHE_TIME] != nil
|
292
|
+
page_cache_time = info[Preference::FIELD_ROUTE_PAGE_CACHE_TIME].to_i
|
293
|
+
if page_cache_time > 0
|
294
|
+
info[Preference::FIELD_ROUTE_PAGE_CACHE_TIME] = page_cache_time
|
295
|
+
else
|
296
|
+
raise Error, Error::MSG_INVALID_FIELD% [Preference::FIELD_ROUTE_PAGE_CACHE_TIME, Preference.instance.path_route_yml]
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
# set app
|
301
|
+
begin
|
302
|
+
routes[info[Preference::FIELD_ROUTE_PATH].strip] = Object.const_get(handler).new(info)
|
303
|
+
rescue NameError
|
304
|
+
raise PreferenceError, PreferenceError::MSG_NO_SUCH_HANDLER% info[Preference::FIELD_ROUTE_HANDLER]
|
305
|
+
end
|
306
|
+
|
307
|
+
paths << path
|
308
|
+
end
|
309
|
+
|
310
|
+
# is there any duplicate path?
|
311
|
+
if paths.size != paths.uniq.size
|
312
|
+
raise PreferenceError, PreferenceError::MSG_DUPLICATE_PATH% Preference.instance.path_route_yml
|
313
|
+
end
|
314
|
+
|
315
|
+
run URLMapper.new routes
|
316
|
+
end # end proc
|
317
|
+
end # end #define_route
|
318
|
+
end
|
319
|
+
end
|