rocketio 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -5
  3. data/.pryrc +2 -0
  4. data/.travis.yml +3 -0
  5. data/README.md +22 -5
  6. data/Rakefile +7 -1
  7. data/bin/console +14 -0
  8. data/bin/setup +7 -0
  9. data/lib/rocketio.rb +131 -3
  10. data/lib/rocketio/application.rb +31 -0
  11. data/lib/rocketio/controller.rb +288 -0
  12. data/lib/rocketio/controller/authentication.rb +141 -0
  13. data/lib/rocketio/controller/authorization.rb +53 -0
  14. data/lib/rocketio/controller/cookies.rb +59 -0
  15. data/lib/rocketio/controller/error_handlers.rb +89 -0
  16. data/lib/rocketio/controller/filters.rb +119 -0
  17. data/lib/rocketio/controller/flash.rb +21 -0
  18. data/lib/rocketio/controller/helpers.rb +438 -0
  19. data/lib/rocketio/controller/middleware.rb +32 -0
  20. data/lib/rocketio/controller/render.rb +148 -0
  21. data/lib/rocketio/controller/render/engine.rb +76 -0
  22. data/lib/rocketio/controller/render/layout.rb +27 -0
  23. data/lib/rocketio/controller/render/layouts.rb +85 -0
  24. data/lib/rocketio/controller/render/templates.rb +83 -0
  25. data/lib/rocketio/controller/request.rb +115 -0
  26. data/lib/rocketio/controller/response.rb +84 -0
  27. data/lib/rocketio/controller/sessions.rb +64 -0
  28. data/lib/rocketio/controller/token_auth.rb +118 -0
  29. data/lib/rocketio/controller/websocket.rb +21 -0
  30. data/lib/rocketio/error_templates/404.html +3 -0
  31. data/lib/rocketio/error_templates/409.html +7 -0
  32. data/lib/rocketio/error_templates/500.html +3 -0
  33. data/lib/rocketio/error_templates/501.html +6 -0
  34. data/lib/rocketio/error_templates/layout.html +1 -0
  35. data/lib/rocketio/exceptions.rb +4 -0
  36. data/lib/rocketio/router.rb +65 -0
  37. data/lib/rocketio/util.rb +122 -0
  38. data/lib/rocketio/version.rb +2 -2
  39. data/rocketio.gemspec +21 -17
  40. data/test/aliases_test.rb +54 -0
  41. data/test/authentication_test.rb +307 -0
  42. data/test/authorization_test.rb +91 -0
  43. data/test/cache_control_test.rb +268 -0
  44. data/test/content_type_test.rb +124 -0
  45. data/test/cookies_test.rb +49 -0
  46. data/test/error_handlers_test.rb +125 -0
  47. data/test/etag_test.rb +445 -0
  48. data/test/filters_test.rb +177 -0
  49. data/test/halt_test.rb +73 -0
  50. data/test/helpers_test.rb +171 -0
  51. data/test/middleware_test.rb +57 -0
  52. data/test/redirect_test.rb +135 -0
  53. data/test/render/engine_test.rb +71 -0
  54. data/test/render/get.erb +1 -0
  55. data/test/render/items.erb +1 -0
  56. data/test/render/layout.erb +1 -0
  57. data/test/render/layout_test.rb +104 -0
  58. data/test/render/layouts/master.erb +1 -0
  59. data/test/render/layouts_test.rb +145 -0
  60. data/test/render/master.erb +1 -0
  61. data/test/render/post.erb +1 -0
  62. data/test/render/put.erb +1 -0
  63. data/test/render/render_test.rb +101 -0
  64. data/test/render/setup.rb +14 -0
  65. data/test/render/templates/a/get.erb +1 -0
  66. data/test/render/templates/master.erb +1 -0
  67. data/test/render/templates_test.rb +146 -0
  68. data/test/request_test.rb +105 -0
  69. data/test/response_test.rb +119 -0
  70. data/test/routes_test.rb +70 -0
  71. data/test/sendfile_test.rb +209 -0
  72. data/test/sessions_test.rb +176 -0
  73. data/test/setup.rb +59 -0
  74. metadata +144 -9
  75. data/LICENSE.txt +0 -22
@@ -0,0 +1 @@
1
+ master <%= yield %> layout
@@ -0,0 +1 @@
1
+ <%= @var %>
@@ -0,0 +1 @@
1
+ <%= var %>
@@ -0,0 +1,101 @@
1
+ require 'setup'
2
+
3
+ spec :Views do
4
+ context :cache do
5
+ engine = Tilt::ERBTemplate
6
+ path = File.expand_path('../templates/a', __FILE__)
7
+ define_method(:file) {mock_controller(:a).initialize_controller.send(:find_template, path, 'get', engine)}
8
+ define_method(:read) {mock_controller(:a).initialize_controller.send(:read_template, file).__id__}
9
+ define_method(:compile) {|tpl| mock_controller(:a).initialize_controller.send(:compile_template, tpl, engine).__id__}
10
+
11
+ it 'resolves template path only once' do
12
+ cache_id = file.__id__
13
+ assert(file.__id__) == cache_id
14
+ end
15
+
16
+ it 'rereads templates only when template file modified' do
17
+ cache_id = read
18
+ assert(read) == cache_id
19
+ FileUtils.touch(file)
20
+ refute(read) == cache_id
21
+ end
22
+
23
+ it 'recompiles template only if it was modified' do
24
+ cache_id = compile('')
25
+ assert(compile('')) == cache_id
26
+ refute(compile('changed')) == cache_id
27
+ end
28
+ end
29
+
30
+ context :scope do
31
+ it 'uses controller instance for scope' do
32
+ app mock_controller {
33
+ before {@var = :val}
34
+ def post; render; end
35
+ }
36
+ post
37
+ assert(last_response).is_ok_with_body('val')
38
+ end
39
+ it 'uses custom scope' do
40
+ app mock_controller {
41
+ before {@var = :val}
42
+ def post
43
+ scope = Class.new {def initialize; @var = :vax; end}.new
44
+ render(scope: scope)
45
+ end
46
+ }
47
+ post
48
+ assert(last_response).is_ok_with_body('vax')
49
+ end
50
+ end
51
+
52
+ context :locals do
53
+ it 'makes :locals accessible via attributes' do
54
+ app mock_controller {
55
+ def put; render(locals: {var: :val}); end
56
+ }
57
+ put
58
+ assert(last_response).is_ok_with_body('val')
59
+ end
60
+ end
61
+
62
+ context 'implicit templates' do
63
+ it 'uses the folder controller resides in as default path' do
64
+ app controller = mock_controller(:a) {
65
+ def get; render end
66
+ }
67
+ get
68
+ assert(last_response).is_ok_with_body '/a'
69
+ end
70
+ end
71
+
72
+ context 'defined templates' do
73
+ it 'prefers defined templates over files' do
74
+ app mock_controller {
75
+ define_template(:get) {'x'}
76
+ def get; render end
77
+ }
78
+ get
79
+ assert(last_response).is_ok_with_body 'x'
80
+ end
81
+
82
+ it 'renders defined template with defined layout' do
83
+ app mock_controller {
84
+ define_template(:t) {'t'}
85
+ define_layout(:x) {'x<%= yield %>x'}
86
+ layout(:x)
87
+ def get; render(:t) end
88
+ }
89
+ get
90
+ assert(last_response).is_ok_with_body 'xtx'
91
+ end
92
+ end
93
+
94
+ it 'uses given block for template' do
95
+ app mock_controller {
96
+ def get; render {'x'} end
97
+ }
98
+ get
99
+ assert(last_response).is_ok_with_body 'x'
100
+ end
101
+ end
@@ -0,0 +1,14 @@
1
+ require 'test/setup'
2
+
3
+ spec do
4
+ # overriding mock_controller cause when defining a controller
5
+ # caller used to set controller's dirname
6
+ # and we do not want to clobber test/ dir with template files
7
+ def mock_controller path = :/, superclass = nil, &block
8
+ path, superclass = :/, path if path.is_a?(Class)
9
+ controller = Class.new(superclass || RocketIO::Controller)
10
+ controller.map(path)
11
+ controller.class_exec(&block) if block
12
+ controller
13
+ end
14
+ end
@@ -0,0 +1 @@
1
+ hi
@@ -0,0 +1 @@
1
+ -<%= yield %>-
@@ -0,0 +1,146 @@
1
+ require 'setup'
2
+
3
+ spec :templates do
4
+ context :compositing do
5
+ it 'inherits templates from superclass' do
6
+ a = mock_controller {
7
+ define_template(:a) {'a'}
8
+ }
9
+ b = mock_controller(a) {
10
+ }.initialize_controller
11
+ assert(b.__send__ b.templates[:a]) == 'a'
12
+ end
13
+
14
+ it 'complements templates inherited from superclass' do
15
+ a = mock_controller {
16
+ define_template(:a) {'a'}
17
+ }
18
+ b = mock_controller(a) {
19
+ define_template(:b) {'b'}
20
+ }.initialize_controller
21
+ assert(b.__send__ b.templates[:a]) == 'a'
22
+ assert(b.__send__ b.templates[:b]) == 'b'
23
+ end
24
+ #
25
+ it 'overrides templates inherited from superclass' do
26
+ a = mock_controller {
27
+ define_template(:x) {'a'}
28
+ }
29
+ b = mock_controller(a) {
30
+ define_template(:x) {'b'}
31
+ }.initialize_controller
32
+ assert(b.__send__ b.templates[:x]) == 'b'
33
+ end
34
+
35
+ test '`inherit` overrides templates inherited from superclass' do
36
+ a = mock_controller {
37
+ define_template(:x) {'a'}
38
+ }
39
+ b = mock_controller(a) {
40
+ define_template(:x) {'b'}
41
+ }
42
+ c = mock_controller(a) {
43
+ inherit :templates, from: b
44
+ }.initialize_controller
45
+ assert(c.__send__ c.templates[:x]) == 'b'
46
+ end
47
+
48
+ test '`inherit` complements templates inherited from superclass' do
49
+ a = mock_controller {
50
+ define_template(:a) {'a'}
51
+ }
52
+ b = mock_controller(a) {
53
+ define_template(:b) {'b'}
54
+ }
55
+ c = mock_controller(a) {
56
+ inherit :templates, from: b
57
+ }.initialize_controller
58
+ assert(c.__send__ c.templates[:a]) == 'a'
59
+ assert(c.__send__ c.templates[:b]) == 'b'
60
+ end
61
+
62
+ test '`inherit` overrides defined templates' do
63
+ a = mock_controller {
64
+ define_template(:x) {'a'}
65
+ }
66
+ b = mock_controller {
67
+ define_template(:x) {'b'}
68
+ inherit :templates, from: a
69
+ }.initialize_controller
70
+ assert(b.__send__ b.templates[:x]) == 'a'
71
+ end
72
+
73
+ test '`inherit` complements defined templates' do
74
+ a = mock_controller {
75
+ define_template(:a) {'a'}
76
+ }
77
+ b = mock_controller {
78
+ define_template(:b) {'b'}
79
+ inherit :templates, from: a
80
+ }.initialize_controller
81
+ assert(b.__send__ b.templates[:a]) == 'a'
82
+ assert(b.__send__ b.templates[:b]) == 'b'
83
+ end
84
+
85
+ it 'overrides templates inherited via `inherit`' do
86
+ a = mock_controller {
87
+ define_template(:x) {'a'}
88
+ }
89
+ b = mock_controller {
90
+ inherit :templates, from: a
91
+ define_template(:x) {'b'}
92
+ }.initialize_controller
93
+ assert(b.__send__ b.templates[:x]) == 'b'
94
+ end
95
+ end
96
+
97
+ context :rendering do
98
+
99
+ it 'uses a file with same name if only name given' do
100
+ c = mock_controller {
101
+ define_template :get
102
+ }.initialize_controller
103
+ assert(c.render(:get)) == "/"
104
+ end
105
+
106
+ it 'raises a TemplateError if there is no file with same name' do
107
+ template = rand.to_s
108
+ c = mock_controller {
109
+ define_template template
110
+ }.initialize_controller
111
+ assert {c.render(template)}.raise RocketIO::TemplateError
112
+ end
113
+
114
+ it 'uses given file - file resides in controller dirname' do
115
+ c = mock_controller {
116
+ define_template :get, file: :items
117
+ }.initialize_controller
118
+ assert(c.render(:get)) == "items\n"
119
+ end
120
+
121
+ it 'uses given file - file resides outside controller dirname' do
122
+ c = mock_controller {
123
+ define_template :get, file: './templates/a/get'
124
+ }.initialize_controller
125
+ assert(c.render(:get)) == "hi\n"
126
+ end
127
+
128
+ it 'accepts a block for given file' do
129
+ c = mock_controller {
130
+ define_template :master, file: -> {@outside ? './templates/a/get' : :items}
131
+ }.initialize_controller
132
+ assert(c.render(:master)) == "items\n"
133
+ c.instance_variable_set(:@outside, true)
134
+ assert(c.render(:master)) == "hi\n"
135
+ end
136
+
137
+ it 'accepts a block and uses returned value as template without searching for file' do
138
+ c = mock_controller {
139
+ define_template(:master) {@admin ? 'admin' : 'user'}
140
+ }.initialize_controller
141
+ assert(c.render(:master)) == "user"
142
+ c.instance_variable_set(:@admin, true)
143
+ assert(c.render(:master)) == "admin"
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,105 @@
1
+ require 'setup'
2
+ require 'stringio'
3
+
4
+ # tests stolen from github.com/sinatra/sinatra
5
+ # Copyright (c) 2007, 2008, 2009 Blake Mizerany
6
+ # Copyright (c) 2010, 2011, 2012, 2013, 2014 Konstantin Haase
7
+ # Copyright (c) 2015 Slee Woo
8
+
9
+ spec RocketIO::Request do
10
+
11
+ it 'responds to #user_agent' do
12
+ request = RocketIO::Request.new({'HTTP_USER_AGENT' => 'Test'})
13
+ assert(request).respond_to?(:user_agent)
14
+ assert('Test') == request.user_agent
15
+ end
16
+
17
+ it 'parses POST params when Content-Type is form-dataish' do
18
+ request = RocketIO::Request.new(
19
+ 'REQUEST_METHOD' => 'PUT',
20
+ 'CONTENT_TYPE' => 'application/x-www-form-urlencoded',
21
+ 'rack.input' => StringIO.new('foo=bar')
22
+ )
23
+ assert('bar') == request.params['foo']
24
+ end
25
+
26
+ it 'is secure when the url scheme is https' do
27
+ request = RocketIO::Request.new('rack.url_scheme' => 'https')
28
+ assert(request).secure?
29
+ end
30
+
31
+ it 'is not secure when the url scheme is http' do
32
+ request = RocketIO::Request.new('rack.url_scheme' => 'http')
33
+ refute(request).secure?
34
+ end
35
+
36
+ it 'respects X-Forwarded-Proto header for proxied SSL' do
37
+ request = RocketIO::Request.new('HTTP_X_FORWARDED_PROTO' => 'https')
38
+ assert(request).secure?
39
+ end
40
+
41
+ it 'is possible to marshal params' do
42
+ request = RocketIO::Request.new(
43
+ 'REQUEST_METHOD' => 'PUT',
44
+ 'CONTENT_TYPE' => 'application/x-www-form-urlencoded',
45
+ 'rack.input' => StringIO.new('foo=bar')
46
+ )
47
+ dumped = Marshal.dump(request.params)
48
+ assert('bar') == Marshal.load(dumped)['foo']
49
+ end
50
+
51
+ it "exposes the preferred type's parameters" do
52
+ request = RocketIO::Request.new(
53
+ 'HTTP_ACCEPT' => 'image/jpeg; compress=0.25'
54
+ )
55
+ assert({ 'compress' => '0.25' }) == request.preferred_type.params
56
+ end
57
+
58
+ it "makes accept types behave like strings" do
59
+ request = RocketIO::Request.new('HTTP_ACCEPT' => 'image/jpeg; compress=0.25')
60
+ assert(request).accept?('image/jpeg')
61
+ assert('image/jpeg') == request.preferred_type.to_s
62
+ assert('image/jpeg; compress=0.25') == request.preferred_type.to_s(true)
63
+ assert('image/jpeg') == request.preferred_type.to_str
64
+ assert('image') == request.preferred_type.split('/').first
65
+
66
+ String.instance_methods.each do |method|
67
+ next unless "".respond_to? method
68
+ assert(request.preferred_type).respond_to?(method)
69
+ end
70
+ end
71
+
72
+ it "accepts types when wildcards are requested" do
73
+ request = RocketIO::Request.new('HTTP_ACCEPT' => 'image/*')
74
+ assert(request).accept?('image/jpeg')
75
+ end
76
+
77
+ it "properly decodes MIME type parameters" do
78
+ request = RocketIO::Request.new(
79
+ 'HTTP_ACCEPT' => 'image/jpeg;unquoted=0.25;quoted="0.25";chartest="\";,\x"'
80
+ )
81
+ expected = { 'unquoted' => '0.25', 'quoted' => '0.25', 'chartest' => '";,x' }
82
+ assert(expected) == request.preferred_type.params
83
+ end
84
+
85
+ it 'accepts */* when HTTP_ACCEPT is not present in the request' do
86
+ request = RocketIO::Request.new Hash.new
87
+ assert(1) == request.accept.size
88
+ assert(request).accept?('text/html')
89
+ assert('*/*') == request.preferred_type.to_s
90
+ assert('*/*') == request.preferred_type.to_s(true)
91
+ end
92
+
93
+ it 'accepts */* when HTTP_ACCEPT is blank in the request' do
94
+ request = RocketIO::Request.new 'HTTP_ACCEPT' => ''
95
+ assert(1) == request.accept.size
96
+ assert(request).accept?('text/html')
97
+ assert('*/*') == request.preferred_type.to_s
98
+ assert('*/*') == request.preferred_type.to_s(true)
99
+ end
100
+
101
+ it 'will not accept types not specified in HTTP_ACCEPT when HTTP_ACCEPT is provided' do
102
+ request = RocketIO::Request.new 'HTTP_ACCEPT' => 'application/json'
103
+ refute(request).accept?('text/html')
104
+ end
105
+ end
@@ -0,0 +1,119 @@
1
+ # Copyright (c) 2007, 2008, 2009 Blake Mizerany
2
+ # Copyright (c) 2010, 2011, 2012, 2013, 2014 Konstantin Haase
3
+ # Copyright (c) 2015 Slee Woo
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person
6
+ # obtaining a copy of this software and associated documentation
7
+ # files (the "Software"), to deal in the Software without
8
+ # restriction, including without limitation the rights to use,
9
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the
11
+ # Software is furnished to do so, subject to the following
12
+ # conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
+ # OTHER DEALINGS IN THE SOFTWARE.
25
+
26
+ require 'setup'
27
+
28
+ spec RocketIO::Response do
29
+ before { @response = RocketIO::Response.new }
30
+
31
+ assert :identical_to? do |a,b|
32
+ a.to_enum(:each).to_a == b.to_enum(:each).to_a
33
+ end
34
+
35
+ it "initializes with 200 status code, empty body and nil content type" do
36
+ assert(@response.status) == 200
37
+ assert(@response['Content-Type']).nil?
38
+ assert(@response.body) == []
39
+ end
40
+
41
+ it 'uses case insensitive headers' do
42
+ @response['content-type'] = 'application/foo'
43
+ assert('application/foo') == @response['Content-Type']
44
+ assert('application/foo') == @response['CONTENT-TYPE']
45
+ end
46
+
47
+ it 'writes to body' do
48
+ @response.body = 'Hello'
49
+ @response.write ' World'
50
+ assert('Hello World') == @response.body.join
51
+ end
52
+
53
+ [204, 304].each do |status_code|
54
+ it "removes the Content-Type header and body when response status is #{status_code}" do
55
+ @response.status = status_code
56
+ @response.body = ['Hello World']
57
+ assert([status_code, {}, []]) == @response.finish
58
+ end
59
+ end
60
+
61
+ it 'does not call #to_ary or #inject on the body' do
62
+ object = Object.new
63
+ def object.inject(*) fail 'called' end
64
+ def object.to_ary(*) fail 'called' end
65
+ def object.each(*) end
66
+ @response.body = object
67
+ refute(@response.finish).nil?
68
+ end
69
+
70
+ it 'does not nest a RocketIO::Response' do
71
+ @response.body = RocketIO::Response.new ["foo"]
72
+ assert(@response.body).identical_to? ["foo"]
73
+ end
74
+
75
+ it 'does not nest a Rack::Response' do
76
+ @response.body = Rack::Response.new ["foo"]
77
+ assert(@response.body).identical_to? ["foo"]
78
+ end
79
+
80
+ it "sets response.body when result is a String" do
81
+ app mock_controller {
82
+ def get; 'Hello World' end
83
+ }
84
+
85
+ get
86
+ assert(last_response).is_ok_with_body 'Hello World'
87
+ end
88
+
89
+ it "sets response.body when result is an Array of Strings" do
90
+ app mock_controller {
91
+ def get; ['Hello', 'World'] end
92
+ }
93
+
94
+ get
95
+ assert(last_response).is_ok_with_body 'HelloWorld'
96
+ end
97
+
98
+ it "sets response.body when result responds to #each" do
99
+ app mock_controller {
100
+ def get
101
+ res = lambda { 'Hello World' }
102
+ def res.each ; yield call ; end
103
+ res
104
+ end
105
+ }
106
+
107
+ get
108
+ assert(last_response).is_ok_with_body 'Hello World'
109
+ end
110
+
111
+ it "sets response.body to [] when result is nil" do
112
+ app mock_controller {
113
+ def get; end
114
+ }
115
+
116
+ get
117
+ assert(last_response).is_ok_with_body ''
118
+ end
119
+ end