kawaii-core 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +21 -0
- data/examples/json.ru +21 -0
- data/lib/kawaii.rb +1 -0
- data/lib/kawaii/formats.rb +185 -0
- data/lib/kawaii/route_handler.rb +3 -2
- data/lib/kawaii/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4ac5408912341100edad70023e719dc15b735d92
|
4
|
+
data.tar.gz: 2a765e3f6108277eec769b70498b6a9fb71e7194
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f53adf2a8620017251471e3ef461b9af0ba93aaf0f35529be3661ceae9dacb8597f1128b0877a67d264fd615df908292a000e569705bf74e38ed274063bb5d65
|
7
|
+
data.tar.gz: 910405f211b29dfd8bbf6857e6bbfd982e750fbaed1f2ea797a1a8ddea257aadca61d34144cbf4454f83408d0868ce992f77ff522148a79333956055e287dc67
|
data/README.md
CHANGED
@@ -166,6 +166,27 @@ get '/' do
|
|
166
166
|
end
|
167
167
|
```
|
168
168
|
|
169
|
+
### MIME types
|
170
|
+
|
171
|
+
You can use `respond_to` in a way similar to Rails in your handlers to match MIME types.
|
172
|
+
|
173
|
+
Example:
|
174
|
+
|
175
|
+
```ruby
|
176
|
+
post '/users' do
|
177
|
+
respond_to do |format|
|
178
|
+
format.json do
|
179
|
+
{ foo: 'bar' }
|
180
|
+
end
|
181
|
+
format.html do
|
182
|
+
'Hello, world'
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
```
|
187
|
+
|
188
|
+
**Important:** Content negotiation is currently only based on the `Content-Type` header field of the HTTP request.
|
189
|
+
|
169
190
|
### View templates
|
170
191
|
|
171
192
|
View templates must currently be stored in `views/` directory of the project using Kawaii. They can be rendered using the `render` method:
|
data/examples/json.ru
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'kawaii'
|
2
|
+
require 'rack'
|
3
|
+
|
4
|
+
class App < Kawaii::Base
|
5
|
+
get '/' do
|
6
|
+
respond_to do |format|
|
7
|
+
format.json { {foo: :bar} }
|
8
|
+
format.html { "Hello, world" }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
post '/' do
|
13
|
+
respond_to do |format|
|
14
|
+
format.json { params }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
run App
|
20
|
+
|
21
|
+
|
data/lib/kawaii.rb
CHANGED
@@ -0,0 +1,185 @@
|
|
1
|
+
# MIME formats.
|
2
|
+
module Kawaii
|
3
|
+
# Registered formats.
|
4
|
+
class FormatRegistry
|
5
|
+
@formats = {}
|
6
|
+
class << self
|
7
|
+
attr_accessor :formats
|
8
|
+
end
|
9
|
+
|
10
|
+
# Registers a new format. Formats are preferred in the order they are
|
11
|
+
# registered; the first format has the highest priority.
|
12
|
+
def self.register!(format)
|
13
|
+
@formats[format.key] = format
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Core format-handling class.
|
18
|
+
class FormatHandler
|
19
|
+
# Creates a format handler for a route handler
|
20
|
+
# @param [Kawaii::RouteHandler] current route handler
|
21
|
+
# @return {FormatHandler}
|
22
|
+
def initialize(route_handler)
|
23
|
+
@route_handler = route_handler
|
24
|
+
@matches = []
|
25
|
+
@blocks = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
# Matches method invoked in end-user code with {FormatBase#key}.
|
29
|
+
# If format matches the current request, it saves it for negotiation
|
30
|
+
# in {FormatHandler#response}.
|
31
|
+
def method_missing(meth, *_args, &block)
|
32
|
+
format = FormatRegistry.formats[meth]
|
33
|
+
return unless format && format.match?(@route_handler.request)
|
34
|
+
@candidates << format
|
35
|
+
@blocks[meth] = block
|
36
|
+
end
|
37
|
+
|
38
|
+
# Encoded response based on matched format (see
|
39
|
+
# {FormatHandler#method_missing}).
|
40
|
+
# @return {Array} Rack response array or nil if no format was matched
|
41
|
+
def response
|
42
|
+
format, block = find_best_match
|
43
|
+
return if format.nil?
|
44
|
+
# @note Request is mutated here!
|
45
|
+
new_params = format.parse_params(@route_handler.request)
|
46
|
+
@route_handler.params.merge!(new_params) if new_params
|
47
|
+
response = @route_handler.instance_exec(&block)
|
48
|
+
format.encode(response)
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def find_best_match
|
54
|
+
# Find matching format trying to match the first registered format
|
55
|
+
# then the second one and so on.
|
56
|
+
registered_fmts = FormatRegistry.formats
|
57
|
+
_, format = registered_fmts.find { |_, fmt| @candidates.include?(fmt) }
|
58
|
+
[format, @blocks[format.key]] if format
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# @abstract Base class for MIME format handlers.
|
63
|
+
class FormatBase
|
64
|
+
# Unique key for the format and at the same time the name of the method used
|
65
|
+
# in end-user-code to define format handler.
|
66
|
+
#
|
67
|
+
# @example Format handler for :json key
|
68
|
+
# respond_to do |format|
|
69
|
+
# format.json { ... }
|
70
|
+
# end
|
71
|
+
def key
|
72
|
+
fail NotImplementedError
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns true if the format is compatible with the request.
|
76
|
+
# @param _request [Rack::Request] current HTTP request
|
77
|
+
# @return true if there's a match.
|
78
|
+
def match?(_request)
|
79
|
+
fail NotImplementedError
|
80
|
+
end
|
81
|
+
|
82
|
+
# Parses params in request body in a way specific to the given format.
|
83
|
+
# @param _request [Rack::Request] contains information about the current
|
84
|
+
# HTTP request
|
85
|
+
# @return {Hash} including parsed params or nil
|
86
|
+
def parse_params(_request)
|
87
|
+
# Optional.
|
88
|
+
end
|
89
|
+
|
90
|
+
# Encodes response appropriately for the given format.
|
91
|
+
# @param _response [String, Hash, Array] response from format handler block.
|
92
|
+
# @return Rack response {Array}
|
93
|
+
def encode(_response)
|
94
|
+
fail NotImplementedError
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
require 'json'
|
99
|
+
|
100
|
+
# JSON MIME format (application/json).
|
101
|
+
class JsonFormat < FormatBase
|
102
|
+
# Unique key for the format and at the same time the name of the method used
|
103
|
+
# in end-user-code to define format handler.
|
104
|
+
#
|
105
|
+
# @example Format handler for :json key
|
106
|
+
# respond_to do |format|
|
107
|
+
# format.json do
|
108
|
+
# { foo: 'bar' }
|
109
|
+
# end
|
110
|
+
# end
|
111
|
+
def key
|
112
|
+
:json
|
113
|
+
end
|
114
|
+
|
115
|
+
# Returns true if the format is compatible with the request.
|
116
|
+
# @param request [Rack::Request] current HTTP request
|
117
|
+
# @return true if there's a match.
|
118
|
+
def match?(request)
|
119
|
+
request.content_type =~ %r{^application/json.*}
|
120
|
+
end
|
121
|
+
|
122
|
+
# Parses JSON string in request body if present and converts it to a hash.
|
123
|
+
# @param request [Rack::Request] contains information about the current HTTP
|
124
|
+
# request
|
125
|
+
# @return {Hash} including parsed params or nil
|
126
|
+
def parse_params(request)
|
127
|
+
json = request.body.read
|
128
|
+
JSON.parse(json).symbolize_keys if json.is_a?(String) && !json.empty?
|
129
|
+
end
|
130
|
+
|
131
|
+
# Encodes response appropriately by converting it to a JSON string.
|
132
|
+
# @param response [String, Hash, Array] response from format handler block.
|
133
|
+
# @return Rack response {Array}
|
134
|
+
def encode(response)
|
135
|
+
json = response.to_json
|
136
|
+
[200,
|
137
|
+
{ Rack::CONTENT_TYPE => 'application/json',
|
138
|
+
Rack::CONTENT_LENGTH => json.length.to_s },
|
139
|
+
[json]]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# HTML MIME format.
|
144
|
+
class HtmlFormat < FormatBase
|
145
|
+
# Unique key for the format and at the same time the name of the method used
|
146
|
+
# in end-user-code to define format handler.
|
147
|
+
#
|
148
|
+
# @example Format handler for :html key
|
149
|
+
# respond_to do |format|
|
150
|
+
# format.html { 'Hello, world' }
|
151
|
+
# end
|
152
|
+
def key
|
153
|
+
:html
|
154
|
+
end
|
155
|
+
|
156
|
+
# Always matches. This is why this format needs to be the last to
|
157
|
+
# be registered so more specific formats are before it.
|
158
|
+
def match?(_request)
|
159
|
+
true
|
160
|
+
end
|
161
|
+
|
162
|
+
# Response with text/html response.
|
163
|
+
# @param response [String] response from format handler block.
|
164
|
+
# @return Rack response {Array}
|
165
|
+
def encode(response)
|
166
|
+
[200,
|
167
|
+
{ Rack::CONTENT_TYPE => 'text/html',
|
168
|
+
Rack::CONTENT_LENGTH => response.size.to_s },
|
169
|
+
[response]]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Include this module to support 'respond_to'.
|
174
|
+
module FormatMethods
|
175
|
+
def respond_to(&block)
|
176
|
+
format_handler = FormatHandler.new(self)
|
177
|
+
instance_exec(format_handler, &block)
|
178
|
+
format_handler.response
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Register supported MIME formats.
|
183
|
+
FormatRegistry.register!(JsonFormat.new)
|
184
|
+
FormatRegistry.register!(HtmlFormat.new)
|
185
|
+
end
|
data/lib/kawaii/route_handler.rb
CHANGED
@@ -9,6 +9,7 @@ module Kawaii
|
|
9
9
|
class RouteHandler
|
10
10
|
include MethodChain
|
11
11
|
include RenderMethods
|
12
|
+
include FormatMethods
|
12
13
|
|
13
14
|
# Params based on request visible in the route handler scope.
|
14
15
|
attr_reader :params
|
@@ -39,7 +40,7 @@ module Kawaii
|
|
39
40
|
class ResponseError < RuntimeError; end
|
40
41
|
|
41
42
|
def process_response(response)
|
42
|
-
if response.is_a?(String)
|
43
|
+
if response.is_a?(String) # @todo Use HtmlFormat
|
43
44
|
[200,
|
44
45
|
{ Rack::CONTENT_TYPE => 'text/html',
|
45
46
|
Rack::CONTENT_LENGTH => response.size.to_s },
|
@@ -47,7 +48,7 @@ module Kawaii
|
|
47
48
|
elsif response.is_a?(Array)
|
48
49
|
response
|
49
50
|
else
|
50
|
-
fail ResponseError, "Unsupported handler
|
51
|
+
fail ResponseError, "Unsupported handler response: #{response.inspect}"
|
51
52
|
end
|
52
53
|
end
|
53
54
|
end
|
data/lib/kawaii/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kawaii-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcin Bilski
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-12-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -156,6 +156,7 @@ files:
|
|
156
156
|
- examples/controller.ru
|
157
157
|
- examples/hello_world.rb
|
158
158
|
- examples/hello_world.ru
|
159
|
+
- examples/json.ru
|
159
160
|
- examples/modular.ru
|
160
161
|
- examples/modular/first_app.rb
|
161
162
|
- examples/modular/second_app.rb
|
@@ -168,6 +169,7 @@ files:
|
|
168
169
|
- lib/kawaii/controller.rb
|
169
170
|
- lib/kawaii/core_ext/hash.rb
|
170
171
|
- lib/kawaii/core_ext/string.rb
|
172
|
+
- lib/kawaii/formats.rb
|
171
173
|
- lib/kawaii/matchers.rb
|
172
174
|
- lib/kawaii/method_chain.rb
|
173
175
|
- lib/kawaii/render_methods.rb
|
@@ -199,7 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
199
201
|
version: '0'
|
200
202
|
requirements: []
|
201
203
|
rubyforge_project:
|
202
|
-
rubygems_version: 2.
|
204
|
+
rubygems_version: 2.4.8
|
203
205
|
signing_key:
|
204
206
|
specification_version: 4
|
205
207
|
summary: A simple web framework based on Rack
|