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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 34266b059482427cf4b508d369a3a82eee1c13b9
4
- data.tar.gz: a44b19872324040f54441b625dd107452e7e88af
3
+ metadata.gz: 4ac5408912341100edad70023e719dc15b735d92
4
+ data.tar.gz: 2a765e3f6108277eec769b70498b6a9fb71e7194
5
5
  SHA512:
6
- metadata.gz: f608c27a33e224eee46f7a3f6d9adb3b9e5cda66c1d98847077ec80b6667b5aba4fbdcf953f685a879f1fdf33db9cdc195485fe541dfa24c4d1a18fc232ae3f8
7
- data.tar.gz: 62f772e16fd0b43d6d7adfc3a038eb247a3c3100dc1999d1f6fc8abafc15be4bb714e2c8f6286c2d4c3b613493901291b76960a3bfe16fd4e1166e9ecfbbe64d
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
@@ -7,6 +7,7 @@ require 'kawaii/method_chain'
7
7
  require 'kawaii/render_methods'
8
8
  require 'kawaii/matchers'
9
9
  require 'kawaii/route_mapping'
10
+ require 'kawaii/formats'
10
11
  require 'kawaii/route_handler'
11
12
  require 'kawaii/route'
12
13
  require 'kawaii/routing_methods'
@@ -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
@@ -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 aresponse: #{response.inspect}"
51
+ fail ResponseError, "Unsupported handler response: #{response.inspect}"
51
52
  end
52
53
  end
53
54
  end
@@ -1,4 +1,4 @@
1
1
  # Gem version.
2
2
  module Kawaii
3
- VERSION = '0.2.0'
3
+ VERSION = '0.2.1'
4
4
  end
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.0
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-27 00:00:00.000000000 Z
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.2.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