merb 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
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