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.
@@ -10,15 +10,14 @@ module Merb
10
10
  module ClassMethods
11
11
 
12
12
  def controlling(name, options = {})
13
- options = { :flash => true }.merge!(options)
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
- include FlashSupport if options[:flash]
19
- @resource_proxy.registered_actions.each do |a|
20
- include Merb::ResourceController::Actions.const_get("#{a[:name].to_s.camel_case}")
21
- show_action(a[:name])
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
- path = resource_proxy.path_to_resource(params)
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 flash_supported?
120
- self.kind_of?(FlashSupport)
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
- @actions << { :name => name.to_sym }.merge(options)
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(*names)
33
- names.each { |n| @actions << n.is_a?(Hash) ? n : { :name => n.to_sym } }
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
 
@@ -1,3 +1,4 @@
1
1
  class Articles < Application
2
+ provides :xml, :json
2
3
  controlling :articles
3
4
  end
@@ -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,11 @@
1
+ <h2>New Rating</h2>
2
+
3
+ <%= form_for(@rating, :action => resource(@comment, :ratings)) do %>
4
+
5
+ <p><%= text_field :rate, :label => "Rating" %></p>
6
+
7
+ <p><%= submit "Create" %></p>
8
+
9
+ <% end =%>
10
+
11
+ <%= link_to 'Show Comment', resource(@comment) %>
@@ -11,7 +11,6 @@ dependency "dm-constraints", dm_gems_version
11
11
  dependency "merb-assets", merb_gems_version
12
12
  dependency "merb-helpers", merb_gems_version
13
13
 
14
-
15
14
  use_orm :datamapper
16
15
  use_test :rspec
17
16
  use_template_engine :erb
@@ -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, :flash => true, :use => :all }
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 { |h| h[:name] }
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, :flash => true, :use => :all }
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, :flash => true, :use => :all }
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, :flash => true, :use => :all }
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, :flash => true, :use => :all }
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, :flash => true, :use => :all }
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