noodles 0.0.1 → 0.0.6
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.travis.yml +10 -0
- data/Gemfile +1 -0
- data/LICENSE.txt +1 -1
- data/README.md +9 -1
- data/Rakefile +10 -0
- data/bin/noodles +2 -0
- data/cli/noodles_cli.rb +92 -0
- data/cli/template/.gitignore +0 -0
- data/cli/template/Gemfile +6 -0
- data/cli/template/app/controllers/.keep +0 -0
- data/cli/template/app/handlers/.keep +0 -0
- data/cli/template/app/templates/.keep +0 -0
- data/cli/template/app/views/.keep +0 -0
- data/cli/template/config.ru +12 -0
- data/cli/template/config/application.rb +7 -0
- data/cli/template/config/router.rb +2 -0
- data/cli/template/config/secrets.yml +7 -0
- data/cli/template/config/setup.rb +3 -0
- data/cli/template/public/css/.keep +0 -0
- data/cli/template/public/images/.keep +0 -0
- data/cli/template/public/js/.keep +0 -0
- data/lib/noodles.rb +51 -3
- data/lib/noodles/application.rb +23 -0
- data/lib/noodles/cache.rb +6 -0
- data/lib/noodles/dependencies.rb +12 -0
- data/lib/noodles/environment.rb +47 -0
- data/lib/noodles/http/application.rb +34 -0
- data/lib/noodles/http/controller.rb +106 -0
- data/lib/noodles/http/errors/no_router_error.rb +9 -0
- data/lib/noodles/http/router.rb +81 -0
- data/lib/noodles/http/view.rb +6 -0
- data/lib/noodles/utils.rb +8 -0
- data/lib/noodles/version.rb +1 -1
- data/lib/noodles/websocket/application.rb +14 -0
- data/lib/noodles/websocket/channel.rb +22 -0
- data/lib/noodles/websocket/handler.rb +47 -0
- data/lib/noodles/websocket/routing.rb +12 -0
- data/noodles.gemspec +22 -6
- data/test/secrets.yml +11 -0
- data/test/templates/current_user_temp.erb +1 -0
- data/test/templates/current_user_temp.haml +1 -0
- data/test/templates/current_user_temp.slim +1 -0
- data/test/templates/index.haml +2 -0
- data/test/templates/index.slim +2 -0
- data/test/templates/layout.haml +3 -0
- data/test/templates/show.erb +1 -0
- data/test/templates/with_variables.erb +2 -0
- data/test/templates/with_variables.haml +2 -0
- data/test/templates/with_variables.slim +2 -0
- data/test/test_application.rb +299 -0
- data/test/test_cache.rb +66 -0
- data/test/test_environment.rb +24 -0
- data/test/test_helper.rb +10 -0
- data/test/test_secrets.rb +24 -0
- metadata +271 -10
@@ -0,0 +1,81 @@
|
|
1
|
+
module Noodles
|
2
|
+
module Http
|
3
|
+
class Router
|
4
|
+
attr_reader :routes
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@routes = []
|
8
|
+
end
|
9
|
+
|
10
|
+
[:get, :post, :put, :delete].each do |method|
|
11
|
+
define_method method do |url, destination|
|
12
|
+
match(method, url, destination)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def root_to(destination)
|
17
|
+
get('', destination)
|
18
|
+
end
|
19
|
+
|
20
|
+
def find_by_url(method, url)
|
21
|
+
method = method.downcase.to_sym
|
22
|
+
|
23
|
+
route = routes.find do |route|
|
24
|
+
route[:method] == method and route[:regexp].match(url)
|
25
|
+
end
|
26
|
+
|
27
|
+
return if route.nil?
|
28
|
+
|
29
|
+
data_match = route[:regexp].match(url)
|
30
|
+
|
31
|
+
path_params = {}
|
32
|
+
route[:path_params].each_with_index do |path_param, index|
|
33
|
+
path_params[path_param] = data_match.captures[index]
|
34
|
+
end
|
35
|
+
get_destination(route[:destination], path_params)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def match(method, url, destination)
|
41
|
+
regexp, path_params = regexed_url_and_path_params(url)
|
42
|
+
|
43
|
+
routes.push method: method, url: url, regexp: Regexp.new("^/#{regexp}$"),
|
44
|
+
destination: destination, path_params: path_params
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def regexed_url_and_path_params(url)
|
49
|
+
url_parts = url.split("/")
|
50
|
+
url_parts.select! { |p| !p.empty? }
|
51
|
+
|
52
|
+
path_params = []
|
53
|
+
|
54
|
+
regexp_parts = url_parts.map do |url_part|
|
55
|
+
if url_part[0] == ":"
|
56
|
+
path_params << url_part[1..-1]
|
57
|
+
"([a-zA-Z0-9]+)"
|
58
|
+
elsif url_part[0] == "*"
|
59
|
+
path_params << url_part[1..-1]
|
60
|
+
"(.*)"
|
61
|
+
else
|
62
|
+
url_part
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
regexp = regexp_parts.join("/")
|
67
|
+
[regexp, path_params]
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_destination(destination, path_params = {})
|
71
|
+
return destination if destination.respond_to?(:call)
|
72
|
+
|
73
|
+
controller_name, action = destination.split('#')
|
74
|
+
controller_name = controller_name.capitalize
|
75
|
+
controller = Object.const_get("#{controller_name}Controller")
|
76
|
+
controller.action(action, path_params)
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/noodles/version.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "noodles/websocket/routing"
|
2
|
+
require "noodles/websocket/handler"
|
3
|
+
require "noodles/websocket/channel"
|
4
|
+
|
5
|
+
module Noodles
|
6
|
+
module Websocket
|
7
|
+
class Application
|
8
|
+
def call(env)
|
9
|
+
handler = get_handler(env)
|
10
|
+
handler.new.call(env)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Noodles
|
2
|
+
module Websocket
|
3
|
+
class Channel
|
4
|
+
# class << self
|
5
|
+
# attr_accessor :connections
|
6
|
+
# end
|
7
|
+
# self.connections = []
|
8
|
+
|
9
|
+
def self.connections
|
10
|
+
@@connections ||= []
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.broadcast(msg)
|
14
|
+
connections.each do |connection|
|
15
|
+
connection.send_data msg
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rack/websocket'
|
2
|
+
|
3
|
+
module Noodles
|
4
|
+
module Websocket
|
5
|
+
class Handler < Rack::WebSocket::Application
|
6
|
+
|
7
|
+
@@connections ||= []
|
8
|
+
|
9
|
+
# def connection
|
10
|
+
# @websocket_handler.instance_variable_get("@connection")
|
11
|
+
# end
|
12
|
+
|
13
|
+
def add_connection handler
|
14
|
+
@@connections << handler
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def remove_connection handler
|
19
|
+
@@connections.delete handler
|
20
|
+
end
|
21
|
+
|
22
|
+
def broadcast msg
|
23
|
+
@@connections.each do |connection|
|
24
|
+
connection.send_data msg
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def broadcast_but_self msg
|
29
|
+
(@@connections - [self]).each do |connection|
|
30
|
+
connection.send_data msg
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def request(env)
|
35
|
+
Rack::Request.new(env)
|
36
|
+
end
|
37
|
+
|
38
|
+
def params(env)
|
39
|
+
request(env).params
|
40
|
+
end
|
41
|
+
|
42
|
+
def connection_storage
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/noodles.gemspec
CHANGED
@@ -6,18 +6,34 @@ require 'noodles/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "noodles"
|
8
8
|
spec.version = Noodles::VERSION
|
9
|
-
spec.authors = ["
|
9
|
+
spec.authors = ["Damir Svrtan"]
|
10
10
|
spec.email = ["damir.svrtan@gmail.com"]
|
11
|
-
spec.
|
12
|
-
spec.summary = "Noodles"
|
11
|
+
spec.summary = "Rack based web framework"
|
13
12
|
spec.homepage = ""
|
14
13
|
spec.license = "MIT"
|
15
14
|
|
16
|
-
spec.files = `git ls-files`.split(
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
16
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
18
|
spec.require_paths = ["lib"]
|
20
19
|
|
21
|
-
spec.add_development_dependency
|
22
|
-
spec.add_development_dependency
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
21
|
+
spec.add_development_dependency 'rake'
|
22
|
+
spec.add_development_dependency 'rack-test'
|
23
|
+
spec.add_development_dependency 'minitest'
|
24
|
+
spec.add_development_dependency 'pry'
|
25
|
+
|
26
|
+
spec.add_runtime_dependency 'rack'
|
27
|
+
spec.add_runtime_dependency 'websocket-rack-noodles'
|
28
|
+
spec.add_runtime_dependency 'better_errors'
|
29
|
+
spec.add_runtime_dependency 'multi_json'
|
30
|
+
spec.add_runtime_dependency 'thor'
|
31
|
+
|
32
|
+
spec.add_runtime_dependency 'erubis'
|
33
|
+
spec.add_runtime_dependency 'slim'
|
34
|
+
spec.add_runtime_dependency 'haml'
|
35
|
+
spec.add_runtime_dependency 'tilt'
|
36
|
+
|
37
|
+
spec.add_runtime_dependency 'colorize'
|
38
|
+
spec.add_runtime_dependency 'dalli'
|
23
39
|
end
|
data/test/secrets.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
<%= current_user %>
|
@@ -0,0 +1 @@
|
|
1
|
+
= current_user
|
@@ -0,0 +1 @@
|
|
1
|
+
= current_user
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>Show</h1>
|
@@ -0,0 +1,299 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class TestApp < Noodles::Application
|
4
|
+
end
|
5
|
+
|
6
|
+
module NoodleCurrent
|
7
|
+
def current_user
|
8
|
+
"Damir"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class NoodleView
|
13
|
+
include NoodleCurrent
|
14
|
+
end
|
15
|
+
|
16
|
+
class TestController < Noodles::Http::Controller
|
17
|
+
view NoodleView
|
18
|
+
|
19
|
+
def root_page
|
20
|
+
text "Root Page"
|
21
|
+
end
|
22
|
+
|
23
|
+
def index
|
24
|
+
text "hello"
|
25
|
+
end
|
26
|
+
|
27
|
+
def show
|
28
|
+
erb 'show'
|
29
|
+
end
|
30
|
+
|
31
|
+
def index_with_slim
|
32
|
+
slim 'index'
|
33
|
+
end
|
34
|
+
|
35
|
+
def index_with_haml
|
36
|
+
haml 'index'
|
37
|
+
end
|
38
|
+
|
39
|
+
def with_current_user
|
40
|
+
erb 'current_user_temp'
|
41
|
+
end
|
42
|
+
|
43
|
+
def with_current_user_haml
|
44
|
+
haml 'current_user_temp'
|
45
|
+
end
|
46
|
+
|
47
|
+
def with_current_user_slim
|
48
|
+
slim 'current_user_temp'
|
49
|
+
end
|
50
|
+
|
51
|
+
def with_variables_erb
|
52
|
+
@username = "Jack"
|
53
|
+
@hello_message = "HI!"
|
54
|
+
erb 'with_variables'
|
55
|
+
end
|
56
|
+
|
57
|
+
def with_variables_haml
|
58
|
+
@username = "Jack"
|
59
|
+
@hello_message = "HI!"
|
60
|
+
haml 'with_variables'
|
61
|
+
end
|
62
|
+
|
63
|
+
def with_variables_slim
|
64
|
+
@username = "Jack"
|
65
|
+
@hello_message = "HI!"
|
66
|
+
slim 'with_variables'
|
67
|
+
end
|
68
|
+
|
69
|
+
def change_response_status_code
|
70
|
+
response.status = 201
|
71
|
+
haml 'index'
|
72
|
+
end
|
73
|
+
|
74
|
+
def post_request
|
75
|
+
haml 'index'
|
76
|
+
end
|
77
|
+
|
78
|
+
def cookie_setting
|
79
|
+
response.set_cookie "user_id", 1
|
80
|
+
haml 'index'
|
81
|
+
end
|
82
|
+
|
83
|
+
def cookie_deletion
|
84
|
+
response.delete_cookie 'user_id'
|
85
|
+
haml 'index'
|
86
|
+
end
|
87
|
+
|
88
|
+
def redirecting_path
|
89
|
+
redirect 'test/index'
|
90
|
+
end
|
91
|
+
|
92
|
+
def json_response
|
93
|
+
json({ username: "Jack", sex: "M" })
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def get_rendering_path(view_name, template_name)
|
99
|
+
File.join 'test', 'templates', "#{view_name}.#{template_name}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class NoodlesTestApp < Minitest::Test
|
104
|
+
include Rack::Test::Methods
|
105
|
+
|
106
|
+
def app
|
107
|
+
app = TestApp.new
|
108
|
+
app.http_app.routes do
|
109
|
+
root_to "test#root_page"
|
110
|
+
get "test/index", "test#index"
|
111
|
+
get "test/show", "test#show"
|
112
|
+
get "test/index_with_slim", "test#index_with_slim"
|
113
|
+
get "test/index_with_haml", "test#index_with_haml"
|
114
|
+
get "pipa/:id/slavina/:slavina_id", "test#hamly"
|
115
|
+
get "sub-app", proc { |env| [200, {}, [env['PATH_INFO']]] }
|
116
|
+
get "sub-app2", proc { [200, {}, ['ANOTHER SUB APP']] }
|
117
|
+
get "with_variables_erb", "test#with_variables_erb"
|
118
|
+
get "with_variables_haml", "test#with_variables_haml"
|
119
|
+
get "with_variables_slim", "test#with_variables_slim"
|
120
|
+
get "change_response_status_code", "test#change_response_status_code"
|
121
|
+
get "cookie_setting", "test#cookie_setting"
|
122
|
+
get "cookie_deletion", "test#cookie_deletion"
|
123
|
+
post "testing_post", "test#post_request"
|
124
|
+
get "redirecting_path", "test#redirecting_path"
|
125
|
+
get 'with_current_user', "test#with_current_user"
|
126
|
+
get 'with_current_user_slim', "test#with_current_user_slim"
|
127
|
+
get 'with_current_user_haml', "test#with_current_user_haml"
|
128
|
+
get 'json_response', 'test#json_response'
|
129
|
+
end
|
130
|
+
app
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_root_request
|
134
|
+
get "/"
|
135
|
+
|
136
|
+
assert last_response.ok?
|
137
|
+
body = last_response.body
|
138
|
+
assert body["Root Page"]
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_index_request
|
142
|
+
get "/test/index"
|
143
|
+
|
144
|
+
assert last_response.ok?
|
145
|
+
assert last_response.body["hello"]
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_show_request
|
149
|
+
get "/test/show"
|
150
|
+
|
151
|
+
assert last_response.ok?
|
152
|
+
assert last_response.body["<h1>Show</h1>"]
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_index_with_slim
|
156
|
+
get "/test/index_with_slim"
|
157
|
+
|
158
|
+
assert last_response.ok?
|
159
|
+
body = last_response.body
|
160
|
+
assert body["Hello"]
|
161
|
+
assert body["Hello Twice"]
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_index_with_haml
|
165
|
+
get "/test/index_with_haml"
|
166
|
+
|
167
|
+
assert last_response.ok?
|
168
|
+
body = last_response.body
|
169
|
+
assert body["Hello"]
|
170
|
+
assert body["Hello Twice"]
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_sub_app
|
174
|
+
get "/sub-app"
|
175
|
+
|
176
|
+
assert last_response.ok?
|
177
|
+
body = last_response.body
|
178
|
+
assert body["sub-app"]
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_sub_app2
|
182
|
+
get "/sub-app2"
|
183
|
+
|
184
|
+
assert last_response.ok?
|
185
|
+
body = last_response.body
|
186
|
+
assert body["ANOTHER SUB APP"]
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_bad_request
|
190
|
+
get "/something-bad"
|
191
|
+
assert last_response.status == 404
|
192
|
+
end
|
193
|
+
|
194
|
+
def test_with_variables_erb
|
195
|
+
get 'with_variables_erb'
|
196
|
+
|
197
|
+
assert last_response.ok?
|
198
|
+
body = last_response.body
|
199
|
+
assert body["Jack"]
|
200
|
+
assert body["HI!"]
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_with_variables_haml
|
204
|
+
get 'with_variables_haml'
|
205
|
+
|
206
|
+
assert last_response.ok?
|
207
|
+
body = last_response.body
|
208
|
+
assert body["Jack"]
|
209
|
+
assert body["HI!"]
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_with_variables_slim
|
213
|
+
get 'with_variables_slim'
|
214
|
+
|
215
|
+
assert last_response.ok?
|
216
|
+
body = last_response.body
|
217
|
+
|
218
|
+
assert body["Jack"]
|
219
|
+
assert body["HI!"]
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
def test_change_response_status_code
|
224
|
+
get 'change_response_status_code'
|
225
|
+
|
226
|
+
assert last_response.status == 201
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_post_request
|
230
|
+
post 'testing_post'
|
231
|
+
|
232
|
+
assert last_response.ok?
|
233
|
+
end
|
234
|
+
|
235
|
+
def test_getting_a_post_request_should_return_bad_request
|
236
|
+
get 'testing_post'
|
237
|
+
|
238
|
+
assert last_response.status == 404
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_cookie_setting
|
242
|
+
get 'cookie_setting'
|
243
|
+
assert last_response.headers['Set-Cookie'] == 'user_id=1'
|
244
|
+
end
|
245
|
+
|
246
|
+
def test_cookie_deletion
|
247
|
+
get 'cookie_deletion'
|
248
|
+
assert last_response.headers['Set-Cookie'] =~ /user_id=; max-age=0;/
|
249
|
+
end
|
250
|
+
|
251
|
+
def test_redirecting_path
|
252
|
+
get 'redirecting_path'
|
253
|
+
assert last_response.status == 302
|
254
|
+
assert last_response['Location'] == "test/index"
|
255
|
+
end
|
256
|
+
|
257
|
+
def test_with_current_user
|
258
|
+
get 'with_current_user'
|
259
|
+
assert last_response.ok?
|
260
|
+
assert last_response.body['Damir']
|
261
|
+
end
|
262
|
+
|
263
|
+
def test_with_current_user_slim
|
264
|
+
get 'with_current_user_slim'
|
265
|
+
assert last_response.ok?
|
266
|
+
assert last_response.body['Damir']
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_with_current_user_haml
|
270
|
+
get 'with_current_user_haml'
|
271
|
+
assert last_response.ok?
|
272
|
+
assert last_response.body['Damir']
|
273
|
+
end
|
274
|
+
|
275
|
+
def test_json_response
|
276
|
+
get 'json_response'
|
277
|
+
assert last_response.ok?
|
278
|
+
body = last_response.body
|
279
|
+
body_hash = JSON.parse(body)
|
280
|
+
assert_equal "Jack", body_hash['username']
|
281
|
+
assert_equal "M", body_hash['sex']
|
282
|
+
end
|
283
|
+
|
284
|
+
end
|
285
|
+
|
286
|
+
|
287
|
+
class NoRouterTestApp < Minitest::Test
|
288
|
+
include Rack::Test::Methods
|
289
|
+
|
290
|
+
def app
|
291
|
+
app = TestApp.new
|
292
|
+
end
|
293
|
+
|
294
|
+
def test_no_routes
|
295
|
+
assert_raises Noodles::Http::NoRouterError do
|
296
|
+
get '/'
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|