tynn 2.0.0.beta3 → 2.0.0.beta4

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.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tynn
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.beta3
4
+ version: 2.0.0.beta4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Francesco Rodriguez
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-22 00:00:00.000000000 Z
11
+ date: 2016-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -30,28 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.x
33
+ version: '1.1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.x
41
- - !ruby/object:Gem::Dependency
42
- name: erubis
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '2.7'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '2.7'
40
+ version: '1.1'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: minitest
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -80,22 +66,9 @@ dependencies:
80
66
  - - "~>"
81
67
  - !ruby/object:Gem::Version
82
68
  version: '11.0'
83
- - !ruby/object:Gem::Dependency
84
- name: tilt
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '2.0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '2.0'
97
- description: A thin library for web development in Ruby
98
- email: hello@frodsan.com
69
+ description: Tynn is a simple and flexible library for building JSON web services
70
+ and web applications in Ruby
71
+ email: frodsan@protonmail.com
99
72
  executables: []
100
73
  extensions: []
101
74
  extra_rdoc_files: []
@@ -103,7 +76,6 @@ files:
103
76
  - LICENSE
104
77
  - README.md
105
78
  - lib/tynn.rb
106
- - lib/tynn/base.rb
107
79
  - lib/tynn/environment.rb
108
80
  - lib/tynn/json.rb
109
81
  - lib/tynn/render.rb
@@ -116,6 +88,7 @@ files:
116
88
  - lib/tynn/test.rb
117
89
  - lib/tynn/utils.rb
118
90
  - lib/tynn/version.rb
91
+ - lib/tynn/x/versioning.rb
119
92
  - test/default_headers_test.rb
120
93
  - test/environment_test.rb
121
94
  - test/helper.rb
@@ -132,6 +105,7 @@ files:
132
105
  - test/settings_test.rb
133
106
  - test/ssl_test.rb
134
107
  - test/static_test.rb
108
+ - test/versioning_test.rb
135
109
  homepage: https://github.com/frodsan/tynn
136
110
  licenses:
137
111
  - MIT
@@ -173,3 +147,4 @@ test_files:
173
147
  - test/settings_test.rb
174
148
  - test/ssl_test.rb
175
149
  - test/static_test.rb
150
+ - test/versioning_test.rb
@@ -1,434 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright (c) 2016 Francesco Rodriguez
4
- # Copyright (c) 2015-2016 Michel Martens (Portions of https://github.com/soveran/syro)
5
- #
6
- # Permission is hereby granted, free of charge, to any person obtaining a copy
7
- # of this software and associated documentation files (the "Software"), to deal
8
- # in the Software without restriction, including without limitation the rights
9
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- # copies of the Software, and to permit persons to whom the Software is
11
- # furnished to do so, subject to the following conditions:
12
- #
13
- # The above copyright notice and this permission notice shall be included in
14
- # all copies or substantial portions of the Software.
15
- #
16
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
- # THE SOFTWARE.
23
-
24
- require "rack"
25
- require "seg"
26
- require_relative "request"
27
- require_relative "response"
28
- require_relative "utils"
29
-
30
- class Tynn
31
- module Base
32
- module ClassMethods
33
- # Sets the application handler.
34
- #
35
- # class Users < Tynn
36
- # end
37
- #
38
- # Users.define do
39
- # on :id do |id|
40
- # on get do
41
- # res.write("GET /users/#{ id }")
42
- # end
43
- #
44
- # on post do
45
- # res.write("POST /users/#{ id }")
46
- # end
47
- # end
48
- # end
49
- #
50
- def define(&block)
51
- @__app = build_app(proc { |env| new(block).call(env) })
52
- end
53
-
54
- def build_app(app) # :nodoc:
55
- middleware.freeze.reverse.inject(app) { |a, e| e.call(a) }
56
- end
57
-
58
- # Adds given Rack <tt>middleware</tt> to the stack.
59
- #
60
- # [middleware] A Rack middleware.
61
- # [*args] A list of arguments passed to the middleware initialization.
62
- # [&block] A block passed to the middleware initialization.
63
- #
64
- # require "rack/common_logger"
65
- # require "rack/show_exceptions"
66
- #
67
- # Tynn.use(Rack::CommonLogger)
68
- # Tynn.use(Rack::ShowExceptions)
69
- #
70
- # If applications handler is already set, it raises an error.
71
- #
72
- # Tynn.define {}
73
- #
74
- # Tynn.use(Rack::CommonLogger)
75
- # # => Application middleware is frozen.
76
- #
77
- def use(middleware, *args, &block)
78
- if self.middleware.frozen?
79
- Tynn::Utils.raise_error("Application middleware is frozen", tag: :frozen_middleware)
80
- else
81
- self.middleware.push(proc { |app| middleware.new(app, *args, &block) })
82
- end
83
- end
84
-
85
- def middleware # :nodoc:
86
- @__middleware ||= []
87
- end
88
-
89
- def call(env) # :nodoc:
90
- app.call(env)
91
- end
92
-
93
- def app # :nodoc:
94
- (defined?(@__app) && @__app) or
95
- Tynn::Utils.raise_error("Application handler is missing", tag: :missing_handler)
96
- end
97
-
98
- # Copies settings into the subclass. If a setting is not found,
99
- # checks parent's settings.
100
- def inherited(subclass) # :nodoc:
101
- subclass.settings.replace(Tynn::Utils.deepclone_hash(settings))
102
- subclass.settings.default_proc = proc { |h, k| h[k] = settings[k] }
103
- end
104
-
105
- # Returns a Hash with the application settings.
106
- #
107
- # Tynn.set(:environment, :development)
108
- #
109
- # Tynn.settings
110
- # # => { :environment => :development }
111
- #
112
- def settings
113
- @settings ||= {}
114
- end
115
-
116
- # Sets an <tt>option</tt> to the given </tt>value</tt>. If a setting
117
- # with the <tt>option</tt> key exists and is a hash value, it merges
118
- # the stored hash with <tt>value</tt>.
119
- #
120
- # Tynn.set(:environment, :staging)
121
- #
122
- # Tynn.settings[:environment]
123
- # # => :staging
124
- #
125
- # Tynn.default_headers
126
- # # => { "Content-Type" => "text/html" }
127
- #
128
- # Tynn.set(:default_headers, "X-Frame-Options" => "DENY")
129
- #
130
- # Tynn.default_headers
131
- # # => { "Content-Type" => "text/html", "X-Frame-Options" => "DENY" }
132
- #
133
- def set(option, value)
134
- v = settings[option]
135
-
136
- if Hash === v
137
- set!(option, v.merge(value))
138
- else
139
- set!(option, value)
140
- end
141
- end
142
-
143
- # Sets an <tt>option</tt> to the given </tt>value</tt>.
144
- #
145
- # Tynn.set!(:environment, :staging)
146
- #
147
- # Tynn.settings[:environment]
148
- # # => :staging
149
- #
150
- # Tynn.default_headers
151
- # # => { "Content-Type" => "text/html" }
152
- #
153
- # Tynn.set!(:default_headers, "X-Frame-Options" => "DENY")
154
- #
155
- # Tynn.default_headers
156
- # # => { "X-Frame-Options" => "DENY" }
157
- #
158
- def set!(option, value)
159
- settings[option] = value
160
- end
161
-
162
- # Returns a Hash with the default headers.
163
- #
164
- # Tynn.set(:default_headers, {
165
- # "Content-Type" => "application/json"
166
- # })
167
- #
168
- # Tynn.default_headers["Content-Type"]
169
- # # => "application/json"
170
- #
171
- def default_headers
172
- settings.fetch(:default_headers, {})
173
- end
174
- end
175
-
176
- # Monkey-patches capture to return the path segment instead of storing it
177
- # in a hash.
178
- class Seg < ::Seg # :nodoc:
179
- def capture
180
- return nil if root?
181
-
182
- len = (@path.index(SLASH, @pos) || @size) - @pos
183
-
184
- segment = @path[@pos, len]
185
-
186
- move(len)
187
-
188
- segment
189
- end
190
- end
191
-
192
- module InstanceMethods
193
- def initialize(code) # :nodoc:
194
- @__code = code
195
- end
196
-
197
- def call(env) # :nodoc:
198
- @__env = env
199
- @__req = Tynn::Request.new(env)
200
- @__res = Tynn::Response.new(Hash[self.class.default_headers])
201
- @__seg = Tynn::Base::Seg.new(env["PATH_INFO"])
202
-
203
- catch(:halt) do
204
- instance_eval(&@__code)
205
-
206
- @__res.finish
207
- end
208
- end
209
-
210
- # Returns the incoming request object. This object is an instance of
211
- # Tynn::Request.
212
- #
213
- # req.post?
214
- # # => true
215
- #
216
- # req.params
217
- # # => { "username" => "bob", "password" => "secret" }
218
- #
219
- # req.headers["Content-Type"]
220
- # # => "application/x-www-form-urlencoded"
221
- #
222
- def req
223
- @__req
224
- end
225
-
226
- # Returns the current response object. This object is an instance of
227
- # Tynn::Response.
228
- #
229
- # res.status = 200
230
- # res.headers["Content-Type"] = "text/html"
231
- # res.write("<h1>Welcome back!</h1>")
232
- #
233
- def res
234
- @__res
235
- end
236
-
237
- # Executes a given block if <tt>arg</tt> matches one of these conditions.
238
- #
239
- # If <tt>arg</tt> is a string, it matches a path segment.
240
- #
241
- # Tynn.define do
242
- # # Matches if /foo
243
- # on "foo" do
244
- # # Matches if /foo/bar/baz
245
- # on "bar/baz" do
246
- # res.write("/foo/bar/baz")
247
- # end
248
- # end
249
- # end
250
- #
251
- # If <tt>arg</tt> is a symbol, it matches and capture a path segment.
252
- #
253
- # Tynn.define do
254
- # # Matches if /users
255
- # on "users" do
256
- # # Captures id if matches /users/id
257
- # on :id do |id|
258
- # res.write("/users/#{ id }")
259
- # end
260
- # end
261
- # end
262
- #
263
- # Finally, if <tt>arg</tt> is <tt>true</tt>, it executes the given block
264
- # inconditionally.
265
- #
266
- # Tynn.define do
267
- # on current_user.nil? do
268
- # res.status = 401
269
- # res.write("Unauthorized")
270
- # end
271
- # end
272
- #
273
- def on(arg)
274
- (v = match(arg)) && yield(v)
275
- end
276
-
277
- def match(arg)
278
- case arg
279
- when String then @__seg.consume(arg)
280
- when Symbol then @__seg.capture
281
- when true then true
282
- else false
283
- end
284
- end
285
-
286
- private :match
287
-
288
- # Immediately stops the request and returns <tt>response</tt>
289
- # as per Rack's specification.
290
- #
291
- # halt([200, { "Content-Type" => "text/html" }, ["hello"]])
292
- # halt(res.finish)
293
- #
294
- def halt(response)
295
- throw(:halt, response)
296
- end
297
-
298
- # Runs a Tynn <tt>app</tt> and pass an optional hash of values to it.
299
- #
300
- # Tynn.define do
301
- # on "admin" do
302
- # run(Admin, subdomain: subdomain)
303
- # end
304
- # end
305
- #
306
- def run(app, inbox = nil)
307
- path, script = @__env["PATH_INFO"], @__env["SCRIPT_NAME"]
308
-
309
- @__env["PATH_INFO"] = @__seg.curr
310
- @__env["SCRIPT_NAME"] = @__seg.prev
311
-
312
- @__env.delete("tynn.inbox")
313
- @__env["tynn.inbox"] = inbox if inbox
314
-
315
- halt(app.call(@__env))
316
- ensure
317
- @__env["PATH_INFO"], @__env["SCRIPT_NAME"] = path, script
318
- end
319
-
320
- # Returns a hash with variables passed to the application.
321
- #
322
- # Tynn.define do
323
- # on "api/v1" do
324
- # run(API, version: 1)
325
- # end
326
- #
327
- # on "api/v2" do
328
- # run(API, version: 2)
329
- # end
330
- # end
331
- #
332
- # API.define do
333
- # version = inbox[:version]
334
- # end
335
- #
336
- def inbox
337
- @__env.fetch("tynn.inbox", {})
338
- end
339
-
340
- # Returns <tt>true</tt> if the request method is <tt>GET</tt> and
341
- # the path yet to be consumed is empty. Otherwise, returns <tt>false</tt>.
342
- #
343
- # Tynn.define do
344
- # on "users" do
345
- # on get do
346
- # res.write("GET /users")
347
- # end
348
- # end
349
- # end
350
- #
351
- def get
352
- root? && req.get?
353
- end
354
-
355
- # Returns <tt>true</tt> if the request method is <tt>POST</tt> and
356
- # the path yet to be consumed is empty. Otherwise, returns <tt>false</tt>.
357
- #
358
- # Tynn.define do
359
- # on "users" do
360
- # post do
361
- # res.write("POST /users")
362
- # end
363
- # end
364
- # end
365
- #
366
- def post
367
- root? && req.post?
368
- end
369
-
370
- # Returns <tt>true</tt> if the request method is <tt>PATCH</tt> and
371
- # the path yet to be consumed is empty. Otherwise, returns <tt>false</tt>.
372
- #
373
- # Tynn.define do
374
- # on "users" do
375
- # on :id do |id|
376
- # on patch do
377
- # res.write("PATCH /users/#{ id }")
378
- # end
379
- # end
380
- # end
381
- # end
382
- #
383
- def patch
384
- root? && req.patch?
385
- end
386
-
387
- # Returns <tt>true</tt> if the request method is <tt>PUT</tt> and
388
- # the path yet to be consumed is empty. Otherwise, returns <tt>false</tt>.
389
- #
390
- # Tynn.define do
391
- # on "users" do
392
- # on :id do |id|
393
- # on put do
394
- # res.write("PUT /users/#{ id }")
395
- # end
396
- # end
397
- # end
398
- # end
399
- #
400
- def put
401
- root? && req.put?
402
- end
403
-
404
- # Returns <tt>true</tt> if the request method is <tt>DELETE</tt> and
405
- # the path yet to be consumed is empty. Otherwise, returns <tt>false</tt>.
406
- #
407
- # Tynn.define do
408
- # on "users" do
409
- # on :id do |id|
410
- # on delete do
411
- # res.write("DELETE /users/#{ id }")
412
- # end
413
- # end
414
- # end
415
- # end
416
- #
417
- def delete
418
- root? && req.delete?
419
- end
420
-
421
- # Returns <tt>true</tt> if the path yet to be consumed is empty.
422
- #
423
- # Tynn.define do
424
- # on root? do
425
- # res.write("/")
426
- # end
427
- # end
428
- #
429
- def root?
430
- @__seg.root?
431
- end
432
- end
433
- end
434
- end