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 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