genki-merb_component 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -5,14 +5,42 @@ Merb plugin that provides composition of controllers.
5
5
 
6
6
  Example of use:
7
7
 
8
- Content of the user (id is 2) goes here
9
- <%= component User, :show, :id => 2 %>
8
+ In config/router.rb:
10
9
 
11
- Index of posts related with the @user go here
12
- <% Post.related_with @user do %>
13
- <%= component Post, :index %>
14
- <% end %>
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 app/views/posts/index.html.erb,
17
- You can access to the corresponding relation like this
18
- <%= Post.relation #=> @user %>
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
@@ -5,7 +5,7 @@ require 'merb-core'
5
5
  require 'merb-core/tasks/merb'
6
6
 
7
7
  GEM_NAME = "merb_component"
8
- GEM_VERSION = "0.1.2"
8
+ GEM_VERSION = "0.2.0"
9
9
  AUTHOR = "Genki Takiuchi"
10
10
  EMAIL = "genki@s21g.com"
11
11
  HOMEPAGE = "http://blog.s21g.com/genki"
@@ -7,59 +7,167 @@ class Merb::Controller
7
7
 
8
8
  class << self
9
9
  private
10
- def aggregates(*args)
11
- @aggregations ||= Mash.new
12
- options = extract_options_from_args!(args) || {}
13
- args.each do |arg|
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
- req = request.dup
23
- req.reset_params!
24
- req.instance_variable_set(:@params, params.merge(
25
- :controller => arg, :action => METHOD_TO_ACTION[req.method]))
26
-
27
- # call action of subsidiary controller with scope
28
- cc = Object.full_const_get(params[:action].camel_case).new(req)
29
- model.send :with_scope, key => id do
30
- cc._abstract_dispatch(req.params[:action])
31
- result = cc.instance_variable_get(var)
32
- c.instance_variable_set(var, result)
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 = :show
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
- controller.new(req)._abstract_dispatch(action)
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
- model = case first
160
+ return super unless aggregator
161
+
162
+ controller = case first
58
163
  when Symbol, String
59
- Object.full_const_get(first.to_s.singular.camel_case)
60
- else first.class
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
- return super unless model.relation
63
- super(model.relation, first, *args)
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
- def build(attrs = {})
4
- all.build(attrs)
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
@@ -0,0 +1,8 @@
1
+ Merb::Router.extensions do
2
+ def aggregates(resource, options = {})
3
+ options[:controller] ||= @params[:controller]
4
+ match("/:action/:id").to(options)
5
+ match("/:action").to(options)
6
+ resources resource
7
+ end
8
+ end
@@ -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/helper_ext'
13
+ require 'merb_component/router_ext'
15
14
  end
16
15
 
17
16
  Merb::BootLoader.after_app_loads do
@@ -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,8 +1,7 @@
1
1
  class Admin < Application
2
- aggregates :comments
2
+ aggregates :show => :comments
3
3
 
4
- def index
5
- @comments = Comment.all
4
+ def show
6
5
  render
7
6
  end
8
7
  end
@@ -1,25 +1,15 @@
1
1
  class Comments < Application
2
- def index
3
- @comments = Comment.all
4
- display @comments
5
- end
2
+ is_component :comment
6
3
 
7
4
  def new
8
- @comment = Comment.build
5
+ @comment = Comment.new
6
+ @comment.body = "new"
9
7
  display @comment
10
8
  end
11
9
 
12
- def create(comment)
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.update_attributes(comment)
19
- end
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
@@ -8,6 +8,7 @@ class Posts < Application
8
8
 
9
9
  def show(id)
10
10
  @post = Post.get(id)
11
+ @comment = @post.comments.build
11
12
  display @post
12
13
  end
13
14
  end
@@ -5,4 +5,6 @@ class Comment
5
5
  property :body, Text
6
6
 
7
7
  belongs_to :post
8
+
9
+ validates_present :body
8
10
  end
@@ -0,0 +1,4 @@
1
+ <h1>Admin</h1>
2
+
3
+ <%= component :comments, :index %>
4
+ <%= form_for_component :comments %>
@@ -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 =%>
@@ -2,6 +2,8 @@
2
2
 
3
3
  <ul>
4
4
  <% @comments.each do |comment| %>
5
- <li><%= comment.body %></li>
5
+ <li>
6
+ <%= link_to h(comment.body), resource(comment) %>
7
+ </li>
6
8
  <% end %>
7
9
  </ul>
@@ -1,3 +1,6 @@
1
+ <%= error_messages_for @comment %>
2
+
1
3
  <%= form_for @comment, :action => resource(:comments) do %>
4
+ <%= text_field :body %>
2
5
  <%= submit "submit" %>
3
6
  <% 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
- <% Comment.related_with(@post) do %>
4
- <%= component Comments, :index %>
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 :posts do |posts|
3
- posts.match("/:action").to(:controller => :posts)
4
- posts.match("/:action/:id").to(:controller => :posts)
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.match("/:action").to(:controller => :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
@@ -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.should be_include("related_with")
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
@@ -10,6 +10,8 @@ dependency "dm-core"
10
10
  dependency "dm-aggregates"
11
11
  dependency "merb-action-args"
12
12
  dependency "merb-helpers"
13
+ dependency "merb-assets"
14
+ dependency "dm-validations"
13
15
 
14
16
  use_orm :datamapper
15
17
  use_test :rspec
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.1.2
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-25 00:00:00 -08:00
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,4 +0,0 @@
1
- module Merb
2
- module GlobalHelpers
3
- end
4
- end
@@ -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