nyara 0.1.pre.0 → 0.1.pre.1
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 +4 -4
- data/bin/nyara +2 -14
- data/changes +3 -0
- data/example/factorial.rb +19 -0
- data/example/hello.rb +5 -0
- data/example/project.rb +11 -0
- data/example/stream.rb +14 -0
- data/ext/extconf.rb +19 -0
- data/ext/hashes.c +160 -57
- data/ext/inc/ary_intern.h +36 -0
- data/ext/route.cc +2 -1
- data/ext/url_encoded.c +1 -0
- data/lib/nyara.rb +1 -0
- data/lib/nyara/command.rb +60 -79
- data/lib/nyara/config.rb +19 -1
- data/lib/nyara/controller.rb +64 -7
- data/lib/nyara/hashes/config_hash.rb +3 -20
- data/lib/nyara/hashes/header_hash.rb +2 -2
- data/lib/nyara/hashes/param_hash.rb +1 -0
- data/lib/nyara/nyara.rb +45 -37
- data/lib/nyara/part.rb +2 -2
- data/lib/nyara/reload.rb +63 -64
- data/lib/nyara/route.rb +7 -6
- data/lib/nyara/session.rb +4 -0
- data/lib/nyara/templates/{Gemfile → Gemfile.tt} +4 -0
- data/lib/nyara/templates/Linnerfile +28 -0
- data/lib/nyara/templates/Rakefile +16 -2
- data/lib/nyara/templates/app/assets/files/favicon.ico +1 -0
- data/lib/nyara/templates/app/assets/files/robots.txt +5 -0
- data/lib/nyara/templates/app/assets/scripts/app.coffee +4 -0
- data/lib/nyara/templates/app/assets/scripts/module-example.coffee +4 -0
- data/lib/nyara/templates/app/assets/styles/app.scss +2 -0
- data/lib/nyara/templates/app/controllers/application_controller.rb +8 -0
- data/lib/nyara/templates/app/views/layouts/application.erb.tt +12 -0
- data/lib/nyara/templates/config/application.rb +4 -0
- data/lib/nyara/templates/config/{database.yml → database.yml.tt} +3 -3
- data/lib/nyara/templates/config/production.rb +2 -0
- data/lib/nyara/view.rb +6 -2
- data/nyara.gemspec +3 -1
- data/rakefile +7 -26
- data/spec/apps/reload.rb +35 -0
- data/spec/command_spec.rb +24 -10
- data/spec/config_spec.rb +19 -8
- data/spec/controller_spec.rb +14 -0
- data/spec/evented_io_spec.rb +3 -1
- data/spec/ext_route_spec.rb +25 -3
- data/spec/hashes_spec.rb +45 -21
- data/spec/integration_spec.rb +28 -2
- data/spec/path_helper_spec.rb +7 -0
- data/spec/performance_spec.rb +1 -1
- data/spec/public/test.css +1 -0
- data/{lib/nyara/templates/public/robot.txt → spec/public/test.jpg} +0 -0
- data/spec/public/test.js +1 -0
- data/spec/reload_spec.rb +50 -0
- data/spec/route_spec.rb +4 -4
- data/spec/spec_helper.rb +15 -9
- data/spec/url_encoded_spec.rb +5 -0
- data/spec/view_spec.rb +7 -0
- data/spec/views/_partial.slim +1 -1
- data/tools/bug.rb +53 -0
- data/tools/hello.rb +49 -0
- data/tools/memcheck.rb +33 -0
- metadata +73 -41
- data/ext/inc/status_codes.inc +0 -64
- data/lib/nyara/templates/app/views/layouts/application.erb +0 -12
- data/lib/nyara/templates/public/css/app.css +0 -1
- data/lib/nyara/templates/public/js/app.js +0 -1
@@ -0,0 +1,36 @@
|
|
1
|
+
/* array internals, from ruby source code array.c */
|
2
|
+
|
3
|
+
#pragma once
|
4
|
+
|
5
|
+
# define ARY_SHARED_P(ary) \
|
6
|
+
(assert(!FL_TEST((ary), ELTS_SHARED) || !FL_TEST((ary), RARRAY_EMBED_FLAG)), \
|
7
|
+
FL_TEST((ary),ELTS_SHARED)!=0)
|
8
|
+
# define ARY_EMBED_P(ary) \
|
9
|
+
(assert(!FL_TEST((ary), ELTS_SHARED) || !FL_TEST((ary), RARRAY_EMBED_FLAG)), \
|
10
|
+
FL_TEST((ary), RARRAY_EMBED_FLAG)!=0)
|
11
|
+
|
12
|
+
#define ARY_SET_PTR(ary, p) do { \
|
13
|
+
assert(!ARY_EMBED_P(ary)); \
|
14
|
+
assert(!OBJ_FROZEN(ary)); \
|
15
|
+
RARRAY(ary)->as.heap.ptr = (p); \
|
16
|
+
} while (0)
|
17
|
+
#define ARY_SET_EMBED_LEN(ary, n) do { \
|
18
|
+
long tmp_n = (n); \
|
19
|
+
assert(ARY_EMBED_P(ary)); \
|
20
|
+
assert(!OBJ_FROZEN(ary)); \
|
21
|
+
RBASIC(ary)->flags &= ~RARRAY_EMBED_LEN_MASK; \
|
22
|
+
RBASIC(ary)->flags |= (tmp_n) << RARRAY_EMBED_LEN_SHIFT; \
|
23
|
+
} while (0)
|
24
|
+
#define ARY_SET_HEAP_LEN(ary, n) do { \
|
25
|
+
assert(!ARY_EMBED_P(ary)); \
|
26
|
+
RARRAY(ary)->as.heap.len = (n); \
|
27
|
+
} while (0)
|
28
|
+
#define ARY_SET_LEN(ary, n) do { \
|
29
|
+
if (ARY_EMBED_P(ary)) { \
|
30
|
+
ARY_SET_EMBED_LEN((ary), (n)); \
|
31
|
+
} \
|
32
|
+
else { \
|
33
|
+
ARY_SET_HEAP_LEN((ary), (n)); \
|
34
|
+
} \
|
35
|
+
assert(RARRAY_LEN(ary) == (n)); \
|
36
|
+
} while (0)
|
data/ext/route.cc
CHANGED
@@ -254,7 +254,8 @@ RouteResult nyara_lookup_route(enum http_method method_num, VALUE vpath, VALUE a
|
|
254
254
|
if (suffix_len) {
|
255
255
|
r.format = extract_ext(suffix, suffix_len);
|
256
256
|
if (r.format == Qnil) {
|
257
|
-
|
257
|
+
// suffix not match
|
258
|
+
continue;
|
258
259
|
}
|
259
260
|
}
|
260
261
|
r.args = rb_ary_new3(1, i->id);
|
data/ext/url_encoded.c
CHANGED
data/lib/nyara.rb
CHANGED
data/lib/nyara/command.rb
CHANGED
@@ -1,105 +1,86 @@
|
|
1
|
-
require
|
2
|
-
|
3
|
-
module Command
|
4
|
-
extend self
|
1
|
+
require "thor"
|
2
|
+
require "shellwords"
|
5
3
|
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
module Nyara
|
5
|
+
class Command < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
map '-v' => :version
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
nyara new APP_NAME\t\tTo initialize a new project with default template in current directory.
|
13
|
-
nyara version\t\t\tDisplay current version
|
14
|
-
)
|
9
|
+
def self.source_root
|
10
|
+
__dir__
|
15
11
|
end
|
16
12
|
|
13
|
+
desc "version", "Show version"
|
17
14
|
def version
|
18
15
|
puts "Nyara #{Nyara::VERSION}"
|
19
16
|
end
|
20
17
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
force: false
|
25
|
-
}
|
26
|
-
OptionParser.new do |opt|
|
27
|
-
opt.banner = 'Usage: nyara new APP_NAME [options]'
|
28
|
-
opt.on('-f', 'Force override old') do
|
29
|
-
opts[:force] = true
|
30
|
-
end
|
31
|
-
end.parse(args)
|
32
|
-
|
18
|
+
desc "new APP_NAME", "Create a project"
|
19
|
+
method_option :force, aliases: '-f', desc: 'Force override old', type: :boolean, default: false
|
20
|
+
def new name
|
33
21
|
require 'fileutils'
|
34
|
-
require "erb"
|
35
|
-
require 'ostruct'
|
36
|
-
require_relative "view_handlers/erb"
|
37
22
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
return
|
42
|
-
end
|
43
|
-
|
44
|
-
app_dir = File.join(Dir.pwd, name)
|
23
|
+
app_dir = File.expand_path File.join(Dir.pwd, name)
|
24
|
+
@rel_dir = name
|
25
|
+
@app_name = File.basename app_dir
|
45
26
|
templte_dir = File.join(File.dirname(__FILE__), "templates")
|
46
27
|
|
47
|
-
FileUtils.rm_rf(app_dir) if
|
48
|
-
|
49
|
-
if Dir.exist?(app_dir)
|
50
|
-
puts "This has same dir name's '#{name}' existed, Nyara can not override it."
|
51
|
-
return
|
52
|
-
end
|
53
|
-
|
54
|
-
Dir.mkdir(app_dir)
|
55
|
-
|
56
|
-
puts "Generate Nyara project..."
|
57
|
-
source_templates = Dir.glob("#{templte_dir}/*")
|
58
|
-
puts source_templates.map{|f| File.basename f }
|
59
|
-
FileUtils.cp_r(source_templates, app_dir)
|
28
|
+
FileUtils.rm_rf(app_dir) if options[:force]
|
29
|
+
directory 'templates', name
|
60
30
|
|
61
|
-
|
62
|
-
|
63
|
-
render_opts = {
|
64
|
-
app_name: name
|
65
|
-
}
|
66
|
-
files.each do |fname|
|
67
|
-
if not File.directory?(fname)
|
68
|
-
render_template(fname, render_opts)
|
69
|
-
end
|
31
|
+
create_file app_dir + '/.gitignore' do
|
32
|
+
%w".DS_Store config/session.key config/session_cipher.key".join "\n"
|
70
33
|
end
|
34
|
+
generate 'session.key'
|
35
|
+
puts ' \\ 👻 /'
|
36
|
+
ensure
|
37
|
+
@app_name = nil
|
38
|
+
@rel_dir = nil
|
39
|
+
end
|
71
40
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
41
|
+
desc "generate THING", "(PROJECT) Generate things, THING can be:
|
42
|
+
session.key # config/session.key
|
43
|
+
session_cipher.key # config/session_cipher.key"
|
44
|
+
def generate thing, app_dir=nil
|
45
|
+
case thing
|
46
|
+
when 'session.key'
|
47
|
+
file = "config/session.key"
|
48
|
+
file = File.join @rel_dir, file if @rel_dir
|
49
|
+
create_file file do
|
50
|
+
Session.generate_key
|
76
51
|
end
|
77
|
-
|
78
|
-
|
79
|
-
File.
|
80
|
-
|
81
|
-
|
52
|
+
when 'session_cipher.key'
|
53
|
+
file = 'config/session_cipher.key'
|
54
|
+
file = File.join @rel_dir, file if @rel_dir
|
55
|
+
create_file file do
|
56
|
+
Session.generate_cipher_key
|
82
57
|
end
|
83
58
|
end
|
84
|
-
|
85
|
-
puts "Enjoy!"
|
86
59
|
end
|
87
60
|
|
88
|
-
|
89
|
-
|
90
|
-
|
61
|
+
desc "server", "(PROJECT) Start server"
|
62
|
+
method_option :environment, aliases: %w'-e -E', default: 'development'
|
63
|
+
def server
|
64
|
+
env = options[:environment].shellescape
|
65
|
+
exec "NYARA_ENV=#{env} ruby config/boot.rb"
|
91
66
|
end
|
92
67
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
68
|
+
desc "console", "(PROJECT) Start console"
|
69
|
+
method_option :environment, aliases: %w'-e -E', default: 'development'
|
70
|
+
method_option :shell, aliases: '-s', desc: "tell me which shell you want to use, pry or irb?"
|
71
|
+
def console
|
72
|
+
env = options[:environment].shellescape
|
73
|
+
cmd = options[:shell]
|
74
|
+
unless cmd
|
75
|
+
if File.read('Gemfile') =~ /\bpry\b/
|
76
|
+
cmd = 'pry'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
cmd ||= 'irb'
|
80
|
+
if cmd != 'irb'
|
81
|
+
cmd = "bundle exec #{cmd}"
|
102
82
|
end
|
83
|
+
exec "NYARA_ENV=#{env} #{cmd} -r./config/application.rb"
|
103
84
|
end
|
104
85
|
|
105
86
|
end
|
data/lib/nyara/config.rb
CHANGED
@@ -7,11 +7,14 @@ module Nyara
|
|
7
7
|
# * `host` - host name used in `url_to` helper
|
8
8
|
# * `root` - root path, default is `Dir.pwd`
|
9
9
|
# * `views` - views (templates) directory, relative to root, default is `"views"`
|
10
|
+
# * `assets` - assets directory, relative to root, default is `"assets"`
|
10
11
|
# * `public` - static files directory, relative to root, default is `"public"`
|
11
12
|
# * `x_send_file` - header field name for `X-Sendfile` or `X-Accel-Redirect`, see [Nyara::Controller#send_file](Controller#send_file.html-instance_method) for details
|
12
13
|
# * `session` - see [Nyara::Session](Session.html) for sub options
|
13
14
|
# * `prefer_erb` - use ERB instead of ERubis for `.erb` templates
|
14
15
|
# * `logger` - if set, every request is logged, and you can use `Nyara.logger` to do your own logging.
|
16
|
+
# * `app_files` - application source file glob patterns, they will be required automatically.
|
17
|
+
# In developemnt mode, this option enables automatic reloading for views and app.
|
15
18
|
# * `before_fork` - a proc to run before forking
|
16
19
|
# * `after_fork` - a proc to run after forking
|
17
20
|
#
|
@@ -51,13 +54,18 @@ module Nyara
|
|
51
54
|
unless self['root']
|
52
55
|
set :root, Dir.pwd
|
53
56
|
end
|
54
|
-
self['root'] = File.expand_path self['root']
|
57
|
+
self['root'] = File.realpath File.expand_path self['root']
|
55
58
|
|
59
|
+
# todo warn paths not under project?
|
56
60
|
self['views'] = project_path(self['views'] || 'views')
|
57
61
|
if self['public']
|
58
62
|
self['public'] = project_path(self['public'])
|
59
63
|
end
|
60
64
|
|
65
|
+
if self['assets']
|
66
|
+
self['assets'] = project_path(self['assets'])
|
67
|
+
end
|
68
|
+
|
61
69
|
self.logger = create_logger
|
62
70
|
|
63
71
|
assert !self['before_fork'] || self['before_fork'].respond_to?('call')
|
@@ -111,6 +119,16 @@ module Nyara
|
|
111
119
|
path_under 'views', path, strict
|
112
120
|
end
|
113
121
|
|
122
|
+
# Get absoute path under assets path
|
123
|
+
#
|
124
|
+
# #### Options
|
125
|
+
#
|
126
|
+
# * `strict` - return `nil` if path is not under the dir
|
127
|
+
#
|
128
|
+
def assets_path path, strict=true
|
129
|
+
path_under "assets", path, strict
|
130
|
+
end
|
131
|
+
|
114
132
|
# Get path under the dir configured `Nyara.config[key]`
|
115
133
|
#
|
116
134
|
# #### Options
|
data/lib/nyara/controller.rb
CHANGED
@@ -9,6 +9,11 @@ module Nyara
|
|
9
9
|
# end
|
10
10
|
#
|
11
11
|
def http method, path, &blk
|
12
|
+
# special treatment: '/' also maps ''
|
13
|
+
if path == '/'
|
14
|
+
http method, '', &blk
|
15
|
+
end
|
16
|
+
|
12
17
|
@routes ||= []
|
13
18
|
@used_ids = {}
|
14
19
|
method = method.to_s.upcase
|
@@ -164,6 +169,40 @@ module Nyara
|
|
164
169
|
end
|
165
170
|
end
|
166
171
|
|
172
|
+
def self.process_reload request, l
|
173
|
+
if request.http_method == 'POST' and request.path =~ /\A\/reload:([\w-]+)\z/
|
174
|
+
ty = $1
|
175
|
+
files = request.param['files']
|
176
|
+
case ty
|
177
|
+
when 'views-modified'
|
178
|
+
files.each do |f|
|
179
|
+
if l
|
180
|
+
l.info "modified: #{f}"
|
181
|
+
end
|
182
|
+
View.on_removed f
|
183
|
+
View.on_modified f
|
184
|
+
end
|
185
|
+
when 'views-removed'
|
186
|
+
files.each do |f|
|
187
|
+
if l
|
188
|
+
l.info "removed: #{f}"
|
189
|
+
end
|
190
|
+
View.on_removed f
|
191
|
+
end
|
192
|
+
when 'app-modified'
|
193
|
+
files.each do |f|
|
194
|
+
if l
|
195
|
+
l.info "modified: #{f}"
|
196
|
+
end
|
197
|
+
Reload.load_file f
|
198
|
+
end
|
199
|
+
else
|
200
|
+
return false
|
201
|
+
end
|
202
|
+
true
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
167
206
|
def self.dispatch request, instance, args
|
168
207
|
if cookie_str = request.header._aref('Cookie')
|
169
208
|
ParamHash.parse_cookie request.cookie, cookie_str
|
@@ -172,25 +211,35 @@ module Nyara
|
|
172
211
|
request.session = Session.decode(request.cookie)
|
173
212
|
)
|
174
213
|
|
214
|
+
l = Nyara.logger
|
215
|
+
|
175
216
|
if instance
|
176
|
-
if l
|
217
|
+
if l
|
177
218
|
l.info "#{request.http_method} #{request.path} => #{instance.class}"
|
219
|
+
if %W"POST PUT PATCH".include?(request.http_method)
|
220
|
+
l.info " params: #{instance.params.inspect}"
|
221
|
+
end
|
178
222
|
end
|
179
223
|
instance.send *args
|
180
224
|
return
|
181
225
|
elsif request.http_method == 'GET' and Config['public']
|
182
226
|
path = Config.public_path request.path
|
183
227
|
if File.file?(path)
|
184
|
-
if l
|
185
|
-
l.info "GET #{path} => public 200"
|
228
|
+
if l
|
229
|
+
l.info "GET #{request.path} => public 200"
|
186
230
|
end
|
187
231
|
instance = Controller.new request
|
188
232
|
instance.send_file path
|
189
233
|
return
|
190
234
|
end
|
235
|
+
elsif Config.development?
|
236
|
+
if process_reload(request, l)
|
237
|
+
Ext.request_send_data request, "HTTP/1.1 200 OK\r\n\r\n"
|
238
|
+
return
|
239
|
+
end
|
191
240
|
end
|
192
241
|
|
193
|
-
if l
|
242
|
+
if l
|
194
243
|
l.info "#{request.http_method} #{request.path} => 404"
|
195
244
|
end
|
196
245
|
Ext.request_send_data request, "HTTP/1.1 404 Not Found\r\nConnection: close\r\nContent-Length: 0\r\n\r\n"
|
@@ -207,6 +256,9 @@ module Nyara
|
|
207
256
|
end
|
208
257
|
|
209
258
|
template, meth = self.class.path_templates[id.to_s]
|
259
|
+
if template.blank? && meth.blank?
|
260
|
+
raise ArgumentError, "#{id} route not found."
|
261
|
+
end
|
210
262
|
r = template % args
|
211
263
|
|
212
264
|
if opts
|
@@ -273,8 +325,11 @@ module Nyara
|
|
273
325
|
end
|
274
326
|
|
275
327
|
# Shortcut for `redirect url_to *xs`
|
276
|
-
def redirect_to *xs
|
277
|
-
|
328
|
+
def redirect_to identifier, *xs
|
329
|
+
if identifier !~ /\A\w*#\w++(?:\-\w++)*\z/
|
330
|
+
raise ArgumentError, "not action identifier: #{identifier.inspect}, did you mean `redirect`?"
|
331
|
+
end
|
332
|
+
redirect url_to(identifier, *xs)
|
278
333
|
end
|
279
334
|
|
280
335
|
# Stop processing and close connection<br>
|
@@ -479,6 +534,8 @@ module Nyara
|
|
479
534
|
unless content_type
|
480
535
|
extname = File.extname(file)
|
481
536
|
extname = File.extname(filename) if extname.blank? and filename
|
537
|
+
extname.gsub!(".","")
|
538
|
+
|
482
539
|
content_type = MIME_TYPES[extname] || 'application/octet-stream'
|
483
540
|
end
|
484
541
|
header['Content-Type'] = content_type
|
@@ -526,7 +583,7 @@ module Nyara
|
|
526
583
|
|
527
584
|
# Render a template as string
|
528
585
|
def partial view_path, locals: nil
|
529
|
-
view = View.new self, view_path, nil,
|
586
|
+
view = View.new self, view_path, nil, locals, {}
|
530
587
|
view.partial
|
531
588
|
end
|
532
589
|
|
@@ -1,33 +1,16 @@
|
|
1
1
|
module Nyara
|
2
2
|
# Extended hash class for the use in configuration.
|
3
3
|
class ConfigHash
|
4
|
-
# @private
|
5
|
-
alias _aref [] # :nodoc:
|
6
|
-
# @private
|
7
|
-
alias _aset []= # :nodoc:
|
8
|
-
|
9
4
|
# #### Call-seq
|
10
5
|
#
|
11
|
-
# config['a', 'very', 'deep', 'key']
|
6
|
+
# config['a', 'very', 'deep', '', 'key']
|
12
7
|
#
|
13
8
|
# Equivalent to
|
14
9
|
#
|
15
|
-
# config['a']['very']['deep']['key'] rescue nil
|
10
|
+
# config['a']['very']['deep'].last['key'] rescue nil
|
16
11
|
#
|
17
12
|
def [] *keys
|
18
|
-
|
19
|
-
keys.each do |key|
|
20
|
-
if h.has_key?(key)
|
21
|
-
if h.is_a?(ConfigHash)
|
22
|
-
h = h._aref key
|
23
|
-
else
|
24
|
-
h = h[key]
|
25
|
-
end
|
26
|
-
else
|
27
|
-
return nil # todo default value?
|
28
|
-
end
|
29
|
-
end
|
30
|
-
h
|
13
|
+
nested_aref keys.map(&:to_s)
|
31
14
|
end
|
32
15
|
|
33
16
|
# #### Call-seq
|