tynn 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.gems +8 -5
  3. data/README.md +8 -0
  4. data/examples/composition.ru +42 -0
  5. data/examples/hello.ru +9 -0
  6. data/examples/render.ru +13 -0
  7. data/examples/views/home.erb +1 -0
  8. data/examples/views/layout.erb +5 -0
  9. data/lib/tynn/default_matcher.rb +7 -0
  10. data/lib/tynn/environment.rb +23 -0
  11. data/lib/tynn/erubis.rb +15 -0
  12. data/lib/tynn/hmote.rb +40 -0
  13. data/lib/tynn/hsts.rb +23 -0
  14. data/lib/tynn/json.rb +11 -0
  15. data/lib/tynn/json_parser.rb +34 -0
  16. data/lib/tynn/render.rb +56 -0
  17. data/lib/tynn/secure_headers.rb +15 -0
  18. data/lib/tynn/send_file.rb +12 -0
  19. data/lib/tynn/session.rb +11 -0
  20. data/lib/tynn/static.rb +10 -0
  21. data/lib/tynn/test.rb +16 -0
  22. data/lib/tynn/version.rb +1 -1
  23. data/lib/tynn.rb +31 -22
  24. data/makefile +9 -2
  25. data/test/core.rb +232 -0
  26. data/test/default_matcher.rb +17 -0
  27. data/test/environment.rb +31 -0
  28. data/test/erubis.rb +20 -0
  29. data/test/helper.rb +4 -11
  30. data/test/hmote.rb +78 -0
  31. data/test/hsts.rb +29 -0
  32. data/test/json.rb +19 -0
  33. data/test/json_parser.rb +22 -0
  34. data/test/render.rb +79 -0
  35. data/test/secure_headers.rb +20 -0
  36. data/test/send_file.rb +31 -0
  37. data/test/session.rb +22 -0
  38. data/test/static.rb +13 -0
  39. data/test/views/custom_layout.erb +1 -0
  40. data/test/views/custom_layout.mote +1 -0
  41. data/test/views/layout.erb +1 -0
  42. data/test/views/layout.mote +1 -0
  43. data/test/views/partial.erb +1 -0
  44. data/test/views/partial.mote +1 -0
  45. data/test/views/view.erb +1 -0
  46. data/test/views/view.mote +1 -0
  47. data/tynn.gemspec +5 -2
  48. metadata +82 -21
  49. data/test/captures.rb +0 -20
  50. data/test/composition.rb +0 -27
  51. data/test/hello.rb +0 -15
  52. data/test/helpers.rb +0 -54
  53. data/test/middleware.rb +0 -86
  54. data/test/settings.rb +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 79036ec0ceb3a8dc00cf95004df88b0e6a0a3f2d
4
- data.tar.gz: 89adaa34ed372a4f271f61bf95b05d4f5673211a
3
+ metadata.gz: b3f1c481e9598f3996534f61913917797c496b2f
4
+ data.tar.gz: 7c5af7d6d35e404d81ec9eece88b35570a314851
5
5
  SHA512:
6
- metadata.gz: 28f394aeaeae75432f8bb87d598d30c9062bdad4d760735193566e7fab27f8bfe4288f95acaabf52e5bcb797f56bb7a9fbb64788cc2e6e7cacb27b7187c7c543
7
- data.tar.gz: 2fb11894379614565e6deb18a110ba2e43e79b2310cf38fabe4ef9a654f003968ed909bda0c0ca360c0fef236bfdd62ea3cf7817115c32c3d9dcd6fc95785082
6
+ metadata.gz: 3b571bda996fc71b5d4a1cf7abdeb99e0eef5cc3d962ca4d064293bedb253d862e2f58b8d440534426228bb9a5946039b88e98c6604bf69acf03547dce90c7bb
7
+ data.tar.gz: 99a7ec1117a9ff0b017bf02c310e9e525045bc30f7ea259ac9d531462e6c821a25c8e0f33e0ca0233d2dfab4a491176fd53cfc3760b202a10d02e921849a9764
data/.gems CHANGED
@@ -1,5 +1,8 @@
1
- cutest -v 1.2.2
2
- syro -v 0.0.7
3
- rack -v 1.6.4
4
- rack-test -v 0.6.3
5
- seteable -v 1.0.0
1
+ cutest:1.2.2
2
+ erubis:2.7.0
3
+ hmote:1.4.0
4
+ rack:1.6.4
5
+ rack-test:0.6.3
6
+ seteable:1.0.0
7
+ syro:0.0.8
8
+ tilt:2.0.1
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
@@ -0,0 +1,9 @@
1
+ require_relative "../lib/tynn"
2
+
3
+ Tynn.define do
4
+ root do
5
+ res.write("hello")
6
+ end
7
+ end
8
+
9
+ run(Tynn)
@@ -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,5 @@
1
+ <h1>Tynn</h1>
2
+
3
+ <p>
4
+ <%= content %>
5
+ </p>
@@ -0,0 +1,7 @@
1
+ module Tynn::DefaultMatcher
2
+ def default
3
+ yield
4
+
5
+ halt(res.finish)
6
+ end
7
+ end
@@ -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
@@ -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,11 @@
1
+ require "json"
2
+
3
+ module Tynn::JSON
4
+ JSON_CONTENT_TYPE = "application/json".freeze # :nodoc:
5
+
6
+ def json(data)
7
+ res.headers[Rack::CONTENT_TYPE] ||= JSON_CONTENT_TYPE
8
+
9
+ res.write(data.to_json)
10
+ end
11
+ end
@@ -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
@@ -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
@@ -0,0 +1,12 @@
1
+ require "rack/file"
2
+
3
+ module Tynn::SendFile
4
+ def send_file(path)
5
+ file = Rack::File.new(nil)
6
+ file.path = path
7
+
8
+ halt(file.serving(env))
9
+ rescue Errno::ENOENT
10
+ res.status = 404
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module Tynn::Session
2
+ RACK_SESSION = "rack.session".freeze # :nodoc:
3
+
4
+ def self.setup(app, options = {}) # :nodoc:
5
+ app.use(Rack::Session::Cookie, options)
6
+ end
7
+
8
+ def session
9
+ return env[RACK_SESSION]
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ module Tynn::Static
2
+ def self.setup(app, urls, options = {}) # :nodoc:
3
+ options = options.dup
4
+
5
+ options[:urls] ||= urls
6
+ options[:root] ||= File.expand_path("public", Dir.pwd)
7
+
8
+ app.use(Rack::Static, options)
9
+ end
10
+ end
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
@@ -1,3 +1,3 @@
1
1
  class Tynn
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
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.call(env)
8
- return to_app.call(env)
7
+ def self.define(&block)
8
+ @syro = Syro.new(self, &block)
9
9
  end
10
10
 
11
- def self.to_app
12
- if __middleware.empty?
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.__middleware
20
- return @__middleware ||= []
21
- end
15
+ def self.helpers(helper, *args)
16
+ self.include(helper)
22
17
 
23
- def self.define(&block)
24
- @__syro = Syro.new(self, &block)
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.use(middleware, *args, &block)
28
- __middleware.unshift(Proc.new { |app| middleware.new(app, *args, &block) })
27
+ def self.call(env) # :nodoc:
28
+ return to_app.call(env)
29
29
  end
30
30
 
31
- def self.helpers(mod)
32
- self.include(mod)
31
+ def self.to_app # :nodoc:
32
+ fail("Missing application handler. Try #{ self }.define") unless @syro
33
33
 
34
- if defined?(mod::ClassMethods)
35
- self.extend(mod::ClassMethods)
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
- if mod.respond_to?(:setup)
39
- mod.setup(self)
40
- end
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"
data/makefile CHANGED
@@ -1,2 +1,9 @@
1
- default:
2
- cutest ./test/*.rb
1
+ default: test
2
+
3
+ install:
4
+ @cat .gems | xargs gem install
5
+
6
+ test:
7
+ @cutest -r ./test/helper.rb ./test/*.rb
8
+
9
+ .PHONY: test