merb 0.3.4 → 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/README +206 -197
  2. data/Rakefile +12 -21
  3. data/bin/merb +1 -1
  4. data/examples/skeleton/Rakefile +6 -20
  5. data/examples/skeleton/dist/app/mailers/layout/application.erb +1 -0
  6. data/examples/skeleton/dist/conf/database.yml +23 -0
  7. data/examples/skeleton/dist/conf/environments/development.rb +1 -0
  8. data/examples/skeleton/dist/conf/environments/production.rb +1 -0
  9. data/examples/skeleton/dist/conf/environments/test.rb +1 -0
  10. data/examples/skeleton/dist/conf/merb.yml +32 -28
  11. data/examples/skeleton/dist/conf/merb_init.rb +16 -13
  12. data/examples/skeleton/dist/conf/router.rb +9 -9
  13. data/examples/skeleton/dist/schema/migrations/001_add_sessions_table.rb +2 -2
  14. data/lib/merb.rb +23 -18
  15. data/lib/merb/caching/fragment_cache.rb +3 -7
  16. data/lib/merb/caching/store/memcache.rb +20 -0
  17. data/lib/merb/core_ext/merb_array.rb +0 -0
  18. data/lib/merb/core_ext/merb_class.rb +44 -4
  19. data/lib/merb/core_ext/merb_enumerable.rb +43 -1
  20. data/lib/merb/core_ext/merb_hash.rb +200 -122
  21. data/lib/merb/core_ext/merb_kernel.rb +2 -0
  22. data/lib/merb/core_ext/merb_module.rb +41 -0
  23. data/lib/merb/core_ext/merb_numeric.rb +57 -5
  24. data/lib/merb/core_ext/merb_object.rb +172 -6
  25. data/lib/merb/generators/merb_app/merb_app.rb +15 -9
  26. data/lib/merb/merb_abstract_controller.rb +193 -0
  27. data/lib/merb/merb_constants.rb +26 -1
  28. data/lib/merb/merb_controller.rb +143 -234
  29. data/lib/merb/merb_dispatcher.rb +28 -20
  30. data/lib/merb/merb_drb_server.rb +2 -3
  31. data/lib/merb/merb_exceptions.rb +194 -49
  32. data/lib/merb/merb_handler.rb +34 -26
  33. data/lib/merb/merb_mail_controller.rb +200 -0
  34. data/lib/merb/merb_mailer.rb +33 -13
  35. data/lib/merb/merb_part_controller.rb +42 -0
  36. data/lib/merb/merb_plugins.rb +293 -0
  37. data/lib/merb/merb_request.rb +6 -4
  38. data/lib/merb/merb_router.rb +99 -65
  39. data/lib/merb/merb_server.rb +65 -21
  40. data/lib/merb/merb_upload_handler.rb +2 -1
  41. data/lib/merb/merb_view_context.rb +36 -15
  42. data/lib/merb/mixins/basic_authentication_mixin.rb +5 -5
  43. data/lib/merb/mixins/controller_mixin.rb +67 -28
  44. data/lib/merb/mixins/erubis_capture_mixin.rb +1 -8
  45. data/lib/merb/mixins/form_control_mixin.rb +280 -42
  46. data/lib/merb/mixins/render_mixin.rb +127 -45
  47. data/lib/merb/mixins/responder_mixin.rb +5 -7
  48. data/lib/merb/mixins/view_context_mixin.rb +260 -94
  49. data/lib/merb/session.rb +23 -0
  50. data/lib/merb/session/merb_ar_session.rb +28 -16
  51. data/lib/merb/session/merb_mem_cache_session.rb +108 -0
  52. data/lib/merb/session/merb_memory_session.rb +65 -20
  53. data/lib/merb/template/erubis.rb +22 -13
  54. data/lib/merb/template/haml.rb +5 -16
  55. data/lib/merb/template/markaby.rb +5 -3
  56. data/lib/merb/template/xml_builder.rb +17 -5
  57. data/lib/merb/test/merb_fake_request.rb +63 -0
  58. data/lib/merb/test/merb_multipart.rb +58 -0
  59. data/lib/tasks/db.rake +2 -0
  60. data/lib/tasks/merb.rake +20 -8
  61. metadata +24 -25
  62. data/examples/skeleton.tar +0 -0
data/README CHANGED
@@ -1,68 +1,68 @@
1
+ = Merb
2
+ <em>Lightweight MVC Ruby app server. For high performance dynamic pages.</em>
1
3
 
2
- Copyright (c) 2006 Ezra Zygmuntowicz
4
+ ==== Dependencies
5
+ Install these gems first:
3
6
 
4
- Merb.
7
+ * mongrel
8
+ * erubis
9
+ * json
10
+ * mime-types
11
+ * archive-tar-minitar
12
+ * rspec
5
13
 
6
- Lightweight MVC Ruby app server. For high performance dynamic pages.
14
+ Then you can build the merb gem from svn trunk like so:
7
15
 
8
- ** Dependencies **
9
- mongrel
10
- erubis
11
- json
12
- mime-types
13
- archive-tar-minitar
14
- rspec
15
-
16
- Install these gems first then you can build the merb gem from svn trunk like so:
17
- $ sudo gem install mongrel erubis json mime-types archive-tar-minitar rspec --include-dependencies
18
- $ svn co http://svn.devjavu.com/merb/trunk merb
19
- $ cd merb
20
- $ rake install
16
+ $ sudo gem install mongrel erubis json mime-types archive-tar-minitar rspec --include-dependencies
17
+ $ svn co http://svn.devjavu.com/merb/trunk merb
18
+ $ cd merb
19
+ $ rake install
21
20
 
22
21
  To generate a new merb app after the gem is installed:
23
- $ merb -g myapp
24
22
 
23
+ $ merb -g myapp
24
+
25
+ To run your application, simply type +merb+ in the project directory.
25
26
 
26
- **FEATURES**
27
+ == Features
27
28
 
28
- *Mongrel handler*
29
- built in that parses incoming requests
30
- including multipart uploads and post as well as ?query=strings. Puts the
29
+ === Mongrel handler
30
+ Merb has a Mongrel handler built in that parses incoming requests
31
+ including multipart uploads and post as well as <tt>?query=strings</tt>. Puts the
31
32
  params into params and the cookies into cookies when it instantiates your
32
33
  controller class.
33
34
 
34
- *RouteMatcher and route compiler*
35
+ === RouteMatcher and route compiler
35
36
 
36
37
  Reads your route definition and compiles
37
38
  a method on the fly that will match the request path against each route and do the right thing.
38
39
 
39
- *** NEW RESTFULL ROUTES ***
40
+ === _NEW_ RESTful Routes
40
41
 
41
- note the r.resource :posts macro. That makes it possible to use a restfull crud style controller for the posts resource
42
+ Note the <tt>r.resource :posts</tt> macro. That makes it possible to use a RESTful CRUD style controller for the posts resource
42
43
 
43
- Merb::RouteMatcher.prepare do |r|
44
- r.resources :posts
45
- r.default_routes
46
- r.add '/', :controller => 'files', :action => 'index'
47
- end
44
+ Merb::Router.prepare do |r|
45
+ r.resources :posts
46
+ r.default_routes
47
+ r.add '/', :controller => 'files', :action => 'index'
48
+ end
48
49
 
49
- The r.default_routes routes adds the standard routes:
50
+ The <tt>r.default_routes</tt> routes adds the standard routes:
50
51
 
51
- /controller/action/id.xml
52
- /controller/action/id
53
- /controller/action.xml
54
- /controller/action
55
- /controller.xml # index action
56
- /controller # index action
52
+ /controller/action/id.xml
53
+ /controller/action/id
54
+ /controller/action.xml
55
+ /controller/action
56
+ /controller.xml # index action
57
+ /controller # index action
57
58
 
59
+ === Controllers
58
60
 
59
-
60
- *Controllers*
61
61
  Classes with built in render method and template handling
62
62
  with instance vars available in the views automatically. Merb also supports
63
63
  layouts. It will look for a layout named after your controller class first and
64
64
  then fall back to application.herb if no layout exists named after your controller.
65
- You can use render :layout => :none.
65
+ You can use render <tt>:layout => :none</tt>.
66
66
 
67
67
  Merb does not automatically render for you in your controller actions, you have
68
68
  to call render yourself. I consider this a big advantage over the way rails does
@@ -70,7 +70,7 @@ it for a few reasons. The main reason is that in rails you can only render once
70
70
  per action, so it knows if you haven’t rendered it shoudl auto render. Merb on
71
71
  the other hand, returns to the browser whatever the return value of your
72
72
  controller’s action method is. This opens up more possibilities imho because
73
- now you can return any string from your action and that will be sent down
73
+ now you can return any string from your action and that will be sent down
74
74
  the pipe. So Merb’s render method just returns a string and needs to be the
75
75
  last thing you call in your action. You can render multiple times and capture
76
76
  the results into @ivars and then render a master template with many embeded
@@ -81,7 +81,7 @@ return value sent to the client.
81
81
 
82
82
  That last point has some cool connotations if you think about it. Merb does
83
83
  have a mutex lock around the call to your controller’s action anywhere that
84
- you can call AR objects. Merb’s lock is way smaller then rails giant lock
84
+ you can call AR objects. Merb’s lock is way smaller then rails giant lock
85
85
  though and allows for many more concurrent requests to be handled by one
86
86
  process. By returning a Proc object from your action, you allow merb to
87
87
  release the lock and the proc is called in multi threaded way. This allows
@@ -90,204 +90,213 @@ release the mutex. It’s basically like handing over the proc to mongrel and
90
90
  mongrel handles calling it in a thread safe manner.
91
91
 
92
92
 
93
- class Test < Merb::Controller
94
- def hello
95
- # params, headers and cookies are available here.
96
- @name = params[:name]
97
- render
98
- end
99
- end
93
+ class Test < Merb::Controller
94
+ def hello
95
+ # params, headers and cookies are available here.
96
+ @name = params[:name]
97
+ render
98
+ end
99
+ end
100
100
 
101
101
  You can also render partials like so:
102
- <%= partial(:comments) %>
103
102
 
104
- This assumes a _comments.rhtml file in the same view dir as the current
105
- controller/view
103
+ <%= partial(:comments) %>
104
+
105
+ This assumes a <tt>_comments.rhtml</tt> file in the same view dir as the current
106
+ controller/view.
106
107
 
107
108
  Partials compile the template ands returns a string. So you can also call
108
109
  them and assign them to a var if you want:
109
110
 
110
- def someaction
111
- @one = partial(:one)
112
- @two = partial(:two)
113
- end
114
-
115
- partials can also render views from other controllers by specifying the path
116
-
117
- partial('/shared/foo')
118
-
119
-
120
- Merb also allows for returning javascript instead of html for ajax actions
121
- You have to use the render_js instead of normal render
122
-
123
- def ajax_action
124
- @posts = Post.find :all
125
- render_js
126
- end
127
-
128
- # ajax_action.jerb
129
- $('comments').update('<%=js partial(:posts) %>');
130
-
131
- # _posts.herb
132
- <ul>
133
- <% @posts.each do |p| %>
134
- <li>
135
- <%= p.title %><br />
136
- <%= p.body %>
137
- </li>
138
- <% end %>
139
- </ul>
140
-
141
-
142
- *Restful Controllers*
143
-
144
- restful controllers use a different dispatch system based on the request method verbs. Merb
145
- supports multi return values based on the accept header via respond_to
146
-
147
- class Posts < Merb::Controller
148
- # GET /posts
149
- # GET /posts.xml
150
- def index
151
- @posts = Post.find :all
152
- respond_to {|format|
153
- format.html { render }
154
- format.js { render :js => 'index' }
155
- format.xml { render :xml => @posts.to_xml }
156
- }
157
- end
158
-
159
- # GET /posts/1
160
- # GET /posts/1.xml
161
- def show
162
- end
163
-
164
- # GET /posts/new
165
- def new
166
- end
167
-
168
- # GET /posts/1;edit
169
- def edit
170
- end
171
-
172
- # POST /posts
173
- # POST /posts.xml
174
- def create
175
- end
176
-
177
- # PUT /posts/1
178
- # PUT /posts/1.xml
179
- def update
180
- end
181
-
182
- # DELETE /posts/1
183
- # DELETE /posts/1.xml
184
- def destroy
185
- end
186
- end
187
-
188
-
189
- *Controllers have powerful before and after filters*
111
+ def someaction
112
+ @one = partial(:one)
113
+ @two = partial(:two)
114
+ end
115
+
116
+ Partials can also render views from other controllers by specifying the path:
117
+
118
+ partial('/shared/foo')
119
+
120
+ Merb also allows for returning JavaScript instead of html for ajax actions
121
+ You have to use the render_js instead of normal render:
122
+
123
+ def ajax_action
124
+ @posts = Post.find :all
125
+ render_js
126
+ end
127
+
128
+ # ajax_action.jerb
129
+ $('comments').update('<%=js partial(:posts) %>');
130
+
131
+ # _posts.herb
132
+ <ul>
133
+ <% @posts.each do |p| %>
134
+ <li>
135
+ <%= p.title %><br />
136
+ <%= p.body %>
137
+ </li>
138
+ <% end %>
139
+ </ul>
140
+
141
+ The .jerb template is used for this purpose.
142
+
143
+ ==== RESTful Controllers
144
+
145
+ RESTful controllers use a different dispatch system based on the request method verbs. Merb
146
+ supports multi return values based on the accept header via +respond_to+.
147
+
148
+ class Posts < Merb::Controller
149
+ # GET /posts
150
+ # GET /posts.xml
151
+ def index
152
+ @posts = Post.find :all
153
+ respond_to {|format|
154
+ format.html { render }
155
+ format.js { render :js => :index }
156
+ format.xml { render :xml => @posts.to_xml }
157
+ }
158
+ end
159
+
160
+ # GET /posts/1
161
+ # GET /posts/1.xml
162
+ def show
163
+ end
164
+
165
+ # GET /posts/new
166
+ def new
167
+ end
168
+
169
+ # GET /posts/1;edit
170
+ def edit
171
+ end
172
+
173
+ # POST /posts
174
+ # POST /posts.xml
175
+ def create
176
+ end
177
+
178
+ # PUT /posts/1
179
+ # PUT /posts/1.xml
180
+ def update
181
+ end
182
+
183
+ # DELETE /posts/1
184
+ # DELETE /posts/1.xml
185
+ def destroy
186
+ end
187
+ end
188
+
189
+ Learn more about this in the controller documentation.
190
+
191
+ ==== Before and after filters
190
192
 
191
193
  Use the before method in your controllers. before accepts either a symbol, string or a Proc/lambda object. If you give it a symbol it will call a method with the same name as the symbol. If you give it a proc that takes one argument it will call the proc with the current controller as that argument. You can use :only and :exclude as options to your filters to exclude or include actionsfrom certain filters. :only and :exclude take :symbols or [:sym, :sam] array of symbols.
192
194
 
193
- class Foo < Merb::Controller
195
+ class Foo < Merb::Controller
194
196
 
195
- before :setup_user, :only => :foo
196
- before lambda {|c| c.headers['X-Foo] = 'bar' }, :exclude => [:foo, :baz]
197
+ before :setup_user, :only => :foo
198
+ before lambda {|c| c.headers['X-Foo] = 'bar' }, :exclude => [:foo, :baz]
197
199
 
198
- def setup_user
199
- # blah blah
200
- end
200
+ def setup_user
201
+ # blah blah
202
+ end
201
203
 
202
- def foo
203
- # blah
204
- end
204
+ def foo
205
+ # blah
206
+ end
205
207
 
206
- def regular_action
207
- # blah
208
- end
208
+ def regular_action
209
+ # blah
210
+ end
209
211
 
210
- end
212
+ end
211
213
 
212
214
  To stop the before filter chain you use throw :halt with a few options:
213
215
 
214
- # halts the filter chain and calls filters_halted which you can override
215
- # in your controller to specialize it.
216
+ # halts the filter chain and calls filters_halted which you can override
217
+ # in your controller to specialize it.
216
218
 
217
- throw :halt
219
+ throw :halt
218
220
 
219
- # halts the filters and calls the method named after the symbol:
221
+ # halts the filters and calls the method named after the symbol:
220
222
 
221
- throw :halt, :other_action
223
+ throw :halt, :other_action
222
224
 
223
- # halts the filter chain and returns the result of the Proc being called
225
+ # halts the filter chain and returns the result of the Proc being called
224
226
 
225
- throw :halt, Proc.new{ |c| c.redirect "/foo" }
227
+ throw :halt, Proc.new{ |c| c.redirect "/foo" }
226
228
 
227
- # halts the chain and returns whatever is in the string
229
+ # halts the chain and returns whatever is in the string
228
230
 
229
- throw :halt, "<h1>You don't have permissions dude!</h1>"
231
+ throw :halt, "<h1>You don't have permissions dude!</h1>"
230
232
 
231
- or even render templates:
233
+ or even render templates:
232
234
 
233
- throw :halt, render 'foo'
234
- throw :halt, partial 'foo'
235
+ throw :halt, render 'foo'
236
+ throw :halt, partial 'foo'
235
237
 
236
- After filters accept a symbol, string or Proc and call that proc with the controller:
238
+ After filters accept a symbol, string or Proc and call that proc with the controller:
237
239
 
238
- after Proc.new {|c| Tidy.new(c.body) }, :only => :index
240
+ after Proc.new {|c| Tidy.new(c.body) }, :only => :index
241
+
242
+ === Sessions
239
243
 
240
244
  Sessions are available when you start merb with the sql_session set to true or the
241
245
  memory_session set to true. See generated app for migration too add session table.
242
246
 
243
- Helpers: dist/app/helpers/global_helper.rb will be available to all of your views.
247
+ === Helpers
248
+
249
+ dist/app/helpers/global_helper.rb will be available to all of your views.
244
250
  Helpers named after your controller plus _helper.rb will be included in the views
245
251
  for that controller only.
246
252
 
247
- *The merb server*
253
+ === The +merb+ server
254
+
248
255
  right now you add your routes in
249
256
  the appdir/dist/conf/router.rb file. So by default it runs on port 4000
250
257
 
251
- $ cd /path/to/your/merb/app
252
- $ merb
258
+ $ cd /path/to/your/merb/app
259
+ $ merb
253
260
 
254
261
  Or to start merb on a different port:
255
- $ merb -p 3500
262
+
263
+ $ merb -p 3500
256
264
 
257
265
  To start a cluster of merb servers you specify the first port and then how many
258
266
  servers you want spawned. SO this command will start a merb instance on ports
259
267
  3000, 3001, 3002
260
268
 
261
- $ merb -p 3000 -c 3
269
+ $ merb -p 3000 -c 3
262
270
 
263
271
  To start a Merb IRB console where all your models and other classes are pre loaded
264
272
  use the -i flag
265
273
 
266
- $merb -i
274
+ $merb -i
267
275
 
268
- *File uploads*
276
+ === File uploads
269
277
  This is one of the things that Merb was written for. Rails doesn't allow
270
278
  multiple concurrent file uploads at once without blocking an entire rails backend for each file upload. Merb allows multiple file uploads at once.
271
- When a file is uploaded with Merb, it gets put in a Tempfile. So
279
+ When a file is uploaded with Merb, it gets put in a Tempfile. So
272
280
  you just want to copy it to the right place on the filesystem.
273
281
 
274
- def upload
275
- puts params[:file].inspect
282
+ def upload
283
+ puts params[:file].inspect
276
284
 
277
- FileUtils.mv params[:file][:tempfile].path, MERB_ROOT+"/uploads/#{params[:file][:filename]}"
285
+ FileUtils.mv params[:file][:tempfile].path, MERB_ROOT+"/uploads/#{params[:file][:filename]}"
278
286
 
279
- render
280
- end
287
+ render
288
+ end
281
289
 
282
290
  A file upload will have a hash of params like this:
283
- {
284
- :filename => File.basename(filename),
285
- :content_type => content_type,
286
- :tempfile => <Tempfile>,
287
- :size => File.size(body)
288
- }
289
291
 
290
- *Merb app layout*
292
+ {
293
+ :filename => File.basename(filename),
294
+ :content_type => content_type,
295
+ :tempfile => <Tempfile>,
296
+ :size => File.size(body)
297
+ }
298
+
299
+ == Merb app layout
291
300
 
292
301
  A Merb app contains everything it needs to run in production in the
293
302
  MERB_ROOT/dist directory. So for deployment you only need to deploy the dist dir. This
@@ -297,21 +306,21 @@ and DIST_ROOT. MERB_ROOT is the root of the whole tree. And DISTROOT is MERB_ROO
297
306
  You will cd into MERB_ROOT to run the merb command line. ANd when you deploy live you
298
307
  will put the dist dir into another empty MERB_ROOT on the production server.
299
308
 
300
- merb_app:
301
- Rakefile
302
- README
303
- scripts
304
- test
305
- spec
306
- unit
307
- plugins
308
- dist
309
- app
310
- controllers
311
- models
312
- views
313
- conf
314
- lib
315
- public
316
- plugins
317
- schema
309
+ merb_app:
310
+ Rakefile
311
+ README
312
+ scripts
313
+ test
314
+ spec
315
+ unit
316
+ plugins
317
+ dist
318
+ app
319
+ controllers
320
+ models
321
+ views
322
+ conf
323
+ lib
324
+ public
325
+ plugins
326
+ schema