nyara 0.0.1.pre.6 → 0.0.1.pre.8

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/example/project.rb +11 -0
  3. data/example/stream.rb +6 -2
  4. data/ext/event.c +83 -32
  5. data/ext/hashes.c +6 -1
  6. data/ext/inc/epoll.h +1 -2
  7. data/ext/inc/kqueue.h +1 -2
  8. data/ext/nyara.h +2 -0
  9. data/ext/request.c +14 -9
  10. data/ext/test_response.c +2 -5
  11. data/ext/url_encoded.c +55 -1
  12. data/lib/nyara/config.rb +68 -17
  13. data/lib/nyara/controller.rb +76 -15
  14. data/lib/nyara/controllers/public_controller.rb +14 -0
  15. data/lib/nyara/cookie.rb +5 -4
  16. data/lib/nyara/flash.rb +2 -0
  17. data/lib/nyara/nyara.rb +153 -20
  18. data/lib/nyara/patches/to_query.rb +1 -2
  19. data/lib/nyara/request.rb +0 -5
  20. data/lib/nyara/route.rb +2 -2
  21. data/lib/nyara/route_entry.rb +5 -4
  22. data/lib/nyara/session.rb +47 -22
  23. data/lib/nyara/test.rb +13 -10
  24. data/lib/nyara/view.rb +27 -49
  25. data/lib/nyara/view_handlers/erb.rb +21 -0
  26. data/lib/nyara/view_handlers/erubis.rb +81 -0
  27. data/lib/nyara/view_handlers/haml.rb +17 -0
  28. data/lib/nyara/view_handlers/slim.rb +16 -0
  29. data/nyara.gemspec +3 -1
  30. data/readme.md +2 -2
  31. data/spec/apps/connect.rb +1 -1
  32. data/spec/config_spec.rb +76 -4
  33. data/spec/{test_spec.rb → integration_spec.rb} +47 -3
  34. data/spec/path_helper_spec.rb +1 -1
  35. data/spec/performance/escape.rb +10 -0
  36. data/spec/performance/layout.slim +14 -0
  37. data/spec/performance/page.slim +16 -0
  38. data/spec/performance_spec.rb +6 -1
  39. data/spec/public/empty file.html +0 -0
  40. data/spec/public/index.html +1 -0
  41. data/spec/request_delegate_spec.rb +1 -1
  42. data/spec/request_spec.rb +20 -0
  43. data/spec/route_entry_spec.rb +7 -0
  44. data/spec/session_spec.rb +8 -4
  45. data/spec/spec_helper.rb +1 -0
  46. data/spec/{ext_parse_spec.rb → url_encoded_spec.rb} +17 -5
  47. data/spec/views/edit.haml +2 -0
  48. data/spec/views/edit.slim +2 -0
  49. data/spec/views/index.liquid +0 -0
  50. data/spec/views/invalid_layout.liquid +0 -0
  51. data/spec/views/layout.erb +1 -0
  52. data/spec/views/show.slim +1 -0
  53. data/tools/foo.rb +9 -0
  54. data/tools/hello.rb +16 -11
  55. metadata +22 -4
@@ -0,0 +1,81 @@
1
+ require "erubis"
2
+
3
+ module Nyara
4
+ class View
5
+ # mostly same as actionpack/action_view/template/handlers/erb.rb
6
+ class Erubis < ::Erubis::Eruby
7
+ def self.src template
8
+ new(template).src
9
+ end
10
+
11
+ def add_preamble(src)
12
+ @newline_pending = 0
13
+ src << "_erbout = @_nyara_view.out;"
14
+ end
15
+
16
+ # ensure 1:1 mapping of "\n" between template and output
17
+ def add_text(src, text)
18
+ return if text.empty?
19
+
20
+ if text == "\n"
21
+ @newline_pending += 1
22
+ else
23
+ src << "_erbout.safe_append='"
24
+ src << "\n" * @newline_pending if @newline_pending > 0
25
+ src << escape_text(text)
26
+ src << "';"
27
+
28
+ @newline_pending = 0
29
+ end
30
+ end
31
+
32
+ # Erubis toggles <%= and <%== behavior when escaping is enabled.
33
+ # We override to always treat <%== as escaped.
34
+ def add_expr(src, code, indicator)
35
+ case indicator
36
+ when '=='
37
+ add_expr_escaped(src, code)
38
+ else
39
+ super
40
+ end
41
+ end
42
+
43
+ BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
44
+
45
+ def add_expr_literal(src, code)
46
+ flush_newline_if_pending(src)
47
+ if code =~ BLOCK_EXPR
48
+ src << '_erbout.append= ' << code
49
+ else
50
+ src << '_erbout.append=(' << code << ');'
51
+ end
52
+ end
53
+
54
+ def add_expr_escaped(src, code)
55
+ flush_newline_if_pending(src)
56
+ if code =~ BLOCK_EXPR
57
+ src << "_erbout.safe_append= " << code
58
+ else
59
+ src << "_erbout.safe_append=(" << code << ");"
60
+ end
61
+ end
62
+
63
+ def add_stmt(src, code)
64
+ flush_newline_if_pending(src)
65
+ super
66
+ end
67
+
68
+ def add_postamble(src)
69
+ flush_newline_if_pending(src)
70
+ src << '_erbout.join'
71
+ end
72
+
73
+ def flush_newline_if_pending(src)
74
+ if @newline_pending > 0
75
+ src << "_erbout.safe_append='#{"\n" * @newline_pending}';"
76
+ @newline_pending = 0
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,17 @@
1
+ require "haml"
2
+
3
+ module Nyara
4
+ class View
5
+ module Haml
6
+ def self.src template
7
+ e = ::Haml::Engine.new template
8
+ # todo trim mode
9
+ <<-RUBY
10
+ _hamlout = ::Haml::Buffer.new(nil, encoding: 'utf-8'); _hamlout.buffer = @_nyara_view.out
11
+ #{e.precompiled}
12
+ _hamlout.buffer.join
13
+ RUBY
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ require "slim"
2
+
3
+ module Nyara
4
+ class View
5
+ class Slim
6
+ def self.src template
7
+ t = ::Slim::Template.new(nil, nil, pretty: false){ template }
8
+ src = t.instance_variable_get :@src
9
+ if src.start_with?('_buf = []')
10
+ src.sub! '_buf = []', '_buf = @_nyara_view.out'
11
+ end
12
+ src
13
+ end
14
+ end
15
+ end
16
+ end
data/nyara.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "nyara"
3
- s.version = "0.0.1.pre.6"
3
+ s.version = "0.0.1.pre.8"
4
4
  s.author = "Zete Lui"
5
5
  s.email = "nobody@example.com"
6
6
  s.homepage = "https://github.com/luikore/nyara"
@@ -11,8 +11,10 @@ Gem::Specification.new do |s|
11
11
  s.licenses = ['BSD 3-Clause']
12
12
 
13
13
  s.files = Dir.glob('{rakefile,nyara.gemspec,readme.md,**/*.{rb,h,c,cc,inc}}')
14
+ s.files += Dir.glob('spec/**/*')
14
15
  s.files += Dir.glob('ext/http-parser/{AUTHORS,CONTRIBUTIONS,LICENSE-MIT}')
15
16
  s.files += Dir.glob('ext/multipart-parser-c/README.md')
17
+ s.files.uniq!
16
18
  s.require_paths = ["lib"]
17
19
  s.extensions = ["ext/extconf.rb"]
18
20
  s.rubygems_version = '2.0.3'
data/readme.md CHANGED
@@ -56,5 +56,5 @@ BSD 3-Clause, see [copying](https://github.com/luikore/nyara/blob/master/copying
56
56
 
57
57
  # Contributors
58
58
 
59
- luikore
60
- hooopo
59
+ - luikore
60
+ - hooopo
data/spec/apps/connect.rb CHANGED
@@ -5,7 +5,7 @@ require "pry"
5
5
  require "open-uri"
6
6
 
7
7
  configure do
8
- port 3003
8
+ set :port, 3003
9
9
  end
10
10
 
11
11
  get '/' do
data/spec/config_spec.rb CHANGED
@@ -6,16 +6,87 @@ module Nyara
6
6
  Config.reset
7
7
  end
8
8
 
9
- it "#workers" do
10
- Nyara.config.workers '3'
9
+ it "Nyara.config forbids block" do
10
+ Nyara.config
11
+ assert_raise ArgumentError do
12
+ Nyara.config{}
13
+ end
14
+ end
15
+
16
+ it "convert workers" do
17
+ Config.configure do
18
+ set :workers, '3'
19
+ end
20
+ Config.init
11
21
  assert_equal 3, Config['workers']
12
22
  end
13
23
 
14
- it "#port" do
15
- Config.port '1000'
24
+ it "convert port" do
25
+ Config.configure do
26
+ set :port, '1000'
27
+ end
28
+ Config.init
16
29
  assert_equal 1000, Config['port']
17
30
  end
18
31
 
32
+ it "port default" do
33
+ Config.reset
34
+ Config.init
35
+ assert_equal 3000, Config['port']
36
+ end
37
+
38
+ it "views and public default" do
39
+ Config.reset
40
+ Config[:root] = '/root'
41
+ Config.init
42
+ assert_equal '/root/public', Config['public']
43
+ assert_equal '/root/views', Config['views']
44
+ end
45
+
46
+ context "#project_path" do
47
+ before :all do
48
+ Config.configure do
49
+ set :root, '/a'
50
+ init
51
+ end
52
+ end
53
+
54
+ it "works" do
55
+ path = Config.project_path 'b/../../c', false
56
+ assert_equal '/c', path
57
+ end
58
+
59
+ it "restrict mode ensures dir safety" do
60
+ path = Config.project_path 'b/../../c'
61
+ assert_equal nil, path
62
+ end
63
+
64
+ it "restrict mode allows '..' if it doesn't get outside" do
65
+ path = Config.project_path 'b/../c', true
66
+ assert_equal '/a/c', path
67
+ end
68
+ end
69
+
70
+ it "#public_path" do
71
+ Config.configure do
72
+ set :root, '/root'
73
+ set :public, 'a'
74
+ init
75
+ end
76
+ path = Config.public_path '/b'
77
+ assert_equal '/root/a/b', path
78
+ end
79
+
80
+ it "#views_path" do
81
+ Config.configure do
82
+ set :root, '/'
83
+ set :views, '/a'
84
+ init
85
+ end
86
+ path = Config.views_path '../..', false
87
+ assert_equal '/', path
88
+ end
89
+
19
90
  it "env helpers" do
20
91
  Config.set :env, 'test'
21
92
  assert_equal true, Config.test?
@@ -23,6 +94,7 @@ module Nyara
23
94
 
24
95
  Config.set :env, 'production'
25
96
  assert_equal false, Config.test?
97
+ assert_equal true, Config.production?
26
98
  end
27
99
  end
28
100
  end
@@ -11,6 +11,14 @@ class TestController < Nyara::Controller
11
11
  post '/create' do
12
12
  redirect_to '#index'
13
13
  end
14
+
15
+ put '/send_file/%z' do |name|
16
+ send_file Nyara.config.views_path name
17
+ end
18
+
19
+ delete '/render' do
20
+ render 'edit.slim'
21
+ end
14
22
  end
15
23
 
16
24
  class MyTest
@@ -18,12 +26,13 @@ class MyTest
18
26
  end
19
27
 
20
28
  module Nyara
21
- describe Nyara::Test do
29
+ describe Nyara::Test, 'integration' do
22
30
  before :all do
23
31
  configure do
24
32
  reset
25
- set :env, 'test'
33
+ # set :env, 'test'
26
34
  map '/', TestController
35
+ set :root, __dir__
27
36
  end
28
37
  Nyara.setup
29
38
  @test = MyTest.new
@@ -40,7 +49,7 @@ module Nyara
40
49
  it "redirect" do
41
50
  @test.post @test.path_to('test#create')
42
51
  assert @test.response.success?
43
- assert_equal 'http://localhost/', @test.redirect_location
52
+ assert_equal 'http://localhost:3000/', @test.redirect_location
44
53
  @test.follow_redirect
45
54
  assert_equal '/', @test.request.path
46
55
  end
@@ -54,5 +63,40 @@ module Nyara
54
63
  assert_equal '4', @test.session['b']
55
64
  assert_equal '3', @test.session['a']
56
65
  end
66
+
67
+ it "send file" do
68
+ @test.put "/send_file/layout.erb"
69
+ data = File.read Nyara.config.views_path('layout.erb')
70
+ assert_equal data, @test.response.body
71
+ end
72
+
73
+ it "render" do
74
+ @test.delete "/render"
75
+ assert_include @test.response.body, "slim:edit"
76
+ end
77
+
78
+ context "public static content" do
79
+ it "found file" do
80
+ @test.get "/index.html"
81
+ assert_equal 200, @test.response.status
82
+ assert_equal "index.html", @test.response.body
83
+ end
84
+
85
+ it "found empty file" do
86
+ @test.get "/empty file.html"
87
+ assert_equal 200, @test.response.status
88
+ assert_empty @test.response.body
89
+ end
90
+
91
+ it "missing file" do
92
+ @test.get "/missing.html"
93
+ assert_equal 404, @test.response.status
94
+ end
95
+
96
+ it "found but directory" do
97
+ @test.get "/empty"
98
+ assert_equal 404, @test.response.status
99
+ end
100
+ end
57
101
  end
58
102
  end
@@ -12,7 +12,7 @@ class FooController < Nyara::Controller
12
12
  end
13
13
 
14
14
  class BazController < Nyara::Controller
15
- set_name 'baz'
15
+ set_controller_name 'baz'
16
16
 
17
17
  meta '#index'
18
18
  get '/%d' do |id|
@@ -0,0 +1,10 @@
1
+ require_relative "performance_helper"
2
+ require "cgi"
3
+
4
+ s = 'abcde マfgイ'
5
+
6
+ GC.disable
7
+
8
+ nyara = bench(10000){ Nyara::Ext.escape s, false }
9
+ cgi = bench(10000){ CGI.escape s }
10
+ dump nyara: nyara, cgi: cgi
@@ -0,0 +1,14 @@
1
+ - # for layout_render.rb, captures: @title
2
+ doctype html
3
+ html
4
+ head
5
+ meta charset="utf-8"
6
+ meta http-equiv="X-UA-Compatible" content="IE=edge"
7
+ title == @title
8
+ link rel="icon" type="image/x-icon" href="/favicon.ico"
9
+ script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"
10
+ body
11
+ == yield
12
+
13
+ div#footer
14
+ | Copyright © #{Time.now}
@@ -0,0 +1,16 @@
1
+ - # for layout_render.rb, locals: items
2
+ h1 Markup examples
3
+
4
+ #content
5
+ p This example shows you how a basic Slim file looks like.
6
+
7
+ - unless items.empty?
8
+ table
9
+ - items.each do |item|
10
+ tr
11
+ td.name = item.name
12
+ td.price = item.price
13
+ - else
14
+ p
15
+ | No items found. Please add some inventory.
16
+ Thank you!
@@ -19,7 +19,7 @@ describe 'performance' do
19
19
 
20
20
  it "[parse_accept_value] faster than sinatra" do
21
21
  res = bm 'parse_accept_value'
22
- assert res[:nyara] * 1.7 < res[:sinatra], res.inspect
22
+ assert res[:nyara] * 1.5 < res[:sinatra], res.inspect
23
23
  end
24
24
 
25
25
  it "[parse_param] faster than parse in pure ruby" do
@@ -31,6 +31,11 @@ describe 'performance' do
31
31
  res = bm 'layout_render'
32
32
  assert res[:nyara] * 1.1 < res[:tilt], res.inspect
33
33
  end
34
+
35
+ it "[escape] faster than CGI.escape" do
36
+ res = bm 'escape'
37
+ assert res[:nyara] * 8 < res[:cgi], res.inspect
38
+ end
34
39
  end
35
40
 
36
41
  end # unless
File without changes
@@ -0,0 +1 @@
1
+ index.html
@@ -11,7 +11,7 @@ module Nyara
11
11
 
12
12
  before :each do
13
13
  @request = Ext.request_new
14
- session = ParamHash.new
14
+ session = Session.new
15
15
  Ext.request_set_attrs @request, {
16
16
  method_num: HTTP_METHODS['GET'],
17
17
  path: '/search',
data/spec/request_spec.rb CHANGED
@@ -38,6 +38,26 @@ module Nyara
38
38
  assert_equal 3000, @request.port
39
39
  end
40
40
 
41
+ it "#host_with_port ignores port on 80" do
42
+ @request.header['Host'] = '127.0.0.1'
43
+ assert_equal '127.0.0.1', @request.host_with_port
44
+ end
45
+
46
+ it "#accept_language" do
47
+ @request.header['accept-language'] = "en-US,en;q=0.8"
48
+ assert_equal ['en-US', 'en'], @request.accept_language
49
+ end
50
+
51
+ it "#accept_encoding with blank header" do
52
+ @request.header.delete 'Accept-Encoding'
53
+ assert_equal [], @request.accept_encoding
54
+ end
55
+
56
+ it "#accept_charset" do
57
+ @request.header['ACCEPT-CHARSET'] = "iso-8859-1;q=0.2, utf-8"
58
+ assert_equal %w[utf-8 iso-8859-1], @request.accept_charset
59
+ end
60
+
41
61
  def request_set_attrs
42
62
  Ext.request_set_attrs @request, @request_attrs
43
63
  end
@@ -44,6 +44,13 @@ module Nyara
44
44
  assert_equal [], conv
45
45
  end
46
46
 
47
+ it "#compile %z" do
48
+ re, conv = @r.compile_re '/%z'
49
+ assert_equal [:to_s], conv
50
+ s = '/foo bar.baz'
51
+ assert_equal [s, s[1..-1]], s.match(Regexp.new re).to_a
52
+ end
53
+
47
54
  it "#compile_re with utf-8 chars" do
48
55
  re, conv = @r.compile_re '/目录/%da/也可以'
49
56
  assert_equal [:to_i], conv
data/spec/session_spec.rb CHANGED
@@ -4,7 +4,8 @@ module Nyara
4
4
  describe Session do
5
5
  context ".encode_set_cookie options" do
6
6
  before :all do
7
- @session = {'hello' => 'world'}
7
+ @session = Session.new
8
+ @session['hello'] = 'world'
8
9
  end
9
10
 
10
11
  it "is HttpOnly" do
@@ -65,7 +66,8 @@ module Nyara
65
66
 
66
67
  it "should encode and decode" do
67
68
  cookie = {}
68
- session = {'hello' => 'world'}
69
+ session = Session.new
70
+ session['hello'] = 'world'
69
71
  Session.encode_to_cookie session, cookie
70
72
 
71
73
  session_data = cookie[Session.name].split('/')[1]
@@ -77,7 +79,8 @@ module Nyara
77
79
 
78
80
  it "drops bad signature" do
79
81
  cookie = {}
80
- session = {'hello' => 'world'}
82
+ session = Session.new
83
+ session['hello'] = 'world'
81
84
  Session.encode_to_cookie session, cookie
82
85
 
83
86
  cookie[Session.name].sub!(/\w/, &:swapcase)
@@ -98,7 +101,8 @@ module Nyara
98
101
 
99
102
  it "encode and decode" do
100
103
  cookie = {}
101
- session = {'hello' => 'world'}
104
+ session = Session.new
105
+ session['hello'] = 'world'
102
106
  Session.encode_to_cookie session, cookie
103
107
 
104
108
  session_data = cookie[Session.name].split('/')[1]
data/spec/spec_helper.rb CHANGED
@@ -4,6 +4,7 @@ require 'rspec/autorun'
4
4
  require "pry"
5
5
  require "slim"
6
6
  require "erb"
7
+ require "erubis"
7
8
  require "haml"
8
9
  require "liquid"
9
10
  require "open-uri"
@@ -1,9 +1,21 @@
1
1
  require_relative "spec_helper"
2
2
 
3
3
  module Nyara
4
- describe Ext, "parse" do
4
+ describe Ext, "url_encoded.c" do
5
+ context "Ext.escape" do
6
+ it "escapes path" do
7
+ s = "/a/path.js"
8
+ assert_equal s, Ext.escape(s, true)
9
+ end
10
+
11
+ it "escapes uri component" do
12
+ s = "/a/path.js"
13
+ assert_equal CGI.escape(s), Ext.escape(s, false)
14
+ end
15
+ end
16
+
5
17
  # note: this method is only used in C code
6
- context "#parse_url_encoded_seg" do
18
+ context "Ext.parse_url_encoded_seg" do
7
19
  [false, true].each do |nested|
8
20
  context (nested ? 'nested mode' : 'flat mode') do
9
21
  it "normal parse" do
@@ -58,7 +70,7 @@ module Nyara
58
70
  end
59
71
  end
60
72
 
61
- context "#parse_path" do
73
+ context "Ext.parse_path" do
62
74
  before :each do
63
75
  @output = ''
64
76
  end
@@ -128,7 +140,7 @@ module Nyara
128
140
  end
129
141
  end
130
142
 
131
- context ".parse_cookie" do
143
+ context "Ext.parse_cookie" do
132
144
  it "parses complex cookie" do
133
145
  history = CGI.escape '历史'
134
146
  cookie = "pgv_pvi; pgv_si= ; pgv_pvi=som; sid=1d6c75f0 ; PLHistory=<#{history}>;"
@@ -146,7 +158,7 @@ module Nyara
146
158
  end
147
159
  end
148
160
 
149
- context ".parse_param" do
161
+ context "Ext.parse_param" do
150
162
  it "parses param with non-utf-8 chars" do
151
163
  bad_s = CGI.escape "\xE2"
152
164
  h = Ext.parse_param ParamHash.new, bad_s
@@ -0,0 +1,2 @@
1
+ %div
2
+ = 'haml:edit'
@@ -0,0 +1,2 @@
1
+ div
2
+ = 'slim:edit'
File without changes
File without changes
@@ -0,0 +1 @@
1
+ <html><%== yield %></html>
@@ -0,0 +1 @@
1
+ = a
data/tools/foo.rb ADDED
@@ -0,0 +1,9 @@
1
+ require_relative "../lib/nyara"
2
+
3
+ post '/' do
4
+ data = File.binread('text.gz')
5
+ set_header 'Content-Length', data.bytesize
6
+ set_header 'Content-Encoding', 'gzip'
7
+ set_header 'Transfer-Encoding', 'chunked'
8
+ send_string data
9
+ end
data/tools/hello.rb CHANGED
@@ -1,23 +1,28 @@
1
- require_relative "../lib/nyara"
1
+ require_relative "../lib/nyara/nyara"
2
2
  # require "open-uri"
3
3
  # require "pry"
4
4
 
5
5
  configure do
6
6
  # set :env, 'production'
7
- # set :workers, 2
7
+ # set :workers, 3
8
+ map '/', 'my'
8
9
  end
9
10
 
10
- get '/' do
11
- # open 'http://baidu.com', &:read
12
- send_string 'hello world'
13
- end
11
+ class MyController < Nyara::Controller
12
+ get '/' do
13
+ send_string 'hello world'
14
+ end
14
15
 
15
- get '/exit' do
16
- exit
17
- end
16
+ get '/exit' do
17
+ exit
18
+ end
18
19
 
19
- get '/redi' do
20
- redirect '/'
20
+ get '/redi' do
21
+ redirect '/'
22
+ end
21
23
  end
22
24
 
25
+ Nyara.setup
26
+ Nyara.start_server
27
+
23
28
  # GC.stress = true