tynn 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gems +8 -5
- data/README.md +8 -0
- data/examples/composition.ru +42 -0
- data/examples/hello.ru +9 -0
- data/examples/render.ru +13 -0
- data/examples/views/home.erb +1 -0
- data/examples/views/layout.erb +5 -0
- data/lib/tynn/default_matcher.rb +7 -0
- data/lib/tynn/environment.rb +23 -0
- data/lib/tynn/erubis.rb +15 -0
- data/lib/tynn/hmote.rb +40 -0
- data/lib/tynn/hsts.rb +23 -0
- data/lib/tynn/json.rb +11 -0
- data/lib/tynn/json_parser.rb +34 -0
- data/lib/tynn/render.rb +56 -0
- data/lib/tynn/secure_headers.rb +15 -0
- data/lib/tynn/send_file.rb +12 -0
- data/lib/tynn/session.rb +11 -0
- data/lib/tynn/static.rb +10 -0
- data/lib/tynn/test.rb +16 -0
- data/lib/tynn/version.rb +1 -1
- data/lib/tynn.rb +31 -22
- data/makefile +9 -2
- data/test/core.rb +232 -0
- data/test/default_matcher.rb +17 -0
- data/test/environment.rb +31 -0
- data/test/erubis.rb +20 -0
- data/test/helper.rb +4 -11
- data/test/hmote.rb +78 -0
- data/test/hsts.rb +29 -0
- data/test/json.rb +19 -0
- data/test/json_parser.rb +22 -0
- data/test/render.rb +79 -0
- data/test/secure_headers.rb +20 -0
- data/test/send_file.rb +31 -0
- data/test/session.rb +22 -0
- data/test/static.rb +13 -0
- data/test/views/custom_layout.erb +1 -0
- data/test/views/custom_layout.mote +1 -0
- data/test/views/layout.erb +1 -0
- data/test/views/layout.mote +1 -0
- data/test/views/partial.erb +1 -0
- data/test/views/partial.mote +1 -0
- data/test/views/view.erb +1 -0
- data/test/views/view.mote +1 -0
- data/tynn.gemspec +5 -2
- metadata +82 -21
- data/test/captures.rb +0 -20
- data/test/composition.rb +0 -27
- data/test/hello.rb +0 -15
- data/test/helpers.rb +0 -54
- data/test/middleware.rb +0 -86
- data/test/settings.rb +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b3f1c481e9598f3996534f61913917797c496b2f
|
4
|
+
data.tar.gz: 7c5af7d6d35e404d81ec9eece88b35570a314851
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b571bda996fc71b5d4a1cf7abdeb99e0eef5cc3d962ca4d064293bedb253d862e2f58b8d440534426228bb9a5946039b88e98c6604bf69acf03547dce90c7bb
|
7
|
+
data.tar.gz: 99a7ec1117a9ff0b017bf02c310e9e525045bc30f7ea259ac9d531462e6c821a25c8e0f33e0ca0233d2dfab4a491176fd53cfc3760b202a10d02e921849a9764
|
data/.gems
CHANGED
data/README.md
CHANGED
@@ -37,6 +37,14 @@ Installation
|
|
37
37
|
$ gem install tynn
|
38
38
|
```
|
39
39
|
|
40
|
+
Contributing
|
41
|
+
------------
|
42
|
+
|
43
|
+
- Fork the project.
|
44
|
+
- Use `make install` to install dependencies.
|
45
|
+
- Use `make test` to run the test suite.
|
46
|
+
- Create a pull request with your changes.
|
47
|
+
|
40
48
|
[cuba]: https://github.com/soveran/cuba
|
41
49
|
[rack]: https://github.com/rack/rack
|
42
50
|
[syro]: https://github.com/soveran/syro
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative "../lib/tynn"
|
2
|
+
|
3
|
+
class Users < Tynn
|
4
|
+
end
|
5
|
+
|
6
|
+
Users.define do
|
7
|
+
on(:id) do
|
8
|
+
id = inbox[:id]
|
9
|
+
|
10
|
+
get do
|
11
|
+
res.write("GET /users/#{ id }")
|
12
|
+
end
|
13
|
+
|
14
|
+
put do
|
15
|
+
res.write("PUT /users/#{ id }")
|
16
|
+
end
|
17
|
+
|
18
|
+
patch do
|
19
|
+
res.write("PATCH /users/#{ id }")
|
20
|
+
end
|
21
|
+
|
22
|
+
delete do
|
23
|
+
res.write("DELETE /users/#{ id }")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
get do
|
28
|
+
res.write("GET /users")
|
29
|
+
end
|
30
|
+
|
31
|
+
post do
|
32
|
+
res.write("POST /users")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
Tynn.define do
|
37
|
+
on("users") do
|
38
|
+
run(Users)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
run(Tynn)
|
data/examples/hello.ru
ADDED
data/examples/render.ru
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "erb"
|
2
|
+
require_relative "../lib/tynn"
|
3
|
+
require_relative "../lib/tynn/render"
|
4
|
+
|
5
|
+
Tynn.helpers(Tynn::Render, views: File.expand_path("views", __dir__))
|
6
|
+
|
7
|
+
Tynn.define do
|
8
|
+
root do
|
9
|
+
render("home", title: "Thanks for using Tynn!")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
run(Tynn)
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= title %>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Tynn::Environment
|
2
|
+
def self.setup(app, env: ENV["RACK_ENV"]) # :nodoc:
|
3
|
+
app.settings[:environment] = (env || :development).to_sym
|
4
|
+
end
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def environment
|
8
|
+
return settings[:environment]
|
9
|
+
end
|
10
|
+
|
11
|
+
def development?
|
12
|
+
return environment == :development
|
13
|
+
end
|
14
|
+
|
15
|
+
def test?
|
16
|
+
return environment == :test
|
17
|
+
end
|
18
|
+
|
19
|
+
def production?
|
20
|
+
return environment == :production
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/tynn/erubis.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "erubis"
|
2
|
+
require_relative "render"
|
3
|
+
|
4
|
+
module Tynn::Erubis
|
5
|
+
def self.setup(app, options = {}) # :nodoc:
|
6
|
+
options = options.dup
|
7
|
+
|
8
|
+
options[:options] ||= {}
|
9
|
+
options[:options] = {
|
10
|
+
escape_html: true
|
11
|
+
}.merge!(options[:options])
|
12
|
+
|
13
|
+
app.helpers(Tynn::Render, options)
|
14
|
+
end
|
15
|
+
end
|
data/lib/tynn/hmote.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require "hmote"
|
2
|
+
|
3
|
+
module Tynn::HMote
|
4
|
+
include ::HMote::Helpers
|
5
|
+
|
6
|
+
def self.setup(app, options = {}) # :nodoc:
|
7
|
+
options = options.dup
|
8
|
+
|
9
|
+
options[:layout] ||= "layout"
|
10
|
+
options[:views] ||= File.expand_path("views", Dir.pwd)
|
11
|
+
|
12
|
+
app.settings[:hmote] ||= options
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def layout(layout)
|
17
|
+
settings[:hmote][:layout] = layout
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def render(template, locals = {}, layout = settings[:hmote][:layout])
|
22
|
+
res.headers[Rack::CONTENT_TYPE] ||= Syro::Response::DEFAULT
|
23
|
+
|
24
|
+
res.write(view(template, locals, layout))
|
25
|
+
end
|
26
|
+
|
27
|
+
def view(template, locals = {}, layout = settings[:hmote][:layout])
|
28
|
+
return partial(layout, locals.merge(content: partial(template, locals)))
|
29
|
+
end
|
30
|
+
|
31
|
+
def partial(template, locals = {})
|
32
|
+
return hmote(template_path(template), locals.merge(app: self), TOPLEVEL_BINDING)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def template_path(template)
|
38
|
+
return File.join(settings[:hmote][:views], "#{ template }.mote")
|
39
|
+
end
|
40
|
+
end
|
data/lib/tynn/hsts.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Tynn::HSTS
|
2
|
+
HSTS_HEADER = "Strict-Transport-Security".freeze # :nodoc:
|
3
|
+
HSTS_EXPIRE = 15_552_000 # 180 days # :nodoc:
|
4
|
+
|
5
|
+
def self.setup(app, options = {}) # :nodoc:
|
6
|
+
max_age = options.fetch(:max_age, HSTS_EXPIRE)
|
7
|
+
subdomains = options.fetch(:subdomains, true)
|
8
|
+
preload = options.fetch(:preload, false)
|
9
|
+
|
10
|
+
header = sprintf("max-age=%i", max_age)
|
11
|
+
header << "; includeSubdomains" if subdomains
|
12
|
+
header << "; preload" if preload
|
13
|
+
|
14
|
+
app.settings[:hsts] = header
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(env, inbox) # :nodoc:
|
18
|
+
result = super(env, inbox)
|
19
|
+
result[1][HSTS_HEADER] = settings[:hsts]
|
20
|
+
|
21
|
+
return result
|
22
|
+
end
|
23
|
+
end
|
data/lib/tynn/json.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module Tynn::JSONParser
|
4
|
+
def self.setup(app) # :nodoc:
|
5
|
+
app.use(Middleware)
|
6
|
+
end
|
7
|
+
|
8
|
+
class Middleware # :nodoc:
|
9
|
+
CONTENT_TYPE = "application/json".freeze
|
10
|
+
FORM_HASH = "rack.request.form_hash".freeze
|
11
|
+
FORM_INPUT = "rack.request.form_input".freeze
|
12
|
+
|
13
|
+
def initialize(app)
|
14
|
+
@app = app
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
request = Rack::Request.new(env)
|
19
|
+
|
20
|
+
if json?(request) && !(body = request.body.read).empty?
|
21
|
+
request.body.rewind
|
22
|
+
|
23
|
+
request.env[FORM_HASH] = JSON.parse(body)
|
24
|
+
request.env[FORM_INPUT] = request.body
|
25
|
+
end
|
26
|
+
|
27
|
+
return @app.call(request.env)
|
28
|
+
end
|
29
|
+
|
30
|
+
def json?(request)
|
31
|
+
return request.media_type == CONTENT_TYPE
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/tynn/render.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require "tilt"
|
2
|
+
|
3
|
+
module Tynn::Render
|
4
|
+
def self.setup(app, options = {}) # :nodoc:
|
5
|
+
options = options.dup
|
6
|
+
|
7
|
+
options[:engine] ||= "erb"
|
8
|
+
options[:layout] ||= "layout"
|
9
|
+
options[:views] ||= File.expand_path("views", Dir.pwd)
|
10
|
+
|
11
|
+
options[:options] ||= {}
|
12
|
+
options[:options] = {
|
13
|
+
default_encoding: Encoding.default_external,
|
14
|
+
outvar: "@_output"
|
15
|
+
}.merge!(options[:options])
|
16
|
+
|
17
|
+
app.settings[:render] ||= options
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
def layout(layout)
|
22
|
+
settings[:render][:layout] = layout
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def render(template, locals = {}, layout = settings[:render][:layout])
|
27
|
+
res.headers[Rack::CONTENT_TYPE] ||= Syro::Response::DEFAULT
|
28
|
+
|
29
|
+
res.write(view(template, locals, layout))
|
30
|
+
end
|
31
|
+
|
32
|
+
def view(template, locals = {}, layout = settings[:render][:layout])
|
33
|
+
return partial(layout, locals.merge(content: partial(template, locals)))
|
34
|
+
end
|
35
|
+
|
36
|
+
def partial(template, locals = {})
|
37
|
+
return tilt(template_path(template), locals, settings[:render][:options])
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def tilt(file, locals = {}, opts = {})
|
43
|
+
return tilt_cache.fetch(file) { Tilt.new(file, 1, opts) }.render(self, locals)
|
44
|
+
end
|
45
|
+
|
46
|
+
def tilt_cache
|
47
|
+
return Thread.current[:tilt_cache] ||= Tilt::Cache.new
|
48
|
+
end
|
49
|
+
|
50
|
+
def template_path(template)
|
51
|
+
dir = settings[:render][:views]
|
52
|
+
ext = settings[:render][:engine]
|
53
|
+
|
54
|
+
return File.join(dir, "#{ template }.#{ ext }")
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Tynn::SecureHeaders
|
2
|
+
HEADERS = {
|
3
|
+
"X-Content-Type-Options" => "nosniff",
|
4
|
+
"X-Frame-Options" => "SAMEORIGIN",
|
5
|
+
"X-Permitted-Cross-Domain-Policies" => "none",
|
6
|
+
"X-XSS-Protection" => "1; mode=block"
|
7
|
+
} # :nodoc:
|
8
|
+
|
9
|
+
def call(env, inbox) # :nodoc:
|
10
|
+
result = super(env, inbox)
|
11
|
+
result[1].merge!(HEADERS)
|
12
|
+
|
13
|
+
return result
|
14
|
+
end
|
15
|
+
end
|
data/lib/tynn/session.rb
ADDED
data/lib/tynn/static.rb
ADDED
data/lib/tynn/test.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "rack/test"
|
2
|
+
|
3
|
+
class Tynn::Test
|
4
|
+
include Rack::Test::Methods
|
5
|
+
|
6
|
+
def initialize(app = Tynn) # :nodoc:
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def app # :nodoc:
|
11
|
+
return @app
|
12
|
+
end
|
13
|
+
|
14
|
+
alias_method :res, :last_response
|
15
|
+
alias_method :req, :last_request
|
16
|
+
end
|
data/lib/tynn/version.rb
CHANGED
data/lib/tynn.rb
CHANGED
@@ -4,39 +4,48 @@ require "syro"
|
|
4
4
|
class Tynn < Syro::Deck
|
5
5
|
include Seteable
|
6
6
|
|
7
|
-
def self.
|
8
|
-
|
7
|
+
def self.define(&block)
|
8
|
+
@syro = Syro.new(self, &block)
|
9
9
|
end
|
10
10
|
|
11
|
-
def self.
|
12
|
-
|
13
|
-
return @__syro
|
14
|
-
else
|
15
|
-
return __middleware.inject(@__syro) { |a, m| m.call(a) }
|
16
|
-
end
|
11
|
+
def self.use(_middleware, *args, &block)
|
12
|
+
middleware.unshift(Proc.new { |app| _middleware.new(app, *args, &block) })
|
17
13
|
end
|
18
14
|
|
19
|
-
def self.
|
20
|
-
|
21
|
-
end
|
15
|
+
def self.helpers(helper, *args)
|
16
|
+
self.include(helper)
|
22
17
|
|
23
|
-
|
24
|
-
|
18
|
+
if defined?(helper::ClassMethods)
|
19
|
+
self.extend(helper::ClassMethods)
|
20
|
+
end
|
21
|
+
|
22
|
+
if helper.respond_to?(:setup)
|
23
|
+
helper.setup(self, *args)
|
24
|
+
end
|
25
25
|
end
|
26
26
|
|
27
|
-
def self.
|
28
|
-
|
27
|
+
def self.call(env) # :nodoc:
|
28
|
+
return to_app.call(env)
|
29
29
|
end
|
30
30
|
|
31
|
-
def self.
|
32
|
-
self.
|
31
|
+
def self.to_app # :nodoc:
|
32
|
+
fail("Missing application handler. Try #{ self }.define") unless @syro
|
33
33
|
|
34
|
-
if
|
35
|
-
|
34
|
+
if middleware.empty?
|
35
|
+
return @syro
|
36
|
+
else
|
37
|
+
return middleware.inject(@syro) { |a, m| m.call(a) }
|
36
38
|
end
|
39
|
+
end
|
37
40
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
+
def self.middleware # :nodoc:
|
42
|
+
return @middleware ||= []
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.reset! # :nodoc:
|
46
|
+
@syro = nil
|
47
|
+
@middleware = []
|
41
48
|
end
|
42
49
|
end
|
50
|
+
|
51
|
+
require_relative "tynn/version"
|