tynn 0.0.1 → 0.0.2

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 (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