happy 0.1.0.pre28 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +3 -1
- data/TUTORIAL.md +346 -1
- data/lib/happy/controller.rb +1 -1
- data/lib/happy/version.rb +1 -1
- metadata +22 -22
data/README.md
CHANGED
@@ -8,13 +8,15 @@ Happy is a toolkit for developing web applications using Ruby. Inspired by both
|
|
8
8
|
|
9
9
|
Furthermore, the way Happy handles incoming requests is vastly different from how most of the other frameworks do it, offering a new, extremely flexible and suspiciously fun way of building your application.
|
10
10
|
|
11
|
+
**For an introduction, please check out the [The Happy Book of Happy](http://rdoc.info/github/hmans/happy/master/file/TUTORIAL.md).** For additional examples, check out the [example application](https://github.com/hmans/happy/tree/master/example).
|
12
|
+
|
11
13
|
## Installing
|
12
14
|
|
13
15
|
Happy is available as a RubyGem, so just install it through `gem install happy` (or add it to your project's `Gemfile`. You know the drill.)
|
14
16
|
|
15
17
|
## Usage
|
16
18
|
|
17
|
-
* [The Happy Book of Happy](
|
19
|
+
* [The Happy Book of Happy](http://rdoc.info/github/hmans/happy/master/file/TUTORIAL.md)
|
18
20
|
* [Reference Documentation](http://rdoc.info/github/hmans/happy/master/)
|
19
21
|
|
20
22
|
## Reporting Bugs & Contributing
|
data/TUTORIAL.md
CHANGED
@@ -1,3 +1,348 @@
|
|
1
1
|
# The Happy Book of Happy
|
2
2
|
|
3
|
-
|
3
|
+
Welcome to the Happy Book of Happy, an introduction on how to develop web applications using Happy, a cute little web application toolkit for Ruby! Let's get straight to it, shall we?
|
4
|
+
|
5
|
+
|
6
|
+
----
|
7
|
+
|
8
|
+
## The Basics
|
9
|
+
|
10
|
+
### "Hello World" with Happy
|
11
|
+
|
12
|
+
So, without further ado, here's the Happy version of "Hello World":
|
13
|
+
|
14
|
+
``` ruby
|
15
|
+
# config.ru
|
16
|
+
require 'happy'
|
17
|
+
|
18
|
+
class MyApp < Happy::Controller
|
19
|
+
def route
|
20
|
+
"Hello World"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
run MyApp
|
25
|
+
```
|
26
|
+
|
27
|
+
You can run this example (assuming it's inside a file called config.ru) by simply issuing the `rackup` command. Try `rackup --help` for available options.
|
28
|
+
|
29
|
+
|
30
|
+
### Happy Controllers
|
31
|
+
|
32
|
+
So, the previous chapter's "Hello World" example isn't terribly exciting, but there's a couple of interesting things to note here.
|
33
|
+
|
34
|
+
First of all, note how you're creating a subclass of `Happy::Controller`. That class is central to how Happy works; pretty much everything you do in Happy revolves around controllers.
|
35
|
+
|
36
|
+
Unlike your may know it from frameworks like Ruby on Rails, controllers are really self-contained applications that describe behaviour. They can be very simple (simply rendering a string, like the example above), but also very complex (for example, they could provide a complete blog engine, or admin backend.)
|
37
|
+
|
38
|
+
So here's some of the things a Happy controller can do:
|
39
|
+
|
40
|
+
* serve a simple string-like response
|
41
|
+
* render a template
|
42
|
+
* process URL paths
|
43
|
+
* pass control over the request to another controller (or Rack app)
|
44
|
+
|
45
|
+
*Note for friends of Rack:* Happy is a very Rack-friendly framework. Happy controllers are also just Rack apps, so you can mount them anywhere that you can mount Rack apps (like inside another Rails application). Happy also happily mounts non-Happy Rack apps, so it works both ways. Life is good.
|
46
|
+
|
47
|
+
|
48
|
+
### The `route` method
|
49
|
+
|
50
|
+
Pretty much the most important part of any Happy controller is the `route` method. In your own controller classes, you're expected to override this method to implement your controller's request handling logic.
|
51
|
+
|
52
|
+
And this is where Happy is very different from most other web frameworks: instead of dispatching incoming requests among a set of controller classes or actions, Happy will route each and every request -- no exceptions -- through your application controller's `route` method. It is then up to this method to decide on how to deal with the request.
|
53
|
+
|
54
|
+
Let's take a look at some examples in the following chapters.
|
55
|
+
|
56
|
+
|
57
|
+
### Handling paths
|
58
|
+
|
59
|
+
In most web applications, you will probably want to serve different responses depending on the URL accessed. In Happy, you use the `on` method to define the behavior for specific URL paths. Here's a simple example:
|
60
|
+
|
61
|
+
``` ruby
|
62
|
+
class MyApp < Happy::Controller
|
63
|
+
def route
|
64
|
+
# When /foo is accessed, respond with 'bar!'
|
65
|
+
on 'foo' do
|
66
|
+
'bar!'
|
67
|
+
end
|
68
|
+
|
69
|
+
# Paths can be nested, of course:
|
70
|
+
on 'one' do
|
71
|
+
on 'two' do
|
72
|
+
'one and two!'
|
73
|
+
end
|
74
|
+
|
75
|
+
'just one!'
|
76
|
+
end
|
77
|
+
|
78
|
+
'Try /foo, /one or /one/two!'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
```
|
82
|
+
|
83
|
+
In other words, `on` lets you provide code blocks that are only executed when a certain path has been requested. Note that `on` calls can be nested; also note that if one of these blocks returns just a string value, it will be rendered as the response.
|
84
|
+
|
85
|
+
|
86
|
+
### Reacting on specific HTTP verbs
|
87
|
+
|
88
|
+
While the `on` command doesn't care about the HTTP verb being used to make the request, there's also `on_get`, `on_post`, `on_put` and `on_delete`. Note that these can also be called without a path argument. Here's an example:
|
89
|
+
|
90
|
+
``` ruby
|
91
|
+
class MyApp < Happy::Controller
|
92
|
+
def route
|
93
|
+
on 'resource' do
|
94
|
+
on_get { 'You accessed /resource using GET!' }
|
95
|
+
on_post { 'You accessed /resource using POST!' }
|
96
|
+
on_put { 'You accessed /resource using PUT!' }
|
97
|
+
on_delete { 'You accessed /resource using DELETE!' }
|
98
|
+
end
|
99
|
+
|
100
|
+
'Try /resource with any HTTP verb!'
|
101
|
+
end
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
105
|
+
### Setting headers
|
106
|
+
|
107
|
+
You can use the `header` method to set any type of HTTP header for your response. Example:
|
108
|
+
|
109
|
+
``` ruby
|
110
|
+
# Set the 'Content-type' header to 'text/css'
|
111
|
+
header :content_type, 'text/css'
|
112
|
+
```
|
113
|
+
|
114
|
+
There's a couple of shortcut methods available to set certain headers directly. Examples:
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
content_type 'text/css'
|
118
|
+
cache_control 'public, max-age=3600, must-revalidate'
|
119
|
+
```
|
120
|
+
|
121
|
+
For a complete list, please check the documentation for [`Happy::Controller::Actions`](http://rdoc.info/github/hmans/happy/master/Happy/Controller/Actions).
|
122
|
+
|
123
|
+
|
124
|
+
### Rendering view templates
|
125
|
+
|
126
|
+
Obviously, just serving simple strings isn't really what you want in most applications, so Happy also allows you to render view templates through myriad of available template engines. (Happy uses the [tilt](https://github.com/rtomayko/tilt) gem, so any template engine supported by tilt is also supported by Happy.)
|
127
|
+
|
128
|
+
All template rendering is done through the `render` method. Simply pass the name of a template file. For example:
|
129
|
+
|
130
|
+
``` ruby
|
131
|
+
class MyApp < Happy::Controller
|
132
|
+
def route
|
133
|
+
on('info') { render 'info.erb' }
|
134
|
+
on('help') { render 'help.erb' }
|
135
|
+
|
136
|
+
render 'home.erb'
|
137
|
+
end
|
138
|
+
end
|
139
|
+
```
|
140
|
+
|
141
|
+
The default directory Happy will look for view templates in is the `views/` subdirectory of your application. This is configurable, of course; more on configuration alter.
|
142
|
+
|
143
|
+
|
144
|
+
### Using layouts
|
145
|
+
|
146
|
+
Happy allows you to define a view template as a layout template, applying it to every response generated. Use the `layout` command to set it. For example:
|
147
|
+
|
148
|
+
``` ruby
|
149
|
+
class MyApp < Happy::Controller
|
150
|
+
def route
|
151
|
+
layout 'layouts/default.erb'
|
152
|
+
|
153
|
+
# From a previous example...
|
154
|
+
on('info') { render 'info.erb' }
|
155
|
+
on('help') { render 'help.erb' }
|
156
|
+
|
157
|
+
on('admin') do
|
158
|
+
# use a different layout inside the admin section
|
159
|
+
layout 'layouts/admin.erb'
|
160
|
+
render 'admin.erb'
|
161
|
+
end
|
162
|
+
|
163
|
+
render 'home.erb'
|
164
|
+
end
|
165
|
+
end
|
166
|
+
```
|
167
|
+
|
168
|
+
The layout file itself should contain an invocation of `yield` where the inner part of the response should appear.
|
169
|
+
|
170
|
+
|
171
|
+
### Adding view helpers
|
172
|
+
|
173
|
+
In Happy, view templates are rendered within the scope of your controller (as opposed to a specific view context object), so any method from your controller will also be available in your views.
|
174
|
+
|
175
|
+
It is advised, however, that you specifically declare helper methods using the `helper` command so that they are available to _all_ controllers. This is necessary if you modularize your applications into several different controller classes that share view files.
|
176
|
+
|
177
|
+
Here's an example:
|
178
|
+
|
179
|
+
``` ruby
|
180
|
+
class MyApp < Happy::Controller
|
181
|
+
# You can provide a block that contains method definitions.
|
182
|
+
#
|
183
|
+
helpers do
|
184
|
+
def some_helper
|
185
|
+
'something useful'
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Alternatively, you can provide a module that contains your
|
190
|
+
# helper methods
|
191
|
+
#
|
192
|
+
helpers MyHelpers
|
193
|
+
|
194
|
+
def route
|
195
|
+
# home.erb contains calls to helper methods
|
196
|
+
render 'home.erb'
|
197
|
+
end
|
198
|
+
end
|
199
|
+
```
|
200
|
+
|
201
|
+
|
202
|
+
### Serving responses explicitly
|
203
|
+
|
204
|
+
You will have noticed by now that if a path block (or the `route` method itself) returns a simple string, it will be used for the response body. However, you can also serve responses explicitly using the `serve!` method. Example:
|
205
|
+
|
206
|
+
``` ruby
|
207
|
+
class MyApp < Happy::Controller
|
208
|
+
def route
|
209
|
+
serve! 'my response', :content_type => 'text/plain'
|
210
|
+
end
|
211
|
+
end
|
212
|
+
```
|
213
|
+
|
214
|
+
Note that calling `serve!` will finish processing of the current request.
|
215
|
+
|
216
|
+
### Passing control over the request to another controller or Rack app
|
217
|
+
|
218
|
+
Happy allows you to modularize your application into several separate controller classes. For example, you could put your admin backend's code into a separate controller and then invoke it within the `/admin` path. For this, you would use the `run` command. Kinda like this:
|
219
|
+
|
220
|
+
``` ruby
|
221
|
+
class MyAdminController < Happy::Controller
|
222
|
+
def route
|
223
|
+
on 'users' do
|
224
|
+
# ...
|
225
|
+
# do some user admin stuff here
|
226
|
+
end
|
227
|
+
|
228
|
+
on 'articles' do
|
229
|
+
# ...
|
230
|
+
# do some articles admin stuff here
|
231
|
+
end
|
232
|
+
|
233
|
+
render 'admin/home.erb'
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
class MyApp < Happy::Controller
|
238
|
+
def route
|
239
|
+
on 'admin' do
|
240
|
+
run MyAdminController
|
241
|
+
end
|
242
|
+
|
243
|
+
render 'home.erb'
|
244
|
+
end
|
245
|
+
end
|
246
|
+
```
|
247
|
+
|
248
|
+
Yup, this also means that you can build reusable controllers that you can distribute within gems for other Happy developers to use.
|
249
|
+
|
250
|
+
|
251
|
+
----
|
252
|
+
|
253
|
+
## Permission Managament
|
254
|
+
|
255
|
+
### Setting and querying permissions
|
256
|
+
|
257
|
+
Happy contains a light-weight run-time permission management system powered by the [Allowance](https://github.com/hmans/allowance) gem. Using the `can` object, you can declare (and later query) permissions at runtime.
|
258
|
+
|
259
|
+
Example:
|
260
|
+
|
261
|
+
``` ruby
|
262
|
+
class MyApp < Happy::Controller
|
263
|
+
def setup_permissions
|
264
|
+
if current_user
|
265
|
+
# Logged in users can submit new stuff
|
266
|
+
can.submit!
|
267
|
+
|
268
|
+
# But only admin users can edit and delete it.
|
269
|
+
if current_user.is_admin?
|
270
|
+
can.edit!
|
271
|
+
can.delete!
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def route
|
277
|
+
setup_permissions
|
278
|
+
|
279
|
+
on 'submit' do
|
280
|
+
if can.submit?
|
281
|
+
render 'submit.erb'
|
282
|
+
else
|
283
|
+
redirect! '/login'
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
# Paths are defined dynamically, so the following is possible, too:
|
288
|
+
if can.edit?
|
289
|
+
on('edit') { render 'edit.erb' }
|
290
|
+
end
|
291
|
+
|
292
|
+
if can.delete?
|
293
|
+
on('delete') { render 'delete.erb' }
|
294
|
+
end
|
295
|
+
|
296
|
+
render 'home.erb'
|
297
|
+
end
|
298
|
+
|
299
|
+
def current_user
|
300
|
+
# ...a method returning the current user.
|
301
|
+
end
|
302
|
+
end
|
303
|
+
```
|
304
|
+
|
305
|
+
### Permissions for specific objects
|
306
|
+
_TODO_
|
307
|
+
|
308
|
+
### ActiveModel integration
|
309
|
+
_TODO_
|
310
|
+
|
311
|
+
----
|
312
|
+
|
313
|
+
## Controller configuration
|
314
|
+
_TODO_
|
315
|
+
|
316
|
+
----
|
317
|
+
|
318
|
+
## Happy Recipes
|
319
|
+
|
320
|
+
### Writing & Reading Session Data
|
321
|
+
_TODO_
|
322
|
+
|
323
|
+
### Setting & Reading Cookies
|
324
|
+
_TODO_
|
325
|
+
|
326
|
+
### Using HAML (and other view engines) in Happy
|
327
|
+
_TODO_
|
328
|
+
|
329
|
+
### Serving assets (stylesheets, JavaScript files etc.)
|
330
|
+
_TODO_
|
331
|
+
|
332
|
+
### Caching
|
333
|
+
_TODO_
|
334
|
+
|
335
|
+
### Dealing with users and authentication
|
336
|
+
_TODO_
|
337
|
+
|
338
|
+
### Using `ResourceController`
|
339
|
+
_TODO_
|
340
|
+
|
341
|
+
### Using `ActiveModelResourceController`
|
342
|
+
_TODO_
|
343
|
+
|
344
|
+
### Authenticating against Twitter, Facebook etc. using OmniAuth
|
345
|
+
_TODO_
|
346
|
+
|
347
|
+
### Handling image uploads using DragonFly
|
348
|
+
_TODO_
|
data/lib/happy/controller.rb
CHANGED
data/lib/happy/version.rb
CHANGED
metadata
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: happy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Hendrik Mans
|
@@ -13,7 +13,7 @@ date: 2012-06-20 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement: &
|
16
|
+
requirement: &70249795375520 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '3.1'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70249795375520
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rack
|
27
|
-
requirement: &
|
27
|
+
requirement: &70249795375020 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '1.4'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70249795375020
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: allowance
|
38
|
-
requirement: &
|
38
|
+
requirement: &70249795374560 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 0.1.1
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70249795374560
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: tilt
|
49
|
-
requirement: &
|
49
|
+
requirement: &70249795374100 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '1.3'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70249795374100
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: rake
|
60
|
-
requirement: &
|
60
|
+
requirement: &70249795373720 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70249795373720
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
|
-
requirement: &
|
71
|
+
requirement: &70249795373180 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ~>
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '2.8'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70249795373180
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rspec-html-matchers
|
82
|
-
requirement: &
|
82
|
+
requirement: &70249795372760 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70249795372760
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: rack-test
|
93
|
-
requirement: &
|
93
|
+
requirement: &70249795372300 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70249795372300
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: watchr
|
104
|
-
requirement: &
|
104
|
+
requirement: &70249795371880 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70249795371880
|
113
113
|
description: A happy little toolkit for writing web applications.
|
114
114
|
email:
|
115
115
|
- hendrik@mans.de
|
@@ -179,9 +179,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
179
179
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
180
180
|
none: false
|
181
181
|
requirements:
|
182
|
-
- - ! '
|
182
|
+
- - ! '>='
|
183
183
|
- !ruby/object:Gem::Version
|
184
|
-
version:
|
184
|
+
version: '0'
|
185
185
|
requirements: []
|
186
186
|
rubyforge_project:
|
187
187
|
rubygems_version: 1.8.11
|