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,398 @@
1
+ module Nekonote
2
+ # define original liquid tag
3
+ ::Liquid::Template.register_tag 'env_get', TagEnvGet
4
+ ::Liquid::Template.register_tag 'setting_get', TagSettingGet
5
+
6
+ class View
7
+ NO_USING_NAME = 'none'
8
+ DEFAULT_LAYOUT_NAME = 'default'
9
+ PATH_TO_TEMPLATE = 'static/template'
10
+ PATH_TO_LAYOUT = 'static/layout'
11
+
12
+ # accessor
13
+ attr_accessor :is_redirect
14
+ attr_reader :is_error_route,
15
+ :info_path,
16
+ :info_exec_method,
17
+ :info_allow_methods,
18
+ :info_params,
19
+ :info_content_type,
20
+ :info_template,
21
+ :info_layout,
22
+ :info_page_cache_time
23
+
24
+ # @return array
25
+ def self.get_default_error_response
26
+ return [
27
+ 500,
28
+ {
29
+ },
30
+ []
31
+ ]
32
+ end
33
+
34
+ # @param hash info
35
+ # @param string handler_name
36
+ # @param nil|string error_field_name
37
+ def initialize(info, handler_name, error_field_name = nil)
38
+ register_info_properies info
39
+
40
+ # initialize response
41
+ init_for_response
42
+
43
+ # check error route or not?
44
+ if error_field_name.is_a? String
45
+ @is_error_route = true
46
+ # set default response code for error (users can customize it on concrete handlers).
47
+ set_code get_error_response_code(error_field_name)
48
+ else
49
+ @is_error_route = false
50
+ end
51
+
52
+ # set template
53
+ if @info_template.is_a? String
54
+ # use template described in route.yml
55
+ @template_path = Nekonote.get_root_path + PATH_TO_TEMPLATE + '/' + @info_template + '.tpl'
56
+ elsif @info_template == nil
57
+ # set default if no template is specified
58
+ @template_path = get_default_template_path handler_name
59
+ else
60
+ # no template with response
61
+ @template_path = nil
62
+ end
63
+
64
+ # set layout
65
+ if @info_layout.is_a? String
66
+ # use layout described in route.yml
67
+ @layout_path = Nekonote.get_root_path + PATH_TO_LAYOUT + '/' + @info_layout + '.tpl'
68
+ elsif @info_layout == nil
69
+ # if no layout is specified, try to use default layout
70
+ @layout_path = Nekonote.get_root_path + PATH_TO_LAYOUT + '/' + DEFAULT_LAYOUT_NAME + '.tpl'
71
+ if !Util::Filer.available_file? @layout_path
72
+ # but if it's not available, no layout with response
73
+ @layout_path = nil
74
+ end
75
+ else
76
+ # no layout with response
77
+ @layout_path = nil
78
+ end
79
+
80
+ # assign extra fields into templates
81
+ assign_custom_fields info
82
+ end
83
+
84
+ # Initialize stored information about response
85
+ public
86
+ def init_for_response
87
+ @response = ::Rack::Response.new
88
+ set_content_type @info_content_type
89
+
90
+ # initialize the properties
91
+ @is_body_set = false
92
+ @is_redirect = false
93
+ end
94
+
95
+ # Is page cache enabled for this route.
96
+ # @return bool
97
+ public
98
+ def enable_page_cache?
99
+ return @info_page_cache_time.is_a? Integer
100
+ end
101
+
102
+ # Need to create page cache?
103
+ # @param string uri
104
+ # @return bool
105
+ public
106
+ def need_create_page_cache?(uri)
107
+ return enable_page_cache? && !PageCache.instance.has_available_cache?(uri, @info_page_cache_time)
108
+ end
109
+
110
+ # Is it Allowed to gets response data from page cache for givevn uri?
111
+ # @param string uri
112
+ # @return bool
113
+ public
114
+ def can_get_from_page_cache?(uri)
115
+ return enable_page_cache? && PageCache.instance.has_available_cache?(uri, @info_page_cache_time)
116
+ end
117
+
118
+ # Makes page cache file
119
+ # @param string uri
120
+ public
121
+ def create_page_cache(uri)
122
+ PageCache.instance.make_cache(
123
+ uri,
124
+ @response.status,
125
+ @response.header,
126
+ @response.body
127
+ )
128
+ end
129
+
130
+ # @return array
131
+ public
132
+ def get_response_data
133
+ return @response.finish
134
+ end
135
+
136
+ # Gets response data for given uri from page cache
137
+ # @param string uri
138
+ public
139
+ def get_response_data_from_page_cache(uri)
140
+ return PageCache.instance.get_page_cache uri
141
+ end
142
+
143
+ # @return string
144
+ public
145
+ def set_body_with_tpl
146
+ # if nil is given for layout and/or template, No template and/or layout will be used
147
+ if @template_path != nil && !Util::Filer.available_file?(@template_path)
148
+ raise ViewError, ViewError::MSG_MISSING_TEMPLATE_FILE% @template_path
149
+ end
150
+
151
+ if @layout_path != nil && !Util::Filer.available_file?(@layout_path)
152
+ raise ViewError, ViewError::MSG_MISSING_LAYOUT_FILE% @layout_path
153
+ end
154
+
155
+ @response.write get_parsed(@template_path, @layout_path)
156
+ end
157
+
158
+ # @param string|symbol subject
159
+ # @param mixed value
160
+ public
161
+ def set_header(subject, value)
162
+ subject = subject.to_s if subject.is_a?(Symbol)
163
+ raise ViewError, ViewError::MSG_WRONG_TYPE%[subject.class, 'String or Symbol'] if !subject.is_a?(String)
164
+ @response[subject] = value
165
+ end
166
+
167
+ # @param string type
168
+ public
169
+ def set_content_type(type)
170
+ @response['Content-Type'] = get_content_type type
171
+ end
172
+
173
+ # @param string|symbol subject
174
+ # @param mixed value
175
+ # @param string delimiter
176
+ public
177
+ def add_header(subject, value, delimiter)
178
+ subject = subject.to_s if subject.is_a?(Symbol)
179
+ raise ViewError, ViewError::MSG_WRONG_TYPE%[subject.class, 'String or Symbol'] if !subject.is_a?(String)
180
+ raise ViewError, ViewError::MSG_WRONG_TYPE%[delimiter.class, 'String'] if !delimiter.is_a?(String)
181
+
182
+ if @response.header.has_key? subject
183
+ @response[subject] = "#{@response[subject]}#{delimiter}#{value}"
184
+ else
185
+ set_header subject, value
186
+ end
187
+ end
188
+
189
+ # @param int code
190
+ public
191
+ def set_code(code)
192
+ begin
193
+ code = code.to_i if !code.is_a?(Fixnum)
194
+ rescue
195
+ raise ViewError, ViewError::MSG_WRONG_TYPE%[code.class, 'Fixnum or convertible types into Fixnum']
196
+ end
197
+ @response.status = code
198
+ end
199
+
200
+ # @param string body
201
+ public
202
+ def set_body(body)
203
+ if !body.is_a?(String)
204
+ begin
205
+ body = body.to_s
206
+ rescue
207
+ raise ViewError, ViewError::MSG_WRONG_TYPE%[body.class, 'String or convertible types into Fixnum']
208
+ end
209
+ end
210
+ @response.body = []
211
+ @response.write body
212
+ @is_body_set = true
213
+ end
214
+
215
+ # @param string body
216
+ public
217
+ def add_body(body)
218
+ if !body.is_a?(String)
219
+ begin
220
+ body = body.to_s
221
+ rescue
222
+ raise ViewError, ViewError::MSG_WRONG_TYPE%[body.class, 'String or convertible types into String']
223
+ end
224
+ end
225
+ @response.write body
226
+ @is_body_set = true
227
+ end
228
+
229
+ # is set something for response body?
230
+ public
231
+ def is_body_set?
232
+ return @is_body_set
233
+ end
234
+
235
+ # assign mapping into teplate and/or layout
236
+ # when already exst mapping it would be merged
237
+ # @param hash list
238
+ # @throw ::Nekonote::Error
239
+ public
240
+ def assign_variables(list)
241
+ if !list.is_a? Hash
242
+ raise ViewError, ViewError::MSG_FAILED_TO_ASSIGN
243
+ end
244
+
245
+ # convert symbol key to string key
246
+ list_cnv = {}
247
+ list.map {|pair| list_cnv[pair[0].to_s] = pair[1] }
248
+
249
+ if defined?(@mapping) && @mapping.is_a?(Hash)
250
+ @mapping.merge! list_cnv
251
+ else
252
+ @mapping = list_cnv
253
+ end
254
+ end
255
+
256
+ # assign custom fields into teplate and/or layout
257
+ # @param bool is_error_route
258
+ public
259
+ def assign_custom_fields(info)
260
+ fields = Preference.get_custom_fields info, @is_error_route
261
+ if fields.is_a?(Hash)
262
+ assign_variables fields
263
+ end
264
+ end
265
+
266
+ # @param hash info
267
+ private
268
+ def register_info_properies(info)
269
+ @info_path = info[Preference::FIELD_ROUTE_PATH]
270
+ @info_exec_method = info[Preference::FIELD_ROUTE_EXEC_METHOD]
271
+ @info_allow_methods = info[Preference::FIELD_ROUTE_ALLOW_METHODS]
272
+ @info_params = info[Preference::FIELD_ROUTE_PARAMS]
273
+ @info_content_type = info[Preference::FIELD_ROUTE_CONTENT_TYPE]
274
+ @info_template = info[Preference::FIELD_ROUTE_TEMPLATE]
275
+ @info_layout = info[Preference::FIELD_ROUTE_LAYOUT]
276
+ @info_page_cache_time = info[Preference::FIELD_ROUTE_PAGE_CACHE_TIME]
277
+ end
278
+
279
+ # initialize the properties
280
+ private
281
+ def init_property
282
+ @is_body_set = false
283
+ @is_redirect = false
284
+ end
285
+
286
+ # Returns template path for the default when it was found and available
287
+ # @param string|nil
288
+ private
289
+ def get_default_template_path(handler_name)
290
+ return nil if !handler_name.is_a? String
291
+
292
+ # get default template path when no template specified
293
+ begin
294
+ template = handler_name.sub(/Handler$/, '').gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
295
+ rescue
296
+ template = nil
297
+ end
298
+
299
+ # invalid template
300
+ return nil if (template.nil? || template == '')
301
+
302
+ template_path = Nekonote.get_root_path + PATH_TO_TEMPLATE + '/' + template + '.tpl'
303
+ if Util::Filer.available_file? template_path
304
+ template_path = template_path
305
+ else
306
+ template_path = nil
307
+ end
308
+
309
+ return template_path
310
+ end
311
+
312
+ # @param string type
313
+ # @return string
314
+ private
315
+ def get_content_type(type)
316
+ type = type.intern if type.is_a?(String)
317
+
318
+ content_type = 'text/plain'
319
+ if type == nil
320
+ content_type = 'text/html'
321
+ elsif type == :html
322
+ content_type = 'text/html'
323
+ elsif type == :json
324
+ content_type = 'application/json'
325
+ elsif type == :xml
326
+ content_type = 'application/xml'
327
+ elsif type == :plain
328
+ content_type = 'text/plain'
329
+ end
330
+ return content_type
331
+ end
332
+
333
+ # @param string field
334
+ private
335
+ def get_error_response_code(field)
336
+ case field
337
+ when Preference::FIELD_ROUTE_ERR_MISSING_ROUTE
338
+ return 404
339
+ when Preference::FIELD_ROUTE_ERR_WRONG_METHOD
340
+ return 405
341
+ when Preference::FIELD_ROUTE_ERR_FATAL
342
+ return 500
343
+ when Preference::FIELD_ROUTE_ERR_NOT_FOUND
344
+ return 404
345
+ else
346
+ raise PreferenceError, PreferenceError::MSG_UNDEFINED_FIELD% field
347
+ end
348
+ end
349
+
350
+ # @param string|nil template_path
351
+ # @param string|nil layout_path
352
+ # @return string
353
+ private
354
+ def get_parsed(template_path = nil, layout_path = nil)
355
+ data = ''
356
+ liq_tpl_template = nil
357
+ liq_tpl_layout = nil
358
+ begin
359
+ if template_path.is_a? String
360
+ liq_tpl_template = Liquid::Template.parse IO.read(template_path)
361
+ end
362
+
363
+ if layout_path.is_a? String
364
+ liq_tpl_layout = Liquid::Template.parse IO.read(layout_path)
365
+ end
366
+
367
+ # parse and render template
368
+ if liq_tpl_template.is_a? Liquid::Template
369
+ content = liq_tpl_template.render @mapping
370
+ else
371
+ content = nil
372
+ end
373
+
374
+ # parse and render layout
375
+ if liq_tpl_layout.is_a? Liquid::Template
376
+ if content != nil
377
+ # assgin tempalte for layout
378
+ mapping = {
379
+ 'content' => content
380
+ }
381
+ # and put it to @mapping
382
+ @mapping.merge! mapping
383
+ end
384
+ data = liq_tpl_layout.render @mapping
385
+
386
+ else
387
+ # if template data is available set it to data
388
+ data = content if content != nil
389
+ end
390
+
391
+ rescue => e
392
+ raise ViewError, e.message
393
+ end
394
+
395
+ return data
396
+ end
397
+ end
398
+ end
@@ -0,0 +1,60 @@
1
+ module Nekonote
2
+ class YamlAccess
3
+ DIR_PREFERENCE = 'preference'
4
+
5
+ # @param string path
6
+ # @return hash
7
+ def self.get_parsed(path)
8
+ if !Util::Filer.available_file? path
9
+ return nil
10
+ end
11
+
12
+ begin
13
+ contents = YAML.load_file path
14
+ contents = {} if (!contents.is_a? Hash)
15
+ return contents
16
+
17
+ rescue Psych::SyntaxError => e
18
+ msg = PreferenceError::MSG_WRONG_YAML_SYNTAX% path
19
+ msg += $/ + $/ + e.message
20
+ raise PreferenceError, msg
21
+ end
22
+ end
23
+
24
+ # Returns the parsed routing information
25
+ # @param string path
26
+ def self.get_parsed_route(path)
27
+ if !Util::Filer.available_file? path
28
+ return nil
29
+ end
30
+
31
+ begin
32
+ ast = YAML.parse_file path
33
+
34
+ route_list = []
35
+ ast.root.children.each_with_index do |node, index|
36
+ cnt = index / 2
37
+ if node.is_a?(Psych::Nodes::Scalar) && node.value != Preference::FIELD_OPTION_ROUTE
38
+ route_list[cnt] = {Preference::FIELD_ROUTE_HANDLER => node.value}
39
+ elsif node.is_a? Psych::Nodes::Mapping
40
+ if route_list[cnt].is_a? Hash
41
+ route_list[cnt] = route_list[cnt].merge node.to_ruby
42
+ end
43
+ end
44
+ end
45
+
46
+ parsed = []
47
+ route_list.each do |info|
48
+ parsed << info if info.is_a?(Hash)
49
+ end
50
+
51
+ return parsed
52
+
53
+ rescue Psych::SyntaxError => e
54
+ msg = PreferenceError::MSG_WRONG_YAML_SYNTAX% path
55
+ msg += $/ + $/ + e.message
56
+ raise PreferenceError, msg
57
+ end
58
+ end
59
+ end
60
+ end