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,295 @@
|
|
1
|
+
module Nekonote
|
2
|
+
class Request
|
3
|
+
STRING = 'string'
|
4
|
+
INTEGER = 'int'
|
5
|
+
ARRAY = 'array'
|
6
|
+
FLOAT = 'float'
|
7
|
+
BOOL = 'bool'
|
8
|
+
|
9
|
+
# accessor
|
10
|
+
attr_reader :path,
|
11
|
+
:uri,
|
12
|
+
:method,
|
13
|
+
:payload
|
14
|
+
|
15
|
+
# @param hash env
|
16
|
+
# @param string|nil restricted
|
17
|
+
def initialize(env, restricted = nil)
|
18
|
+
# set properties
|
19
|
+
@path = env['REQUEST_PATH']
|
20
|
+
@uri = env['REQUEST_URI']
|
21
|
+
@method = env['REQUEST_METHOD']
|
22
|
+
@accepted_list = get_accepted_list restricted
|
23
|
+
|
24
|
+
# query string
|
25
|
+
@query_string = {}
|
26
|
+
@query_string_raw = {}
|
27
|
+
|
28
|
+
# POST data
|
29
|
+
@post_data = {}
|
30
|
+
@post_data_raw = {}
|
31
|
+
|
32
|
+
# URL path parameters
|
33
|
+
@path_params = {}
|
34
|
+
@path_params_raw = {}
|
35
|
+
|
36
|
+
# request body
|
37
|
+
@payload = nil
|
38
|
+
|
39
|
+
# set query string
|
40
|
+
if env['QUERY_STRING'].is_a? String
|
41
|
+
@query_string_raw = get_param_maps env['QUERY_STRING']
|
42
|
+
@query_string = get_sanitized @query_string_raw
|
43
|
+
end
|
44
|
+
|
45
|
+
# set POST data
|
46
|
+
if env['rack.input'].is_a? StringIO
|
47
|
+
@post_data_raw = get_param_maps env['rack.input'].gets
|
48
|
+
@post_data = get_sanitized @post_data_raw
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns sanitized query string
|
53
|
+
# @params string|symbol name
|
54
|
+
# @return mixed
|
55
|
+
public
|
56
|
+
def query_string(name = nil)
|
57
|
+
return get_value name, @query_string
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns raw query string
|
61
|
+
# @params string|symbol name
|
62
|
+
# @return mixed
|
63
|
+
public
|
64
|
+
def query_string_raw(name = nil)
|
65
|
+
return get_value name, @query_string_raw
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns sanitized POST data
|
69
|
+
# @params string|symbol name
|
70
|
+
# @return mixed
|
71
|
+
public
|
72
|
+
def post_data(name = nil)
|
73
|
+
return get_value name, @post_data
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns raw POST data
|
77
|
+
# @params string|symbol name
|
78
|
+
# @return mixed
|
79
|
+
public
|
80
|
+
def post_data_raw(name = nil)
|
81
|
+
return get_value name, @post_data_raw
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns sanitized URL parameters
|
85
|
+
# @params string|symbol name
|
86
|
+
# @return mixed
|
87
|
+
public
|
88
|
+
def path_params(name = nil)
|
89
|
+
return get_value name, @path_params
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns raw URL parameters
|
93
|
+
# @params string|symbol name
|
94
|
+
# @return mixed
|
95
|
+
public
|
96
|
+
def path_params_raw(name = nil)
|
97
|
+
return get_value name, @path_params_raw
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns sanitized parameters
|
101
|
+
# @params string|symbol name
|
102
|
+
# @return mixed
|
103
|
+
public
|
104
|
+
def params(name = nil)
|
105
|
+
case @method
|
106
|
+
when 'GET'
|
107
|
+
maps = @query_string
|
108
|
+
when 'POST'
|
109
|
+
maps = @post_data
|
110
|
+
else
|
111
|
+
maps = {}
|
112
|
+
end
|
113
|
+
return get_value name, maps
|
114
|
+
end
|
115
|
+
|
116
|
+
# Returns raw parameters
|
117
|
+
# @params string|symbol name
|
118
|
+
# @return mixed
|
119
|
+
public
|
120
|
+
def params_raw(name = nil)
|
121
|
+
case @method
|
122
|
+
when 'GET'
|
123
|
+
maps = @query_string_raw
|
124
|
+
when 'POST'
|
125
|
+
maps = @post_data_raw
|
126
|
+
else
|
127
|
+
maps = {}
|
128
|
+
end
|
129
|
+
return get_value name, maps
|
130
|
+
end
|
131
|
+
|
132
|
+
# Returns parsed payload as json format
|
133
|
+
# @return hash|nil|false
|
134
|
+
public
|
135
|
+
def json_payload
|
136
|
+
if @payload != nil
|
137
|
+
begin
|
138
|
+
parsed = JSON.parse @payload
|
139
|
+
rescue
|
140
|
+
# unable to parse
|
141
|
+
parsed = false
|
142
|
+
end
|
143
|
+
else
|
144
|
+
# no payload given
|
145
|
+
parsed = nil
|
146
|
+
end
|
147
|
+
|
148
|
+
return parsed
|
149
|
+
end
|
150
|
+
|
151
|
+
# @param hash map
|
152
|
+
public
|
153
|
+
def assign_from_url(map)
|
154
|
+
return nil if !map.is_a? Hash
|
155
|
+
|
156
|
+
# set url params
|
157
|
+
@path_params_raw = map
|
158
|
+
@path_params = get_sanitized @path_params_raw
|
159
|
+
end
|
160
|
+
|
161
|
+
# @param mixed payload
|
162
|
+
public
|
163
|
+
def set_payload(payload)
|
164
|
+
@payload = payload
|
165
|
+
end
|
166
|
+
|
167
|
+
# @param string|symbol name
|
168
|
+
# @return bool
|
169
|
+
public
|
170
|
+
def valid_str?(name)
|
171
|
+
params(name) != nil && params(name) != ''
|
172
|
+
end
|
173
|
+
|
174
|
+
# @param string|symbol name
|
175
|
+
public
|
176
|
+
def having?(name)
|
177
|
+
params(name) != nil
|
178
|
+
end
|
179
|
+
|
180
|
+
# @param string|symbol name
|
181
|
+
# @param hash maps
|
182
|
+
# @return mixed
|
183
|
+
private
|
184
|
+
def get_value(name, maps)
|
185
|
+
if name.is_a? String
|
186
|
+
return maps[name]
|
187
|
+
|
188
|
+
elsif name.is_a? Symbol
|
189
|
+
return maps[name.to_s]
|
190
|
+
|
191
|
+
else
|
192
|
+
return maps
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# Returns the accepable name list
|
197
|
+
# @param string|nil restricted
|
198
|
+
# @return array
|
199
|
+
private
|
200
|
+
def get_accepted_list(restricted)
|
201
|
+
accepted_list = []
|
202
|
+
if restricted.is_a? String
|
203
|
+
restricted.split(',').each do |data|
|
204
|
+
data.strip!
|
205
|
+
pair = data.split('=')
|
206
|
+
if pair.size != 2
|
207
|
+
raise Error, Error::MSG_INVALID_FIELD%['params', Preference.instance.path_route_yml]
|
208
|
+
end
|
209
|
+
# add field name and hash as Hash into array
|
210
|
+
accepted_list << {pair[0] => pair[1]}
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
return accepted_list
|
215
|
+
end
|
216
|
+
|
217
|
+
# @param string str query string
|
218
|
+
# @return hash
|
219
|
+
private
|
220
|
+
def get_param_maps(str)
|
221
|
+
maps = {}
|
222
|
+
return maps if !str.is_a? String
|
223
|
+
|
224
|
+
str.split('&').each do |field|
|
225
|
+
pair = field.split('=')
|
226
|
+
if pair.size == 2
|
227
|
+
v = pair[1]
|
228
|
+
else
|
229
|
+
v = nil
|
230
|
+
end
|
231
|
+
maps[pair[0]] = v
|
232
|
+
end
|
233
|
+
|
234
|
+
return maps
|
235
|
+
end
|
236
|
+
|
237
|
+
# Removing waste parameter and converting to the exected type
|
238
|
+
# @param hash maps
|
239
|
+
# @param bool decode
|
240
|
+
# @return hash
|
241
|
+
private
|
242
|
+
def get_sanitized(maps, decode = false)
|
243
|
+
return maps if @accepted_list.size == 0
|
244
|
+
|
245
|
+
sanitized_maps = {}
|
246
|
+
@accepted_list.each do |field|
|
247
|
+
field.each_pair do |name, type|
|
248
|
+
converted = get_expected type, maps[name]
|
249
|
+
|
250
|
+
# URL decode if necessary
|
251
|
+
if decode || converted.is_a?(String)
|
252
|
+
converted = URI.decode_www_form_component converted
|
253
|
+
end
|
254
|
+
|
255
|
+
sanitized_maps[name] = converted
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
return sanitized_maps
|
260
|
+
end
|
261
|
+
|
262
|
+
# @param string type type expected
|
263
|
+
# @param mixed value real value
|
264
|
+
# @param string converted value by the expected type
|
265
|
+
private
|
266
|
+
def get_expected(type, value)
|
267
|
+
return nil if value == nil
|
268
|
+
|
269
|
+
v = nil
|
270
|
+
begin
|
271
|
+
case type
|
272
|
+
when INTEGER
|
273
|
+
v = value.to_i
|
274
|
+
when STRING
|
275
|
+
v = value.to_s
|
276
|
+
when ARRAY
|
277
|
+
v = value.to_s.split(',')
|
278
|
+
v.map! { |val| val.strip }
|
279
|
+
when FLOAT
|
280
|
+
v = value.to_f
|
281
|
+
when BOOL
|
282
|
+
if value == nil || value == false || value == 'false' || value == 0 || value == '0' || value == 'no' || value == ''
|
283
|
+
v = false
|
284
|
+
else
|
285
|
+
v = true
|
286
|
+
end
|
287
|
+
end
|
288
|
+
rescue
|
289
|
+
# value is nil if failed to convert value to expected type
|
290
|
+
end
|
291
|
+
|
292
|
+
return v
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Nekonote
|
2
|
+
class Setting
|
3
|
+
include Singleton
|
4
|
+
DIR_SETTING = 'setting'
|
5
|
+
|
6
|
+
# read yaml data from files under setting directory
|
7
|
+
def self.init
|
8
|
+
path = Nekonote.get_root_path + YamlAccess::DIR_PREFERENCE + '/' + Nekonote.get_env + '/' + DIR_SETTING
|
9
|
+
Dir.chdir path
|
10
|
+
|
11
|
+
@setting = {}
|
12
|
+
Dir["#{Dir.pwd}/**/*.yml"].each do |file|
|
13
|
+
next if File.directory? file
|
14
|
+
parsed = YamlAccess::get_parsed file
|
15
|
+
if parsed.is_a? Hash
|
16
|
+
@setting.merge! parsed
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Get all root filed names
|
22
|
+
# @return array
|
23
|
+
def self.keys
|
24
|
+
return @setting.keys
|
25
|
+
end
|
26
|
+
|
27
|
+
# Get the whole environments
|
28
|
+
# @return hash
|
29
|
+
def self.get_all
|
30
|
+
return @setting
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get values in a specified field(s).
|
34
|
+
# @param string|synbol fields you can set plual arguments like field1, field2, field3, ...
|
35
|
+
# @return mixed|nil in the case of that missing specified key or missing fields will return nil
|
36
|
+
def self.get(*fields)
|
37
|
+
if !defined?(@setting) || !@setting.is_a?(Hash)
|
38
|
+
return nil
|
39
|
+
end
|
40
|
+
|
41
|
+
if fields.count == 1 && fields[0].is_a?(Array)
|
42
|
+
fields = fields[0]
|
43
|
+
end
|
44
|
+
|
45
|
+
stack = nil
|
46
|
+
fields.each do |field|
|
47
|
+
field = field.to_s.strip
|
48
|
+
if stack.is_a? Hash
|
49
|
+
# get next field
|
50
|
+
stack = stack[field]
|
51
|
+
else
|
52
|
+
stack = @setting[field]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
return stack
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Nekonote
|
2
|
+
LIBS_NAME = %(nekonote-framework).freeze
|
3
|
+
VERSION = %(1.0.0-beta).freeze
|
4
|
+
HOMEPAGE = %(https://nekonote-framework.github.io).freeze
|
5
|
+
SUMMARY = %(Simple and Lightweight Ruby Framework for Web Development).freeze
|
6
|
+
DESCRIPTION = %(Nekonote Framework is a small web application framework that helps your web development.).freeze
|
7
|
+
INSTALL_MESSAGE = <<EOS
|
8
|
+
|
9
|
+
.*・゜゚・*:.。..。.:・Thanks installing Nekonote Framework .*・゜゚・*:.。..。.:*・
|
10
|
+
|
11
|
+
^___^
|
12
|
+
(=^x^=) < meow meow
|
13
|
+
/ ) !
|
14
|
+
. ~~( h h . . . . . . =(**=)~~
|
15
|
+
|
16
|
+
Note:
|
17
|
+
Installing dependent libraries is not completed yet.
|
18
|
+
After generating an application structure by 'nekonote new app some_app_name', you are supposed to get a Gemfile to install the dependencies.
|
19
|
+
Please install the dependent libraries from the Gemfile by Bundler.
|
20
|
+
|
21
|
+
EOS
|
22
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Nekonote
|
2
|
+
module Util
|
3
|
+
module Filer
|
4
|
+
# is path file? and is it readable?
|
5
|
+
# @param string|io path
|
6
|
+
# @return bool
|
7
|
+
def available_file?(path)
|
8
|
+
return File.file?(path) && File.readable?(path)
|
9
|
+
end
|
10
|
+
|
11
|
+
# is path directory? and is it friendly permission?
|
12
|
+
# @param string|io path
|
13
|
+
# @return bool
|
14
|
+
def available_dir?(path)
|
15
|
+
evaluation = false
|
16
|
+
if File.directory? path
|
17
|
+
stat = File::Stat.new path
|
18
|
+
evaluation = stat.readable? && stat.writable? && stat.executable?
|
19
|
+
end
|
20
|
+
return evaluation
|
21
|
+
end
|
22
|
+
|
23
|
+
# Makes an empty file named the given name if it doesn't exist
|
24
|
+
# @param string path
|
25
|
+
def safe_make_empty_file(path)
|
26
|
+
if File.exist? path
|
27
|
+
File.open(path, 'r') do |f|
|
28
|
+
if !f.read.empty?
|
29
|
+
raise Error, Error::MSG_EMPTY_FILE_NOT_EMPTY% path
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# make an empty file
|
35
|
+
File.open(path, 'a') do |f|
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# @param string path
|
40
|
+
def safe_delete_empty_file(path)
|
41
|
+
if File.exist? path
|
42
|
+
File.open(path, 'r') do |f|
|
43
|
+
if !f.read.empty?
|
44
|
+
raise Error, Error::MSG_EMPTY_FILE_NOT_EMPTY% path
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# delete an empty file
|
50
|
+
File.delete path
|
51
|
+
end
|
52
|
+
|
53
|
+
# delete end of slash if it exists
|
54
|
+
# @param string path
|
55
|
+
# @return string
|
56
|
+
def unslashed(path)
|
57
|
+
path.sub! /\/$/, '' if path.end_with? '/'
|
58
|
+
return path
|
59
|
+
end
|
60
|
+
|
61
|
+
# define them as module function
|
62
|
+
module_function :available_file?,
|
63
|
+
:available_dir?,
|
64
|
+
:safe_make_empty_file,
|
65
|
+
:safe_delete_empty_file,
|
66
|
+
:unslashed
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Nekonote
|
2
|
+
module Util
|
3
|
+
module Process
|
4
|
+
# @param string path
|
5
|
+
# @return int|nil
|
6
|
+
def get_server_pid(path)
|
7
|
+
return nil if !Filer.available_file? path
|
8
|
+
|
9
|
+
pid = nil
|
10
|
+
File.open(path, 'r') do |f|
|
11
|
+
pid = f.read
|
12
|
+
pid.rstrip! && pid = pid.to_i if pid.is_a? String
|
13
|
+
end
|
14
|
+
|
15
|
+
# There's pid file but actually the process is dead
|
16
|
+
if pid != nil && !alive_process?(pid)
|
17
|
+
pid = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
return pid
|
21
|
+
end
|
22
|
+
|
23
|
+
# Is process of given pid running?
|
24
|
+
# @param int pid
|
25
|
+
# @return bool
|
26
|
+
def alive_process?(pid)
|
27
|
+
return false if !pid.is_a? Integer
|
28
|
+
|
29
|
+
begin
|
30
|
+
::Process.getpgid pid
|
31
|
+
alive = true
|
32
|
+
rescue Errno::ESRCH
|
33
|
+
alive = false
|
34
|
+
end
|
35
|
+
|
36
|
+
return alive
|
37
|
+
end
|
38
|
+
|
39
|
+
module_function :get_server_pid,
|
40
|
+
:alive_process?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|