tynn 0.0.4 → 1.0.0.rc1

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/lib/tynn/all_methods.rb +17 -0
  3. data/lib/tynn/environment.rb +12 -8
  4. data/lib/tynn/matchers.rb +37 -19
  5. data/lib/tynn/request.rb +4 -0
  6. data/lib/tynn/response.rb +151 -0
  7. data/lib/tynn/secure_headers.rb +28 -4
  8. data/lib/tynn/session.rb +74 -3
  9. data/lib/tynn/ssl.rb +2 -2
  10. data/lib/tynn/static.rb +26 -0
  11. data/lib/tynn/test.rb +37 -2
  12. data/lib/tynn/version.rb +7 -2
  13. data/lib/tynn.rb +88 -8
  14. data/test/all_methods_test.rb +16 -0
  15. data/test/core_test.rb +0 -86
  16. data/test/matchers_test.rb +11 -8
  17. data/test/middleware_test.rb +79 -0
  18. data/test/protection_test.rb +37 -0
  19. data/test/session_test.rb +1 -6
  20. metadata +45 -52
  21. data/.gems +0 -10
  22. data/docs/bin/build +0 -38
  23. data/docs/guides/security.md +0 -1
  24. data/docs/index.md +0 -89
  25. data/docs/layout.html +0 -61
  26. data/docs/public/.gitignore +0 -1
  27. data/docs/public/css/styles.css +0 -111
  28. data/docs/public/guides/.gitignore +0 -2
  29. data/docs/syro/syro.rb +0 -112
  30. data/examples/composition.ru +0 -40
  31. data/examples/hello.ru +0 -9
  32. data/examples/protection.ru +0 -18
  33. data/examples/render.ru +0 -13
  34. data/examples/views/home.erb +0 -1
  35. data/examples/views/layout.erb +0 -5
  36. data/lib/tynn/csrf.rb +0 -48
  37. data/lib/tynn/options.rb +0 -9
  38. data/makefile +0 -15
  39. data/test/csrf_test.rb +0 -98
  40. data/test/options_test.rb +0 -16
  41. data/test/views/custom_layout.erb +0 -1
  42. data/test/views/custom_layout.mote +0 -1
  43. data/test/views/layout.erb +0 -1
  44. data/test/views/layout.mote +0 -1
  45. data/test/views/partial.erb +0 -1
  46. data/test/views/partial.mote +0 -1
  47. data/test/views/view.erb +0 -1
  48. data/test/views/view.mote +0 -1
  49. data/tynn.gemspec +0 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4782dd0580d83defcbda873cd5cd6286e9471dff
4
- data.tar.gz: 4084f3b30cec83e6147b1e2afdde38a381285fe2
3
+ metadata.gz: 4778b186382c25ab99b1687323ec3562c045a0ee
4
+ data.tar.gz: 3b8c8d0c9a80cf5cce5cfb235e27be3b34093197
5
5
  SHA512:
6
- metadata.gz: 99d8b65373259f09d6c340ea148c4da3f1c33c55bdd7686b4ac278a5ed609955bed273f31371842b6521e74580e29def9c6c155e26ab8cdda9da2702edba2d65
7
- data.tar.gz: e6571863d347e2c749582fa4db18abdf79938727e47cc4b8f1d912b650c26a8464c690995385e6f4fe1a34dd1c22e2add4720c4f7ec248c7b7aeff9acdf085a2
6
+ metadata.gz: ef2895b73ebb6b9180e747a28499de003fb430a6e6eaee6027f7d7ae5c2569c9161347aed31aacb25552ce010dff48a01ebdbdf39af026f61702316c38ac3036
7
+ data.tar.gz: 47e3ccf946f417ba6c444d4197d511eef8df1c987e83468214a5949d3ffa6c46a89e891da13d032e077bdd6b1781ec64313a60a3a399e5eb259ced0513fe6869
@@ -0,0 +1,17 @@
1
+ module Tynn::AllMethods
2
+ def head
3
+ if root? && req.head?
4
+ yield
5
+
6
+ halt(res.finish)
7
+ end
8
+ end
9
+
10
+ def options
11
+ if root? && req.options?
12
+ yield
13
+
14
+ halt(res.finish)
15
+ end
16
+ end
17
+ end
@@ -1,19 +1,23 @@
1
1
  # Adds helper methods to get and check the current environment.
2
2
  #
3
- # require "tynn"
4
- # require "tynn/environment"
3
+ # ```
4
+ # require "tynn"
5
+ # require "tynn/environment"
5
6
  #
6
- # Tynn.helpers(Tynn::Environment)
7
+ # Tynn.helpers(Tynn::Environment)
7
8
  #
8
- # Tynn.environment # => :development
9
+ # Tynn.environment # => :development
9
10
  #
10
- # Tynn.development? # => true
11
- # Tynn.production? # => false
12
- # Tynn.test? # => false
11
+ # Tynn.development? # => true
12
+ # Tynn.production? # => false
13
+ # Tynn.test? # => false
14
+ # ```
13
15
  #
14
16
  # By default, the environment is based on `ENV["RACK_ENV"]`.
15
17
  #
16
- # Tynn.helpers(Tynn::Environment, env: ENV["RACK_ENV"])
18
+ # ```
19
+ # Tynn.helpers(Tynn::Environment, env: ENV["RACK_ENV"])
20
+ # ```
17
21
  #
18
22
  module Tynn::Environment
19
23
  def self.setup(app, env: ENV["RACK_ENV"]) # :nodoc:
data/lib/tynn/matchers.rb CHANGED
@@ -1,22 +1,26 @@
1
1
  # Adds extra matchers to Tynn.
2
2
  #
3
- # require "tynn"
4
- # require "tynn/matchers"
3
+ # ```
4
+ # require "tynn"
5
+ # require "tynn/matchers"
5
6
  #
6
- # Tynn.helpers(Tynn::Matchers)
7
+ # Tynn.helpers(Tynn::Matchers)
8
+ # ```
7
9
  #
8
10
  module Tynn::Matchers
9
11
  # A catch-all matcher.
10
12
  #
11
- # Tynn.define do
12
- # authenticated? do
13
- # # ...
14
- # end
13
+ # ```
14
+ # Tynn.define do
15
+ # authenticated? do
16
+ # # ...
17
+ # end
15
18
  #
16
- # default do # on true
17
- # # ...
18
- # end
19
- # end
19
+ # default do # on true
20
+ # # ...
21
+ # end
22
+ # end
23
+ # ```
20
24
  #
21
25
  # :call-seq: default(&block)
22
26
  #
@@ -26,15 +30,29 @@ module Tynn::Matchers
26
30
  halt(res.finish)
27
31
  end
28
32
 
29
- # Match if the given `params` are present.
33
+ # Match if the given `key` is present in `req.params`.
30
34
  #
31
- # Tynn.define do
32
- # on param?(:token) do
33
- # # ...
34
- # end
35
- # end
35
+ # ```
36
+ # Tynn.define do
37
+ # param(:user) do |params|
38
+ # user = User.create(params)
36
39
  #
37
- def param?(*params)
38
- return params.all? { |param| (v = req[param]) && !v.empty? }
40
+ # # ...
41
+ # end
42
+ #
43
+ # default do
44
+ # res.write("missing param")
45
+ # end
46
+ # end
47
+ # ```
48
+ #
49
+ # :call-seq: param(key, &block)
50
+ #
51
+ def param(key)
52
+ if (v = req[key]) && !v.empty?
53
+ yield(v)
54
+
55
+ halt(res.finish)
56
+ end
39
57
  end
40
58
  end
@@ -0,0 +1,4 @@
1
+ class Tynn
2
+ class Request < Rack::Request
3
+ end
4
+ end
@@ -0,0 +1,151 @@
1
+ class Tynn
2
+ class Response < Syro::Response
3
+ ##
4
+ # :method: []
5
+ #
6
+ # Returns the response header corresponding to `key`.
7
+ #
8
+ # res["Content-Type"] # => "text/html"
9
+ # res["Content-Length"] # => "42"
10
+
11
+ ##
12
+ # :method: []=
13
+ # :call-seq: []=(value)
14
+ #
15
+ # Sets the given `value` with the header corresponding to `key`.
16
+ #
17
+ # res["Content-Type"] = "application/json"
18
+ # res["Content-Type"] # => "application/json"
19
+
20
+ ##
21
+ # :method: body
22
+ #
23
+ # Returns the body of the response.
24
+ #
25
+ # res.body
26
+ # # => []
27
+ #
28
+ # res.write("there is")
29
+ # res.write("no try")
30
+ #
31
+ # res.body
32
+ # # => ["there is", "no try"]
33
+
34
+ ##
35
+ # :method: finish
36
+ #
37
+ # Returns an array with three elements: the status, headers and body.
38
+ # If the status is not set, the status is set to 404 if empty body,
39
+ # otherwise the status is set to 200 and updates the `Content-Type`
40
+ # header to `text/html`.
41
+ #
42
+ # res.status = 200
43
+ # res.finish
44
+ # # => [200, {}, []]
45
+ #
46
+ # res.status = nil
47
+ # res.finish
48
+ # # => [404, {}, []]
49
+ #
50
+ # res.status = nil
51
+ # res.write("yo!")
52
+ # res.finish
53
+ # # => [200, { "Content-Type" => "text/html" }, ["yo!"]]
54
+
55
+ ##
56
+ # :method: headers
57
+ #
58
+ # Returns a hash with the response headers.
59
+ #
60
+ # res.headers
61
+ # # => { "Content-Type" => "text/html", "Content-Length" => "42" }
62
+
63
+ ##
64
+ # :method: redirect
65
+ # :call-seq: redirect(path, 302)
66
+ #
67
+ # Sets the `Location` header to `path` and updates the status to
68
+ # `status`. By default, `status` is `302`.
69
+ #
70
+ # res.redirect("/path")
71
+ #
72
+ # res["Location"] # => "/path"
73
+ # res.status # => 302
74
+ #
75
+ # res.redirect("http://tynn.ru", 303)
76
+ #
77
+ # res["Location"] # => "http://tynn.ru"
78
+ # res.status # => 303
79
+
80
+ ##
81
+ # :method: status
82
+ #
83
+ # Returns the status of the response.
84
+ #
85
+ # res.status # => 200
86
+ #
87
+
88
+ ##
89
+ # :method: status=
90
+ # :call-seq: status=(status)
91
+ #
92
+ # Sets the status of the response.
93
+ #
94
+ # res.status = 200
95
+ #
96
+
97
+ ##
98
+ # :method: write
99
+ # :call-seq: write(str)
100
+ #
101
+ # Appends `str` to `body` and updates the `Content-Length` header.
102
+ #
103
+ # res.body # => []
104
+ #
105
+ # res.write("foo")
106
+ # res.write("bar")
107
+ #
108
+ # res.body
109
+ # # => ["foo", "bar"]
110
+ #
111
+ # res["Content-Length"]
112
+ # # => 6
113
+
114
+ ##
115
+ # :method: set_cookie
116
+ # :call-seq: set_cookie(key, value)
117
+ #
118
+ # Sets a cookie into the response.
119
+ #
120
+ # res.set_cookie("foo", "bar")
121
+ # res["Set-Cookie"] # => "foo=bar"
122
+ #
123
+ # res.set_cookie("foo2", "bar2")
124
+ # res["Set-Cookie"] # => "foo=bar\nfoo2=bar2"
125
+ #
126
+ # res.set_cookie("bar", {
127
+ # domain: ".example.com",
128
+ # path: "/",
129
+ # # max_age: 0,
130
+ # # expires: Time.now + 10_000,
131
+ # secure: true,
132
+ # httponly: true,
133
+ # value: "bar"
134
+ # })
135
+ #
136
+ # res["Set-Cookie"].split("\n").last
137
+ # # => "bar=bar; domain=.example.com; path=/; secure; HttpOnly
138
+ #
139
+ # **NOTE:** This method doesn't sign and/or encrypt the value of the cookie.
140
+
141
+ ##
142
+ # :method: delete_cookie
143
+ # :call-seq: delete_cookie(key, value = {})
144
+ #
145
+ # Deletes cookie.
146
+ #
147
+ # res.set_cookie("foo", "bar")
148
+ # res["Set-Cookie"]
149
+ # # => "foo=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 -0000"
150
+ end
151
+ end
@@ -1,9 +1,33 @@
1
1
  # Adds security related HTTP headers.
2
2
  #
3
- # require "tynn"
4
- # require "tynn/secure_headers"
3
+ # ```
4
+ # require "tynn"
5
+ # require "tynn/secure_headers"
5
6
  #
6
- # Tynn.helpers(Tynn::SecureHeaders)
7
+ # Tynn.helpers(Tynn::SecureHeaders)
8
+ # ```
9
+ #
10
+ # This helper applies the following headers:
11
+ #
12
+ # * **X-Content-Type-Options:** Prevents IE and Chrome from
13
+ # [content type sniffing][mime-sniffing].
14
+ #
15
+ # * **X-Frame-Options (XFO):** Provides [Clickjacking][clickjacking]
16
+ # protection. Check the [X-Frame-Options draft][x-frame-options] for
17
+ # more information.
18
+ #
19
+ # * **X-Permitted-Cross-Domain-Policies:** Restricts Adobe Flash Player's
20
+ # access to data. Check this [article][pcdp] for more information.
21
+ #
22
+ # * **X-XSS-Protection:** Enables the [XSS][xss] protection filter built
23
+ # into IE, Chrome and Safari. This filter is usually enabled by default,
24
+ # the use of this header is to re-enable it if it was disabled by the user.
25
+ #
26
+ # [clickjacking]: https://www.owasp.org/index.php/Clickjacking
27
+ # [mime-sniffing]: https://msdn.microsoft.com/library/gg622941(v=vs.85).aspx
28
+ # [pcdp]: https://www.adobe.com/devnet/adobe-media-server/articles/cross-domain-xml-for-streaming.html
29
+ # [x-frame-options]: https://tools.ietf.org/html/draft-ietf-websec-x-frame-options-02
30
+ # [xss]: https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)
7
31
  #
8
32
  module Tynn::SecureHeaders
9
33
  HEADERS = {
@@ -13,7 +37,7 @@ module Tynn::SecureHeaders
13
37
  "X-XSS-Protection" => "1; mode=block"
14
38
  } # :nodoc:
15
39
 
16
- def default_headers
40
+ def default_headers # :nodoc:
17
41
  return super.merge(HEADERS)
18
42
  end
19
43
  end
data/lib/tynn/session.rb CHANGED
@@ -1,13 +1,84 @@
1
+ # Adds simple cookie based session management. If a secret token is
2
+ # given, it signs the cookie data to ensure that it cannot be altered
3
+ # by unauthorized means.
4
+ #
5
+ # ```
6
+ # require "tynn"
7
+ # require "tynn/session"
8
+ #
9
+ # Tynn.helpers(Tynn::Session, secret: "__change_me__")
10
+ #
11
+ # Tynn.define do
12
+ # root do
13
+ # res.write(sprintf("hei %s", session[:username]))
14
+ # end
15
+ #
16
+ # on(:username) do |username|
17
+ # session[:username] = username
18
+ # end
19
+ # end
20
+ # ```
21
+ #
22
+ # The following command generates a cryptographically secure secret ready
23
+ # to use:
24
+ #
25
+ # ```
26
+ # $ ruby -r securerandom -e "puts SecureRandom.hex(64)"
27
+ # ```
28
+ #
29
+ # It's important to keep the token secret. Knowing the token allows an
30
+ # attacker to tamper the data. So, it's recommended to load the token
31
+ # from the environment.
32
+ #
33
+ # ```
34
+ # Tynn.helpers(Tynn::Session, secret: ENV["SESSION_SECRET"])
35
+ # ```
36
+ #
37
+ # Under the hood, Tynn::Session uses the [Rack::Session::Cookie][rack-session]
38
+ # middleware. Thus, supports all the options available for this middleware.
39
+ #
40
+ # * `:key` - the name of the cookie. Defaults to `"rack.session"`.
41
+ # * `:expire_after` - sets the lifespan of the cookie. If `nil`,
42
+ # the cookie will be deleted after the user close the browser.
43
+ # Defaults to `nil`.
44
+ # * `:httponly` - if `true`, sets the [HttpOnly][cookie-httponly] attribute.
45
+ # This mitigates the risk of client side scripting accessing the cookie.
46
+ # Defaults to `true`.
47
+ # * `:secure` - if `true`, sets the [Secure][cookie-secure] attribute.
48
+ # This tells the browser to only transmit the cookie over HTTPS. Defaults
49
+ # to `false`.
50
+ #
51
+ # ```
52
+ # Tynn.helpers(
53
+ # Tynn::Session,
54
+ # key: "app",
55
+ # secret: ENV["SESSION_SECRET"],
56
+ # expire_after: 36_000, # seconds
57
+ # httponly: true,
58
+ # secure: true
59
+ # )
60
+ # ```
61
+ #
62
+ # [cookie-httponly]: https://www.owasp.org/index.php/Session_Management_Cheat_Sheet#HttpOnly_Attribute
63
+ # [cookie-secure]: https://www.owasp.org/index.php/Session_Management_Cheat_Sheet#Secure_Attribute
64
+ # [rack-session]: http://www.rubydoc.info/gems/rack/Rack/Session/Cookie
65
+ #
1
66
  module Tynn::Session
2
67
  RACK_SESSION = "rack.session".freeze # :nodoc:
3
68
 
4
69
  def self.setup(app, options = {}) # :nodoc:
5
- options = options.dup
6
- options[:http_only] ||= true
7
-
8
70
  app.use(Rack::Session::Cookie, options)
9
71
  end
10
72
 
73
+ # Returns the session hash.
74
+ #
75
+ # ```
76
+ # session # => {}
77
+ #
78
+ # session[:foo] = "foo"
79
+ # session[:foo] # => "foo"
80
+ # ```
81
+ #
11
82
  def session
12
83
  return env[RACK_SESSION]
13
84
  end
data/lib/tynn/ssl.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Tynn::SSL
2
- def self.setup(app, options = {}) # :nodoc:
3
- app.use(Tynn::SSL::Middleware, options)
2
+ def self.setup(app, hsts: {}) # :nodoc:
3
+ app.use(Tynn::SSL::Middleware, hsts: hsts)
4
4
  end
5
5
 
6
6
  class Middleware # :nodoc:
data/lib/tynn/static.rb CHANGED
@@ -1,3 +1,29 @@
1
+ # Adds support for static files (javascript files, images, stylesheets, etc).
2
+ #
3
+ # ```
4
+ # require "tynn"
5
+ # require "tynn/static"
6
+ #
7
+ # Tynn.helpers(Tynn::Static, ["/js", "/css"])
8
+ # ```
9
+ #
10
+ # By default, serve all requests beginning with the given paths from the folder
11
+ # `public` in the current directory (e.g. `public/js/*`, `public/css/*`). You
12
+ # can change the default by passing the `:root` option.
13
+ #
14
+ # ```
15
+ # Tynn.helpers(Tynn::Static, ["/js", "/css"], root: "assets")
16
+ # ```
17
+ #
18
+ # Under the hood, it uses the [Rack::Static][rack-static] middleware.
19
+ # Thus, supports all the options available for this middleware.
20
+ #
21
+ # ```
22
+ # Tynn.helpers(Tynn::Static, ["/js", "/css"], index: "index.html")
23
+ # ```
24
+ #
25
+ # [rack-static]: http://www.rubydoc.info/gems/rack/Rack/Static
26
+ #
1
27
  module Tynn::Static
2
28
  def self.setup(app, urls, options = {}) # :nodoc:
3
29
  options = options.dup
data/lib/tynn/test.rb CHANGED
@@ -1,10 +1,45 @@
1
1
  require "rack/test"
2
2
 
3
+ # A simple helper class that uses [rack-test][rack-test] to simulate requests
4
+ # to your application.
5
+ #
6
+ # ```
7
+ # require "tynn"
8
+ # require "tynn/test"
9
+ #
10
+ # Tynn.define do
11
+ # root do
12
+ # res.write("hei")
13
+ # end
14
+ # end
15
+ #
16
+ # app = Tynn::Test.new
17
+ # app.get("/")
18
+ #
19
+ # 200 == app.res.status # => true
20
+ # "hei" == app.res.body # => true
21
+ # ```
22
+ #
23
+ # **NOTE:** Tynn doesn't ship with [rack-test][rack-test]. In order to
24
+ # use this plugin, you need to install it first.
25
+ #
26
+ # [rack-test]: http://rubygems.org/gems/rack-test
27
+ #
3
28
  class Tynn::Test
4
29
  include Rack::Test::Methods
5
30
 
6
- def initialize(app = Tynn) # :nodoc:
7
- @app = app
31
+ # Instantiates a new Tynn::Test object with the given `application` to test.
32
+ #
33
+ # ```
34
+ # class API < Tynn
35
+ # end
36
+ #
37
+ # app = Tynn::Test.new(API)
38
+ # app.get("/json")
39
+ # ```
40
+ #
41
+ def initialize(application = Tynn)
42
+ @app = application
8
43
  end
9
44
 
10
45
  def app # :nodoc:
data/lib/tynn/version.rb CHANGED
@@ -1,3 +1,8 @@
1
- class Tynn
2
- VERSION = "0.0.4"
1
+ class Tynn # :nodoc:
2
+ VERSION = [
3
+ MAJOR_VERSION = 1,
4
+ MINOR_VERSION = 0,
5
+ PATCH_VERSION = 0,
6
+ PRE_VERSION = "rc1"
7
+ ].compact.join(".")
3
8
  end
data/lib/tynn.rb CHANGED
@@ -1,15 +1,48 @@
1
1
  require "seteable"
2
2
  require "syro"
3
+ require_relative "tynn/request"
4
+ require_relative "tynn/response"
5
+ require_relative "tynn/version"
3
6
 
4
- class Tynn < Syro::Deck
7
+ class Tynn
5
8
  include Seteable
9
+ include Syro::Deck::API
6
10
 
11
+ # Sets the application handler.
12
+ #
13
+ # ```
14
+ # class Users < Tynn
15
+ # end
16
+ #
17
+ # Users.define do
18
+ # on(:id) do |id|
19
+ # get do
20
+ # res.write("GET /users")
21
+ # end
22
+ #
23
+ # post do
24
+ # res.write("POST /users")
25
+ # end
26
+ # end
27
+ # end
28
+ # ```
29
+ #
7
30
  def self.define(&block)
8
31
  @syro = Syro.new(self, &block)
9
32
  end
10
33
 
11
- def self.use(_middleware, *args, &block)
12
- middleware << proc { |app| _middleware.new(app, *args, &block) }
34
+ # Adds given Rack `middleware` to the stack.
35
+ #
36
+ # ```
37
+ # require "rack/common_logger"
38
+ # require "rack/show_exceptions"
39
+ #
40
+ # Tynn.use(Rack::CommonLogger)
41
+ # Tynn.use(Rack::ShowExceptions)
42
+ # ```
43
+ #
44
+ def self.use(middleware, *args, &block)
45
+ __middleware << proc { |app| middleware.new(app, *args, &block) }
13
46
  end
14
47
 
15
48
  def self.call(env) # :nodoc:
@@ -19,14 +52,14 @@ class Tynn < Syro::Deck
19
52
  def self.to_app # :nodoc:
20
53
  fail("Missing application handler. Try #{ self }.define") unless @syro
21
54
 
22
- if middleware.empty?
55
+ if __middleware.empty?
23
56
  return @syro
24
57
  else
25
- return middleware.reverse.inject(@syro) { |a, m| m.call(a) }
58
+ return __middleware.reverse.inject(@syro) { |a, m| m.call(a) }
26
59
  end
27
60
  end
28
61
 
29
- def self.middleware # :nodoc:
62
+ def self.__middleware # :nodoc:
30
63
  return @middleware ||= []
31
64
  end
32
65
 
@@ -35,6 +68,47 @@ class Tynn < Syro::Deck
35
68
  @middleware = []
36
69
  end
37
70
 
71
+ # Extends Tynn functionality with the given `helper` module.
72
+ #
73
+ # ```
74
+ # module AppName
75
+ # def self.setup(app, name)
76
+ # app.settings[:app_name] = name
77
+ # end
78
+ #
79
+ # def app_name
80
+ # return self.class.app_name
81
+ # end
82
+ #
83
+ # module ClassMethods
84
+ # def app_name=(new_name)
85
+ # settings[:app_name] = new_name
86
+ # end
87
+ #
88
+ # def app_name
89
+ # return settings[:app_name]
90
+ # end
91
+ # end
92
+ # end
93
+ #
94
+ # Tynn.helpers(AppName, "MyApplication")
95
+ #
96
+ # Tynn.app_name # => "MyApplication"
97
+ #
98
+ # Tynn.app_name = "MyGreatestApp"
99
+ # Tynn.app_name # => "MyGreatestApp"
100
+ #
101
+ # Tynn.define do
102
+ # root do
103
+ # res.write(app_name)
104
+ # end
105
+ # end
106
+ # ```
107
+ #
108
+ # Check the [helpers][examples] that come with tynn for more examples.
109
+ #
110
+ # [examples]: https://github.com/harmoni/tynn/tree/master/lib/tynn
111
+ #
38
112
  def self.helpers(helper, *args, &block)
39
113
  self.include(helper)
40
114
 
@@ -46,6 +120,12 @@ class Tynn < Syro::Deck
46
120
  helper.setup(self, *args, &block)
47
121
  end
48
122
  end
49
- end
50
123
 
51
- require_relative "tynn/version"
124
+ def request_class # :nodoc:
125
+ return Tynn::Request
126
+ end
127
+
128
+ def response_class # :nodoc:
129
+ return Tynn::Response
130
+ end
131
+ end
@@ -0,0 +1,16 @@
1
+ require_relative "../lib/tynn/all_methods"
2
+
3
+ Tynn.helpers(Tynn::AllMethods)
4
+
5
+ test "methods" do
6
+ [:head, :options].each do |method|
7
+ Tynn.define do
8
+ send(method) { res.write "" }
9
+ end
10
+
11
+ app = Tynn::Test.new
12
+ app.send(method, "/")
13
+
14
+ assert_equal 200, app.res.status
15
+ end
16
+ end