merb 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. data/README +138 -56
  2. data/Rakefile +23 -8
  3. data/app_generators/merb/templates/Rakefile +13 -0
  4. data/app_generators/merb/templates/app/helpers/global_helper.rb +1 -1
  5. data/app_generators/merb/templates/app/views/exceptions/internal_server_error.html.erb +12 -3
  6. data/app_generators/merb/templates/config/merb.yml +14 -1
  7. data/app_generators/merb/templates/spec/spec_helper.rb +6 -0
  8. data/app_generators/merb/templates/test/test_helper.rb +1 -0
  9. data/lib/merb.rb +27 -7
  10. data/lib/merb/abstract_controller.rb +76 -36
  11. data/lib/merb/caching/store/memcache.rb +20 -0
  12. data/lib/merb/constants.rb +2 -4
  13. data/lib/merb/controller.rb +44 -2
  14. data/lib/merb/core_ext/get_args.rb +23 -4
  15. data/lib/merb/core_ext/hash.rb +16 -11
  16. data/lib/merb/core_ext/inflections.rb +1 -1
  17. data/lib/merb/core_ext/kernel.rb +106 -26
  18. data/lib/merb/core_ext/numeric.rb +1 -1
  19. data/lib/merb/core_ext/string.rb +10 -13
  20. data/lib/merb/dispatcher.rb +2 -2
  21. data/lib/merb/exceptions.rb +3 -1
  22. data/lib/merb/logger.rb +15 -6
  23. data/lib/merb/mail_controller.rb +18 -2
  24. data/lib/merb/mailer.rb +1 -1
  25. data/lib/merb/mixins/controller.rb +64 -228
  26. data/lib/merb/mixins/erubis_capture.rb +1 -1
  27. data/lib/merb/mixins/general_controller.rb +258 -0
  28. data/lib/merb/mixins/render.rb +45 -24
  29. data/lib/merb/mixins/responder.rb +89 -18
  30. data/lib/merb/mixins/view_context.rb +32 -5
  31. data/lib/merb/mixins/web_controller.rb +8 -1
  32. data/lib/merb/mongrel_handler.rb +27 -17
  33. data/lib/merb/part_controller.rb +10 -0
  34. data/lib/merb/request.rb +34 -14
  35. data/lib/merb/router.rb +77 -45
  36. data/lib/merb/server.rb +116 -72
  37. data/lib/merb/session/cookie_store.rb +14 -22
  38. data/lib/merb/session/mem_cache_session.rb +2 -2
  39. data/lib/merb/session/memory_session.rb +12 -1
  40. data/lib/merb/template/erubis.rb +31 -0
  41. data/lib/merb/template/haml.rb +4 -14
  42. data/lib/merb/template/xml_builder.rb +1 -1
  43. data/lib/merb/test/helper.rb +90 -18
  44. data/lib/merb/test/rspec.rb +145 -74
  45. data/lib/merb/version.rb +11 -0
  46. data/lib/merb/view_context.rb +3 -6
  47. data/lib/patch +69 -0
  48. data/lib/tasks/merb.rake +1 -1
  49. data/spec/fixtures/config/environments/environment_config_test.yml +1 -0
  50. data/spec/fixtures/controllers/render_spec_controllers.rb +63 -4
  51. data/spec/fixtures/views/examples/template_throw_content_without_block.html.erb +3 -0
  52. data/spec/fixtures/views/partials/_erubis.html.erb +1 -1
  53. data/spec/merb/abstract_controller_spec.rb +1 -0
  54. data/spec/merb/controller_filters_spec.rb +68 -3
  55. data/spec/merb/controller_spec.rb +35 -68
  56. data/spec/merb/cookie_store_spec.rb +7 -20
  57. data/spec/merb/core_ext_spec.rb +35 -1
  58. data/spec/merb/dispatch_spec.rb +8 -2
  59. data/spec/merb/generator_spec.rb +12 -4
  60. data/spec/merb/mail_controller_spec.rb +33 -0
  61. data/spec/merb/part_controller_spec.rb +33 -1
  62. data/spec/merb/render_spec.rb +74 -0
  63. data/spec/merb/request_spec.rb +43 -0
  64. data/spec/merb/responder_spec.rb +1 -0
  65. data/spec/merb/router_spec.rb +118 -13
  66. data/spec/merb/server_spec.rb +19 -0
  67. data/spec/merb/view_context_spec.rb +31 -3
  68. data/spec/spec_helper.rb +8 -0
  69. data/spec/spec_helpers/url_shared_behaviour.rb +112 -0
  70. metadata +124 -87
@@ -22,7 +22,6 @@ module Merb
22
22
  @_format_value
23
23
  @_content_type
24
24
  @_merb_unmatched
25
- @_template_format
26
25
  @_provided_formats
27
26
  @template]
28
27
 
@@ -69,13 +68,11 @@ module Merb
69
68
  # catch any method calls that the controller responds to
70
69
  # and delegate them back to the controller.
71
70
  def method_missing(sym, *args, &blk)
72
- if @web_controller.respond_to? sym
73
- @web_controller.send(sym, *args, &blk)
74
- elsif @_merb_partial_locals.key? sym
71
+ if @_merb_partial_locals.key?(sym)
75
72
  @_merb_partial_locals[sym]
76
73
  else
77
- super
78
- end
74
+ @web_controller.send(sym, *args, &blk)
75
+ end
79
76
  end
80
77
 
81
78
  end
@@ -0,0 +1,69 @@
1
+ Index: Rakefile
2
+ ===================================================================
3
+ --- Rakefile (revision 888)
4
+ +++ Rakefile (working copy)
5
+ @@ -1,4 +1,4 @@
6
+ -
7
+ +PLATFORM = RUBY_PLATFORM if !defined?(PLATFORM)
8
+ require 'rubygems'
9
+ gem 'echoe', '>=2.7'
10
+ require 'echoe'
11
+ Index: ext/http11/http11.c
12
+ ===================================================================
13
+ --- ext/http11/http11.c (revision 888)
14
+ +++ ext/http11/http11.c (working copy)
15
+ @@ -74,7 +74,7 @@
16
+ f = rb_str_dup(global_http_prefix);
17
+ f = rb_str_buf_cat(f, field, flen);
18
+
19
+ - for(ch = RSTRING(f)->ptr, end = ch + RSTRING(f)->len; ch < end; ch++) {
20
+ + for(ch = RSTRING_PTR(f), end = ch + RSTRING_LEN(f); ch < end; ch++) {
21
+ if(*ch == '-') {
22
+ *ch = '_';
23
+ } else {
24
+ @@ -169,12 +169,12 @@
25
+ rb_hash_aset(req, global_gateway_interface, global_gateway_interface_value);
26
+ if((temp = rb_hash_aref(req, global_http_host)) != Qnil) {
27
+ /* ruby better close strings off with a '\0' dammit */
28
+ - colon = strchr(RSTRING(temp)->ptr, ':');
29
+ + colon = strchr(RSTRING_PTR(temp), ':');
30
+ if(colon != NULL) {
31
+ - rb_hash_aset(req, global_server_name, rb_str_substr(temp, 0, colon - RSTRING(temp)->ptr));
32
+ + rb_hash_aset(req, global_server_name, rb_str_substr(temp, 0, colon - RSTRING_PTR(temp)));
33
+ rb_hash_aset(req, global_server_port,
34
+ - rb_str_substr(temp, colon - RSTRING(temp)->ptr+1,
35
+ - RSTRING(temp)->len));
36
+ + rb_str_substr(temp, colon - RSTRING_PTR(temp)+1,
37
+ + RSTRING_LEN(temp)));
38
+ } else {
39
+ rb_hash_aset(req, global_server_name, temp);
40
+ rb_hash_aset(req, global_server_port, global_port_80);
41
+ @@ -295,8 +295,8 @@
42
+ DATA_GET(self, http_parser, http);
43
+
44
+ from = FIX2INT(start);
45
+ - dptr = RSTRING(data)->ptr;
46
+ - dlen = RSTRING(data)->len;
47
+ + dptr = RSTRING_PTR(data);
48
+ + dlen = RSTRING_LEN(data);
49
+
50
+ if(from >= dlen) {
51
+ rb_raise(eHttpParserError, "Requested start is after data buffer end.");
52
+ Index: ext/http11/ext_help.h
53
+ ===================================================================
54
+ --- ext/http11/ext_help.h (revision 888)
55
+ +++ ext/http11/ext_help.h (working copy)
56
+ @@ -11,4 +11,13 @@
57
+ #define TRACE()
58
+ #endif
59
+
60
+ +/* ruby 1.9 compat */
61
+ +#ifndef RSTRING_PTR
62
+ +#define RSTRING_PTR(str) RSTRING(str)->ptr
63
+ +#endif
64
+ +
65
+ +#ifndef RSTRING_LEN
66
+ +#define RSTRING_LEN(str) RSTRING(str)->len
67
+ +#endif
68
+ +
69
+ #endif
@@ -36,7 +36,7 @@ namespace :merb do
36
36
  FileUtils.rm_rf install_path
37
37
 
38
38
  puts " Freezing Merb Framework from svn, revision #{revision}"
39
- system "svn co -r #{revision} http://svn.devjavu.com/merb/trunk/lib #{install_path}"
39
+ system "svn export -r #{revision} http://svn.devjavu.com/merb/trunk/lib #{install_path}"
40
40
  install_merb_script
41
41
 
42
42
  puts " Use script/merb to start instead of plain merb"
@@ -0,0 +1 @@
1
+ :loaded_config_for_environment_config_test: true
@@ -21,17 +21,32 @@ end
21
21
 
22
22
  class FakeModel
23
23
 
24
- def to_json
24
+ def to_json(*args)
25
25
  "{'foo':'bar'}"
26
26
  end
27
27
 
28
- def to_xml
28
+ def to_xml(*args)
29
29
  "<foo>bar</foo>"
30
30
  end
31
31
  end
32
32
 
33
- class RenderObjectController < Merb::Controller
33
+ class FakeModelWithArguments
34
+
35
+ def to_json(*args)
36
+ options = args.last.is_a?(Hash) ? args.pop : {}
37
+ '[' + args.map { |arg| "'#{arg}'" }.join(',') + ']'
38
+ end
39
+
40
+ def to_xml(*args)
41
+ options = args.last.is_a?(Hash) ? args.pop.stringify_keys : {}
42
+ options.keys.sort.inject('') do |str, tag|
43
+ str << "<#{tag}>#{options[tag]}</#{tag}>"
44
+ end
45
+ end
34
46
 
47
+ end
48
+
49
+ class RenderObjectController < Merb::Controller
35
50
 
36
51
  def render_object
37
52
  provides :xml,:json
@@ -47,6 +62,49 @@ class RenderObjectController < Merb::Controller
47
62
 
48
63
  end
49
64
 
65
+ class RenderObjectWithArgumentsController < Merb::Controller
66
+
67
+ provides :xml, :foo => 'bar'
68
+ provides :json, ['foo', 'bar']
69
+
70
+ def render_standard
71
+ @foo = FakeModelWithArguments.new
72
+ render @foo
73
+ end
74
+
75
+ def render_specific
76
+ provides :xml, :foo => 'bar', :biz => 'baz'
77
+ provides :json, ['foo', 'bar', 'baz']
78
+ @foo = FakeModelWithArguments.new
79
+ render @foo
80
+ end
81
+
82
+ end
83
+
84
+ class RenderObjectWithBlockController < Merb::Controller
85
+
86
+ provides :xml do |obj, controller|
87
+ obj.to_xml(:foo => controller.class.name)
88
+ end
89
+
90
+ provides :json do |obj|
91
+ obj.to_json('foo')
92
+ end
93
+
94
+ def render_standard
95
+ @foo = FakeModelWithArguments.new
96
+ render @foo
97
+ end
98
+
99
+ def render_specific
100
+ callback = lambda { |obj, controller, method| obj.send(method, controller.class.name, 'foo', 'bar', 'baz', :foo => controller.class.name.upcase) }
101
+ provides :xml, :json, callback
102
+ @foo = FakeModelWithArguments.new
103
+ render @foo
104
+ end
105
+
106
+ end
107
+
50
108
  class ExtensionTemplateController < Merb::Controller
51
109
  provides :js, :xml
52
110
  def erubis_templates
@@ -112,4 +170,5 @@ class ExtensionTemplateController < Merb::Controller
112
170
  end
113
171
 
114
172
  Merb::Server.load_action_arguments
115
- Merb::Server.load_controller_template_path_cache
173
+ Merb::Server.load_controller_template_path_cache
174
+ Merb::Server.load_erubis_inline_helpers
@@ -0,0 +1,3 @@
1
+ <% throw_content(:content_without_block, "Content Without Block") -%>
2
+
3
+ <%= catch_content :content_without_block %>
@@ -1 +1 @@
1
- <%= respond_to?(:yo) ? yo : "No Locals!" %>
1
+ <%= respond_to?(:yo) && yo ? yo : "No Locals!" %>
@@ -14,6 +14,7 @@ describe Merb::AbstractController do
14
14
 
15
15
  after(:all) do
16
16
  Merb::Server.load_controller_template_path_cache
17
+ Merb::Server.load_erubis_inline_helpers
17
18
  end
18
19
 
19
20
  it "should add a template path" do
@@ -4,12 +4,26 @@ class TestFiltersController < Merb::Controller
4
4
 
5
5
  before :filter1
6
6
  before :will_halt, :only => :four
7
+
8
+ before :overwrite_before_filter, :only => :two
9
+ after :overwrite_after_filter, :exclude => :four
10
+
11
+ after :after_will_be_skipped
12
+ before :before_will_be_skipped
13
+
7
14
  before Proc.new {|c| c.one }, :exclude => [:one, :three, :uses_params]
8
15
  after Proc.new {|c| c.five }, :exclude => [:one, :three, :uses_params]
9
16
  after :filter2
10
17
  before :modifies_param, :only => :uses_params
11
- after :restores_param, :only => :uses_params
18
+ after :restores_param, :only => :uses_params
19
+
20
+ before :overwrite_before_filter, :only => :three
21
+ after :overwrite_after_filter, :exclude => [:one, :two, :uses_param]
22
+
23
+ skip_before :before_will_be_skipped
24
+ skip_after :after_will_be_skipped
12
25
 
26
+ # filters
13
27
 
14
28
  def will_halt
15
29
  throw :halt
@@ -37,7 +51,25 @@ class TestFiltersController < Merb::Controller
37
51
  def filter2
38
52
  @filter2='called'
39
53
  end
40
-
54
+
55
+ def before_will_be_skipped
56
+ @before_skip='called'
57
+ end
58
+
59
+ def after_will_be_skipped
60
+ @after_skip='called'
61
+ end
62
+
63
+ def overwrite_before_filter
64
+ @overwrite_before_filter='called'
65
+ end
66
+
67
+ def overwrite_after_filter
68
+ @overwrite_after_filter='called'
69
+ end
70
+
71
+ # actions
72
+
41
73
  def one
42
74
  session.data.should == {}
43
75
  @one = 'one'
@@ -89,7 +121,8 @@ class TestPrivateActions < Merb::Controller
89
121
  "notcallable"
90
122
  end
91
123
 
92
- end
124
+ end
125
+
93
126
  describe "Dispatch and before/after filters" do
94
127
 
95
128
  def call_filter_action(action, extra_params = {})
@@ -184,5 +217,37 @@ describe "Dispatch and before/after filters" do
184
217
  lambda { TestFiltersController.send(filter_type, []) }.should raise_error(ArgumentError)
185
218
  end
186
219
  end
220
+
221
+ it "should be overwritten by a subsequent call with the same filter" do
222
+ c = new_controller( 'two', TestFiltersController )
223
+ c.dispatch(:two)
224
+ c.body.should == 'two'
225
+ c.instance_variable_get('@overwrite_before_filter').should == nil
226
+ c.instance_variable_get('@overwrite_after_filter').should == nil
227
+
228
+ c = new_controller( 'three', TestFiltersController )
229
+ c.dispatch(:three)
230
+ c.body.should == 'three'
231
+ c.instance_variable_get('@overwrite_before_filter').should == 'called'
232
+ c.instance_variable_get('@overwrite_after_filter').should == 'called'
233
+ end
234
+
235
+ it "should not run if skipped" do
236
+ c = new_controller( 'one', TestFiltersController )
237
+ c.dispatch(:one)
238
+ c.body.should == 'one'
239
+ c.instance_variable_get('@one').should == 'one'
240
+ c.instance_variable_get('@two').should == nil
241
+ c.instance_variable_get('@three').should == nil
242
+
243
+ c.instance_variable_get('@before_skip').should == nil
244
+ c.instance_variable_get('@after_skip').should == nil
245
+ end
246
+
247
+ it "should not allow skipping a filter that is not a symbol or string" do
248
+ ["before", "after"].each do |filter_type|
249
+ lambda { TestFiltersController.send('skip_'+filter_type, Proc.new{|c|puts c}) }.should raise_error(ArgumentError)
250
+ end
251
+ end
187
252
 
188
253
  end
@@ -13,9 +13,20 @@ describe "Merb::Controller" do
13
13
  c = new_controller
14
14
  c._layout.should == :application
15
15
  end
16
+
17
+ it "should have a spec helper to dispatch that skips the router" do
18
+ Merb::Router.should_not_receive(:match)
19
+ dispatch_to(Bar, :foo, :id => "1") do |controller|
20
+ controller.should_receive(:foo).with("1")
21
+ end
22
+ end
23
+
16
24
  end
17
25
 
18
26
  describe Merb::Controller, "url generator tests" do
27
+
28
+ it_should_behave_like "class with general url generation"
29
+
19
30
  def new_url_controller(route, params = {:action => 'show', :controller => 'Test'})
20
31
  request = OpenStruct.new
21
32
  request.route = route
@@ -25,43 +36,6 @@ describe Merb::Controller, "url generator tests" do
25
36
 
26
37
  Merb::Controller.build(request, response)
27
38
  end
28
-
29
- before(:all) do
30
- Merb::Router.prepare do |r|
31
- @resource_routes = r.resources(:blogs)
32
- r.resources(:gardens) do |gardens|
33
- @nested_resource = gardens.resources :flowers
34
- end
35
- @test_route = r.match("/the/:place/:goes/here").to(:controller => "Test", :action => "show").name(:test)
36
- @default_route = r.default_routes
37
- end
38
- end
39
-
40
- it "should generate a url from a route using a hash" do
41
- c = new_url_controller(@test_route, :place => "1")
42
- c.url_from_route(@test_route, :goes => "g").should == "/the/1/g/here"
43
- end
44
-
45
- it "should generate a url from a route using an object" do
46
- c = new_url_controller(@test_route, :place => "2")
47
- obj = OpenStruct.new(:goes => "elsewhere")
48
- c.url_from_route(@test_route, obj).should == "/the/2/elsewhere/here"
49
- end
50
-
51
- it "should generate a url and tack extra params on as a query string" do
52
- c = new_url_controller(@test_route, :place => "1")
53
- c.url_from_route(@test_route, :goes => "g", :page => 2).should == "/the/1/g/here?page=2"
54
- end
55
-
56
- it "should generate a url directly from a hash using the current route as a default" do
57
- c = new_url_controller(@test_route, :goes => "swimmingly")
58
- c.url(:place => "provo").should == "/the/provo/swimmingly/here"
59
- end
60
-
61
- it "should generate a default route url with just :controller" do
62
- c = new_url_controller(@default_route)
63
- c.url(:controller => "welcome").should == "/welcome"
64
- end
65
39
 
66
40
  it "should generate a default route url with just :action" do
67
41
  c = new_url_controller(@default_route, :controller => "foo")
@@ -73,11 +47,6 @@ describe Merb::Controller, "url generator tests" do
73
47
  c.url(:id => "23").should == "/foo/bar/23"
74
48
  end
75
49
 
76
- it 'should generate urls from nested resources' do
77
- c = new_url_controller(@nested_resource, :garden => 5)
78
- c.url(:flower, :garden_id => 1, :id => 3).should == "/gardens/1/flowers/3"
79
- end
80
-
81
50
  it "should generate a default route url with an extra param" do
82
51
  c = new_url_controller(@default_route, :controller => "foo", :action => "bar")
83
52
  c.url(:controller => :current, :monkey => "quux").should == "/foo/bar?monkey=quux"
@@ -105,40 +74,38 @@ describe Merb::Controller, "url generator tests" do
105
74
  c.url(:action => :recent, :format => :txt).should == "/foo/recent.txt"
106
75
  end
107
76
 
108
- it "should generate a default route url with all options" do
109
- c = new_url_controller(@default_route, :controller => "foo", :action => "bar")
110
- c.url(:controller => "foo", :action => "bar", :id => "baz", :format => :js, :monkey => "quux").should == "/foo/bar/baz.js?monkey=quux"
111
- end
112
-
113
77
  it "should handle nested nested and more nested hashes and arrays" do
114
78
  c = new_url_controller(@default_route, :controller => "foo", :action => "bar")
115
79
  url = c.url(:controller => :current, :user => {:filter => {:name => "quux*"}, :order => ["name"]})
116
80
  url.should match(%r{/foo/bar?.*user\[filter\]\[name\]=quux%2A})
117
81
  url.should match(%r{/foo/bar?.*user\[order\]\[\]=name})
118
82
  end
83
+ end
84
+
85
+ describe "Controller", "redirect spec helpers" do
86
+ class Redirector < Merb::Controller
87
+ def index
88
+ redirect("/foo")
89
+ end
90
+ def show
91
+ end
92
+ end
119
93
 
120
- it "should handle an object as the second arg" do
121
- c = new_url_controller(@resource_routes, :controller => "blogs", :action => "show")
122
- blog = mock("blog")
123
- blog.should_receive(:id).once.and_return(7)
124
- url = c.url(:blog, blog)
125
- url.should == "/blogs/7"
94
+ before(:each) do
95
+ @controller = Redirector.build(fake_request)
126
96
  end
127
-
128
- it "should point to /blogs/:blog_id if @blog is not new_record" do
129
- c = new_url_controller(@resource_routes, :controller => "blogs", :action => "index")
130
- blog = mock("blog")
131
- blog.should_receive(:id).once.and_return(7)
132
- blog.should_receive(:new_record?).once.and_return(false)
133
- url = c.url(:blog, blog)
134
- url.should == "/blogs/7"
97
+
98
+ it "should be able to match redirects" do
99
+ @controller.dispatch('index')
100
+ @controller.status.should be_redirect
101
+ @controller.should redirect
102
+ @controller.should redirect_to("/foo")
135
103
  end
136
-
137
- it "should point to /blogs/ if @blog is new_record" do
138
- c = new_url_controller(@resource_routes, :controller => "blogs", :action => "index")
139
- blog = mock("blog")
140
- blog.should_receive(:new_record?).once.and_return(true)
141
- url = c.url(:blog, blog)
142
- url.should == "/blogs/"
104
+
105
+ it "should be able to negative match redirects" do
106
+ @controller.dispatch('show')
107
+ @controller.status.should_not be_redirect
108
+ @controller.should_not redirect
109
+ @controller.should_not redirect_to("/foo")
143
110
  end
144
111
  end