genki-merb_component 0.1.2 → 0.2.0
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.
- data/README +37 -9
- data/Rakefile +1 -1
- data/lib/merb_component/controller_ext.rb +132 -24
- data/lib/merb_component/resource_ext.rb +6 -2
- data/lib/merb_component/router_ext.rb +8 -0
- data/lib/merb_component.rb +1 -2
- data/spec/admin_spec.rb +96 -0
- data/spec/fixture/app/controllers/admin.rb +2 -3
- data/spec/fixture/app/controllers/comments.rb +6 -16
- data/spec/fixture/app/controllers/posts.rb +1 -0
- data/spec/fixture/app/models/comment.rb +2 -0
- data/spec/fixture/app/views/admin/show.html.erb +4 -0
- data/spec/fixture/app/views/comments/edit.html.erb +11 -0
- data/spec/fixture/app/views/comments/index.html.erb +3 -1
- data/spec/fixture/app/views/comments/new.html.erb +3 -0
- data/spec/fixture/app/views/layout/application.html.erb +11 -0
- data/spec/fixture/app/views/posts/show.html.erb +3 -5
- data/spec/fixture/config/router.rb +5 -8
- data/spec/merb_component_spec.rb +16 -2
- data/spec/posts_spec.rb +62 -2
- data/spec/spec_helper.rb +2 -0
- metadata +9 -5
- data/lib/merb_component/helper_ext.rb +0 -4
- data/lib/merb_component/model_ext.rb +0 -26
data/README
CHANGED
@@ -5,14 +5,42 @@ Merb plugin that provides composition of controllers.
|
|
5
5
|
|
6
6
|
Example of use:
|
7
7
|
|
8
|
-
|
9
|
-
<%= component User, :show, :id => 2 %>
|
8
|
+
In config/router.rb:
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
resources :posts do |post|
|
11
|
+
post.aggregates :comments
|
12
|
+
end
|
13
|
+
resource :admin, :controller => :admin do |admin|
|
14
|
+
admin.aggregates :comments
|
15
|
+
end
|
15
16
|
|
16
|
-
In
|
17
|
-
|
18
|
-
|
17
|
+
In controllers:
|
18
|
+
|
19
|
+
class Posts < Application
|
20
|
+
aggregates :comments
|
21
|
+
|
22
|
+
class Admin < Application
|
23
|
+
aggregates :show => :comments
|
24
|
+
|
25
|
+
In views:
|
26
|
+
|
27
|
+
Content of the user (id is 2) goes here
|
28
|
+
<%= component Users, :show, :id => 2 %>
|
29
|
+
|
30
|
+
Or, you can use symbol to specify subsidiary controller
|
31
|
+
<%= component :users, :show, :id => 2 %>
|
32
|
+
|
33
|
+
Index of posts related with the @user go here
|
34
|
+
<% Post.related_with @user do %>
|
35
|
+
<%= component Posts, :index %>
|
36
|
+
<% end %>
|
37
|
+
|
38
|
+
In app/views/posts/index.html.erb,
|
39
|
+
You can access to the corresponding relation like this
|
40
|
+
<%= Post.relation #=> @user %>
|
41
|
+
|
42
|
+
For detail, you can see spec/fixture as an example.
|
43
|
+
|
44
|
+
Enjoy!
|
45
|
+
|
46
|
+
Genki Takiuchi
|
data/Rakefile
CHANGED
@@ -7,59 +7,167 @@ class Merb::Controller
|
|
7
7
|
|
8
8
|
class << self
|
9
9
|
private
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
def is_component(resource = nil)
|
11
|
+
resource = controller_name.singular if resource.nil?
|
12
|
+
r = resource.to_s
|
13
|
+
m = r.camel_case
|
14
|
+
iv = proc{|i| "(@#{r} = #{m}.#{i})"}
|
15
|
+
ivs = proc{|i| "(@#{r.pluralize} = #{m}.#{i})"}
|
16
|
+
class_eval <<-"RUBY"
|
17
|
+
def index; display #{ivs["all"]} end
|
18
|
+
def show(id) display #{iv["get(id)"]} end
|
19
|
+
def new; display #{iv["new"]} end
|
20
|
+
def edit(id) display #{iv["get(id)"]} end
|
21
|
+
def create(#{r}) #{iv["create(#{r})"]} end
|
22
|
+
def update(id,#{r}) #{iv["get(id)"]}.update_attributes(#{r}) end
|
23
|
+
def destroy(id) #{iv["get(id)"]}.destroy end
|
24
|
+
RUBY
|
25
|
+
end
|
26
|
+
|
27
|
+
def aggregates(aggregation, options = {})
|
28
|
+
if aggregation.is_a?(Symbol)
|
29
|
+
aggregation = {:show => aggregation}
|
30
|
+
end
|
31
|
+
aggregation.each do |agg_action, arg|
|
14
32
|
define_method(arg){} unless method_defined?(arg)
|
15
33
|
model = Object.full_const_get(arg.to_s.singular.camel_case)
|
16
34
|
key = "#{controller_name.singular}_id"
|
17
35
|
var = "@#{arg.to_s.singular}"
|
18
36
|
|
19
37
|
add_filter(_before_filters, proc{|c|
|
20
|
-
# setup request
|
21
38
|
id = params.delete(key)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
39
|
+
method = request.method
|
40
|
+
scope = Mash.new
|
41
|
+
scope[key] = id if id
|
42
|
+
object = nil
|
43
|
+
if action = METHOD_TO_ACTION[method]
|
44
|
+
# setup request
|
45
|
+
req = request.dup
|
46
|
+
req.reset_params!
|
47
|
+
req.instance_variable_set(:@params,
|
48
|
+
params.merge(:controller => arg, :action => action))
|
49
|
+
|
50
|
+
# call action of subsidiary controller with scope
|
51
|
+
cc = Object.full_const_get(params[:action].camel_case).new(req)
|
52
|
+
model.send :with_scope, scope do
|
53
|
+
begin
|
54
|
+
layout = cc.class.default_layout
|
55
|
+
cc.class.layout(options[:layout])
|
56
|
+
response = cc._abstract_dispatch(action)
|
57
|
+
ensure
|
58
|
+
cc.class.layout(layout)
|
59
|
+
end
|
60
|
+
object = cc.instance_variable_get(var)
|
61
|
+
c.instance_variable_set(var, object)
|
62
|
+
object = model.new if object.errors.empty?
|
63
|
+
end
|
64
|
+
elsif params[:id]
|
65
|
+
# GET with component id
|
66
|
+
object = model.get(params[:id])
|
67
|
+
c.instance_variable_set(var, object)
|
33
68
|
end
|
69
|
+
c.instance_variable_set("#{var}_component", object)
|
34
70
|
|
35
71
|
# prepare for performing actoin of principal controller
|
36
|
-
params[:id] = id
|
37
|
-
params[:action] = c.action_name =
|
72
|
+
c.params[:id] = id if id
|
73
|
+
c.params[:action] = c.action_name = agg_action.to_s
|
38
74
|
}, :only => arg)
|
39
75
|
end
|
40
76
|
end
|
41
77
|
end
|
42
78
|
|
79
|
+
class Aggregator
|
80
|
+
attr_reader :controller, :object, :result
|
81
|
+
|
82
|
+
def initialize(context, controller, &block)
|
83
|
+
@context = context
|
84
|
+
@controller = controller
|
85
|
+
@agg_name = @context.controller_name.singular.intern
|
86
|
+
model_class = Object.full_const_get(controller.name.singular)
|
87
|
+
@object = @context.instance_variable_get("@#{@agg_name}")
|
88
|
+
@scope = {}
|
89
|
+
|
90
|
+
if @object
|
91
|
+
relationship = model_class.relationships[@agg_name]
|
92
|
+
key_names = relationship.child_key.map{|i| i.name}
|
93
|
+
@scope = Hash[key_names.zip(@object.key)] if @object
|
94
|
+
end
|
95
|
+
|
96
|
+
@result = begin
|
97
|
+
Thread.critical = true
|
98
|
+
aggregators = Thread::current[:aggregators] ||= {}
|
99
|
+
(aggregators[controller] ||= []).push(self)
|
100
|
+
if model_class.respond_to?(:with_scope)
|
101
|
+
model_class.send(:with_scope, @scope, &block)
|
102
|
+
else
|
103
|
+
block.call
|
104
|
+
end
|
105
|
+
ensure
|
106
|
+
aggregators[controller].pop
|
107
|
+
Thread.critical = false
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def key
|
112
|
+
@object || @agg_name
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
43
116
|
def _abstract_dispatch(*args)
|
44
117
|
_dispatch = Merb::AbstractController.instance_method(:_dispatch)
|
45
118
|
_dispatch.bind(self).call(*args)
|
46
119
|
end
|
47
120
|
|
121
|
+
def aggregator
|
122
|
+
aggregators = Thread::current[:aggregators] ||= {}
|
123
|
+
(aggregators[self.class] ||= []).last
|
124
|
+
end
|
125
|
+
|
48
126
|
private
|
49
127
|
def component(controller, action, params = {})
|
128
|
+
var = "@#{controller.to_s.singular}"
|
129
|
+
object = instance_variable_get("#{var}_component")
|
130
|
+
controller = Object.full_const_get(controller.to_s.camel_case)
|
50
131
|
req = request.dup
|
51
132
|
req.reset_params!
|
52
133
|
req.instance_variable_set :@params, params
|
53
|
-
|
134
|
+
|
135
|
+
Aggregator.new(self, controller) do
|
136
|
+
controller.new(req)._dispatch(action).instance_eval do
|
137
|
+
if object
|
138
|
+
original = instance_variable_get(var)
|
139
|
+
object.attributes = original.attributes if original
|
140
|
+
instance_variable_set(var, object)
|
141
|
+
end
|
142
|
+
render :layout => false
|
143
|
+
end
|
144
|
+
end.result
|
145
|
+
end
|
146
|
+
|
147
|
+
def form_for_component(controller, params = {}, &block)
|
148
|
+
var = "@#{controller.to_s.singular}"
|
149
|
+
object = instance_variable_get(var)
|
150
|
+
return nil if object.nil?
|
151
|
+
object = instance_variable_get("#{var}_component") || object
|
152
|
+
if object.new_record?
|
153
|
+
component(controller, :new, params)
|
154
|
+
else
|
155
|
+
component(controller, :edit, {:id => object.id}.merge(params))
|
156
|
+
end
|
54
157
|
end
|
55
158
|
|
56
159
|
def resource(first, *args)
|
57
|
-
|
160
|
+
return super unless aggregator
|
161
|
+
|
162
|
+
controller = case first
|
58
163
|
when Symbol, String
|
59
|
-
Object.full_const_get(first.to_s.
|
60
|
-
else
|
164
|
+
Object.full_const_get(first.to_s.camel_case)
|
165
|
+
else
|
166
|
+
Object.full_const_get(first.class.to_s.pluralize.camel_case)
|
61
167
|
end
|
62
|
-
|
63
|
-
super
|
168
|
+
|
169
|
+
return super unless controller <=> aggregator.controller
|
170
|
+
return super unless key = aggregator.key
|
171
|
+
super(key, first, *args)
|
64
172
|
end
|
65
173
|
end
|
@@ -1,7 +1,11 @@
|
|
1
1
|
module DataMapper::Resource
|
2
2
|
module ClassMethods
|
3
|
-
|
4
|
-
|
3
|
+
# set scope
|
4
|
+
def new(attrs = {})
|
5
|
+
collection = all
|
6
|
+
collection.repository.scope do
|
7
|
+
super(collection.default_attributes.merge(attrs))
|
8
|
+
end
|
5
9
|
end
|
6
10
|
end
|
7
11
|
end
|
data/lib/merb_component.rb
CHANGED
@@ -9,9 +9,8 @@ if defined?(Merb::Plugins)
|
|
9
9
|
Merb::BootLoader.before_app_loads do
|
10
10
|
# require code that must be loaded before the application
|
11
11
|
require 'merb_component/controller_ext'
|
12
|
-
require 'merb_component/model_ext'
|
13
12
|
require 'merb_component/resource_ext'
|
14
|
-
require 'merb_component/
|
13
|
+
require 'merb_component/router_ext'
|
15
14
|
end
|
16
15
|
|
17
16
|
Merb::BootLoader.after_app_loads do
|
data/spec/admin_spec.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe Admin do
|
4
|
+
before do
|
5
|
+
@req = Merb::Request.new(
|
6
|
+
Merb::Const::REQUEST_PATH => "/admin",
|
7
|
+
Merb::Const::REQUEST_METHOD => "GET",
|
8
|
+
Merb::Const::QUERY_STRING => "")
|
9
|
+
@c = Admin.new(@req)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should be a controller" do
|
13
|
+
@c.should be_kind_of(Merb::Controller)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "Admin controller" do
|
18
|
+
before :all do
|
19
|
+
@post = Post.create
|
20
|
+
@comment = @post.comments.create(:body => "test")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should be tested on at least one post and comment" do
|
24
|
+
Post.count.should > 0
|
25
|
+
Comment.count.should > 0
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should index html" do
|
29
|
+
res = request(resource(:admin))
|
30
|
+
res.should be_successful
|
31
|
+
res.should have_xpath("//h1")
|
32
|
+
res.should have_xpath("//h2")
|
33
|
+
res.should have_xpath("//ul/li")
|
34
|
+
res.should_not have_xpath("//form")
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should show html after update a comment" do
|
38
|
+
comment = @post.comments.last
|
39
|
+
comment.should be_kind_of(Comment)
|
40
|
+
res = request(resource(:admin, comment),
|
41
|
+
:method => 'PUT', :params => {:comment => {:body => "bar"}})
|
42
|
+
res.should be_successful
|
43
|
+
res.should have_xpath("//h1")
|
44
|
+
res.should have_xpath("//h2")
|
45
|
+
res.should have_xpath("//ul/li[1]")
|
46
|
+
res.should have_xpath("//form[@action='/admin/comments']")
|
47
|
+
res.should have_xpath("//form[@method='post']")
|
48
|
+
res.should_not have_xpath("//input[@value='put']")
|
49
|
+
res.should contain("bar")
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should show html after failed to update a comment" do
|
53
|
+
comment = @post.comments.last
|
54
|
+
comment.should be_kind_of(Comment)
|
55
|
+
res = request(resource(:admin, comment),
|
56
|
+
:method => 'PUT', :params => {:comment => {:body => ""}})
|
57
|
+
res.should be_successful
|
58
|
+
res.should have_xpath("//h1")
|
59
|
+
res.should have_xpath("//h2")
|
60
|
+
res.should have_xpath("//ul/li[1]")
|
61
|
+
res.should have_xpath("//form[@action='/admin/comments/#{comment.id}']")
|
62
|
+
res.should have_xpath("//form[@method='post']")
|
63
|
+
res.should have_xpath("//input[@value='put']")
|
64
|
+
res.should have_tag("div.error")
|
65
|
+
res.should have_tag("input.error[@name='comment[body]']")
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should show html after delete a comment" do
|
69
|
+
count = @post.comments.count
|
70
|
+
comment = @post.comments.last
|
71
|
+
comment.should be_kind_of(Comment)
|
72
|
+
res = request(resource(:admin, comment), :method => 'DELETE')
|
73
|
+
res.should be_successful
|
74
|
+
res.should have_xpath("//h1")
|
75
|
+
res.should have_xpath("//h2")
|
76
|
+
res.should have_xpath("//form")
|
77
|
+
res.should have_xpath("//form[@action='/admin/comments']")
|
78
|
+
res.should have_xpath("//form[@method='post']")
|
79
|
+
res.should_not have_xpath("//input[@value='put']")
|
80
|
+
res.should_not have_xpath("//body/meta")
|
81
|
+
@post.comments.count.should == count - 1
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should show html after show a comment" do
|
85
|
+
comment = @post.comments.create(:body => "hello")
|
86
|
+
comment.should_not be_new_record
|
87
|
+
res = request(resource(:admin, comment), :method => 'GET')
|
88
|
+
res.should be_successful
|
89
|
+
res.should have_xpath("//h1")
|
90
|
+
res.should have_xpath("//h2")
|
91
|
+
res.should have_xpath("//form[@action='/admin/comments/#{comment.id}']")
|
92
|
+
res.should have_xpath("//form[@method='post']")
|
93
|
+
res.should have_xpath("//input[@value='put']")
|
94
|
+
res.should_not have_xpath("//body/meta")
|
95
|
+
end
|
96
|
+
end
|
@@ -1,25 +1,15 @@
|
|
1
1
|
class Comments < Application
|
2
|
-
|
3
|
-
@comments = Comment.all
|
4
|
-
display @comments
|
5
|
-
end
|
2
|
+
is_component :comment
|
6
3
|
|
7
4
|
def new
|
8
|
-
@comment = Comment.
|
5
|
+
@comment = Comment.new
|
6
|
+
@comment.body = "new"
|
9
7
|
display @comment
|
10
8
|
end
|
11
9
|
|
12
|
-
def
|
13
|
-
@comment = Comment.all.create(comment)
|
14
|
-
end
|
15
|
-
|
16
|
-
def update(id, comment)
|
10
|
+
def edit(id)
|
17
11
|
@comment = Comment.get(id)
|
18
|
-
@comment.
|
19
|
-
|
20
|
-
|
21
|
-
def destroy(id)
|
22
|
-
@comment = Comment.get(id)
|
23
|
-
@comment.destroy
|
12
|
+
@comment.body = "edit"
|
13
|
+
display @comment
|
24
14
|
end
|
25
15
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<h3>
|
2
|
+
Edit Comment of
|
3
|
+
<%= link_to h(@comment.post.id), resource(@comment.post) %>
|
4
|
+
</h3>
|
5
|
+
|
6
|
+
<%= error_messages_for @comment %>
|
7
|
+
|
8
|
+
<%= form_for @comment, :action => resource(@comment), :method => :put do %>
|
9
|
+
<%= text_field :body %>
|
10
|
+
<%= submit "Submit" %>
|
11
|
+
<% end =%>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
2
|
+
<html xmlns="http://www.w3.org/1999/xhtml"
|
3
|
+
xmlns:v="urn:schemas-microsoft-com:vml" xml:lang="en-us" lang="en-us">
|
4
|
+
<head>
|
5
|
+
<title>merb_component</title>
|
6
|
+
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<%= catch_content :for_layout %>
|
10
|
+
</body>
|
11
|
+
</html>
|
@@ -1,6 +1,4 @@
|
|
1
|
-
<h1><%= @post.id %></h1>
|
1
|
+
<h1><%= link_to @post.id.to_s, resource(@post) %></h1>
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
<%= component Comments, :new %>
|
6
|
-
<% end %>
|
3
|
+
<%= component Comments, :index %>
|
4
|
+
<%= form_for_component :comments %>
|
@@ -1,13 +1,10 @@
|
|
1
1
|
Merb::Router.prepare do
|
2
|
-
resources :
|
3
|
-
|
4
|
-
|
5
|
-
posts.resources :comments#, :controller => :posts
|
2
|
+
resources :comments
|
3
|
+
resources :posts do |post|
|
4
|
+
post.aggregates :comments
|
6
5
|
end
|
7
|
-
resource :admin do |admin|
|
8
|
-
admin.
|
9
|
-
admin.match("/:action/:id").to(:controller => :admin)
|
10
|
-
admin.resources :comments#, :controller => :admin
|
6
|
+
resource :admin, :controller => :admin do |admin|
|
7
|
+
admin.aggregates :comments
|
11
8
|
end
|
12
9
|
|
13
10
|
default_routes
|
data/spec/merb_component_spec.rb
CHANGED
@@ -3,9 +3,23 @@ require File.dirname(__FILE__) + '/spec_helper'
|
|
3
3
|
describe "merb_component" do
|
4
4
|
it "should extend controller" do
|
5
5
|
Posts.private_instance_methods.should be_include("component")
|
6
|
+
Posts.private_instance_methods.should be_include("form_for_component")
|
7
|
+
Posts.instance_methods.should be_include("aggregator")
|
6
8
|
end
|
7
9
|
|
8
|
-
it "should extend model" do
|
9
|
-
Post.public_methods.
|
10
|
+
it "should not extend model" do
|
11
|
+
Post.public_methods.should_not be_include("related_with")
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should accept controller class as the first param of compoent" do
|
15
|
+
req = Merb::Request.new({})
|
16
|
+
result = Posts.new(req).send(:component, Comments, :index)
|
17
|
+
result.should be_kind_of(String)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should accept symbol as the first param of compoent" do
|
21
|
+
req = Merb::Request.new({})
|
22
|
+
result = Posts.new(req).send(:component, :comments, :index)
|
23
|
+
result.should be_kind_of(String)
|
10
24
|
end
|
11
25
|
end
|
data/spec/posts_spec.rb
CHANGED
@@ -17,7 +17,7 @@ end
|
|
17
17
|
describe "Posts controller" do
|
18
18
|
before :all do
|
19
19
|
@post = Post.create
|
20
|
-
@comment = @post.comments.create
|
20
|
+
@comment = @post.comments.create(:body => "test")
|
21
21
|
end
|
22
22
|
|
23
23
|
it "should be tested on at least one post" do
|
@@ -33,6 +33,8 @@ describe "Posts controller" do
|
|
33
33
|
res.should have_xpath("//ul/li")
|
34
34
|
res.should have_xpath("//form[@method='post']")
|
35
35
|
res.should have_xpath("//form[@action='/posts/#{@post.id}/comments']")
|
36
|
+
res.should_not have_xpath("//input[@value='put']")
|
37
|
+
res.should have_xpath("//input[@value='new']")
|
36
38
|
end
|
37
39
|
|
38
40
|
it "should show html after post a comment" do
|
@@ -45,10 +47,29 @@ describe "Posts controller" do
|
|
45
47
|
res.should have_xpath("//ul/li[1]")
|
46
48
|
res.should have_xpath("//ul/li[2]")
|
47
49
|
res.should have_xpath("//form[@method='post']")
|
50
|
+
res.should have_xpath("//form[@action='/posts/#{@post.id}/comments']")
|
51
|
+
res.should_not have_xpath("//input[@value='put']")
|
48
52
|
res.should contain("foo")
|
49
53
|
Comment.all(:post_id => @post.id).count.should == count + 1
|
50
54
|
end
|
51
55
|
|
56
|
+
it "should show html after failed to post a comment" do
|
57
|
+
count = Comment.all(:post_id => @post.id).count
|
58
|
+
res = request(resource(@post, :comments),
|
59
|
+
:method => 'POST', :params => {:comment => {:body => ""}})
|
60
|
+
res.should be_successful
|
61
|
+
res.should have_xpath("//h1")
|
62
|
+
res.should have_xpath("//h2")
|
63
|
+
res.should have_xpath("//ul/li[1]")
|
64
|
+
res.should have_xpath("//ul/li[2]")
|
65
|
+
res.should have_xpath("//form[@method='post']")
|
66
|
+
res.should have_xpath("//form[@action='/posts/#{@post.id}/comments']")
|
67
|
+
res.should_not have_xpath("//input[@value='put']")
|
68
|
+
res.should have_tag("div.error")
|
69
|
+
res.should have_tag("input.error[@name='comment[body]']")
|
70
|
+
Comment.all(:post_id => @post.id).count.should == count
|
71
|
+
end
|
72
|
+
|
52
73
|
it "should show html after update a comment" do
|
53
74
|
comment = @post.comments.last
|
54
75
|
comment.should be_kind_of(Comment)
|
@@ -60,10 +81,30 @@ describe "Posts controller" do
|
|
60
81
|
res.should have_xpath("//ul/li[1]")
|
61
82
|
res.should have_xpath("//ul/li[2]")
|
62
83
|
res.should have_xpath("//form[@method='post']")
|
84
|
+
res.should have_xpath("//form[@action='/posts/#{@post.id}/comments']")
|
85
|
+
res.should_not have_xpath("//input[@value='put']")
|
63
86
|
res.should contain("bar")
|
64
87
|
end
|
65
88
|
|
66
|
-
it "should show html after update a comment" do
|
89
|
+
it "should show html after failed to update a comment" do
|
90
|
+
comment = @post.comments.last
|
91
|
+
comment.should be_kind_of(Comment)
|
92
|
+
res = request(resource(@post, comment),
|
93
|
+
:method => 'PUT', :params => {:comment => {:body => ""}})
|
94
|
+
res.should be_successful
|
95
|
+
res.should have_xpath("//h1")
|
96
|
+
res.should have_xpath("//h2")
|
97
|
+
res.should have_xpath("//ul/li[1]")
|
98
|
+
res.should have_xpath("//ul/li[2]")
|
99
|
+
res.should have_xpath("//form[@method='post']")
|
100
|
+
url = "/posts/#{@post.id}/comments/#{comment.id}"
|
101
|
+
res.should have_xpath("//form[@action='#{url}']")
|
102
|
+
res.should have_xpath("//input[@value='put']")
|
103
|
+
res.should have_tag("div.error")
|
104
|
+
res.should have_tag("input.error[@name='comment[body]']")
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should show html after delete a comment" do
|
67
108
|
count = @post.comments.count
|
68
109
|
comment = @post.comments.last
|
69
110
|
comment.should be_kind_of(Comment)
|
@@ -71,6 +112,25 @@ describe "Posts controller" do
|
|
71
112
|
res.should be_successful
|
72
113
|
res.should have_xpath("//h1")
|
73
114
|
res.should have_xpath("//h2")
|
115
|
+
res.should have_xpath("//form[@action='/posts/#{@post.id}/comments']")
|
116
|
+
res.should have_xpath("//form[@method='post']")
|
117
|
+
res.should_not have_xpath("//input[@value='put']")
|
74
118
|
@post.comments.count.should == count - 1
|
75
119
|
end
|
120
|
+
|
121
|
+
it "should show html after show a comment" do
|
122
|
+
comment = @post.comments.create(:body => "test")
|
123
|
+
comment.should_not be_new_record
|
124
|
+
res = request(resource(@post, comment), :method => 'GET')
|
125
|
+
res.should be_successful
|
126
|
+
res.should have_xpath("//h1")
|
127
|
+
res.should have_xpath("//h2")
|
128
|
+
url = "/posts/#{@post.id}/comments/#{comment.id}"
|
129
|
+
res.should have_xpath("//form[@action='#{url}']")
|
130
|
+
res.should have_xpath("//input[@value='put']")
|
131
|
+
res.should_not have_xpath("//body/meta")
|
132
|
+
res.should have_xpath("//input[@value='edit']")
|
133
|
+
|
134
|
+
pending "should check pagination"
|
135
|
+
end
|
76
136
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: genki-merb_component
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Genki Takiuchi
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-01-
|
12
|
+
date: 2009-01-26 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -38,11 +38,11 @@ files:
|
|
38
38
|
- TODO
|
39
39
|
- lib/merb_component
|
40
40
|
- lib/merb_component/controller_ext.rb
|
41
|
-
- lib/merb_component/helper_ext.rb
|
42
41
|
- lib/merb_component/merbtasks.rb
|
43
|
-
- lib/merb_component/model_ext.rb
|
44
42
|
- lib/merb_component/resource_ext.rb
|
43
|
+
- lib/merb_component/router_ext.rb
|
45
44
|
- lib/merb_component.rb
|
45
|
+
- spec/admin_spec.rb
|
46
46
|
- spec/fixture
|
47
47
|
- spec/fixture/app
|
48
48
|
- spec/fixture/app/controllers
|
@@ -54,15 +54,19 @@ files:
|
|
54
54
|
- spec/fixture/app/models/comment.rb
|
55
55
|
- spec/fixture/app/models/post.rb
|
56
56
|
- spec/fixture/app/views
|
57
|
+
- spec/fixture/app/views/admin
|
58
|
+
- spec/fixture/app/views/admin/show.html.erb
|
57
59
|
- spec/fixture/app/views/comments
|
60
|
+
- spec/fixture/app/views/comments/edit.html.erb
|
58
61
|
- spec/fixture/app/views/comments/index.html.erb
|
59
62
|
- spec/fixture/app/views/comments/new.html.erb
|
63
|
+
- spec/fixture/app/views/layout
|
64
|
+
- spec/fixture/app/views/layout/application.html.erb
|
60
65
|
- spec/fixture/app/views/posts
|
61
66
|
- spec/fixture/app/views/posts/index.html.erb
|
62
67
|
- spec/fixture/app/views/posts/show.html.erb
|
63
68
|
- spec/fixture/config
|
64
69
|
- spec/fixture/config/router.rb
|
65
|
-
- spec/fixture/tmp
|
66
70
|
- spec/merb_component_spec.rb
|
67
71
|
- spec/posts_spec.rb
|
68
72
|
- spec/spec_helper.rb
|
@@ -1,26 +0,0 @@
|
|
1
|
-
module DataMapper::Model
|
2
|
-
def related_with(model, &block)
|
3
|
-
model_class = model.class
|
4
|
-
storage_name = model_class.storage_name
|
5
|
-
assoc_name = storage_name.singular.intern
|
6
|
-
key_names = relationships[assoc_name].child_key.map{|i| i.name}
|
7
|
-
push_relation(model)
|
8
|
-
with_scope(Hash[key_names.zip(model.key)], &block)
|
9
|
-
ensure
|
10
|
-
pop_relation
|
11
|
-
end
|
12
|
-
|
13
|
-
def relation
|
14
|
-
(Thread::current[:relation] || []).last
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
def push_relation(relation)
|
19
|
-
Thread::current[:relation] ||= []
|
20
|
-
Thread::current[:relation].push relation
|
21
|
-
end
|
22
|
-
|
23
|
-
def pop_relation
|
24
|
-
Thread::current[:relation].pop
|
25
|
-
end
|
26
|
-
end
|