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 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](https://github.com/hmans/happy/blob/master/TUTORIAL.md)
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
@@ -1,3 +1,348 @@
1
1
  # The Happy Book of Happy
2
2
 
3
- Lorem to the ipsum.
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_
@@ -106,7 +106,7 @@ module Happy
106
106
  # def my_little_helper
107
107
  # "something useful"
108
108
  # end
109
- # end
109
+ # end
110
110
  #
111
111
  def self.helpers(*args, &blk)
112
112
  args.flatten.each do |arg|
@@ -1,3 +1,3 @@
1
1
  module Happy
2
- VERSION = "0.1.0.pre28"
2
+ VERSION = "0.1.0"
3
3
  end
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.pre28
5
- prerelease: 6
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: &70101332488280 !ruby/object:Gem::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: *70101332488280
24
+ version_requirements: *70249795375520
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rack
27
- requirement: &70101332487780 !ruby/object:Gem::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: *70101332487780
35
+ version_requirements: *70249795375020
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: allowance
38
- requirement: &70101332487320 !ruby/object:Gem::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: *70101332487320
46
+ version_requirements: *70249795374560
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: tilt
49
- requirement: &70101332486860 !ruby/object:Gem::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: *70101332486860
57
+ version_requirements: *70249795374100
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rake
60
- requirement: &70101345428800 !ruby/object:Gem::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: *70101345428800
68
+ version_requirements: *70249795373720
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
- requirement: &70101345428260 !ruby/object:Gem::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: *70101345428260
79
+ version_requirements: *70249795373180
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rspec-html-matchers
82
- requirement: &70101345427840 !ruby/object:Gem::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: *70101345427840
90
+ version_requirements: *70249795372760
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rack-test
93
- requirement: &70101345427380 !ruby/object:Gem::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: *70101345427380
101
+ version_requirements: *70249795372300
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: watchr
104
- requirement: &70101345426960 !ruby/object:Gem::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: *70101345426960
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: 1.3.1
184
+ version: '0'
185
185
  requirements: []
186
186
  rubyforge_project:
187
187
  rubygems_version: 1.8.11