nyara 0.0.1.pre

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