tynn 2.0.0.beta3 → 2.0.0.beta4

Sign up to get free protection for your applications and to get access to all the features.
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