nekonote-framework 1.0.0.pre.beta

Sign up to get free protection for your applications and to get access to all the features.
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