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,55 @@
|
|
1
|
+
module Nekonote
|
2
|
+
class CmdParser
|
3
|
+
# @param array argv
|
4
|
+
public
|
5
|
+
def initialize(argv)
|
6
|
+
@argv = argv
|
7
|
+
end
|
8
|
+
|
9
|
+
# @return bool
|
10
|
+
public
|
11
|
+
def version_option?
|
12
|
+
return @argv.index('-v') || @argv.index('--version')
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return bool
|
16
|
+
public
|
17
|
+
def help_option?
|
18
|
+
return @argv.index('-h') || @argv.index('--help')
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return bool
|
22
|
+
public
|
23
|
+
def root_option?
|
24
|
+
return @argv.index '--root'
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return nil|mixed
|
28
|
+
public
|
29
|
+
def get_op_val_root
|
30
|
+
index = @argv.index '--root'
|
31
|
+
return nil if index == nil
|
32
|
+
return @argv[index+1]
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return cmd, subcmd, val
|
36
|
+
public
|
37
|
+
def parse_un_options
|
38
|
+
argv = @argv.clone
|
39
|
+
|
40
|
+
# delete options
|
41
|
+
index = argv.index '--root'
|
42
|
+
if index != nil
|
43
|
+
argv.delete_at(index+1) if argv[index+1] != nil
|
44
|
+
argv.delete_at index
|
45
|
+
end
|
46
|
+
|
47
|
+
# untaint
|
48
|
+
argv.map! do |v|
|
49
|
+
v.intern.to_s if v.is_a? String
|
50
|
+
end
|
51
|
+
|
52
|
+
return *argv
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module Nekonote
|
2
|
+
@@env ||= ENV['NEKONOTE_ENV']
|
3
|
+
@@root = nil
|
4
|
+
@@root_path = nil
|
5
|
+
@@logger_enabled = nil
|
6
|
+
@@logger_write_exception = nil
|
7
|
+
|
8
|
+
# set root directory to the application
|
9
|
+
# @param string root
|
10
|
+
def self.set_root(root)
|
11
|
+
if root.is_a?(String) && @@root != ''
|
12
|
+
root = File.expand_path root
|
13
|
+
root_path = root + '/'
|
14
|
+
@@root ||= root
|
15
|
+
@@root_path ||= root_path
|
16
|
+
else
|
17
|
+
# root is empty
|
18
|
+
raise Error, Error::MSG_MISSING_ROOT
|
19
|
+
end
|
20
|
+
|
21
|
+
# root exist?
|
22
|
+
if !Util::Filer.available_dir? @@root
|
23
|
+
raise Error, Error::MSG_MISSING_DIR% @@root
|
24
|
+
end
|
25
|
+
|
26
|
+
# config.ru exist?
|
27
|
+
if !Util::Filer.available_file? @@root_path + 'config.ru'
|
28
|
+
msg = Error::MSG_MISSING_RACKUP% @@root_path + $/
|
29
|
+
msg += Error::SPACE + Error::MSG_WRONG_ROOT
|
30
|
+
raise Error, msg
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return string
|
35
|
+
def self.get_env
|
36
|
+
if !has_valid_env?
|
37
|
+
raise Error, Error::MSG_MISSING_ENV
|
38
|
+
end
|
39
|
+
return @@env
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return bool
|
43
|
+
def self.has_valid_env?
|
44
|
+
return @@env.is_a?(String) && @@env != '' && @@env.match('/') == nil && @@env.match('\*') == nil
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return string
|
48
|
+
def self.get_root
|
49
|
+
if @@root == nil
|
50
|
+
raise Error, Error::MSG_NOT_DEFINED_ROOT
|
51
|
+
end
|
52
|
+
return @@root
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return string
|
56
|
+
def self.get_root_path
|
57
|
+
if @@root_path == nil
|
58
|
+
raise Error, Error::MSG_NOT_DEFINED_ROOT
|
59
|
+
end
|
60
|
+
return @@root_path
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return bool
|
64
|
+
def self.has_root?
|
65
|
+
return @@root != nil
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return bool
|
69
|
+
def self.from_cli?
|
70
|
+
return defined?(@@from_cli) && @@from_cli
|
71
|
+
end
|
72
|
+
|
73
|
+
# logger is enabled or not?
|
74
|
+
# @return bool
|
75
|
+
def self.logger_enabled?
|
76
|
+
return @@logger_enabled
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return bool
|
80
|
+
def self.need_logging_exception?
|
81
|
+
return logger_enabled? && @@logger_write_exception
|
82
|
+
end
|
83
|
+
|
84
|
+
# load and initialize logger if it has been enabled
|
85
|
+
def self.init_logger
|
86
|
+
pref_logger = Preference.instance.get_logger true # don't use property cache
|
87
|
+
|
88
|
+
if pref_logger['write_exception'] == true
|
89
|
+
@@logger_write_exception = true
|
90
|
+
else
|
91
|
+
@@logger_write_exception = false
|
92
|
+
end
|
93
|
+
|
94
|
+
if pref_logger['enabled'] == true
|
95
|
+
# the method for logger will be defined
|
96
|
+
Logger.instance.init pref_logger
|
97
|
+
@@logger_enabled = true
|
98
|
+
else
|
99
|
+
# remove the defined method for logging
|
100
|
+
if Object.respond_to? :logwrite, true
|
101
|
+
Object.class_eval { remove_method :logwrite }
|
102
|
+
end
|
103
|
+
@@logger_enabled = false
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# load base handler from app root
|
108
|
+
def self.load_base_handler
|
109
|
+
begin
|
110
|
+
require get_root_path + 'handler/base'
|
111
|
+
|
112
|
+
rescue LoadError
|
113
|
+
raise LoadError, Error::MSG_MISSING_FILE% path
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/lib/nekonote/env.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Nekonote
|
2
|
+
class Env
|
3
|
+
private_class_method :new
|
4
|
+
@rackenv = {}
|
5
|
+
|
6
|
+
# Get values in a specified field
|
7
|
+
# @param string|synbol|nil field
|
8
|
+
# @return mixed|nil in the case of that missing specified key or missing fields will return nil
|
9
|
+
def self.get(field = nil)
|
10
|
+
return nil if field == nil
|
11
|
+
|
12
|
+
if !field.is_a? String
|
13
|
+
field = field.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
field.strip!
|
17
|
+
return '' if field == ''
|
18
|
+
|
19
|
+
return @rackenv[field]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Get the whole environments
|
23
|
+
# @return hash
|
24
|
+
def self.get_all
|
25
|
+
return @rackenv
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return string
|
29
|
+
def self.current
|
30
|
+
return Nekonote.get_env
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return string
|
34
|
+
def self.root
|
35
|
+
return Nekonote.get_root
|
36
|
+
end
|
37
|
+
|
38
|
+
# @return string
|
39
|
+
def self.root_path
|
40
|
+
return Nekonote.get_root_path
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return array|nil
|
44
|
+
def self.keys
|
45
|
+
if @rackenv.is_a? Hash
|
46
|
+
return @rackenv.keys
|
47
|
+
end
|
48
|
+
return nil
|
49
|
+
end
|
50
|
+
|
51
|
+
# @param hash rackenv
|
52
|
+
def self.set_rackenv(rackenv)
|
53
|
+
@rackenv = rackenv
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Nekonote
|
2
|
+
class CLIError < Error
|
3
|
+
MSG_PERMIT_MAKE_DIR = %{Failed to generate an application structure in '%s' because of invalid permission or not found.}
|
4
|
+
MSG_UNABLE_TO_LOAD = %(Unable to load %s. Did you really install it?)
|
5
|
+
|
6
|
+
MSG_MISSING_AFTER_NEW = %(Please set something after new.)
|
7
|
+
MSG_MISSING_NEW_PATH = %(Please set some name to generate.)
|
8
|
+
MSG_MISSING_STRUCTURE_DIR = %(The specified directory was not found. Please make sure '%s' directory exists on your server.)
|
9
|
+
MSG_MISSING_DEST_PATH = %('%s' was not found in the application structure.)
|
10
|
+
MSG_MISSING_AFTER_SERVER = %('nekonote server' requires some sub-command.)
|
11
|
+
|
12
|
+
MSG_INVALID_NEW_NAME = %(Invalid name '%s'.)
|
13
|
+
MSG_INVALID_HANDLER_NAME = %(Invalid handler name '%s'.)
|
14
|
+
MSG_INVALID_TEMPLATE_NAME = %(Invalid template name '%s'.)
|
15
|
+
MSG_INVALID_LAYOUT_NAME = %(Invalid layout name '%s'.)
|
16
|
+
MSG_INVALID_ENV_NAME = %(Invalid environment name '%s'.)
|
17
|
+
|
18
|
+
MSG_ALREADY_EXISTS_APP = %('%s' exists already. You need to remove it at first.)
|
19
|
+
MSG_ALREADY_EXISTS_HANDLER = %(Handler '%s' exists already. Nothing to do.)
|
20
|
+
MSG_ALREADY_EXISTS_TEMPLATE = %(Template '%s' exists already. Nothing to do.)
|
21
|
+
MSG_ALREADY_EXISTS_LAYOUT = %(Layout '%s' exists already. Nothing to do.)
|
22
|
+
MSG_ALREADY_EXISTS_ENV = %(Environment '%s' exists already. Nothing to do.)
|
23
|
+
|
24
|
+
MSG_FAILED_CREATE_HANDLER = %(Failed to create a handler by the following reason '%s')
|
25
|
+
MSG_FAILED_CREATE_TEMPLATE = %(Failed to create a template by the following reason '%s')
|
26
|
+
MSG_FAILED_CREATE_LAYOUT = %(Failed to create a layout by the following reason '%s')
|
27
|
+
MSG_FAILED_GEN_DIR_BY_FILE = %(Failed to create a directory '%s'. There is the file which the same name.)
|
28
|
+
MSG_FAILED_START_SERVER = %(Failed to start the web server. Please check the error message.)
|
29
|
+
|
30
|
+
MSG_UNKNOWN_AFTER_NEW = %(Unknown sub command 'nekonote new %s'.)
|
31
|
+
MSG_UNKNOWN_AFTER_SERVER = %(Unknown sub command 'nekonote server %s'.)
|
32
|
+
MSG_UNKNOWN_SUB_COMMAND = %(Unknown sub command '%s'. Typing 'nekonote -h' will help you.)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Nekonote
|
2
|
+
# static methods class
|
3
|
+
class Error < StandardError
|
4
|
+
SPACE = ' '
|
5
|
+
MSG_MISSING_ENV = %(Environment variable NEKONOTE_ENV is empty or invalid environment name is set.)
|
6
|
+
MSG_MISSING_ROOT = %(Missing root directory to the application structure.)
|
7
|
+
MSG_NOT_DEFINED_ROOT = %(Application root is not defined yet.)
|
8
|
+
MSG_MISSING_FILE = %(No such file '%s' or can't read it.)
|
9
|
+
MSG_MISSING_DIR = %(No such directory '%s' or can't read it.)
|
10
|
+
MSG_MISSING_RACKUP = %(Missing config.ru under '%s' or can't read it.)
|
11
|
+
MSG_LACK_FIELD_IN_YAML = %(Lack of the required field '%s'. Please check if '%s' is set properly.)
|
12
|
+
MSG_EMPTY_YAML = %('%s' is empty. You must configure something.)
|
13
|
+
MSG_WRONG_ROOT = %(You'd better run the command at the application root, or --root option will solve the problem.)
|
14
|
+
MSG_WRONG_TYPE = %(You gave %s but the expected type is '%s'.)
|
15
|
+
MSG_MISSING_FIELD = %(The required field '%s' was not found in '%s'.)
|
16
|
+
MSG_INVALID_FIELD = %(Invalid format field '%s' in '%s'.)
|
17
|
+
MSG_MISSING_CONST = %(Missing such class or module or contant -> '%s'.)
|
18
|
+
MSG_EMPTY_FILE_NOT_EMPTY = %('%s' is not empty. Failed to create an empty file.)
|
19
|
+
|
20
|
+
# write message as warning to log file if logging is enabled
|
21
|
+
# @param string msg
|
22
|
+
def self.warning(msg)
|
23
|
+
logging_warn msg
|
24
|
+
|
25
|
+
begin
|
26
|
+
if Nekonote.from_cli?
|
27
|
+
warn 'Warning: ' + msg
|
28
|
+
end
|
29
|
+
rescue
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param StandardError e
|
34
|
+
def self.abort(e)
|
35
|
+
logging_error e
|
36
|
+
|
37
|
+
# if executed from cli do not throw exception
|
38
|
+
if Nekonote.from_cli?
|
39
|
+
warn "#{e.class}; =(-x-=;)" + $/
|
40
|
+
warn SPACE + e.message + $/ + $/
|
41
|
+
if !e.is_a? Nekonote::Error
|
42
|
+
warn e.backtrace
|
43
|
+
end
|
44
|
+
exit 1
|
45
|
+
end
|
46
|
+
|
47
|
+
raise e
|
48
|
+
end
|
49
|
+
|
50
|
+
# write error informaton to log file if logging is enabled
|
51
|
+
# @param string msg
|
52
|
+
def self.logging_warn(msg)
|
53
|
+
begin
|
54
|
+
if Nekonote.need_logging_exception?
|
55
|
+
logwrite msg, Nekonote::Logger::WARN
|
56
|
+
Nekonote::Logger.instance.set_level_default
|
57
|
+
end
|
58
|
+
rescue
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# write error informaton to log file if logging is enabled
|
63
|
+
# @param StandardError e
|
64
|
+
def self.logging_error(e)
|
65
|
+
begin
|
66
|
+
if Nekonote.need_logging_exception?
|
67
|
+
msg = %(#{e.class} - #{e.message}) + $/ + e.backtrace.join($/)
|
68
|
+
logwrite msg, Nekonote::Logger::FATAL
|
69
|
+
Nekonote::Logger.instance.set_level_default
|
70
|
+
end
|
71
|
+
rescue
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
module Nekonote
|
2
|
+
class LoggerError < Error
|
3
|
+
MSG_MISSING_LOGFILE = %(Lack of the required directives 'logfile' and 'keep' and 'limit' in logger.yml.)
|
4
|
+
MSG_FAILED_INITIALIZE = %(Failed to initialize logger. Wrong syntax in logger.yml or '%s' doesn't have a permission to create '%s'.)
|
5
|
+
MSG_FAILED_DEF_OPT = %(Failed to define optional value. Maybe there is wrong syntax in logger.yml. Please check the reference manual.)
|
6
|
+
MSG_UNDIFINED_LOG_LEVEL = %(Undifined log level was given. Please check the reference manual.)
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Nekonote
|
2
|
+
class PreferenceError < Error
|
3
|
+
MSG_UNDEFINED_FIELD = %(Undefined field '%s'.)
|
4
|
+
MSG_WRONG_YAML_SYNTAX = %(The yaml file '%s' is invalid syntax.)
|
5
|
+
MSG_MISSING_INCLUDE = %(No such field '%s' in %s.)
|
6
|
+
MSG_INVALID_HANDLER_NAME = %(Handler class name '%s' is invalid.)
|
7
|
+
MSG_NO_SUCH_HANDLER = %(No such handler class '%s'. You must make it at first.)
|
8
|
+
MSG_DUPLICATE_PATH = %(There is the duplicate path in %s. Values of 'path' directive are supposed to be uniq.)
|
9
|
+
MSG_EVAL_MIDDLEWARES = %(Unable to evaluate '%s' because there's something wrong.)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module Nekonote
|
2
|
+
class ViewError < Error
|
3
|
+
MSG_MISSING_TEMPLATE_FILE = %(Failed to load the tempalte file. No such file '%s')
|
4
|
+
MSG_MISSING_LAYOUT_FILE = %(Failed to load the layout file. No such file '%s')
|
5
|
+
MSG_FAILED_TO_ASSIGN = %(Failed to assign variables into templates. You gave wrong type. The expected type is Hash.)
|
6
|
+
end
|
7
|
+
end
|
@@ -0,0 +1,274 @@
|
|
1
|
+
module Nekonote
|
2
|
+
class Handler
|
3
|
+
EXIT = 'Nekonote exit from queue'
|
4
|
+
require Nekonote.get_lib_root_path + 'handler/protected_methods'
|
5
|
+
include ProtectedMethods
|
6
|
+
|
7
|
+
# =============================================
|
8
|
+
# Accessors
|
9
|
+
# =============================================
|
10
|
+
attr_accessor :route_regexp,
|
11
|
+
:url_path_params_mapper
|
12
|
+
|
13
|
+
# =============================================
|
14
|
+
# Static method
|
15
|
+
# =============================================
|
16
|
+
# make error handler and execute it
|
17
|
+
# @param string field
|
18
|
+
# @param hash env
|
19
|
+
# @param nil e
|
20
|
+
# @return array
|
21
|
+
def self.call_error_handler(field, env = {}, e = nil)
|
22
|
+
pref = Preference.instance.get_route_error
|
23
|
+
|
24
|
+
# field is expected String and pref[field] is expected Hash
|
25
|
+
if !field.is_a?(String) || !pref[field].is_a?(Hash)
|
26
|
+
raise HandlerError, HandlerError::MSG_MISSING_FIELD%[field, Preference.instance.path_route_error_yml]
|
27
|
+
end
|
28
|
+
|
29
|
+
# make handler newly
|
30
|
+
handler_name = pref[field][Preference::FIELD_ROUTE_HANDLER]
|
31
|
+
if handler_name.is_a? String
|
32
|
+
begin
|
33
|
+
handler_class = Object.const_get handler_name
|
34
|
+
error_handler = handler_class.new pref[field].clone, field, e
|
35
|
+
rescue
|
36
|
+
raise HandlerError, HandlerError::MSG_MISSING_CONST% handler_name
|
37
|
+
end
|
38
|
+
else
|
39
|
+
raise HandlerError, HandlerError::MSG_MISSING_ERR_HANDLER
|
40
|
+
end
|
41
|
+
|
42
|
+
return error_handler.call env
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
# It would be called only one time
|
47
|
+
# @param hash info route information
|
48
|
+
# @param bool|nil error_field_name
|
49
|
+
# @param StandardError error
|
50
|
+
def initialize(info={}, error_field_name = nil, error = nil)
|
51
|
+
# Both the properties are allowed to access in sub classes
|
52
|
+
@view = View.new (info || {}), self.class.to_s, error_field_name
|
53
|
+
|
54
|
+
@request = nil # Object of Nekonote::Request
|
55
|
+
@session = nil # Object about session management
|
56
|
+
@route_regexp = nil # Object of Regexp
|
57
|
+
@url_path_params_mapper = nil # Hash
|
58
|
+
|
59
|
+
# exception object will be set if fatal error occured
|
60
|
+
@error = error
|
61
|
+
|
62
|
+
# custom fields will be set, if no custom field just {} will be set
|
63
|
+
@custom_fields = Preference.get_custom_fields info, error_field_name.is_a?(String)
|
64
|
+
end
|
65
|
+
|
66
|
+
# reload preferences
|
67
|
+
private
|
68
|
+
def pref_reloader
|
69
|
+
path = Nekonote.get_root_path + Preference::FILE_NAME_FOR_RELOAD
|
70
|
+
if File.exist? path
|
71
|
+
# reload logger
|
72
|
+
Nekonote.init_logger
|
73
|
+
|
74
|
+
# reload setting
|
75
|
+
Setting.init
|
76
|
+
|
77
|
+
Util::Filer::safe_delete_empty_file path
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# This method would be called from rack and called in every request
|
82
|
+
# @param hash env rack environment
|
83
|
+
public
|
84
|
+
def call(env)
|
85
|
+
# reload preferences if needed
|
86
|
+
pref_reloader
|
87
|
+
|
88
|
+
# get reponse data from page cache if it's available
|
89
|
+
if @view.can_get_from_page_cache?(env['REQUEST_URI'])
|
90
|
+
response_data = @view.get_response_data_from_page_cache env['REQUEST_URI']
|
91
|
+
if response_data.size == 3
|
92
|
+
# return the cache
|
93
|
+
return response_data
|
94
|
+
else
|
95
|
+
# invalid page cache file, put warning message
|
96
|
+
Error.warning 'Wrong page cache file was detected. Please remove page cache.'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# initialize response
|
101
|
+
@view.init_for_response
|
102
|
+
|
103
|
+
# set env to Nekonote::env
|
104
|
+
Env.set_rackenv env
|
105
|
+
|
106
|
+
# set session if it's enabled
|
107
|
+
@session = Env.get 'rack.session'
|
108
|
+
|
109
|
+
# set request
|
110
|
+
@request = Request.new env, @view.info_params
|
111
|
+
|
112
|
+
# set request body to request object if it exists
|
113
|
+
if env['rack.input'].is_a? StringIO
|
114
|
+
# reverting file pointer I don't know why the pointer moved just one...?
|
115
|
+
env['rack.input'].rewind
|
116
|
+
@request.set_payload env['rack.input'].read
|
117
|
+
end
|
118
|
+
|
119
|
+
# execute
|
120
|
+
if !@view.is_error_route
|
121
|
+
begin
|
122
|
+
return execute env
|
123
|
+
|
124
|
+
rescue StandardError, ScriptError => e
|
125
|
+
# fatal error occured
|
126
|
+
process_exception_raised e
|
127
|
+
|
128
|
+
# if ShowExceptions is disabled and fatal error route has been defined, forward custom error page
|
129
|
+
if Preference.instance.has_error_route? Preference::FIELD_ROUTE_ERR_FATAL
|
130
|
+
return Handler.call_error_handler Preference::FIELD_ROUTE_ERR_FATAL, Env.get_all, e
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
else
|
135
|
+
# If self is Handler for error routes
|
136
|
+
begin
|
137
|
+
execute_handler_methods @view.info_exec_method
|
138
|
+
return get_response_data
|
139
|
+
|
140
|
+
rescue StandardError, ScriptError => e
|
141
|
+
process_exception_raised e
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# in the case of an exception raised but
|
146
|
+
# there is no fatal error route OR the exception raised in fatal error route
|
147
|
+
# and also ShowExceptons does not handle an exception
|
148
|
+
# returns an empty response
|
149
|
+
# TODO Do I have to change them to be customizable?
|
150
|
+
return View.get_default_error_response
|
151
|
+
end
|
152
|
+
|
153
|
+
# @param StandardError|ScriptError e
|
154
|
+
# @throws StandardError|ScriptError
|
155
|
+
private
|
156
|
+
def process_exception_raised(e)
|
157
|
+
# logging if logger is enabled
|
158
|
+
Error.logging_error e
|
159
|
+
|
160
|
+
# raise the exception for ShowExceptions if it's enabled
|
161
|
+
raise e if Preference.instance.is_enabled_show_exceptions
|
162
|
+
end
|
163
|
+
|
164
|
+
# It would be called by every request
|
165
|
+
# @param hash env
|
166
|
+
# @return array
|
167
|
+
# response_code int
|
168
|
+
# response_header hash
|
169
|
+
# response_body array
|
170
|
+
private
|
171
|
+
def execute(env)
|
172
|
+
# check path machs the expected path
|
173
|
+
if matched_route_strictly? @request.path, @view.info_path
|
174
|
+
# check request HTTP method
|
175
|
+
if is_allowed_http_method @request.method
|
176
|
+
# matched some route then call methods defined in concrete handlers
|
177
|
+
execute_handler_methods @view.info_exec_method
|
178
|
+
else
|
179
|
+
# request method error
|
180
|
+
return Handler.call_error_handler Preference::FIELD_ROUTE_ERR_WRONG_METHOD, Env.get_all
|
181
|
+
end
|
182
|
+
|
183
|
+
else
|
184
|
+
# doesn't match any routes
|
185
|
+
return Handler.call_error_handler Preference::FIELD_ROUTE_ERR_MISSING_ROUTE, Env.get_all
|
186
|
+
end
|
187
|
+
|
188
|
+
return get_response_data
|
189
|
+
end
|
190
|
+
|
191
|
+
# Check does requested path correspond with the given value to #map
|
192
|
+
# @return bool
|
193
|
+
private
|
194
|
+
def matched_route_strictly?(requested_path, expected_path)
|
195
|
+
match_data = @route_regexp.match requested_path
|
196
|
+
if match_data.is_a? MatchData
|
197
|
+
# set URL path parameters to Request object
|
198
|
+
if @url_path_params_mapper.is_a? Hash
|
199
|
+
stack = requested_path.split('/')
|
200
|
+
map = {}
|
201
|
+
@url_path_params_mapper.each_pair do |name, index|
|
202
|
+
map[name] = stack[index]
|
203
|
+
end
|
204
|
+
@request.assign_from_url map
|
205
|
+
end
|
206
|
+
|
207
|
+
return true
|
208
|
+
|
209
|
+
else
|
210
|
+
# doesn't match, the requested path is wrong
|
211
|
+
return false
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# Get response data and return values as rack needed
|
216
|
+
# @return array
|
217
|
+
private
|
218
|
+
def get_response_data
|
219
|
+
# return response if redirection
|
220
|
+
if @view.is_redirect
|
221
|
+
return @view.get_response_data
|
222
|
+
end
|
223
|
+
|
224
|
+
# set response body with template and/or layout when response body hasn't been set by __set_body
|
225
|
+
@view.set_body_with_tpl if !@view.is_body_set?
|
226
|
+
|
227
|
+
# make page cache file if need it
|
228
|
+
if @view.need_create_page_cache? @request.uri
|
229
|
+
@view.create_page_cache @request.uri
|
230
|
+
end
|
231
|
+
|
232
|
+
return @view.get_response_data
|
233
|
+
end
|
234
|
+
|
235
|
+
# @param string|symbol|nil task method name defined in 'klass'
|
236
|
+
private
|
237
|
+
def execute_handler_methods(task)
|
238
|
+
if task != nil && !task.is_a?(String) && !task.is_a?(Symbol)
|
239
|
+
raise HandlerError, HandlerError::MSG_WRONG_TYPE%[task.class, 'String|Symbol|nil']
|
240
|
+
end
|
241
|
+
|
242
|
+
# execute methods when it's defined
|
243
|
+
# if __pre is defined execute it first
|
244
|
+
return if execute_method(:__pre, self) == EXIT
|
245
|
+
# execute particular method specified with routes.yml when it isn't nil
|
246
|
+
return if execute_method(task, self) == EXIT
|
247
|
+
# if __post is defined execute it last
|
248
|
+
execute_method :__post, self
|
249
|
+
end
|
250
|
+
|
251
|
+
# @param method symbol|string
|
252
|
+
private
|
253
|
+
def execute_method(method, handler)
|
254
|
+
if !@view.is_redirect && (method != nil) && handler.respond_to?(method, true)
|
255
|
+
handler.method(method).call
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
# Is given method allowed?
|
260
|
+
# @pram string method
|
261
|
+
# @return false|nil|int
|
262
|
+
private
|
263
|
+
def is_allowed_http_method(method)
|
264
|
+
return false if !method.is_a? String
|
265
|
+
http_methods = @view.info_allow_methods
|
266
|
+
return true if http_methods == nil
|
267
|
+
http_methods = http_methods.split(',')
|
268
|
+
http_methods.map! do |val|
|
269
|
+
val.strip
|
270
|
+
end
|
271
|
+
return http_methods.index method
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|