tynn 1.0.0.rc2 → 1.0.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5991d5053c18550ff9e4640a0fb6ce8877e2e8d9
4
- data.tar.gz: 546da7cc32f33b70f95abb79557fb05a1045bc01
3
+ metadata.gz: 8e2fe7081578c608775773d67ab5e4dc92a33414
4
+ data.tar.gz: 96e869a9ec51ed45ab5baf116cd8126c32c4b597
5
5
  SHA512:
6
- metadata.gz: 73682ff6496225b2fee11bdf76bf262ded91308c5db2b7c4bd4442a5b152247b5a8ea5a23d57b7f96acc96f67e180eca4165518a38f5bb7b2feb9f84481e0b1a
7
- data.tar.gz: 0a4b872f14749623d88aaac9e6ade93a787a67ac1ee5eb93350028845ba5d55f217923dd8f5d62aed61b2bfd4b40c29d238763659dec36cb4778570a20495d3f
6
+ metadata.gz: dd4c49a2f298af29cefebca3650c488ab2bbb527299f700e9a72964e01a4fc1352fa7da6ef2264b25be24cedaaf6272ac53b5a603619da19c3d24a1b207235e4
7
+ data.tar.gz: 4ba63a68c74cbc71463b0e010ae985b8dab7d34d55e2043f1ed776774c8de93b4e07a33d7b08724fb1bacfd9e3156fa70bde9a37fe0912c214ecff1c159f6779
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- tynn [![Gem Version](https://badge.fury.io/rb/tynn.svg)](https://rubygems.org/gems/tynn)
1
+ tynn [![Build Status](https://travis-ci.org/frodsan/tynn.svg)](https://travis-ci.org/frodsan/tynn) [![Code Climate](https://codeclimate.com/github/frodsan/tynn/badges/gpa.svg)](https://codeclimate.com/github/frodsan/tynn)
2
2
  ====
3
3
 
4
4
  A thin library for web development.
@@ -48,8 +48,6 @@ Contributing
48
48
  You can install the gems globally, but we recommend [gs][gs] (or
49
49
  [gst][gst] if you're using chruby) to keep things isolated.
50
50
 
51
- [cuba]: https://github.com/soveran/cuba
52
- [rack]: https://github.com/rack/rack
53
51
  [syro]: https://github.com/soveran/syro
54
52
  [gs]: https://github.com/soveran/gs
55
53
  [gst]: https://github.com/tonchis/gst
data/lib/tynn.rb CHANGED
@@ -1,45 +1,70 @@
1
- require "seteable"
2
1
  require "syro"
3
2
  require_relative "tynn/request"
4
3
  require_relative "tynn/response"
4
+ require_relative "tynn/settings"
5
5
  require_relative "tynn/version"
6
6
 
7
7
  class Tynn
8
- include Seteable
9
8
  include Syro::Deck::API
10
9
 
11
- # Sets the application handler.
10
+ # Public: Extends Tynn functionality with the given +helper+ module.
12
11
  #
13
- # ```
14
- # class Users < Tynn
15
- # end
12
+ # Examples
16
13
  #
17
- # Users.define do
18
- # on(:id) do |id|
19
- # get do
20
- # res.write("GET /users")
21
- # end
14
+ # require "tynn"
15
+ # require "tynn/protection"
16
+ #
17
+ # Tynn.helpers(Tynn::Protection)
22
18
  #
23
- # post do
24
- # res.write("POST /users")
19
+ def self.helpers(helper, *args, &block)
20
+ if defined?(helper::InstanceMethods)
21
+ self.include(helper::InstanceMethods)
22
+ end
23
+
24
+ if defined?(helper::ClassMethods)
25
+ self.extend(helper::ClassMethods)
26
+ end
27
+
28
+ if helper.respond_to?(:setup)
29
+ helper.setup(self, *args, &block)
30
+ end
31
+ end
32
+
33
+ # Internal: Default helpers.
34
+ helpers(Tynn::Settings)
35
+
36
+ # Public: Sets the application handler.
37
+ #
38
+ # Examples
39
+ #
40
+ # class Users < Tynn
41
+ # end
42
+ #
43
+ # Users.define do
44
+ # on(:id) do |id|
45
+ # get do
46
+ # res.write("GET /users")
47
+ # end
48
+ #
49
+ # post do
50
+ # res.write("POST /users")
51
+ # end
25
52
  # end
26
53
  # end
27
- # end
28
- # ```
29
54
  #
30
55
  def self.define(&block)
31
56
  build_app(Syro.new(self, &block))
32
57
  end
33
58
 
34
- # Adds given Rack `middleware` to the stack.
59
+ # Public: Adds given Rack +middleware+ to the stack.
60
+ #
61
+ # Examples
35
62
  #
36
- # ```
37
- # require "rack/common_logger"
38
- # require "rack/show_exceptions"
63
+ # require "rack/common_logger"
64
+ # require "rack/show_exceptions"
39
65
  #
40
- # Tynn.use(Rack::CommonLogger)
41
- # Tynn.use(Rack::ShowExceptions)
42
- # ```
66
+ # Tynn.use(Rack::CommonLogger)
67
+ # Tynn.use(Rack::ShowExceptions)
43
68
  #
44
69
  def self.use(middleware, *args, &block)
45
70
  __middleware << proc { |app| middleware.new(app, *args, &block) }
@@ -66,57 +91,27 @@ class Tynn
66
91
  @middleware = []
67
92
  end
68
93
 
69
- # Extends Tynn functionality with the given `helper` module.
70
- #
71
- # ```
72
- # module AppName
73
- # def self.setup(app, name)
74
- # app.set(:app_name, name)
75
- # end
76
- #
77
- # def app_name
78
- # return self.class.app_name
79
- # end
94
+ # Public: Sets an +option+ to the given +value+.
80
95
  #
81
- # module ClassMethods
82
- # def app_name
83
- # return settings[:app_name]
84
- # end
85
- # end
86
- # end
96
+ # Examples
87
97
  #
88
- # Tynn.helpers(AppName, "MyApplication")
98
+ # require "tynn"
99
+ # require "tynn/environment"
89
100
  #
90
- # Tynn.app_name # => "MyApplication"
101
+ # Tynn.helpers(Tynn::Environment)
91
102
  #
92
- # Tynn.set(:app_name, "MyGreatestApp")
93
- # Tynn.app_name # => "MyGreatestApp"
94
- #
95
- # Tynn.define do
96
- # root do
97
- # res.write(app_name)
98
- # end
99
- # end
100
- # ```
103
+ # Tynn.set(:environment, :staging)
104
+ # Tynn.environment
105
+ # # => :staging
101
106
  #
102
- # Check the [helpers][examples] that come with tynn for more examples.
103
- #
104
- # [examples]: https://github.com/frodsan/tynn/tree/master/lib/tynn
105
- #
106
- def self.helpers(helper, *args, &block)
107
- self.include(helper)
108
-
109
- if defined?(helper::ClassMethods)
110
- self.extend(helper::ClassMethods)
111
- end
112
-
113
- if helper.respond_to?(:setup)
114
- helper.setup(self, *args, &block)
115
- end
107
+ def self.set(option, value)
108
+ settings[option] = value
116
109
  end
117
110
 
118
- def self.set(key, value)
119
- settings[key] = value
111
+ set(:default_headers, {})
112
+
113
+ def default_headers # :nodoc:
114
+ return Hash[settings[:default_headers]]
120
115
  end
121
116
 
122
117
  def request_class # :nodoc:
@@ -126,40 +121,4 @@ class Tynn
126
121
  def response_class # :nodoc:
127
122
  return Tynn::Response
128
123
  end
129
-
130
- ##
131
- # :method: halt(response)
132
- #
133
- # Immediately stops the request and returns `response` as per
134
- # Rack's specification.
135
- #
136
- # ```
137
- # halt([200, { "Content-Type" => "text/html" }, ["hello"]])
138
- # halt([res.status, res.headers, res.body])
139
- # halt(res.finish)
140
- # ```
141
-
142
- ##
143
- # :method: req
144
- #
145
- # Returns the incoming request object. This object is an instance
146
- # of Tynn::Request.
147
- #
148
- # ```
149
- # req.post? # => true
150
- # req.params # => { "username" => "bob", "password" => "secret" }
151
- # req[:username] # => "bob"
152
- # ```
153
-
154
- ##
155
- # :method: res
156
- #
157
- # Returns the current response object. This object is an instance
158
- # of Tynn::Response.
159
- #
160
- # ```
161
- # res.status = 200
162
- # res["Content-Type"] = "text/html"
163
- # res.write("<h1>Welcome back!</h1>")
164
- # ```
165
124
  end
@@ -1,18 +1,20 @@
1
1
  class Tynn
2
2
  module AllMethods
3
- def head
4
- if root? && req.head?
5
- yield
3
+ module InstanceMethods
4
+ def head
5
+ if root? && req.head?
6
+ yield
6
7
 
7
- halt(res.finish)
8
+ halt(res.finish)
9
+ end
8
10
  end
9
- end
10
11
 
11
- def options
12
- if root? && req.options?
13
- yield
12
+ def options
13
+ if root? && req.options?
14
+ yield
14
15
 
15
- halt(res.finish)
16
+ halt(res.finish)
17
+ end
16
18
  end
17
19
  end
18
20
  end
@@ -1,24 +1,24 @@
1
1
  class Tynn
2
- # Adds helper methods to get and check the current environment.
2
+ # Public: Adds helper methods to get and check the current environment.
3
3
  #
4
- # ```
5
- # require "tynn"
6
- # require "tynn/environment"
4
+ # Examples
7
5
  #
8
- # Tynn.helpers(Tynn::Environment)
6
+ # require "tynn"
7
+ # require "tynn/environment"
9
8
  #
10
- # Tynn.environment # => :development
9
+ # Tynn.helpers(Tynn::Environment)
11
10
  #
12
- # Tynn.development? # => true
13
- # Tynn.production? # => false
14
- # Tynn.test? # => false
15
- # ```
11
+ # Tynn.environment # => :development
12
+ #
13
+ # Tynn.development? # => true
14
+ # Tynn.production? # => false
15
+ # Tynn.test? # => false
16
16
  #
17
17
  # By default, the environment is based on `ENV["RACK_ENV"]`.
18
18
  #
19
- # ```
20
- # Tynn.helpers(Tynn::Environment, env: ENV["RACK_ENV"])
21
- # ```
19
+ # Examples
20
+ #
21
+ # Tynn.helpers(Tynn::Environment, env: ENV["RACK_ENV"])
22
22
  #
23
23
  module Environment
24
24
  def self.setup(app, env: ENV["RACK_ENV"]) # :nodoc:
@@ -0,0 +1,55 @@
1
+ class Tynn
2
+ # Public: HTTP requests are permanently redirected to their HTTPS
3
+ # counterparts.
4
+ #
5
+ # Examples
6
+ #
7
+ # require "tynn"
8
+ # require "tynn/force_ssl"
9
+ # require "tynn/test"
10
+ #
11
+ # Tynn.helpers(Tynn::ForceSSL)
12
+ #
13
+ # Tynn.define { }
14
+ #
15
+ # app = Tynn::Test.new
16
+ # app.get("/", {}, "HTTP_HOST" => "tynn.ru")
17
+ #
18
+ # app.res.headers["Location"]
19
+ # # => "https://tynn.ru/"
20
+ #
21
+ module ForceSSL
22
+ # Internal: Sets the HTTPS redirect middleware.
23
+ def self.setup(app)
24
+ app.use(Tynn::ForceSSL::Middleware)
25
+ end
26
+
27
+ class Middleware # :nodoc:
28
+ def initialize(app)
29
+ @app = app
30
+ end
31
+
32
+ def call(env)
33
+ request = Rack::Request.new(env)
34
+
35
+ if request.ssl?
36
+ return @app.call(env)
37
+ else
38
+ return [301, redirect_headers(request), []]
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def redirect_headers(request)
45
+ return { "Location" => https_location(request) }
46
+ end
47
+
48
+ HTTPS_LOCATION = "https://%s%s".freeze
49
+
50
+ def https_location(request)
51
+ return sprintf(HTTPS_LOCATION, request.host, request.fullpath)
52
+ end
53
+ end
54
+ end
55
+ end
data/lib/tynn/hmote.rb ADDED
@@ -0,0 +1,34 @@
1
+ require "hmote"
2
+
3
+ class Tynn
4
+ module HMote
5
+ def self.setup(app, options = {}) # :nodoc:
6
+ app.set(:layout, options.fetch(:layout, "layout"))
7
+ app.set(:views, options.fetch(:views, File.expand_path("views", Dir.pwd)))
8
+ end
9
+
10
+ module InstanceMethods
11
+ include ::HMote::Helpers
12
+
13
+ def render(template, locals = {}, layout = settings[:layout])
14
+ res.headers[Rack::CONTENT_TYPE] ||= Syro::Response::DEFAULT
15
+
16
+ res.write(view(template, locals, layout))
17
+ end
18
+
19
+ def view(template, locals = {}, layout = settings[:layout])
20
+ return partial(layout, locals.merge(content: partial(template, locals)))
21
+ end
22
+
23
+ def partial(template, locals = {})
24
+ return hmote(template_path(template), locals.merge(app: self), TOPLEVEL_BINDING)
25
+ end
26
+
27
+ private
28
+
29
+ def template_path(template)
30
+ return File.join(settings[:views], "#{ template }.mote")
31
+ end
32
+ end
33
+ end
34
+ end
data/lib/tynn/hsts.rb ADDED
@@ -0,0 +1,64 @@
1
+ class Tynn
2
+ # Public: Sets the +Strict-Transport-Security+ header. This ensures the
3
+ # browser never visits the http version of a website. This reduces the
4
+ # impact of leaking session data through cookies and external links, and
5
+ # defends against Man-in-the-middle attacks.
6
+ #
7
+ # Examples
8
+ #
9
+ # require "tynn"
10
+ # require "tynn/hsts"
11
+ #
12
+ # Tynn.helpers(Tynn::HSTS)
13
+ #
14
+ # Tynn.define { }
15
+ #
16
+ # Tynn.call("PATH_INFO" => "/")[1]["Strict-Transport-Security"]
17
+ # # => "max-age=15552000; includeSubdomains"
18
+ #
19
+ # It supports the following options:
20
+ #
21
+ # expires - The time, in seconds, that the browser access the site only
22
+ # by HTTPS. Defaults to 180 days.
23
+ # subdomains - If this is +true+, the rule applies to all the site's
24
+ # subdomains as well. Defaults to +true+.
25
+ # preload - A limitation of HSTS is that the initial request remains
26
+ # unprotected if it uses HTTP. The same applies to the first
27
+ # request after the activity period specified by +max-age+.
28
+ # Modern browsers implements a "STS preloaded list", which
29
+ # contains known sites supporting HSTS. If you would like to
30
+ # include your website into the list, set this options to +true+
31
+ # and submit your domain to this {form}[https://hstspreload.appspot.com/].
32
+ # Supported by Chrome, Firefox, IE11+ and IE Edge.
33
+ #
34
+ # Examples
35
+ #
36
+ # Tynn.helpers(
37
+ # Tynn::HSTS,
38
+ # expires: 31_536_000,
39
+ # includeSubdomains: true,
40
+ # preload: true
41
+ # )
42
+ #
43
+ # Tynn.define { }
44
+ #
45
+ # Tynn.call("PATH_INFO" => "/")[1]["Strict-Transport-Security"]
46
+ # # => "max-age=31536000; includeSubdomains; preload"
47
+ #
48
+ # To disable HSTS, you will need to tell the browser to expire it immediately.
49
+ #
50
+ # Examples
51
+ #
52
+ # Tynn.helpers(Tynn::HSTS, expires: 0)
53
+ #
54
+ module HSTS
55
+ # Internal: Sets the HSTS header as a default header.
56
+ def self.setup(app, options = {})
57
+ header = sprintf("max-age=%i", options.fetch(:expires, 15_552_000))
58
+ header << "; includeSubdomains" if options.fetch(:subdomains, true)
59
+ header << "; preload" if options[:preload]
60
+
61
+ app.settings[:default_headers]["Strict-Transport-Security"] = header
62
+ end
63
+ end
64
+ end