tynn 1.0.0.rc2 → 1.0.0.rc3

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