nyara 0.0.1.pre

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/example/design.rb +62 -0
  3. data/example/fib.rb +15 -0
  4. data/example/hello.rb +5 -0
  5. data/example/stream.rb +10 -0
  6. data/ext/accept.c +133 -0
  7. data/ext/event.c +89 -0
  8. data/ext/extconf.rb +34 -0
  9. data/ext/hashes.c +130 -0
  10. data/ext/http-parser/AUTHORS +41 -0
  11. data/ext/http-parser/CONTRIBUTIONS +4 -0
  12. data/ext/http-parser/LICENSE-MIT +23 -0
  13. data/ext/http-parser/contrib/parsertrace.c +156 -0
  14. data/ext/http-parser/contrib/url_parser.c +44 -0
  15. data/ext/http-parser/http_parser.c +2175 -0
  16. data/ext/http-parser/http_parser.h +304 -0
  17. data/ext/http-parser/test.c +3425 -0
  18. data/ext/http_parser.c +1 -0
  19. data/ext/inc/epoll.h +60 -0
  20. data/ext/inc/kqueue.h +77 -0
  21. data/ext/inc/status_codes.inc +64 -0
  22. data/ext/inc/str_intern.h +66 -0
  23. data/ext/inc/version.inc +1 -0
  24. data/ext/mime.c +107 -0
  25. data/ext/multipart-parser-c/README.md +18 -0
  26. data/ext/multipart-parser-c/multipart_parser.c +309 -0
  27. data/ext/multipart-parser-c/multipart_parser.h +48 -0
  28. data/ext/multipart_parser.c +1 -0
  29. data/ext/nyara.c +56 -0
  30. data/ext/nyara.h +59 -0
  31. data/ext/request.c +474 -0
  32. data/ext/route.cc +325 -0
  33. data/ext/url_encoded.c +304 -0
  34. data/hello.rb +5 -0
  35. data/lib/nyara/config.rb +64 -0
  36. data/lib/nyara/config_hash.rb +51 -0
  37. data/lib/nyara/controller.rb +336 -0
  38. data/lib/nyara/cookie.rb +31 -0
  39. data/lib/nyara/cpu_counter.rb +65 -0
  40. data/lib/nyara/header_hash.rb +18 -0
  41. data/lib/nyara/mime_types.rb +612 -0
  42. data/lib/nyara/nyara.rb +82 -0
  43. data/lib/nyara/param_hash.rb +5 -0
  44. data/lib/nyara/request.rb +144 -0
  45. data/lib/nyara/route.rb +138 -0
  46. data/lib/nyara/route_entry.rb +43 -0
  47. data/lib/nyara/session.rb +104 -0
  48. data/lib/nyara/view.rb +317 -0
  49. data/lib/nyara.rb +25 -0
  50. data/nyara.gemspec +20 -0
  51. data/rakefile +91 -0
  52. data/readme.md +35 -0
  53. data/spec/ext_mime_match_spec.rb +27 -0
  54. data/spec/ext_parse_accept_value_spec.rb +29 -0
  55. data/spec/ext_parse_spec.rb +138 -0
  56. data/spec/ext_route_spec.rb +70 -0
  57. data/spec/hashes_spec.rb +71 -0
  58. data/spec/path_helper_spec.rb +77 -0
  59. data/spec/request_delegate_spec.rb +67 -0
  60. data/spec/request_spec.rb +56 -0
  61. data/spec/route_entry_spec.rb +12 -0
  62. data/spec/route_spec.rb +84 -0
  63. data/spec/session_spec.rb +66 -0
  64. data/spec/spec_helper.rb +52 -0
  65. data/spec/view_spec.rb +87 -0
  66. data/tools/bench-cookie.rb +22 -0
  67. 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
@@ -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
@@ -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
@@ -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