nyara 0.0.1.pre.9 → 0.1.pre.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/nyara +3 -3
- data/changes +1 -0
- data/ext/event.c +16 -22
- data/ext/hashes.c +222 -4
- data/ext/inc/rdtsc.h +56 -0
- data/ext/inc/status_codes.inc +64 -0
- data/ext/inc/version.inc +1 -1
- data/ext/nyara.c +12 -10
- data/ext/nyara.h +5 -5
- data/ext/request.c +18 -24
- data/ext/request_parse.c +1 -1
- data/ext/route.cc +2 -4
- data/ext/url_encoded.c +51 -193
- data/lib/nyara/command.rb +39 -12
- data/lib/nyara/config.rb +10 -10
- data/lib/nyara/controller.rb +60 -14
- data/lib/nyara/cookie.rb +1 -1
- data/lib/nyara/hashes/config_hash.rb +2 -24
- data/lib/nyara/nyara.rb +33 -19
- data/lib/nyara/part.rb +7 -3
- data/lib/nyara/reload.rb +85 -0
- data/lib/nyara/request.rb +1 -1
- data/lib/nyara/route.rb +55 -19
- data/lib/nyara/templates/Gemfile +10 -1
- data/lib/nyara/templates/Rakefile +6 -1
- data/lib/nyara/templates/app/controllers/application_controller.rb +3 -0
- data/lib/nyara/templates/app/controllers/welcome_controller.rb +5 -0
- data/lib/nyara/templates/app/views/layouts/application.erb +12 -0
- data/lib/nyara/templates/app/views/welcome/index.erb +1 -0
- data/lib/nyara/templates/config/application.rb +34 -0
- data/lib/nyara/templates/config/boot.rb +4 -0
- data/lib/nyara/templates/config/development.rb +5 -0
- data/lib/nyara/templates/config/production.rb +8 -0
- data/lib/nyara/templates/config/test.rb +2 -0
- data/lib/nyara/templates/public/css/app.css +1 -0
- data/lib/nyara/templates/public/js/app.js +1 -0
- data/lib/nyara/templates/spec/spec_helper.rb +9 -0
- data/lib/nyara/test.rb +10 -2
- data/lib/nyara/view.rb +116 -67
- data/nyara.gemspec +3 -1
- data/rakefile +1 -1
- data/readme.md +1 -1
- data/spec/command_spec.rb +28 -24
- data/spec/config_spec.rb +24 -1
- data/spec/dummy/app/controllers/dummy_controller.rb +2 -0
- data/spec/dummy/app/models/dmmy_model.rb +2 -0
- data/spec/evented_io_spec.rb +2 -1
- data/spec/ext_route_spec.rb +2 -2
- data/spec/flash_spec.rb +8 -0
- data/spec/hashes_spec.rb +127 -0
- data/spec/integration_spec.rb +15 -0
- data/spec/path_helper_spec.rb +17 -5
- data/spec/performance/escape.rb +15 -4
- data/spec/performance/layout_render.rb +15 -10
- data/spec/performance/parse_accept_value.rb +24 -8
- data/spec/performance/parse_param.rb +14 -8
- data/spec/performance/performance_helper.rb +8 -21
- data/spec/performance_spec.rb +5 -4
- data/spec/route_spec.rb +7 -2
- data/spec/url_encoded_spec.rb +18 -74
- data/spec/view_spec.rb +1 -3
- data/spec/views/_partial.slim +1 -0
- data/spec/views/_partial_with_yield.erb +1 -0
- metadata +73 -43
- data/example/factorial.rb +0 -19
- data/example/hello.rb +0 -5
- data/example/project.rb +0 -11
- data/example/stream.rb +0 -14
- data/lib/nyara/controllers/public_controller.rb +0 -14
- data/lib/nyara/templates/config/session.key +0 -1
- data/tools/bench-cookie.rb +0 -22
- data/tools/foo.rb +0 -9
- data/tools/hello.rb +0 -46
- data/tools/memcheck.rb +0 -33
- data/tools/s.rb +0 -11
data/lib/nyara/command.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'optparse'
|
1
2
|
module Nyara
|
2
3
|
module Command
|
3
4
|
extend self
|
@@ -9,9 +10,6 @@ module Nyara
|
|
9
10
|
commands:
|
10
11
|
nyara help\t\t\tShow this message
|
11
12
|
nyara new APP_NAME\t\tTo initialize a new project with default template in current directory.
|
12
|
-
options:
|
13
|
-
-f\t\t\tForce override if same name path existed
|
14
|
-
|
15
13
|
nyara version\t\t\tDisplay current version
|
16
14
|
)
|
17
15
|
end
|
@@ -20,23 +18,33 @@ commands:
|
|
20
18
|
puts "Nyara #{Nyara::VERSION}"
|
21
19
|
end
|
22
20
|
|
23
|
-
def new_project(
|
21
|
+
def new_project(*args)
|
24
22
|
args ||= []
|
25
|
-
|
23
|
+
opts = {
|
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
|
+
|
26
33
|
require 'fileutils'
|
27
34
|
require "erb"
|
28
35
|
require 'ostruct'
|
29
36
|
require_relative "view_handlers/erb"
|
30
37
|
|
38
|
+
name = args.shift
|
31
39
|
if name.blank?
|
32
40
|
puts "Need project name: \n\tnyara new xxx"
|
33
41
|
return
|
34
42
|
end
|
35
43
|
|
36
|
-
app_dir = File.join(Dir.pwd,name)
|
37
|
-
templte_dir = File.join(File.dirname(__FILE__),"templates")
|
44
|
+
app_dir = File.join(Dir.pwd, name)
|
45
|
+
templte_dir = File.join(File.dirname(__FILE__), "templates")
|
38
46
|
|
39
|
-
FileUtils.rm_rf(app_dir) if
|
47
|
+
FileUtils.rm_rf(app_dir) if opts[:force]
|
40
48
|
|
41
49
|
if Dir.exist?(app_dir)
|
42
50
|
puts "This has same dir name's '#{name}' existed, Nyara can not override it."
|
@@ -46,8 +54,9 @@ commands:
|
|
46
54
|
Dir.mkdir(app_dir)
|
47
55
|
|
48
56
|
puts "Generate Nyara project..."
|
49
|
-
|
50
|
-
|
57
|
+
source_templates = Dir.glob("#{templte_dir}/*")
|
58
|
+
puts source_templates.map{|f| File.basename f }
|
59
|
+
FileUtils.cp_r(source_templates, app_dir)
|
51
60
|
|
52
61
|
# render template
|
53
62
|
files = Dir.glob("#{app_dir}/**/*")
|
@@ -56,13 +65,31 @@ commands:
|
|
56
65
|
}
|
57
66
|
files.each do |fname|
|
58
67
|
if not File.directory?(fname)
|
59
|
-
render_template(fname,render_opts)
|
68
|
+
render_template(fname, render_opts)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
Dir.chdir app_dir do
|
73
|
+
puts "config/session.key"
|
74
|
+
File.open 'config/session.key', 'wb' do |f|
|
75
|
+
f << Session.generate_key
|
76
|
+
end
|
77
|
+
|
78
|
+
puts ".gitignore"
|
79
|
+
File.open '.gitignore', 'w' do |f|
|
80
|
+
f.puts ".DS_Store"
|
81
|
+
f.puts "config/session.key"
|
60
82
|
end
|
61
83
|
end
|
62
84
|
|
63
85
|
puts "Enjoy!"
|
64
86
|
end
|
65
87
|
|
88
|
+
def run_server(*args)
|
89
|
+
args ||= []
|
90
|
+
system("bundle exec ruby config/boot.rb")
|
91
|
+
end
|
92
|
+
|
66
93
|
private
|
67
94
|
def render_template(fname, opts = {})
|
68
95
|
renderer = ERB.new(File.read(fname))
|
@@ -70,7 +97,7 @@ commands:
|
|
70
97
|
app_name: opts[:app_name],
|
71
98
|
nyara_version: Nyara::VERSION
|
72
99
|
}
|
73
|
-
File.open(fname,'w+') do |f|
|
100
|
+
File.open(fname, 'w+') do |f|
|
74
101
|
f.write renderer.result(OpenStruct.new(locals).instance_eval { binding })
|
75
102
|
end
|
76
103
|
end
|
data/lib/nyara/config.rb
CHANGED
@@ -54,16 +54,14 @@ module Nyara
|
|
54
54
|
self['root'] = File.expand_path self['root']
|
55
55
|
|
56
56
|
self['views'] = project_path(self['views'] || 'views')
|
57
|
-
|
57
|
+
if self['public']
|
58
|
+
self['public'] = project_path(self['public'])
|
59
|
+
end
|
58
60
|
|
59
61
|
self.logger = create_logger
|
60
62
|
|
61
|
-
assert !self['before_fork']
|
62
|
-
assert !self['after_fork']
|
63
|
-
|
64
|
-
if self['public']
|
65
|
-
map '/', PublicController
|
66
|
-
end
|
63
|
+
assert !self['before_fork'] || self['before_fork'].respond_to?('call')
|
64
|
+
assert !self['after_fork'] || self['after_fork'].respond_to?('call')
|
67
65
|
end
|
68
66
|
|
69
67
|
attr_accessor :logger
|
@@ -73,11 +71,8 @@ module Nyara
|
|
73
71
|
l = self['logger']
|
74
72
|
|
75
73
|
if l == true or l.nil?
|
76
|
-
# see Nyara.summary_request
|
77
|
-
Ext.summary_request true if development?
|
78
74
|
::Logger.new(production? ? project_path('production.log') : STDOUT)
|
79
75
|
elsif l.is_a?(Class)
|
80
|
-
Ext.summary_request true if development?
|
81
76
|
l.new(production? ? project_path('production.log') : STDOUT)
|
82
77
|
elsif l.is_a?(Proc)
|
83
78
|
l.call
|
@@ -140,6 +135,10 @@ module Nyara
|
|
140
135
|
self['env'].to_s
|
141
136
|
end
|
142
137
|
|
138
|
+
def root
|
139
|
+
self['root'].to_s
|
140
|
+
end
|
141
|
+
|
143
142
|
def development?
|
144
143
|
e = env
|
145
144
|
e.empty? or e == 'development'
|
@@ -179,4 +178,5 @@ configure do
|
|
179
178
|
set 'env', 'development'
|
180
179
|
set 'views', 'views'
|
181
180
|
set 'public', 'public'
|
181
|
+
set 'root', Dir.pwd
|
182
182
|
end
|
data/lib/nyara/controller.rb
CHANGED
@@ -1,8 +1,4 @@
|
|
1
1
|
module Nyara
|
2
|
-
# Contain render methods
|
3
|
-
module Renderable
|
4
|
-
end
|
5
|
-
|
6
2
|
Controller = Struct.new :request
|
7
3
|
class Controller
|
8
4
|
module ClassMethods
|
@@ -15,9 +11,12 @@ module Nyara
|
|
15
11
|
def http method, path, &blk
|
16
12
|
@routes ||= []
|
17
13
|
@used_ids = {}
|
14
|
+
method = method.to_s.upcase
|
18
15
|
|
19
16
|
action = Route.new
|
20
|
-
action.http_method = HTTP_METHODS[method]
|
17
|
+
unless action.http_method = HTTP_METHODS[method]
|
18
|
+
raise ArgumentError, "missing http method: #{method.inspect}"
|
19
|
+
end
|
21
20
|
action.path = path
|
22
21
|
action.set_accept_exts @formats
|
23
22
|
action.id = @curr_id if @curr_id
|
@@ -132,8 +131,6 @@ module Nyara
|
|
132
131
|
class_eval <<-RUBY
|
133
132
|
def __nyara_tmp_action *xs
|
134
133
|
#{senders.join}
|
135
|
-
rescue Exception => e
|
136
|
-
handle_error e
|
137
134
|
end
|
138
135
|
alias :#{e.id.inspect} __nyara_tmp_action
|
139
136
|
undef __nyara_tmp_action
|
@@ -141,7 +138,7 @@ module Nyara
|
|
141
138
|
|
142
139
|
e.compile self, scope
|
143
140
|
e.validate
|
144
|
-
@path_templates[e.id] = e.path_template
|
141
|
+
@path_templates[e.id] = [e.path_template, e.http_method_override]
|
145
142
|
end
|
146
143
|
@routes
|
147
144
|
end
|
@@ -149,8 +146,6 @@ module Nyara
|
|
149
146
|
attr_accessor :path_templates
|
150
147
|
end
|
151
148
|
|
152
|
-
include Renderable
|
153
|
-
|
154
149
|
def self.inherited klass
|
155
150
|
# note: klass will also have this inherited method
|
156
151
|
|
@@ -169,17 +164,62 @@ module Nyara
|
|
169
164
|
end
|
170
165
|
end
|
171
166
|
|
167
|
+
def self.dispatch request, instance, args
|
168
|
+
if cookie_str = request.header._aref('Cookie')
|
169
|
+
ParamHash.parse_cookie request.cookie, cookie_str
|
170
|
+
end
|
171
|
+
request.flash = Flash.new(
|
172
|
+
request.session = Session.decode(request.cookie)
|
173
|
+
)
|
174
|
+
|
175
|
+
if instance
|
176
|
+
if l = Nyara.logger
|
177
|
+
l.info "#{request.http_method} #{request.path} => #{instance.class}"
|
178
|
+
end
|
179
|
+
instance.send *args
|
180
|
+
return
|
181
|
+
elsif request.http_method == 'GET' and Config['public']
|
182
|
+
path = Config.public_path request.path
|
183
|
+
if File.file?(path)
|
184
|
+
if l = Nyara.logger
|
185
|
+
l.info "GET #{path} => public 200"
|
186
|
+
end
|
187
|
+
instance = Controller.new request
|
188
|
+
instance.send_file path
|
189
|
+
return
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
if l = Nyara.logger
|
194
|
+
l.info "#{request.http_method} #{request.path} => 404"
|
195
|
+
end
|
196
|
+
Ext.request_send_data request, "HTTP/1.1 404 Not Found\r\nConnection: close\r\nContent-Length: 0\r\n\r\n"
|
197
|
+
Fiber.yield :term_close
|
198
|
+
|
199
|
+
rescue Exception
|
200
|
+
instance.handle_error($!) if instance
|
201
|
+
end
|
202
|
+
|
172
203
|
# Path helper
|
173
204
|
def path_to id, *args
|
174
205
|
if args.last.is_a?(Hash)
|
175
206
|
opts = args.pop
|
176
207
|
end
|
177
208
|
|
178
|
-
|
209
|
+
template, meth = self.class.path_templates[id.to_s]
|
210
|
+
r = template % args
|
179
211
|
|
180
212
|
if opts
|
181
213
|
format = opts.delete :format
|
182
214
|
r << ".#{format}" if format
|
215
|
+
if meth and !opts.key?(:_method) and !opts.key?('_method')
|
216
|
+
opts['_method'] = meth
|
217
|
+
end
|
218
|
+
elsif meth
|
219
|
+
opts = {'_method' => meth}
|
220
|
+
end
|
221
|
+
|
222
|
+
if opts
|
183
223
|
r << '?' << opts.to_query unless opts.empty?
|
184
224
|
end
|
185
225
|
r
|
@@ -210,7 +250,7 @@ module Nyara
|
|
210
250
|
raise "unsupported redirect status: #{status}" unless HTTP_REDIRECT_STATUS.include?(status)
|
211
251
|
|
212
252
|
r = request
|
213
|
-
header = r.
|
253
|
+
header = r.response_header
|
214
254
|
self.status status
|
215
255
|
|
216
256
|
uri = URI.parse url_or_path
|
@@ -219,7 +259,7 @@ module Nyara
|
|
219
259
|
uri.port = request.port
|
220
260
|
end
|
221
261
|
uri.scheme = r.ssl? ? 'https' : 'http'
|
222
|
-
|
262
|
+
header['Location'] = uri.to_s
|
223
263
|
|
224
264
|
# similar to send_header, but without content-type
|
225
265
|
Ext.request_send_data r, HTTP_STATUS_FIRST_LINES[r.status]
|
@@ -484,6 +524,12 @@ module Nyara
|
|
484
524
|
Fiber.yield :sleep # see event.c for the handler
|
485
525
|
end
|
486
526
|
|
527
|
+
# Render a template as string
|
528
|
+
def partial view_path, locals: nil
|
529
|
+
view = View.new self, view_path, nil, nil, {}
|
530
|
+
view.partial
|
531
|
+
end
|
532
|
+
|
487
533
|
# One shot render, and terminate the action.
|
488
534
|
#
|
489
535
|
# #### Call-seq
|
@@ -545,7 +591,7 @@ module Nyara
|
|
545
591
|
def handle_error e
|
546
592
|
if l = Nyara.logger
|
547
593
|
l.error "#{e.class}: #{e.message}"
|
548
|
-
l.error e.backtrace
|
594
|
+
l.error e.backtrace.join "\n"
|
549
595
|
end
|
550
596
|
status 500
|
551
597
|
send_header rescue nil
|
data/lib/nyara/cookie.rb
CHANGED
@@ -35,30 +35,8 @@ module Nyara
|
|
35
35
|
# config['a', 'very', 'deep', 'key'] = value
|
36
36
|
#
|
37
37
|
# All intermediate level ConfigHashes are created automatically
|
38
|
-
def []= *keys,
|
39
|
-
|
40
|
-
keys.each do |key|
|
41
|
-
if h.has_key?(key)
|
42
|
-
if h.is_a?(ConfigHash)
|
43
|
-
h = h._aref key
|
44
|
-
else
|
45
|
-
h = h[key]
|
46
|
-
end
|
47
|
-
else
|
48
|
-
new_h = ConfigHash.new
|
49
|
-
if h.is_a?(ConfigHash)
|
50
|
-
h._aset key, new_h
|
51
|
-
else
|
52
|
-
h[key] = new_h
|
53
|
-
end
|
54
|
-
h = new_h
|
55
|
-
end
|
56
|
-
end
|
57
|
-
if h.is_a?(ConfigHash)
|
58
|
-
h._aset last_key, value
|
59
|
-
else
|
60
|
-
h[last_key] = value
|
61
|
-
end
|
38
|
+
def []= *keys, value
|
39
|
+
nested_aset keys.map(&:to_s), value
|
62
40
|
end
|
63
41
|
end
|
64
42
|
end
|
data/lib/nyara/nyara.rb
CHANGED
@@ -28,9 +28,6 @@ require_relative "cpu_counter"
|
|
28
28
|
require_relative "part"
|
29
29
|
require_relative "command"
|
30
30
|
|
31
|
-
# default controllers
|
32
|
-
require_relative "controllers/public_controller"
|
33
|
-
|
34
31
|
module Nyara
|
35
32
|
HTTP_STATUS_FIRST_LINES = Hash[HTTP_STATUS_CODES.map{|k,v|[k, "HTTP/1.1 #{k} #{v}\r\n".freeze]}].freeze
|
36
33
|
|
@@ -80,6 +77,24 @@ module Nyara
|
|
80
77
|
View.init
|
81
78
|
end
|
82
79
|
|
80
|
+
def load_app
|
81
|
+
Dir.chdir Config.root do
|
82
|
+
if Config.development?
|
83
|
+
require_relative "reload"
|
84
|
+
Reload.init do
|
85
|
+
# NOTE app_files can be an array
|
86
|
+
Dir.glob(Config['app_files']).uniq.each do |file|
|
87
|
+
Reload.load_file Config.project_path file
|
88
|
+
end
|
89
|
+
end
|
90
|
+
else
|
91
|
+
Dir.glob Config['app_files'] do |file|
|
92
|
+
require Config.project_path file
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
83
98
|
def start_server
|
84
99
|
port = Config[:port]
|
85
100
|
|
@@ -105,13 +120,6 @@ module Nyara
|
|
105
120
|
require_relative "patches/tcp_socket"
|
106
121
|
end
|
107
122
|
|
108
|
-
def summary_request method_num, path, controller
|
109
|
-
if l = logger
|
110
|
-
method = HTTP_METHODS.find{|k, v| method_num == v}.first
|
111
|
-
l.info "#{method} #{path} => #{controller}"
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
123
|
def start_development_server port
|
116
124
|
trap :INT do
|
117
125
|
exit!
|
@@ -210,15 +218,21 @@ module Nyara
|
|
210
218
|
def spawn_new_master sig
|
211
219
|
fork do
|
212
220
|
@server.close_on_exec = false
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
221
|
+
reload_all
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# Reload everything
|
226
|
+
def reload_all
|
227
|
+
# todo set 1-1024 close_on_exec
|
228
|
+
Dir.chdir START_CTX[:cwd]
|
229
|
+
if File.executable?(START_CTX[0])
|
230
|
+
exec START_CTX[0], *START_CTX[:argv], close_others: false
|
231
|
+
else
|
232
|
+
# gemset env should be correct because env is inherited
|
233
|
+
require "rbconfig"
|
234
|
+
ruby = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
|
235
|
+
exec ruby, START_CTX[0], *START_CTX[:argv], close_others: false
|
222
236
|
end
|
223
237
|
end
|
224
238
|
|
data/lib/nyara/part.rb
CHANGED
@@ -100,19 +100,22 @@ module Nyara
|
|
100
100
|
end
|
101
101
|
|
102
102
|
# NOTE `[` are `]` are escaped in url-encoded, so should not split before decode
|
103
|
-
keys =
|
103
|
+
keys = ParamHash.split_name(name)
|
104
|
+
|
104
105
|
if self['filename']
|
105
|
-
|
106
|
+
params.nested_aset keys, self
|
106
107
|
elsif self['type']
|
107
108
|
warn "looks like bad part: #{self['header'].inspect}"
|
108
109
|
else
|
109
|
-
|
110
|
+
params.nested_aset keys, CGI.unescape(self['data'])
|
110
111
|
end
|
111
112
|
end
|
112
113
|
|
113
114
|
# #### Params
|
114
115
|
#
|
115
116
|
# - `raw` in binary encoding
|
117
|
+
#
|
118
|
+
# NOTE close connection on error
|
116
119
|
def update raw
|
117
120
|
case self['mechanism']
|
118
121
|
when 'base64'
|
@@ -148,6 +151,7 @@ module Nyara
|
|
148
151
|
end
|
149
152
|
end
|
150
153
|
|
154
|
+
# NOTE close connection on error
|
151
155
|
def final
|
152
156
|
case self['mechanism']
|
153
157
|
when 'base64'
|