regal 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -1
- data/README.md +145 -0
- data/lib/regal/app.rb +395 -137
- data/lib/regal/request.rb +17 -14
- data/lib/regal/response.rb +24 -0
- data/lib/regal/version.rb +2 -1
- data/spec/regal/app_spec.rb +606 -146
- data/spec/regal/request_spec.rb +12 -19
- data/spec/spec_helper.rb +7 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 93df06eabeeeab76187242a2fef5943f00f44e4c
|
4
|
+
data.tar.gz: 879f67a1905fb2f50fb83d36c040533a398feebb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e80aa3aebcb0af7e5a99b11394ebcae70e91fbfa86a7b6e8118479f4ab8941ae08140bf404e1ec8cf595007645694334226697c2c32ab707ccebce57767e59fd
|
7
|
+
data.tar.gz: 12ae48d478d7072c34be83383f7eb38e3c4a7da59e4a3d3e1265353f8100757303c09757c62658b6a24da8d8f3c449775a334ce72938a93cde9247b7b09feead
|
data/.yardopts
CHANGED
data/README.md
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
# Regal ♔
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/iconara/regal.png?branch=master)](https://travis-ci.org/iconara/regal)
|
4
|
+
[![Coverage Status](https://coveralls.io/repos/iconara/regal/badge.png)](https://coveralls.io/r/iconara/regal)
|
5
|
+
[![Blog](http://b.repl.ca/v1/blog-regal-ff69b4.png)](http://architecturalatrocities.com/tagged/regal)
|
6
|
+
|
7
|
+
_If you're reading this on GitHub, please note that this is the readme for the development version and that some features described here might not yet have been released. You can find the readme for a specific version either through [rubydoc.info](http://rubydoc.info/find/gems?q=regal) or via the release tags ([here is an example](https://github.com/iconara/regal/tree/v0.1.0))._
|
8
|
+
|
9
|
+
Regal is a Rack framework where you model your application as a tree of routes.
|
10
|
+
|
11
|
+
## Just give me an example already
|
12
|
+
|
13
|
+
Stick this in a `config.ru` and `rackup`:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
require 'regal'
|
17
|
+
require 'json'
|
18
|
+
|
19
|
+
# Regal apps are classes, so you can create multiple
|
20
|
+
# instances of them with different configuration
|
21
|
+
ThingsApp = Regal::App.create do
|
22
|
+
# you build your app up by defining routes, these
|
23
|
+
# map directly to the request path, so this route
|
24
|
+
# matches requests that begin with /things
|
25
|
+
route 'things' do
|
26
|
+
# a route can have a handler for each HTTP method, these
|
27
|
+
# are passed request and response objects, but unless you
|
28
|
+
# need them you can leave those out, like this one does
|
29
|
+
#
|
30
|
+
# the response is what is returned from the handler, but
|
31
|
+
# below you will see how to make sure it's formatted properly
|
32
|
+
get do |request|
|
33
|
+
# when you create an instance of an app you can give it a hash,
|
34
|
+
# a copy of this hash is available through request.attributes,
|
35
|
+
# and is shared between all before, after and rescue blocks, as
|
36
|
+
# well as the handler blocks, like here
|
37
|
+
request.attributes[:database].values
|
38
|
+
end
|
39
|
+
|
40
|
+
# this handler uses both the request and the response
|
41
|
+
post do |request, response|
|
42
|
+
# request bodies are easily available
|
43
|
+
thing = JSON.load(request.body.read)
|
44
|
+
request.attributes[:database].store(thing['name'], thing)
|
45
|
+
# this is how you set the response code and headers
|
46
|
+
response.status = 201
|
47
|
+
response.headers['Location'] = '/things'
|
48
|
+
# the handler's return value will be set as response body
|
49
|
+
thing
|
50
|
+
end
|
51
|
+
|
52
|
+
# routes with symbols are wildcards and capture their value, so for the
|
53
|
+
# path /things/bees the parameter `:thing` will get the value "bees"
|
54
|
+
route :thing do
|
55
|
+
# helper methods don't need to be defined in special `helper` blocks,
|
56
|
+
# they can be defined like this
|
57
|
+
#
|
58
|
+
# they are available in all child routes, but not sibling routes
|
59
|
+
def find_thing(database, name)
|
60
|
+
database.fetch(name)
|
61
|
+
end
|
62
|
+
|
63
|
+
# rescue_from works a bit like regular rescue, if any before or after
|
64
|
+
# block, or handler in this or any child route raises an error, the
|
65
|
+
# first matching `rescue_from` block will be called – and unless it
|
66
|
+
# re-raises the error it is assumed to have been handled and the after
|
67
|
+
# blocks will be called
|
68
|
+
rescue_from KeyError do |error, request, response|
|
69
|
+
response.status = 404
|
70
|
+
response.body = {'error' => 'Thing not found'}
|
71
|
+
end
|
72
|
+
|
73
|
+
# before blocks run before the handler and can inspect the request
|
74
|
+
# and stop the request processing by calling #finish on the response
|
75
|
+
before do |request, response|
|
76
|
+
thing = find_thing(request.attributes[:database], request.parameters[:thing])
|
77
|
+
if thing
|
78
|
+
# before blocks can communicate with other before blocks, handlers
|
79
|
+
# and after blocks by setting request attributes
|
80
|
+
#
|
81
|
+
# it might look like this is a way to share things between requests,
|
82
|
+
# but each request has its own copy, so anything you add is only
|
83
|
+
# going to be accessible during the request
|
84
|
+
#
|
85
|
+
# you're of course allowed to put mutable objects in the attributes,
|
86
|
+
# like this app's `:database`, which makes it possible to share
|
87
|
+
# things between requests
|
88
|
+
request.attributes[:thing] = thing
|
89
|
+
else
|
90
|
+
response.status = 404
|
91
|
+
response.body = {'error' => 'Not Found'}
|
92
|
+
# finish will stop all remaining before blocks and the handler
|
93
|
+
# from running, but after blocks (see below) will still run
|
94
|
+
response.finish
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
get do |request|
|
99
|
+
# this will not run if a before block stops the request processing
|
100
|
+
# and it can access anything that the before blocks have put in
|
101
|
+
# the attributes hash
|
102
|
+
request.attributes[:thing]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# this handler is defined at the top level, I just defined it down here
|
108
|
+
# because it's not very important in this app, the order doesn't matter
|
109
|
+
get do |request, response|
|
110
|
+
response.headers['Location'] = '/things'
|
111
|
+
response.status = 302
|
112
|
+
# when you don't want to send any body you can call #no_body on the
|
113
|
+
# response, it doesn't matter where you do it, it doesn't have to be last
|
114
|
+
response.no_body
|
115
|
+
end
|
116
|
+
|
117
|
+
# after all of the request handling has been done the after blocks are called
|
118
|
+
# and they get to do whatever they like with the response, for example
|
119
|
+
# turning it into JSON, like this
|
120
|
+
after do |request, response|
|
121
|
+
response.headers['Content-Type'] = 'application/json'
|
122
|
+
response.body = JSON.pretty_generate(response.body) << "\n"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# to run your app with Rack you need to create an instance,
|
127
|
+
# the arguments you pass here are available as request.attributes
|
128
|
+
run ThingsApp.new(database: {})
|
129
|
+
```
|
130
|
+
|
131
|
+
You can do lots more with Regal, check out the tests to see more.
|
132
|
+
|
133
|
+
# How to contribute
|
134
|
+
|
135
|
+
[See CONTRIBUTING.md](CONTRIBUTING.md)
|
136
|
+
|
137
|
+
# Regal?
|
138
|
+
|
139
|
+
Besides being the Rack framework for kings and queens, the name can be roughly translated from German as "rack".
|
140
|
+
|
141
|
+
# Copyright
|
142
|
+
|
143
|
+
Copyright 2015 Theo Hultberg/Iconara and contributors.
|
144
|
+
|
145
|
+
_Licensed under the BSD 3-Clause license see [http://opensource.org/licenses/BSD-3-Clause](http://opensource.org/licenses/BSD-3-Clause)_
|