snusnu-merb_resource_controller 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +168 -18
- data/Rakefile +1 -1
- data/TODO +0 -1
- data/lib/merb_resource_controller.rb +2 -1
- data/lib/merb_resource_controller/action_descriptor.rb +107 -0
- data/lib/merb_resource_controller/actions.rb +159 -13
- data/lib/merb_resource_controller/resource_controller.rb +28 -44
- data/lib/merb_resource_controller/resource_proxy.rb +43 -12
- data/spec/mrc_test_app/app/controllers/articles.rb +1 -0
- data/spec/mrc_test_app/app/models/community/comment.rb +20 -0
- data/spec/mrc_test_app/app/models/community/rating.rb +19 -0
- data/spec/mrc_test_app/app/views/community/ratings/new.html.erb +11 -0
- data/spec/mrc_test_app/config/init.rb +0 -1
- data/spec/mrc_test_app/spec/lib/action_descriptor_spec.rb +137 -0
- data/spec/mrc_test_app/spec/lib/resource_proxy_spec.rb +7 -7
- data/spec/mrc_test_app/spec/request/article_comment_ratings_spec.rb +196 -0
- data/spec/mrc_test_app/spec/request/articles_spec.rb +266 -0
- metadata +19 -18
- data/spec/mrc_test_app/Rakefile +0 -52
- data/spec/mrc_test_app/app/controllers/editors.rb +0 -7
- data/spec/mrc_test_app/app/views/community/ratings/edit.html.erb +0 -11
@@ -10,15 +10,14 @@ module Merb
|
|
10
10
|
module ClassMethods
|
11
11
|
|
12
12
|
def controlling(name, options = {})
|
13
|
-
|
14
|
-
@resource_proxy = Merb::ResourceController::ResourceProxy.new(name, options)
|
13
|
+
@resource_proxy = ResourceProxy.new(name, class_provided_formats, options)
|
15
14
|
yield @resource_proxy if block_given?
|
16
15
|
class_inheritable_reader :resource_proxy
|
17
16
|
include InstanceMethods
|
18
|
-
|
19
|
-
|
20
|
-
include
|
21
|
-
show_action(
|
17
|
+
@resource_proxy.registered_actions.each do |action_descriptor|
|
18
|
+
include action_descriptor.action_module
|
19
|
+
include action_descriptor.flash_module if action_descriptor.supports_flash_messages?
|
20
|
+
show_action(action_descriptor.action_name)
|
22
21
|
end
|
23
22
|
end
|
24
23
|
|
@@ -33,6 +32,26 @@ module Merb
|
|
33
32
|
end
|
34
33
|
|
35
34
|
|
35
|
+
def handle_content_type(action, format, scenario)
|
36
|
+
if handler = content_type_handler(action, format, scenario)
|
37
|
+
self.send(handler) if self.respond_to?(handler)
|
38
|
+
else
|
39
|
+
raise "no content type handler registered for #{action} #{format} #{scenario}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def content_type_handler(action, format, scenario)
|
44
|
+
resource_proxy.content_type_handler(action, format, scenario)
|
45
|
+
end
|
46
|
+
|
47
|
+
def set_action_specific_provides(action)
|
48
|
+
if resource_proxy.has_format_restriction?(action)
|
49
|
+
provides_api, formats = resource_proxy.action_specific_provides(action)
|
50
|
+
self.send(provides_api, *formats)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
36
55
|
def singleton_controller?
|
37
56
|
resource_proxy.singleton_resource?
|
38
57
|
end
|
@@ -63,10 +82,7 @@ module Merb
|
|
63
82
|
|
64
83
|
|
65
84
|
def load_resource
|
66
|
-
|
67
|
-
# puts "path_to_resource: #{path.inspect}"
|
68
|
-
path.each do |pc|
|
69
|
-
# puts "setting @#{pc[0]} to #{pc[1].inspect}" if pc[1]
|
85
|
+
resource_proxy.path_to_resource(params).each do |pc|
|
70
86
|
instance_variable_set("@#{pc[0]}", pc[1]) if pc[1]
|
71
87
|
end
|
72
88
|
end
|
@@ -116,43 +132,11 @@ module Merb
|
|
116
132
|
end
|
117
133
|
|
118
134
|
|
119
|
-
def
|
120
|
-
|
135
|
+
def flash_messages_for?(action)
|
136
|
+
resource_proxy.flash_messages_for?(action)
|
121
137
|
end
|
122
138
|
|
123
139
|
end
|
124
|
-
|
125
|
-
module FlashSupport
|
126
|
-
|
127
|
-
protected
|
128
|
-
|
129
|
-
def successful_create_messages
|
130
|
-
{ :notice => "#{member.class.name} was successfully created" }
|
131
|
-
end
|
132
|
-
|
133
|
-
def failed_create_messages
|
134
|
-
{ :error => "Failed to create new #{member.class.name}" }
|
135
|
-
end
|
136
|
-
|
137
|
-
|
138
|
-
def successful_update_messages
|
139
|
-
{ :notice => "#{member.class.name} was successfully updated" }
|
140
|
-
end
|
141
|
-
|
142
|
-
def failed_update_messages
|
143
|
-
{ :error => "Failed to update #{member.class.name}" }
|
144
|
-
end
|
145
|
-
|
146
|
-
|
147
|
-
def successful_destroy_messages
|
148
|
-
{ :notice => "#{member.class.name} was successfully destroyed" }
|
149
|
-
end
|
150
|
-
|
151
|
-
def failed_destroy_messages
|
152
|
-
{ :error => "Failed to destroy #{member.class.name}" }
|
153
|
-
end
|
154
|
-
|
155
|
-
end
|
156
140
|
|
157
141
|
end
|
158
142
|
|
@@ -13,11 +13,12 @@ module Merb
|
|
13
13
|
:use => :all
|
14
14
|
})
|
15
15
|
|
16
|
-
attr_reader :resource, :parents, :registered_methods
|
16
|
+
attr_reader :resource, :provided_formats, :parents, :registered_methods
|
17
17
|
|
18
|
-
def initialize(resource, options = {})
|
18
|
+
def initialize(resource, provided_formats, options = {})
|
19
19
|
options = DEFAULT_OPTIONS.merge(options)
|
20
20
|
@resource, @singleton = load_resource(resource), !!options[:singleton]
|
21
|
+
@provided_formats = provided_formats || [ :html ]
|
21
22
|
@fully_qualified = !!options[:fully_qualified]
|
22
23
|
@actions, @registered_methods, @parents = [], [], []
|
23
24
|
@specific_methods_registered = options[:use] != :all
|
@@ -26,17 +27,54 @@ module Merb
|
|
26
27
|
end
|
27
28
|
|
28
29
|
def action(name, options = {})
|
29
|
-
|
30
|
+
options = { :default_formats => true }.merge(options)
|
31
|
+
descriptor = ActionDescriptor.new(name, @provided_formats, options)
|
32
|
+
yield descriptor if block_given?
|
33
|
+
@actions << descriptor
|
30
34
|
end
|
31
35
|
|
32
|
-
def actions(*
|
33
|
-
|
36
|
+
def actions(*action_specs)
|
37
|
+
action_specs.each { |a| a.is_a?(Hash) ? action(a.delete(:name), a) : action(a) }
|
34
38
|
end
|
35
39
|
|
36
40
|
def registered_actions
|
37
41
|
@actions
|
38
42
|
end
|
39
43
|
|
44
|
+
def flash_messages_for?(action)
|
45
|
+
return false unless @actions.map { |ad| ad.action_name }.include?(action.to_sym)
|
46
|
+
@actions.any? { |ad| ad.action_name == action.to_sym && ad.supports_flash_messages? }
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def action_descriptor(action)
|
51
|
+
ad = @actions.select { |ad| ad.action_name == action.to_sym }
|
52
|
+
ad.first ? ad.first : raise("No action named #{action} is registered for this controller")
|
53
|
+
end
|
54
|
+
|
55
|
+
def content_type_handler(action, format, scenario)
|
56
|
+
action_descriptor(action).content_type_handler(format, scenario)
|
57
|
+
end
|
58
|
+
|
59
|
+
def has_format_restriction?(action)
|
60
|
+
action_descriptor(action).has_format_restriction?
|
61
|
+
end
|
62
|
+
|
63
|
+
def action_specific_provides(action)
|
64
|
+
ad = action_descriptor(action)
|
65
|
+
[ ad.format_restriction_api, ad.restricted_formats ]
|
66
|
+
end
|
67
|
+
|
68
|
+
def register_default_actions!
|
69
|
+
action :index unless @singleton
|
70
|
+
action :show
|
71
|
+
action :new, :only_provides => :html
|
72
|
+
action :edit, :only_provides => :html
|
73
|
+
action :create, :flash => true
|
74
|
+
action :update, :flash => true
|
75
|
+
action :destroy, :flash => true
|
76
|
+
end
|
77
|
+
|
40
78
|
# ----------------------------------------------------------------------------------------
|
41
79
|
# # one level nestings
|
42
80
|
# ----------------------------------------------------------------------------------------
|
@@ -275,13 +313,6 @@ module Merb
|
|
275
313
|
end
|
276
314
|
end
|
277
315
|
|
278
|
-
def register_default_actions!
|
279
|
-
action :index unless @singleton
|
280
|
-
[ :show, :new, :edit, :create, :update, :destroy ].each do |a|
|
281
|
-
action(a)
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
316
|
|
286
317
|
# KEEP THESE for later
|
287
318
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Community
|
2
|
+
|
3
|
+
class Comment
|
4
|
+
|
5
|
+
include DataMapper::Resource
|
6
|
+
|
7
|
+
property :id, Serial
|
8
|
+
property :article_id, Integer, :nullable => false
|
9
|
+
property :body, String, :nullable => false, :length => (3..255)
|
10
|
+
|
11
|
+
belongs_to :article
|
12
|
+
has n, :ratings, :class_name => "Community::Rating"
|
13
|
+
|
14
|
+
def article_title
|
15
|
+
article.title
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Community
|
2
|
+
|
3
|
+
class Rating
|
4
|
+
|
5
|
+
include DataMapper::Resource
|
6
|
+
|
7
|
+
property :id, Serial
|
8
|
+
property :comment_id, Integer, :nullable => false
|
9
|
+
property :rate, Integer, :nullable => false
|
10
|
+
|
11
|
+
belongs_to :comment
|
12
|
+
|
13
|
+
def comment_body
|
14
|
+
comment.body
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
describe "Merb::ResourceController::ActionDescriptor" do
|
2
|
+
|
3
|
+
it "should raise if no action is given" do
|
4
|
+
lambda { Merb::ResourceController::ActionDescriptor.new }.should raise_error
|
5
|
+
end
|
6
|
+
|
7
|
+
it "should raise if more than one format restriction was specified" do
|
8
|
+
provided_formats = [ :html, :xml, :json, :yml ]
|
9
|
+
options = { :provides => :xml, :does_not_provide => :json, :only_provides => :yml }
|
10
|
+
lambda { Merb::ResourceController::ActionDescriptor.new(:index, provided_formats, options) }.should raise_error
|
11
|
+
options = { :provides => :xml, :does_not_provide => :json }
|
12
|
+
lambda { Merb::ResourceController::ActionDescriptor.new(:index, provided_formats, options) }.should raise_error
|
13
|
+
options = { :provides => :xml, :only_provides => :json }
|
14
|
+
lambda { Merb::ResourceController::ActionDescriptor.new(:index, provided_formats, options) }.should raise_error
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should allow valid format restriction apis" do
|
18
|
+
provided_formats = [ :html, :xml, :json, :yml ]
|
19
|
+
lambda { Merb::ResourceController::ActionDescriptor.new(:index, provided_formats, :provides => :xml) }.should_not raise_error
|
20
|
+
lambda { Merb::ResourceController::ActionDescriptor.new(:index, provided_formats, :does_not_provide => :xml) }.should_not raise_error
|
21
|
+
lambda { Merb::ResourceController::ActionDescriptor.new(:index, provided_formats, :only_provides => :xml) }.should_not raise_error
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should be able to infer the format restriction api" do
|
25
|
+
provided_formats = [ :html, :xml, :json, :yml ]
|
26
|
+
p = Merb::ResourceController::ActionDescriptor.new(:index, provided_formats)
|
27
|
+
p.format_restriction_api.should == nil
|
28
|
+
p.has_format_restriction?.should be_false
|
29
|
+
p = Merb::ResourceController::ActionDescriptor.new(:index, provided_formats, :provides => :xml)
|
30
|
+
p.format_restriction_api.should == :provides
|
31
|
+
p.has_format_restriction?.should be_true
|
32
|
+
p = Merb::ResourceController::ActionDescriptor.new(:index, provided_formats, :provides => [ :xml, :json ])
|
33
|
+
p.format_restriction_api.should == :provides
|
34
|
+
p.has_format_restriction?.should be_true
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should be able to infer the restricted formats" do
|
38
|
+
provided_formats = [ :html, :xml, :json, :yml ]
|
39
|
+
p = Merb::ResourceController::ActionDescriptor.new(:index, provided_formats)
|
40
|
+
p.restricted_formats.should be_empty
|
41
|
+
p = Merb::ResourceController::ActionDescriptor.new(:index, provided_formats, :provides => :xml)
|
42
|
+
p.restricted_formats.should == [ :xml ]
|
43
|
+
p = Merb::ResourceController::ActionDescriptor.new(:index, provided_formats, :provides => [ :xml, :json ])
|
44
|
+
p.restricted_formats.should == [ :xml, :json ]
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
it "should remember the action it is proxying" do
|
49
|
+
provided_formats = [ :html, :xml, :json, :yml ]
|
50
|
+
p = Merb::ResourceController::ActionDescriptor.new(:index, provided_formats)
|
51
|
+
p.action_name.should == :index
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should know about the module that defines the action" do
|
55
|
+
provided_formats = [ :html, :xml, :json, :yml ]
|
56
|
+
p = Merb::ResourceController::ActionDescriptor.new(:index, provided_formats)
|
57
|
+
p.action_module.should == Merb::ResourceController::Actions::Index
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should know about the module that defines the flash support" do
|
61
|
+
provided_formats = [ :html, :xml, :json, :yml ]
|
62
|
+
p = Merb::ResourceController::ActionDescriptor.new(:index, provided_formats)
|
63
|
+
p.supports_flash_messages?.should be_false
|
64
|
+
p.has_flash_module?.should be_false
|
65
|
+
p.flash_module.should == nil
|
66
|
+
p = Merb::ResourceController::ActionDescriptor.new(:show, provided_formats)
|
67
|
+
p.supports_flash_messages?.should be_false
|
68
|
+
p.has_flash_module?.should be_false
|
69
|
+
p.flash_module.should == nil
|
70
|
+
p = Merb::ResourceController::ActionDescriptor.new(:new, provided_formats)
|
71
|
+
p.supports_flash_messages?.should be_false
|
72
|
+
p.has_flash_module?.should be_false
|
73
|
+
p.flash_module.should == nil
|
74
|
+
|
75
|
+
p = Merb::ResourceController::ActionDescriptor.new(:edit, provided_formats)
|
76
|
+
p.supports_flash_messages?.should be_false
|
77
|
+
p.has_flash_module?.should be_false
|
78
|
+
p.flash_module.should == nil
|
79
|
+
|
80
|
+
p = Merb::ResourceController::ActionDescriptor.new(:create, provided_formats)
|
81
|
+
p.supports_flash_messages?.should be_false
|
82
|
+
p.has_flash_module?.should be_true
|
83
|
+
p.flash_module.should == Merb::ResourceController::Actions::Create::FlashSupport
|
84
|
+
|
85
|
+
p = Merb::ResourceController::ActionDescriptor.new(:update, provided_formats)
|
86
|
+
p.supports_flash_messages?.should be_false
|
87
|
+
p.has_flash_module?.should be_true
|
88
|
+
p.flash_module.should == Merb::ResourceController::Actions::Update::FlashSupport
|
89
|
+
|
90
|
+
p = Merb::ResourceController::ActionDescriptor.new(:destroy, provided_formats)
|
91
|
+
p.supports_flash_messages?.should be_false
|
92
|
+
p.has_flash_module?.should be_true
|
93
|
+
p.flash_module.should == Merb::ResourceController::Actions::Destroy::FlashSupport
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should be able to infer the content_type_handler_method" do
|
98
|
+
provided_formats = [ :html, :xml, :json, :yml ]
|
99
|
+
p = Merb::ResourceController::ActionDescriptor.new(:create, provided_formats)
|
100
|
+
# builtin formats
|
101
|
+
p.content_type_handler_method(:html, :success).should == "html_response_on_successful_create"
|
102
|
+
p.content_type_handler_method(:html, :failure).should == "html_response_on_failed_create"
|
103
|
+
p.content_type_handler_method(:xml, :success).should == "xml_response_on_successful_create"
|
104
|
+
p.content_type_handler_method(:xml, :failure).should == "xml_response_on_failed_create"
|
105
|
+
p.content_type_handler_method(:json, :success).should == "json_response_on_successful_create"
|
106
|
+
p.content_type_handler_method(:json, :failure).should == "json_response_on_failed_create"
|
107
|
+
p.content_type_handler_method(:yml, :success).should == "yml_response_on_successful_create"
|
108
|
+
p.content_type_handler_method(:yml, :failure).should == "yml_response_on_failed_create"
|
109
|
+
# custom formats
|
110
|
+
p.content_type_handler_method(:foo, :success).should == "foo_response_on_successful_create"
|
111
|
+
p.content_type_handler_method(:foo, :failure).should == "foo_response_on_failed_create"
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should be able to register content type handlers" do
|
115
|
+
provided_formats = [ :html, :xml, :json, :yml ]
|
116
|
+
|
117
|
+
p = Merb::ResourceController::ActionDescriptor.new(:create, provided_formats)
|
118
|
+
p.handle :json, :success
|
119
|
+
# p.content_type_handler(:json, :success).should == "json_response_on_successful_create"
|
120
|
+
# p.content_type_handler(:json, :failure).should be_nil
|
121
|
+
|
122
|
+
# p = Merb::ResourceController::ActionDescriptor.new(:create, provided_formats)
|
123
|
+
# p.handle [ :xml, :json ], :success
|
124
|
+
# p.content_type_handler(:xml, :succes).should == "xml_response_on_successful_create"
|
125
|
+
# p.content_type_handler(:xml, :failure).should be_nil
|
126
|
+
# p.content_type_handler(:json, :succes).should == "json_response_on_successful_create"
|
127
|
+
# p.content_type_handler(:json, :failure).should be_nil
|
128
|
+
#
|
129
|
+
# p = Merb::ResourceController::ActionDescriptor.new(:create, provided_formats)
|
130
|
+
# p.handle [ :xml, :json ]
|
131
|
+
# p.content_type_handler(:xml, :succes).should == "xml_response_on_successful_create"
|
132
|
+
# p.content_type_handler(:xml, :failure).should == "xml_response_on_failed_create"
|
133
|
+
# p.content_type_handler(:json, :succes).should == "json_response_on_successful_create"
|
134
|
+
# p.content_type_handler(:json, :failure).should == "json_response_on_failed_create"
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
@@ -31,7 +31,7 @@ describe "Merb::ResourceController::ResourceProxy" do
|
|
31
31
|
describe "with default options" do
|
32
32
|
|
33
33
|
before(:each) do
|
34
|
-
options = { :defaults => true, :
|
34
|
+
options = { :defaults => true, :use => :all }
|
35
35
|
@p = Merb::ResourceController::ResourceProxy.new(:articles, options)
|
36
36
|
end
|
37
37
|
|
@@ -53,7 +53,7 @@ describe "Merb::ResourceController::ResourceProxy" do
|
|
53
53
|
|
54
54
|
it "should have the default actions registered" do
|
55
55
|
default_actions = [ :index, :show, :new, :edit, :create, :update, :destroy ]
|
56
|
-
actions = @p.registered_actions.map { |
|
56
|
+
actions = @p.registered_actions.map { |ad| ad.action_name }
|
57
57
|
|
58
58
|
actions.size.should == default_actions.size
|
59
59
|
actions.all? { |a| default_actions.include?(a) }.should be_true
|
@@ -77,14 +77,14 @@ describe "Merb::ResourceController::ResourceProxy" do
|
|
77
77
|
describe "with invalid (parent) resource" do
|
78
78
|
|
79
79
|
it "should raise NameError when initialized with an invalid resource" do
|
80
|
-
options = { :defaults => true, :
|
80
|
+
options = { :defaults => true, :use => :all }
|
81
81
|
lambda {
|
82
82
|
Merb::ResourceController::ResourceProxy.new(:foo, options)
|
83
83
|
}.should raise_error(NameError)
|
84
84
|
end
|
85
85
|
|
86
86
|
it "should raise NameError when it should belong to an invalid parent resource" do
|
87
|
-
options = { :defaults => true, :
|
87
|
+
options = { :defaults => true, :use => :all }
|
88
88
|
lambda {
|
89
89
|
p = Merb::ResourceController::ResourceProxy.new("Community::Comment", options)
|
90
90
|
p.belongs_to :foo
|
@@ -97,7 +97,7 @@ describe "Merb::ResourceController::ResourceProxy" do
|
|
97
97
|
describe "with no parent resource" do
|
98
98
|
|
99
99
|
before(:each) do
|
100
|
-
options = { :defaults => true, :
|
100
|
+
options = { :defaults => true, :use => :all }
|
101
101
|
@p = Merb::ResourceController::ResourceProxy.new(:articles, options)
|
102
102
|
end
|
103
103
|
|
@@ -146,7 +146,7 @@ describe "Merb::ResourceController::ResourceProxy" do
|
|
146
146
|
describe "with a single parent resource" do
|
147
147
|
|
148
148
|
before(:each) do
|
149
|
-
options = { :defaults => true, :
|
149
|
+
options = { :defaults => true, :use => :all }
|
150
150
|
@p = Merb::ResourceController::ResourceProxy.new("Community::Comment", options)
|
151
151
|
@p.belongs_to :article
|
152
152
|
end
|
@@ -208,7 +208,7 @@ describe "Merb::ResourceController::ResourceProxy" do
|
|
208
208
|
describe "with multiple parent resources with default keys" do
|
209
209
|
|
210
210
|
before(:each) do
|
211
|
-
options = { :defaults => true, :
|
211
|
+
options = { :defaults => true, :use => :all }
|
212
212
|
@p = Merb::ResourceController::ResourceProxy.new("Community::Rating", options)
|
213
213
|
@p.belongs_to [ :article, "Community::Comment" ]
|
214
214
|
end
|