nyara 0.0.1.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/example/design.rb +62 -0
- data/example/fib.rb +15 -0
- data/example/hello.rb +5 -0
- data/example/stream.rb +10 -0
- data/ext/accept.c +133 -0
- data/ext/event.c +89 -0
- data/ext/extconf.rb +34 -0
- data/ext/hashes.c +130 -0
- data/ext/http-parser/AUTHORS +41 -0
- data/ext/http-parser/CONTRIBUTIONS +4 -0
- data/ext/http-parser/LICENSE-MIT +23 -0
- data/ext/http-parser/contrib/parsertrace.c +156 -0
- data/ext/http-parser/contrib/url_parser.c +44 -0
- data/ext/http-parser/http_parser.c +2175 -0
- data/ext/http-parser/http_parser.h +304 -0
- data/ext/http-parser/test.c +3425 -0
- data/ext/http_parser.c +1 -0
- data/ext/inc/epoll.h +60 -0
- data/ext/inc/kqueue.h +77 -0
- data/ext/inc/status_codes.inc +64 -0
- data/ext/inc/str_intern.h +66 -0
- data/ext/inc/version.inc +1 -0
- data/ext/mime.c +107 -0
- data/ext/multipart-parser-c/README.md +18 -0
- data/ext/multipart-parser-c/multipart_parser.c +309 -0
- data/ext/multipart-parser-c/multipart_parser.h +48 -0
- data/ext/multipart_parser.c +1 -0
- data/ext/nyara.c +56 -0
- data/ext/nyara.h +59 -0
- data/ext/request.c +474 -0
- data/ext/route.cc +325 -0
- data/ext/url_encoded.c +304 -0
- data/hello.rb +5 -0
- data/lib/nyara/config.rb +64 -0
- data/lib/nyara/config_hash.rb +51 -0
- data/lib/nyara/controller.rb +336 -0
- data/lib/nyara/cookie.rb +31 -0
- data/lib/nyara/cpu_counter.rb +65 -0
- data/lib/nyara/header_hash.rb +18 -0
- data/lib/nyara/mime_types.rb +612 -0
- data/lib/nyara/nyara.rb +82 -0
- data/lib/nyara/param_hash.rb +5 -0
- data/lib/nyara/request.rb +144 -0
- data/lib/nyara/route.rb +138 -0
- data/lib/nyara/route_entry.rb +43 -0
- data/lib/nyara/session.rb +104 -0
- data/lib/nyara/view.rb +317 -0
- data/lib/nyara.rb +25 -0
- data/nyara.gemspec +20 -0
- data/rakefile +91 -0
- data/readme.md +35 -0
- data/spec/ext_mime_match_spec.rb +27 -0
- data/spec/ext_parse_accept_value_spec.rb +29 -0
- data/spec/ext_parse_spec.rb +138 -0
- data/spec/ext_route_spec.rb +70 -0
- data/spec/hashes_spec.rb +71 -0
- data/spec/path_helper_spec.rb +77 -0
- data/spec/request_delegate_spec.rb +67 -0
- data/spec/request_spec.rb +56 -0
- data/spec/route_entry_spec.rb +12 -0
- data/spec/route_spec.rb +84 -0
- data/spec/session_spec.rb +66 -0
- data/spec/spec_helper.rb +52 -0
- data/spec/view_spec.rb +87 -0
- data/tools/bench-cookie.rb +22 -0
- metadata +111 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
module Nyara
|
4
|
+
describe Ext, "route" do
|
5
|
+
before :each do
|
6
|
+
Ext.clear_route
|
7
|
+
@e1 = RouteEntry.new{
|
8
|
+
@http_method = 'GET'
|
9
|
+
@scope = '/hello'
|
10
|
+
@prefix = '/hello/'
|
11
|
+
@suffix = '(\d+)world'
|
12
|
+
@id = :'#1'
|
13
|
+
@conv = [:to_i]
|
14
|
+
@controller = 'stub'
|
15
|
+
}
|
16
|
+
@e2 = RouteEntry.new{
|
17
|
+
@http_method = 'GET'
|
18
|
+
@scope = '/hello'
|
19
|
+
@prefix = '/hello'
|
20
|
+
@suffix = ''
|
21
|
+
@id = :'#second'
|
22
|
+
@conv = []
|
23
|
+
@controller = 'stub2'
|
24
|
+
}
|
25
|
+
@e3 = RouteEntry.new{
|
26
|
+
@http_method = 'GET'
|
27
|
+
@scope = '/a目录'
|
28
|
+
@prefix = '/a目录/'
|
29
|
+
@suffix = '(\d+)-(\d+)-(\d+)'
|
30
|
+
@id = :'#dir'
|
31
|
+
@conv = [:to_i, :to_i, :to_i]
|
32
|
+
@controller = 'stub3'
|
33
|
+
}
|
34
|
+
Ext.register_route @e1
|
35
|
+
Ext.register_route @e2
|
36
|
+
Ext.register_route @e3
|
37
|
+
end
|
38
|
+
|
39
|
+
after :all do
|
40
|
+
Ext.clear_route
|
41
|
+
end
|
42
|
+
|
43
|
+
it '#register_route sub-prefix optimization' do
|
44
|
+
rules = Ext.list_route['GET']
|
45
|
+
assert_equal 3, rules.size
|
46
|
+
|
47
|
+
assert_equal false, rules[0].first # first
|
48
|
+
assert_equal true, rules[1].first # is sub of prev
|
49
|
+
assert_equal false, rules[2].first # not sub of prev
|
50
|
+
end
|
51
|
+
|
52
|
+
it '#lookup_route' do
|
53
|
+
scope, cont, args = Ext.lookup_route 'GET', '/hello'
|
54
|
+
assert_equal @e2.scope, scope
|
55
|
+
assert_equal @e2.controller, cont
|
56
|
+
assert_equal [:'#second'], args
|
57
|
+
|
58
|
+
scope, cont, args = Ext.lookup_route 'GET', '/hello/3world'
|
59
|
+
assert_equal @e1.scope, scope
|
60
|
+
assert_equal @e1.controller, cont
|
61
|
+
assert_equal [3, :'#1'], args
|
62
|
+
|
63
|
+
scope, _ = Ext.lookup_route 'GET', '/world'
|
64
|
+
assert_equal nil, scope
|
65
|
+
|
66
|
+
scope, _, args = Ext.lookup_route 'GET', '/a目录/2013-6-1'
|
67
|
+
assert_equal [2013, 6, 1, :'#dir'], args
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/spec/hashes_spec.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
module Nyara
|
4
|
+
describe ParamHash do
|
5
|
+
it "symbol/string keys in ParamHash are the same" do
|
6
|
+
h = ParamHash.new
|
7
|
+
h[:a] = 3
|
8
|
+
assert_equal 3, h['a']
|
9
|
+
assert_equal true, h.key?(:a)
|
10
|
+
assert_equal true, h.key?('a')
|
11
|
+
assert_equal 1, h.size
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe HeaderHash do
|
16
|
+
it "ignores case in key" do
|
17
|
+
h = HeaderHash.new
|
18
|
+
h['a-bc'] = 'good'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "headerlizes key and stringify value" do
|
22
|
+
h = HeaderHash.new
|
23
|
+
h['Content-type'] = 'text/html'
|
24
|
+
h[:'content-tYpe'] = :'text/plain'
|
25
|
+
assert_equal 1, h.size
|
26
|
+
assert_equal ['Content-Type', 'text/plain'], h.to_a.first
|
27
|
+
end
|
28
|
+
|
29
|
+
class HaHash < HeaderHash
|
30
|
+
end
|
31
|
+
|
32
|
+
it "#reverse_merge! raises error if other is not HeaderHash" do
|
33
|
+
h = HeaderHash.new
|
34
|
+
h.reverse_merge! HaHash.new # :)
|
35
|
+
assert_raise ArgumentError do
|
36
|
+
h.reverse_merge!({})
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it "#reverse_merge!" do
|
41
|
+
h = HeaderHash.new
|
42
|
+
g = HeaderHash.new
|
43
|
+
h['a'] = 'h'
|
44
|
+
g['a'] = 'g'
|
45
|
+
g['b'] = 'b'
|
46
|
+
h.reverse_merge! g
|
47
|
+
assert_equal 2, h.size
|
48
|
+
assert_equal 'h', h['a']
|
49
|
+
assert_equal 'b', h['b']
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe ConfigHash do
|
54
|
+
it "deep key assignment" do
|
55
|
+
h = ConfigHash.new
|
56
|
+
h['a', 'deep', 'key1'] = 'value1'
|
57
|
+
h['a', 'deep', :key2] = 'value2'
|
58
|
+
assert_equal 'value1', h['a', 'deep', :key1]
|
59
|
+
assert_equal 'value2', h['a']['deep']['key2']
|
60
|
+
end
|
61
|
+
|
62
|
+
it "works when last available key exists as other hash type" do
|
63
|
+
h = ConfigHash.new
|
64
|
+
other_h = {}
|
65
|
+
h['a'] = other_h
|
66
|
+
h['a', 'b'] = 3
|
67
|
+
assert_equal 3, h['a', 'b']
|
68
|
+
assert_equal other_h.object_id, h['a'].object_id
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
class FooController < Nyara::Controller
|
4
|
+
meta '#index'
|
5
|
+
get '/%d' do |id|
|
6
|
+
end
|
7
|
+
|
8
|
+
class BarController < Nyara::Controller
|
9
|
+
meta '#index'
|
10
|
+
get '/' do
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class BazController < Nyara::Controller
|
15
|
+
set_name 'baz'
|
16
|
+
|
17
|
+
meta '#index'
|
18
|
+
get '/%d' do |id|
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module Nyara
|
24
|
+
describe [Controller, Route] do
|
25
|
+
before :all do
|
26
|
+
Route.clear
|
27
|
+
Config.configure do
|
28
|
+
set 'host', 'yavaeye.com'
|
29
|
+
map '/', 'foo'
|
30
|
+
map '/bar-prefix', 'foo_controller::bar'
|
31
|
+
map '/baz-prefix', 'foo_controller::baz'
|
32
|
+
end
|
33
|
+
Route.compile
|
34
|
+
end
|
35
|
+
|
36
|
+
context '#path_for' do
|
37
|
+
it "local query" do
|
38
|
+
c = FooController.new :stub_request
|
39
|
+
assert_equal '/12', c.path_for('#index', 12)
|
40
|
+
assert_raise ArgumentError do
|
41
|
+
c.path_for '#index'
|
42
|
+
end
|
43
|
+
assert_raise ArgumentError do
|
44
|
+
c.path_for('#index', 'a')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it "global query" do
|
49
|
+
c = FooController::BarController.new :stub_request
|
50
|
+
assert_equal '/bar-prefix/', c.path_for('foo_controller::bar#index')
|
51
|
+
assert_equal '/baz-prefix/1', c.path_for('baz#index', 1)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "generates for nested query" do
|
55
|
+
pending
|
56
|
+
end
|
57
|
+
|
58
|
+
it "perserves _method query" do
|
59
|
+
pending
|
60
|
+
end
|
61
|
+
|
62
|
+
it "appends format and query" do
|
63
|
+
c = FooController.new :stub_request
|
64
|
+
generated = c.path_for '#index', 1, format: 'js', 'utm_source' => 'a spam'
|
65
|
+
assert_equal "/1.js?utm_source=a+spam", generated
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context '#url_for' do
|
70
|
+
it "works" do
|
71
|
+
c = FooController::BazController.new :stub_request
|
72
|
+
assert_equal '//yavaeye.com/baz-prefix/1', c.url_for('#index', 1)
|
73
|
+
assert_equal 'https://localhost:4567/1', c.url_for('foo#index', 1, scheme: 'https', host: 'localhost:4567')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
module Nyara
|
4
|
+
describe [Controller, Request] do
|
5
|
+
class DelegateController < Controller
|
6
|
+
end
|
7
|
+
|
8
|
+
before :all do
|
9
|
+
Ext.set_skip_on_url true
|
10
|
+
end
|
11
|
+
|
12
|
+
after :all do
|
13
|
+
Ext.set_skip_on_url false
|
14
|
+
end
|
15
|
+
|
16
|
+
before :each do
|
17
|
+
@client, @server = Socket.pair :UNIX, :STREAM
|
18
|
+
Ext.set_nonblock @server.fileno
|
19
|
+
@request = Ext.handle_request @server.fileno
|
20
|
+
Ext.set_request_attrs @request, {
|
21
|
+
method_num: HTTP_METHODS['GET'],
|
22
|
+
path: '/search',
|
23
|
+
param: ParamHash.new.tap{|h| h['q'] = 'nyara' },
|
24
|
+
fiber: Fiber.new{},
|
25
|
+
scope: '/scope',
|
26
|
+
header: HeaderHash.new.tap{|h| h['Accept'] = 'en-US' }
|
27
|
+
# ext: nil
|
28
|
+
# response_header:
|
29
|
+
# response_header_extra_lines:
|
30
|
+
}
|
31
|
+
@c = DelegateController.new @request
|
32
|
+
end
|
33
|
+
|
34
|
+
it "#content_type" do
|
35
|
+
@c.content_type :js
|
36
|
+
assert_equal 'application/javascript', @request.response_content_type
|
37
|
+
end
|
38
|
+
|
39
|
+
it "#status" do
|
40
|
+
assert_raise ArgumentError do
|
41
|
+
@c.status 1000
|
42
|
+
end
|
43
|
+
@c.status 404
|
44
|
+
assert_equal 404, @request.status
|
45
|
+
end
|
46
|
+
|
47
|
+
it "request header" do
|
48
|
+
assert_equal 'en-US', @c.header['accept']
|
49
|
+
end
|
50
|
+
|
51
|
+
it "set response header and send" do
|
52
|
+
pending
|
53
|
+
@c.set_header
|
54
|
+
@c.add_header_line
|
55
|
+
@c.send_header
|
56
|
+
@client
|
57
|
+
end
|
58
|
+
|
59
|
+
it "set / delete / clear cookie" do
|
60
|
+
pending
|
61
|
+
end
|
62
|
+
|
63
|
+
it "#session" do
|
64
|
+
pending
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
module Nyara
|
4
|
+
describe Request do
|
5
|
+
before :all do
|
6
|
+
Ext.set_skip_on_url true
|
7
|
+
end
|
8
|
+
|
9
|
+
after :all do
|
10
|
+
Ext.set_skip_on_url false
|
11
|
+
end
|
12
|
+
|
13
|
+
before :each do
|
14
|
+
@server, @client = Socket.pair :UNIX, :STREAM, 0
|
15
|
+
Ext.set_nonblock @server.fileno
|
16
|
+
Ext.set_nonblock @client.fileno
|
17
|
+
@request = Ext.handle_request @server.fileno
|
18
|
+
@request_attrs = {
|
19
|
+
method_num: HTTP_METHODS['GET'],
|
20
|
+
path: '/',
|
21
|
+
param: HeaderHash.new.tap{|h| h['id'] = 1 },
|
22
|
+
fiber: nil,
|
23
|
+
scope: '/',
|
24
|
+
ext: nil
|
25
|
+
}
|
26
|
+
set_request_attrs
|
27
|
+
end
|
28
|
+
|
29
|
+
context "#scheme detect by forwarded.." do
|
30
|
+
it "ssl" do
|
31
|
+
@request.header['X-Forwarded-Ssl'] = 'on'
|
32
|
+
assert_equal 'https', @request.scheme
|
33
|
+
end
|
34
|
+
|
35
|
+
it "scheme" do
|
36
|
+
@request.header['X-Forwarded-Scheme'] = 'ical'
|
37
|
+
assert_equal 'ical', @request.scheme
|
38
|
+
end
|
39
|
+
|
40
|
+
it "protocol" do
|
41
|
+
@request.header['X-Forwarded-Proto'] = 'https,http'
|
42
|
+
assert_equal 'https', @request.scheme
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it "#domain and #port" do
|
47
|
+
@request.header['Host'] = "yavaeye.com:3000"
|
48
|
+
assert_equal 'yavaeye.com', @request.domain
|
49
|
+
assert_equal 3000, @request.port
|
50
|
+
end
|
51
|
+
|
52
|
+
def set_request_attrs
|
53
|
+
Ext.set_request_attrs @request, @request_attrs
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
module Nyara
|
4
|
+
describe RouteEntry do
|
5
|
+
it "#set_accept_exts" do
|
6
|
+
r = RouteEntry.new
|
7
|
+
r.set_accept_exts ['html', :js]
|
8
|
+
assert_equal [%w"text html html", %w"application javascript js"], r.accept_mimes
|
9
|
+
assert_equal ({'html'=>true, 'js'=>true}), r.accept_exts
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/spec/route_spec.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
module Nyara
|
4
|
+
describe Route do
|
5
|
+
# fixme: ugly code
|
6
|
+
it "#process" do
|
7
|
+
entries1 = [
|
8
|
+
RouteEntry.new{
|
9
|
+
@http_method = 'GET',
|
10
|
+
@path = '/hello/%f',
|
11
|
+
@id = :'#hello_f'
|
12
|
+
},
|
13
|
+
RouteEntry.new{
|
14
|
+
@http_method = 'POST',
|
15
|
+
@path = '/%s/%u-%d',
|
16
|
+
@id = :'#post'
|
17
|
+
}
|
18
|
+
]
|
19
|
+
entries2 = [
|
20
|
+
RouteEntry.new{
|
21
|
+
@http_method = 'GET',
|
22
|
+
@path = '/',
|
23
|
+
@id = :'#hel'
|
24
|
+
}
|
25
|
+
]
|
26
|
+
entries3 = [
|
27
|
+
RouteEntry.new{
|
28
|
+
@http_method = 'GET',
|
29
|
+
@path = '/%s',
|
30
|
+
@id = :'#ello_s'
|
31
|
+
}
|
32
|
+
]
|
33
|
+
|
34
|
+
preprocessed_rules = [
|
35
|
+
['/', 'Stub1', entries1],
|
36
|
+
['/hel', 'Stub2', entries2],
|
37
|
+
['/ello', 'Stub3', entries3]
|
38
|
+
]
|
39
|
+
|
40
|
+
rules = Route.process preprocessed_rules
|
41
|
+
e_prefices, e_scopes, e_ids = [
|
42
|
+
['/hello/', '/', :'#hello_f'],
|
43
|
+
['/hel', '/hel', :'#hel'],
|
44
|
+
['/ello/', '/ello', :'#ello_s'],
|
45
|
+
['/', '/', :'#post']
|
46
|
+
].transpose
|
47
|
+
|
48
|
+
assert_equal e_prefices, rules.map(&:prefix)
|
49
|
+
assert_equal e_scopes, rules.map(&:scope)
|
50
|
+
assert_equal e_ids, rules.map(&:id)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "#compile_re" do
|
54
|
+
re, conv = Route.compile_re '%s/%u/%d/%f/%x'
|
55
|
+
assert_equal [:to_s, :to_i, :to_i, :to_f, :hex], conv
|
56
|
+
s = '1/2/-3/4.5/F'
|
57
|
+
assert_equal [s, *s.split('/')], s.match(Regexp.new re).to_a
|
58
|
+
|
59
|
+
re, conv = Route.compile_re '/'
|
60
|
+
assert_equal '^/$', re
|
61
|
+
assert_equal [], conv
|
62
|
+
end
|
63
|
+
|
64
|
+
it "#compile_re with utf-8 chars" do
|
65
|
+
re, conv = Route.compile_re '/目录/%da/也可以'
|
66
|
+
assert_equal [:to_i], conv
|
67
|
+
s = "/目录/12a/也可以"
|
68
|
+
assert_equal [s, '12'], s.match(Regexp.new re).to_a
|
69
|
+
end
|
70
|
+
|
71
|
+
it "#analyse_path" do
|
72
|
+
r = Route.analyse_path '/hello/%d-world%u/%s/'
|
73
|
+
assert_equal ['/hello/', '%d-world%u/%s'], r
|
74
|
+
|
75
|
+
prefix, suffix = Route.analyse_path '/hello'
|
76
|
+
assert_equal '/hello', prefix
|
77
|
+
assert_equal nil, suffix
|
78
|
+
|
79
|
+
prefix, suffix = Route.analyse_path '/'
|
80
|
+
assert_equal '/', prefix
|
81
|
+
assert_equal nil, suffix
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
module Nyara
|
4
|
+
describe Session do
|
5
|
+
context "no cipher" do
|
6
|
+
before :all do
|
7
|
+
Config['session', 'cipher_key'] = nil
|
8
|
+
Session.init
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should encode and decode" do
|
12
|
+
cookie = {}
|
13
|
+
session = {'hello' => 'world'}
|
14
|
+
Session.encode session, cookie
|
15
|
+
|
16
|
+
assert_includes cookie[Session.name], 'world'
|
17
|
+
|
18
|
+
session2 = Session.decode cookie
|
19
|
+
assert_equal 'world', session2[:hello]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "drops bad signature" do
|
23
|
+
cookie = {}
|
24
|
+
session = {'hello' => 'world'}
|
25
|
+
Session.encode session, cookie
|
26
|
+
|
27
|
+
cookie[Session.name].sub!(/\w/, &:swapcase)
|
28
|
+
|
29
|
+
session = Session.decode cookie
|
30
|
+
assert_empty session
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "with cipher" do
|
35
|
+
before :all do
|
36
|
+
Config['session', 'cipher_key'] = "some cipher key"
|
37
|
+
Session.init
|
38
|
+
end
|
39
|
+
|
40
|
+
it "encode and decode" do
|
41
|
+
cookie = {}
|
42
|
+
session = {'hello' => 'world'}
|
43
|
+
Session.encode session, cookie
|
44
|
+
|
45
|
+
assert_not_includes cookie[Session.name], 'world'
|
46
|
+
|
47
|
+
session2 = Session.decode cookie
|
48
|
+
assert_equal 'world', session2[:hello]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "cipher should not be pure" do
|
52
|
+
message = 'OCB is by far the best mode, as it allows encryption and authentication in a single pass. However there are patents on it in USA.'
|
53
|
+
r1 = Session.cipher message
|
54
|
+
r2 = Session.cipher message
|
55
|
+
assert_not_equal r1, r2
|
56
|
+
end
|
57
|
+
|
58
|
+
it "decipher returns blank str when message too short" do
|
59
|
+
r = Session.decipher Base64.urlsafe_encode64 'short one'
|
60
|
+
assert_empty r
|
61
|
+
r = Session.decipher Base64.urlsafe_encode64 's' * (256/8)
|
62
|
+
assert_empty r
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require_relative "../lib/nyara/nyara"
|
2
|
+
require 'rspec/core'
|
3
|
+
require 'rspec/mocks'
|
4
|
+
require 'rspec/autorun'
|
5
|
+
require "pry"
|
6
|
+
require "slim"
|
7
|
+
require "erb"
|
8
|
+
require "haml"
|
9
|
+
require "liquid"
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.expect_with :stdlib
|
13
|
+
if config.formatters.first.class.to_s =~ /TextMate/
|
14
|
+
def puts *xs
|
15
|
+
xs.each do |x|
|
16
|
+
$stdout.puts "<pre style='word-wrap:break-word;word-break:break-all;'>#{CGI.escape_html x.to_s}</pre>"
|
17
|
+
end
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def print *xs
|
22
|
+
$stdout.print "<span style='word-wrap:break-word;word-break:break-all;'>"
|
23
|
+
xs.each do |x|
|
24
|
+
$stdout.print CGI.escape_html x.to_s
|
25
|
+
end
|
26
|
+
$stdout.print "</span>"
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def p *xs
|
31
|
+
xs.each do |x|
|
32
|
+
$stdout.puts "<pre style='word-wrap:break-word;word-break:break-all;'>#{CGI.escape_html x.inspect}</pre>"
|
33
|
+
end
|
34
|
+
xs
|
35
|
+
end
|
36
|
+
|
37
|
+
require 'pp'
|
38
|
+
module Kernel
|
39
|
+
def pp obj
|
40
|
+
s = CGI.escape_html(PP.pp obj, '')
|
41
|
+
$stdout.puts "<pre style='word-wrap:break-word;word-break:break-all;'>#{s}</pre>"
|
42
|
+
obj
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
configure do
|
49
|
+
set :env, 'test'
|
50
|
+
end
|
51
|
+
|
52
|
+
# todo a test helper to compile routes after app loaded
|
data/spec/view_spec.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
class RenderableMock
|
4
|
+
include Nyara::Renderable
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@result = ''
|
8
|
+
end
|
9
|
+
attr_reader :result
|
10
|
+
|
11
|
+
def send_chunk data
|
12
|
+
@result << data
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module Nyara
|
17
|
+
describe [View, Renderable] do
|
18
|
+
before :all do
|
19
|
+
Config['views'] = __dir__ + '/views'
|
20
|
+
View.init
|
21
|
+
end
|
22
|
+
|
23
|
+
def render *xs
|
24
|
+
@instance = RenderableMock.new
|
25
|
+
view = View.new @instance, *xs
|
26
|
+
Fiber.new{ view.render }.resume
|
27
|
+
end
|
28
|
+
|
29
|
+
it "inline render with locals" do
|
30
|
+
render nil, nil, {a: 3}, erb: '<%= a %>'
|
31
|
+
assert_equal '3', @instance.result
|
32
|
+
end
|
33
|
+
|
34
|
+
it "file render" do
|
35
|
+
render 'show', nil, {a: 3}, {}
|
36
|
+
assert_equal '3', @instance.result
|
37
|
+
end
|
38
|
+
|
39
|
+
it "file render with layouts" do
|
40
|
+
render 'show', 'layout', {a: 3}, {}
|
41
|
+
assert_equal "<html>3</html>\n", @instance.result
|
42
|
+
end
|
43
|
+
|
44
|
+
it "raises for ambiguous template" do
|
45
|
+
assert_raise ArgumentError do
|
46
|
+
render 'edit', nil, nil, {}
|
47
|
+
end
|
48
|
+
render 'edit.slim', nil, nil, {}
|
49
|
+
assert_equal "<div>slim:edit</div>", @instance.result.gsub(/\s/, '')
|
50
|
+
render 'edit.haml', nil, nil, {}
|
51
|
+
assert_equal "<div>haml:edit</div>", @instance.result.gsub(/\s/, '')
|
52
|
+
end
|
53
|
+
|
54
|
+
context "fallback to tilt" do
|
55
|
+
it "inline render" do
|
56
|
+
render nil, nil, {a: 3}, {liquid: '{{a}}'}
|
57
|
+
assert_equal '3', @instance.result
|
58
|
+
end
|
59
|
+
|
60
|
+
it "forbids tilt layout" do
|
61
|
+
assert_raise RuntimeError do
|
62
|
+
render nil, 'invalid_layout', nil, {liquid: 'page'}
|
63
|
+
end
|
64
|
+
assert_raise RuntimeError do
|
65
|
+
render 'show', ['invalid_layout'], nil, {}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it "allows tilt page with stream-friendly layout" do
|
70
|
+
render nil, 'layout', nil, {liquid: 'page'}
|
71
|
+
assert_equal "<html>page</html>\n", @instance.result
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
it "stream render" do
|
76
|
+
@instance = RenderableMock.new
|
77
|
+
view = View.new @instance, nil, 'layout', nil, {erb: '<% 3.times do |i| %><%= i %><% Fiber.yield %><% end %>'}
|
78
|
+
v = view.stream
|
79
|
+
v.resume
|
80
|
+
assert_equal "<html>0", @instance.result
|
81
|
+
v.resume
|
82
|
+
assert_equal "<html>01", @instance.result
|
83
|
+
Fiber.new{ v.end }.resume
|
84
|
+
assert_equal "<html>012</html>\n", @instance.result
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative "../lib/nyara/nyara"
|
2
|
+
include Nyara
|
3
|
+
require "benchmark"
|
4
|
+
|
5
|
+
def cookie1 s
|
6
|
+
res = ParamHash.new
|
7
|
+
s.split(/[,;] */n).reverse_each do |seg|
|
8
|
+
Ext.parse_url_encoded_seg res, seg, false
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def cookie2 s
|
13
|
+
res = ParamHash.new
|
14
|
+
Ext.parse_cookie res, s
|
15
|
+
end
|
16
|
+
|
17
|
+
history = CGI.escape '历史'
|
18
|
+
s = "pgv_pvi; pgv_si=; pgv_pvi=som; sid=1d6c75f0 ; PLHistory=<#{history}>;"
|
19
|
+
|
20
|
+
puts Benchmark.measure{ 1000.times{cookie1 s} }
|
21
|
+
puts Benchmark.measure{ 1000.times{cookie2 s} }
|
22
|
+
# cookie2 should be faster
|