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.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +49 -0
  4. data/bin/nekonote +45 -0
  5. data/data/structure/Gemfile +25 -0
  6. data/data/structure/config.ru +14 -0
  7. data/data/structure/handler/base.rb +21 -0
  8. data/data/structure/handler/error.rb +35 -0
  9. data/data/structure/handler/welcome.rb +11 -0
  10. data/data/structure/lib/.gitkeep +0 -0
  11. data/data/structure/preference/development/logger.yml +62 -0
  12. data/data/structure/preference/development/middlewares.rb +152 -0
  13. data/data/structure/preference/development/public.yml +29 -0
  14. data/data/structure/preference/development/route.yml +30 -0
  15. data/data/structure/preference/development/route_error.yml +28 -0
  16. data/data/structure/preference/development/route_include.yml +22 -0
  17. data/data/structure/preference/development/server/puma.rb +63 -0
  18. data/data/structure/preference/development/setting/example.yml +40 -0
  19. data/data/structure/preference/development/setting/site.yml +3 -0
  20. data/data/structure/preference/development/setting/welcome.yml +7 -0
  21. data/data/structure/public/css/layout/common.css +11 -0
  22. data/data/structure/public/css/layout/default.css +3 -0
  23. data/data/structure/public/css/layout/error.css +3 -0
  24. data/data/structure/public/css/welcome.css +47 -0
  25. data/data/structure/public/favicon.ico +0 -0
  26. data/data/structure/public/img/.gitkeep +0 -0
  27. data/data/structure/public/img/logo.png +0 -0
  28. data/data/structure/public/js/.gitkeep +0 -0
  29. data/data/structure/static/layout/default.tpl +19 -0
  30. data/data/structure/static/layout/error.tpl +15 -0
  31. data/data/structure/static/sass/welcome.scss +52 -0
  32. data/data/structure/static/template/error.tpl +4 -0
  33. data/data/structure/static/template/welcome/index.tpl +26 -0
  34. data/data/structure/tmp/pids/.gitkeep +0 -0
  35. data/lib/loader.rb +83 -0
  36. data/lib/nekonote.rb +9 -0
  37. data/lib/nekonote/cli.rb +702 -0
  38. data/lib/nekonote/cmd_parser.rb +55 -0
  39. data/lib/nekonote/core.rb +116 -0
  40. data/lib/nekonote/env.rb +56 -0
  41. data/lib/nekonote/exception/cli_error.rb +34 -0
  42. data/lib/nekonote/exception/error.rb +75 -0
  43. data/lib/nekonote/exception/handler_error.rb +5 -0
  44. data/lib/nekonote/exception/logger_error.rb +8 -0
  45. data/lib/nekonote/exception/page_cache_error.rb +6 -0
  46. data/lib/nekonote/exception/preference_error.rb +11 -0
  47. data/lib/nekonote/exception/view_error.rb +7 -0
  48. data/lib/nekonote/handler.rb +274 -0
  49. data/lib/nekonote/handler/protected_methods.rb +119 -0
  50. data/lib/nekonote/liquid/tag_env_get.rb +12 -0
  51. data/lib/nekonote/liquid/tag_setting_get.rb +12 -0
  52. data/lib/nekonote/logger.rb +135 -0
  53. data/lib/nekonote/page_cache.rb +111 -0
  54. data/lib/nekonote/preference.rb +215 -0
  55. data/lib/nekonote/puma.rb +131 -0
  56. data/lib/nekonote/rack/rack_static.rb +17 -0
  57. data/lib/nekonote/rack/rack_static_file.rb +19 -0
  58. data/lib/nekonote/rack/url_mapper.rb +193 -0
  59. data/lib/nekonote/rackup.rb +319 -0
  60. data/lib/nekonote/request.rb +295 -0
  61. data/lib/nekonote/setting.rb +59 -0
  62. data/lib/nekonote/spec.rb +22 -0
  63. data/lib/nekonote/util/filer.rb +69 -0
  64. data/lib/nekonote/util/process.rb +43 -0
  65. data/lib/nekonote/view.rb +398 -0
  66. data/lib/nekonote/yaml_access.rb +60 -0
  67. 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