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,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