cells 3.3.10 → 3.4.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +0 -8
- data/Gemfile +4 -1
- data/README.rdoc +91 -107
- data/Rakefile +0 -4
- data/lib/cell.rb +5 -6
- data/lib/{cells/cell → cell}/active_helper.rb +1 -1
- data/lib/cell/base.rb +134 -0
- data/lib/cell/base_methods.rb +100 -0
- data/lib/cell/caching.rb +153 -0
- data/lib/cell/rails.rb +239 -0
- data/lib/cells.rb +25 -3
- data/lib/cells/assertions_helper.rb +1 -1
- data/lib/cells/helpers/capture_helper.rb +3 -3
- data/lib/cells/rails.rb +65 -4
- data/lib/cells/version.rb +3 -1
- data/rails_generators/cell/cell_generator.rb +47 -35
- data/rails_generators/cell/templates/cell.rb +1 -1
- data/rails_generators/cells_install/cells_install_generator.rb +5 -3
- data/rails_generators/erb/cell_generator.rb +20 -0
- data/rails_generators/{cell → erb}/templates/view.html.erb +0 -0
- data/test/active_helper_test.rb +1 -0
- data/test/app/cells/bad_guitarist_cell.rb +2 -0
- data/test/app/cells/bassist_cell.rb +1 -1
- data/test/app/controllers/musician_controller.rb +16 -0
- data/test/assertions_helper_test.rb +8 -18
- data/test/base_methods_test.rb +40 -0
- data/test/cell_generator_test.rb +33 -21
- data/test/helper_test.rb +31 -123
- data/test/rails/caching_test.rb +215 -0
- data/test/rails/capture_test.rb +52 -0
- data/test/rails/cells_test.rb +88 -0
- data/test/rails/integration_test.rb +37 -0
- data/test/rails/render_test.rb +140 -0
- data/test/rails/router_test.rb +74 -0
- data/test/rails/view_test.rb +24 -0
- data/test/test_helper.rb +30 -29
- metadata +68 -133
- data/.gitignore +0 -3
- data/about.yml +0 -7
- data/cells.gemspec +0 -26
- data/lib/cells/cell.rb +0 -16
- data/lib/cells/cell/base.rb +0 -470
- data/lib/cells/cell/caching.rb +0 -163
- data/lib/cells/cell/test_case.rb +0 -158
- data/lib/cells/cell/view.rb +0 -55
- data/lib/cells/rails/action_controller.rb +0 -37
- data/lib/cells/rails/action_view.rb +0 -37
- data/rails/init.rb +0 -44
- data/rails_generators/cells_install/templates/tasks.rake +0 -6
- data/test/app/cells/a/another_state.html.erb +0 -1
- data/test/app/cells/a/existing_view.html.erb +0 -1
- data/test/app/cells/a/inherited_view.html.erb +0 -1
- data/test/app/cells/a/inherited_view.js.erb +0 -1
- data/test/app/cells/a/view_with_locals.html.erb +0 -1
- data/test/app/cells/a/view_with_render_call.html.erb +0 -1
- data/test/app/cells/b/existing_view.html.erb +0 -1
- data/test/app/cells/b/existing_view.js.erb +0 -1
- data/test/app/cells/b/layouts/metal.html.erb +0 -1
- data/test/app/cells/b/view_with_render_call.html.erb +0 -1
- data/test/app/cells/bassist/jam.html.erb +0 -3
- data/test/app/cells/bassist/play.html.erb +0 -1
- data/test/app/cells/cells_test_one/renamed_instance_view.html.erb +0 -1
- data/test/app/cells/cells_test_one/super_state.html.erb +0 -1
- data/test/app/cells/cells_test_one_cell.rb +0 -20
- data/test/app/cells/cells_test_two_cell.rb +0 -4
- data/test/app/cells/helper_using/state_using_application_helper.html.erb +0 -3
- data/test/app/cells/helper_using/state_with_automatic_helper_invocation.html.erb +0 -3
- data/test/app/cells/helper_using/state_with_helper_invocation.html.erb +0 -3
- data/test/app/cells/helper_using/state_with_helper_method_invocation.html.erb +0 -3
- data/test/app/cells/layouts/metal.html.erb +0 -1
- data/test/app/cells/my_child/hello.html.erb +0 -1
- data/test/app/cells/my_mother/bye.html.erb +0 -1
- data/test/app/cells/my_mother/hello.html.erb +0 -1
- data/test/app/cells/my_test/_broken_partial.html.erb +0 -1
- data/test/app/cells/my_test/_partial.html.erb +0 -1
- data/test/app/cells/my_test/state_with_instance_var.html.erb +0 -1
- data/test/app/cells/my_test/state_with_link_to.html.erb +0 -3
- data/test/app/cells/my_test/state_with_not_included_helper_method.html.erb +0 -8
- data/test/app/cells/my_test/view_containing_broken_partial.html.erb +0 -3
- data/test/app/cells/my_test/view_containing_nonexistant_partial.html.erb +0 -3
- data/test/app/cells/my_test/view_containing_partial.html.erb +0 -3
- data/test/app/cells/my_test/view_containing_partial_without_cell_name.html.erb +0 -3
- data/test/app/cells/my_test/view_in_local_test_views_dir.html.erb +0 -1
- data/test/app/cells/my_test/view_with_explicit_english_translation.en.html.erb +0 -1
- data/test/app/cells/my_test/view_with_explicit_english_translation.html.erb +0 -1
- data/test/app/cells/my_test/view_with_instance_var.html.erb +0 -4
- data/test/app/cells/really_module/nested/happy_state.html.erb +0 -1
- data/test/app/cells/really_module/nested_cell.rb +0 -11
- data/test/app/cells/simple/two_templates_state.html.mytpl +0 -1
- data/test/app/cells/simple_cell.rb +0 -7
- data/test/app/cells/test/beep.html.erb +0 -1
- data/test/app/cells/test/state_invoking_capture.html.erb +0 -7
- data/test/app/cells/test/state_invoking_content_for.html.erb +0 -7
- data/test/app/cells/test/state_invoking_content_for_twice.html.erb +0 -9
- data/test/app/cells/test/state_with_not_included_helper_method.html.erb +0 -8
- data/test/app/cells/two_helpers_including/state_using_another_helper.html.erb +0 -3
- data/test/bugs_test.rb +0 -23
- data/test/caching_test.rb +0 -270
- data/test/capture_helper_test.rb +0 -59
- data/test/cells_test.rb +0 -352
- data/test/rails_test.rb +0 -35
- data/test/render_test.rb +0 -305
- data/test/test_case_test.rb +0 -106
data/CHANGES
CHANGED
@@ -1,11 +1,3 @@
|
|
1
|
-
- 3.3.10
|
2
|
-
* TestCase#render_cell now processes options properly.
|
3
|
-
* added TestCase#assigns.
|
4
|
-
|
5
|
-
- 3.3.9
|
6
|
-
* fixed loading test_case.rb
|
7
|
-
* added TestCase#view_assigns
|
8
|
-
|
9
1
|
- 2.3
|
10
2
|
* ::Cell::Base#new(controller, opts={})
|
11
3
|
We got rid of the second argument cell_name, since it was completely useless.
|
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -1,150 +1,134 @@
|
|
1
|
-
=
|
1
|
+
= Cells
|
2
2
|
|
3
|
-
|
4
|
-
However, their big advantage to controllers is their <em>modularity</em>: you can have
|
5
|
-
as many cells on a page as you want. That's as if you had multiple controllers in one
|
6
|
-
page, where each "controller" renders only a certain part of the page.
|
7
|
-
As if this wasn't enough, cells are superfast and lightweight.
|
3
|
+
<em>View Components for Rails.</em>
|
8
4
|
|
9
|
-
|
10
|
-
Michael.
|
5
|
+
== Overview
|
11
6
|
|
12
|
-
|
7
|
+
Say you're writing a Rails online shop - the shopping cart is reappearing again and again in every view. You're thinking about a clean solution for that part. A mixture of controller code, before-filters, partials and helpers?
|
13
8
|
|
14
|
-
|
15
|
-
|
16
|
-
script/generate cell Article newest top_article
|
9
|
+
No. That sucks. Take Cells.
|
17
10
|
|
11
|
+
Cells are View Components for Rails. They look and feel like controllers. They don't have no +DoubleRenderError+. They are callable everywhere in your controllers or views. They are cacheable, testable, fast and wonderful. They bring back OOP to your view and improve your software design.
|
18
12
|
|
19
|
-
|
20
|
-
this, after some editing:
|
13
|
+
== Installation
|
21
14
|
|
22
|
-
|
23
|
-
helper :my_formatting_and_escaping_helper # you can use helpers in cell views!
|
24
|
-
|
25
|
-
def newest
|
26
|
-
@articles = Article.get_newest
|
27
|
-
render # will render the view named newest.html.[erb|haml|...]".
|
28
|
-
end
|
29
|
-
|
30
|
-
def top_article
|
31
|
-
@article = Article.top_article
|
32
|
-
render :view => :top_article_v2, # renders top_article_v2.html.[erb|haml|...]
|
33
|
-
:layout => :box # and put it in the layout "box.html".
|
34
|
-
end
|
35
|
-
end
|
15
|
+
It's a gem!
|
36
16
|
|
37
|
-
|
17
|
+
Rails 3:
|
38
18
|
|
39
|
-
|
40
|
-
<ul>
|
41
|
-
<% @articles.each do |article| %>
|
42
|
-
<li><%= article.title %></li>
|
43
|
-
<% end %>
|
44
|
-
</ul>
|
19
|
+
gem install cells
|
45
20
|
|
46
|
-
|
21
|
+
Rails 2.3:
|
47
22
|
|
48
|
-
|
49
|
-
= @article.title
|
50
|
-
= format_and_escape(@article.text)
|
23
|
+
gem install cells --version 3.3.4
|
51
24
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
25
|
+
|
26
|
+
== Generate
|
27
|
+
|
28
|
+
Creating a cell is nothing more than
|
29
|
+
|
30
|
+
$ rails generate cell ShoppingCart display
|
31
|
+
create app/cells/
|
32
|
+
create app/cells/shopping_cart
|
33
|
+
create app/cells/shopping_cart_cell.rb
|
34
|
+
create app/cells/shopping_cart/display.html.erb
|
35
|
+
create test/cells/shopping_cart_test.rb
|
36
|
+
|
37
|
+
That looks very familiar.
|
38
|
+
|
39
|
+
== Render the cell
|
40
|
+
|
41
|
+
Now, render your cart. Why not put it in <tt>layouts/application.html.erb</tt> for now?
|
42
|
+
|
43
|
+
<div id="header">
|
44
|
+
<%= render_cell :shopping_cart, :display, :user => @current_user %>
|
45
|
+
|
46
|
+
Feels like rendering a controller action. As additional encapsulation we pass the current +user+ from outside. Call it knowledge hiding.
|
47
|
+
|
48
|
+
== Code
|
49
|
+
|
50
|
+
Time to improve our cell code. Let's start with <tt>app/cells/shopping_cart_cell.rb</tt>:
|
51
|
+
|
52
|
+
class ShoppingCartCell < Cell::Rails
|
53
|
+
def display
|
54
|
+
@items = @opts[:user].items_in_cart
|
55
|
+
|
56
|
+
render # renders display.html.erb
|
59
57
|
end
|
60
58
|
end
|
61
59
|
|
62
|
-
|
63
|
-
|
64
|
-
<%= yield %>
|
65
|
-
|
66
|
-
<div><%= render_cell(:article, :newest) %></div>
|
67
|
-
<div><%= render_cell(:article, :top_article) %></div>
|
68
|
-
|
69
|
-
The "top page" would consist of the controller action's content, and two additional
|
70
|
-
independent boxes with interesting content. These two boxes are <em>cells</em> and could
|
71
|
-
be used on another page, too.
|
60
|
+
Is that a controller? Hell, yeah. We even got a +render+ method as we know it from the good ol' +ActionController+.
|
72
61
|
|
73
|
-
= Caching
|
74
62
|
|
75
|
-
|
76
|
-
If this it configured (e.g. using our fast friend memcached) all you have to do is to
|
77
|
-
tell Cells which state you want to cache. You can further attach a proc for deciding
|
78
|
-
versions or to instruct re-rendering.
|
63
|
+
== Views
|
79
64
|
|
80
|
-
|
65
|
+
Since a plain call to +render+ will start rendering <tt>app/cells/shopping_cart/display.html.erb</tt> we should put some meaningful markup there.
|
81
66
|
|
82
|
-
|
83
|
-
|
67
|
+
<div id="cart">
|
68
|
+
You have <%= @items.size %> items in your shopping cart.
|
69
|
+
</div>
|
70
|
+
|
71
|
+
=== Haml? Builder?
|
84
72
|
|
85
|
-
|
73
|
+
Yes, Cells support all template types that are supported by Rails itself. Remember- it's a controller!
|
86
74
|
|
87
|
-
|
75
|
+
=== Helpers
|
88
76
|
|
89
|
-
|
77
|
+
Yes, Cells have helpers just like controllers. If you need some specific helper, do
|
90
78
|
|
91
|
-
|
79
|
+
class ShoppingCartCell < Cell::Rails
|
80
|
+
helper MyExtraHelper
|
92
81
|
|
93
|
-
|
94
|
-
|
95
|
-
from the i18n helper can also be used in cell views.
|
82
|
+
and it will be around in your cart views.
|
96
83
|
|
97
|
-
=== Haml
|
98
84
|
|
99
|
-
|
100
|
-
of your choice (.erb, .haml, ...) to write your cell views.
|
85
|
+
== Caching
|
101
86
|
|
102
|
-
|
87
|
+
Cells do strict view caching. No cluttered fragment caching. Add
|
103
88
|
|
104
|
-
|
105
|
-
|
106
|
-
and can be used everywhere in your application.
|
89
|
+
class ShoppingCartCell < Cell::Rails
|
90
|
+
cache :display, :expires_in => 10.minutes
|
107
91
|
|
108
|
-
|
92
|
+
and your cart will be re-rendered after 10 minutes.
|
109
93
|
|
110
|
-
|
94
|
+
There are multiple advanced options for expiring your view caches, including an expiration lambda.
|
95
|
+
|
96
|
+
class ShoppingCartCell < Cell::Rails
|
97
|
+
cache :display do |cell|
|
98
|
+
Item.still_valid?
|
99
|
+
end
|
111
100
|
|
112
|
-
script/plugin install git://github.com/apotonick/cells.git
|
113
|
-
|
114
|
-
This release is tested and runs with Rails 2.3.
|
115
101
|
|
102
|
+
== Testing
|
116
103
|
|
117
|
-
|
104
|
+
Another big advantage compared to monolithic controller/helper/partial piles is the ability to test your cells isolated.
|
118
105
|
|
119
|
-
|
106
|
+
So what if you wanna test the cart cell? Use the generated <tt>test/cells/shopping_cart_test.rb</tt> test.
|
120
107
|
|
121
|
-
|
122
|
-
|
123
|
-
|
108
|
+
class ShoppingCartTest < ActionController::TestCase
|
109
|
+
include Cells::AssertionsHelper
|
110
|
+
|
111
|
+
test "display" do
|
112
|
+
html = render_cell(:shopping_cart, :diplay, :user => @user_fixture)
|
113
|
+
assert_selekt html, "#cart", "You have 3 items in your shopping cart."
|
124
114
|
|
125
|
-
|
115
|
+
That's easy, clean and strongly improves your component-driven software quality. How'd you do that with partials?
|
126
116
|
|
127
|
-
Copyright (c) 2007-2009, Nick Sutterer
|
128
117
|
|
129
|
-
|
118
|
+
== More features
|
130
119
|
|
131
|
-
|
120
|
+
Cells can do more.
|
121
|
+
|
122
|
+
<b>View Inheritance</b>:: Inherit view files dynamically from parent cells.
|
123
|
+
<b>Cell Nesting</b>:: Have complex cell hierarchies as you can call +render_cell+ within cells, too.
|
124
|
+
|
125
|
+
Go for it, you'll love it!
|
132
126
|
|
133
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
134
|
-
of this software and associated documentation files (the "Software"), to deal
|
135
|
-
in the Software without restriction, including without limitation the rights
|
136
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
137
|
-
copies of the Software, and to permit persons to whom the Software is
|
138
|
-
furnished to do so, subject to the following conditions:
|
139
127
|
|
140
|
-
|
141
|
-
all copies or substantial portions of the Software.
|
128
|
+
== LICENSE
|
142
129
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
147
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
148
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
149
|
-
THE SOFTWARE.
|
130
|
+
Copyright (c) 2007-2010, Nick Sutterer
|
131
|
+
|
132
|
+
Copyright (c) 2007-2008, Solide ICT by Peter Bex and Bob Leers
|
150
133
|
|
134
|
+
Released under the MIT License.
|
data/Rakefile
CHANGED
data/lib/cell.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
|
1
|
+
# encoding: utf-8
|
2
2
|
|
3
|
-
# Make cell class interface leaner, i.e. ::Cell::Base < ::Cells::Cell::Base, etc.
|
4
|
-
# Note: Reason for doing like so is to make load path-resolving complexity to a minimum.
|
5
|
-
#
|
6
3
|
module Cell
|
7
|
-
Base
|
8
|
-
View
|
4
|
+
#autoload :Base, 'cell/base'
|
5
|
+
autoload :View, 'cell/view'
|
6
|
+
autoload :Caching, 'cell/caching'
|
7
|
+
autoload :ActiveHelper, 'cell/active_helper'
|
9
8
|
end
|
data/lib/cell/base.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
# == Basic overview
|
2
|
+
#
|
3
|
+
# A Cell is the central notion of the cells plugin. A cell acts as a
|
4
|
+
# lightweight controller in the sense that it will assign variables and
|
5
|
+
# render a view. Cells can be rendered from other cells as well as from
|
6
|
+
# regular controllers and views (see ActionView::Base#render_cell and
|
7
|
+
# ControllerMethods#render_cell)
|
8
|
+
#
|
9
|
+
# == A render_cell() cycle
|
10
|
+
#
|
11
|
+
# A typical <tt>render_cell</tt> state rendering cycle looks like this:
|
12
|
+
# render_cell :blog, :newest_article, {...}
|
13
|
+
# - an instance of the class <tt>BlogCell</tt> is created, and a hash containing
|
14
|
+
# arbitrary parameters is passed
|
15
|
+
# - the <em>state method</em> <tt>newest_article</tt> is executed and assigns instance
|
16
|
+
# variables to be used in the view
|
17
|
+
# - Usually the state method will call #render and return
|
18
|
+
# - #render will retrieve the corresponding view
|
19
|
+
# (e.g. <tt>app/cells/blog/newest_article.html. [erb|haml|...]</tt>),
|
20
|
+
# renders this template and returns the markup.
|
21
|
+
#
|
22
|
+
# == Design Principles
|
23
|
+
# A cell is a completely autonomous object and it should not know or have to know
|
24
|
+
# from what controller it is being rendered. For this reason, the controller's
|
25
|
+
# instance variables and params hash are not directly available from the cell or
|
26
|
+
# its views. This is not a bug, this is a feature! It means cells are truly
|
27
|
+
# reusable components which can be plugged in at any point in your application
|
28
|
+
# without having to think about what information is available at that point.
|
29
|
+
# When rendering a cell, you can explicitly pass variables to the cell in the
|
30
|
+
# extra opts argument hash, just like you would pass locals in partials.
|
31
|
+
# This hash is then available inside the cell as the @opts instance variable.
|
32
|
+
#
|
33
|
+
# == Directory hierarchy
|
34
|
+
#
|
35
|
+
# To get started creating your own cells, you can simply create a new directory
|
36
|
+
# structure under your <tt>app</tt> directory called <tt>cells</tt>. Cells are
|
37
|
+
# ruby classes which end in the name Cell. So for example, if you have a
|
38
|
+
# cell which manages all user information, it would be called <tt>UserCell</tt>.
|
39
|
+
# A cell which manages a shopping cart could be called <tt>ShoppingCartCell</tt>.
|
40
|
+
#
|
41
|
+
# The directory structure of this example would look like this:
|
42
|
+
# app/
|
43
|
+
# models/
|
44
|
+
# ..
|
45
|
+
# views/
|
46
|
+
# ..
|
47
|
+
# helpers/
|
48
|
+
# application_helper.rb
|
49
|
+
# product_helper.rb
|
50
|
+
# ..
|
51
|
+
# controllers/
|
52
|
+
# ..
|
53
|
+
# cells/
|
54
|
+
# shopping_cart_cell.rb
|
55
|
+
# shopping_cart/
|
56
|
+
# status.html.erb
|
57
|
+
# product_list.html.erb
|
58
|
+
# empty_prompt.html.erb
|
59
|
+
# user_cell.rb
|
60
|
+
# user/
|
61
|
+
# login.html.erb
|
62
|
+
# layouts/
|
63
|
+
# box.html.erb
|
64
|
+
# ..
|
65
|
+
#
|
66
|
+
# The directory with the same name as the cell contains views for the
|
67
|
+
# cell's <em>states</em>. A state is an executed method along with a
|
68
|
+
# rendered view, resulting in content. This means that states are to
|
69
|
+
# cells as actions are to controllers, so each state has its own view.
|
70
|
+
# The use of partials is deprecated with cells, it is better to just
|
71
|
+
# render a different state on the same cell (which also works recursively).
|
72
|
+
#
|
73
|
+
# Anyway, <tt>render :partial </tt> in a cell view will work, if the
|
74
|
+
# partial is contained in the cell's view directory.
|
75
|
+
#
|
76
|
+
# As can be seen above, Cells also can make use of helpers. All Cells
|
77
|
+
# include ApplicationHelper by default, but you can add additional helpers
|
78
|
+
# as well with the ::Cell::Base.helper class method:
|
79
|
+
# class ShoppingCartCell < ::Cell::Base
|
80
|
+
# helper :product
|
81
|
+
# ...
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# This will make the <tt>ProductHelper</tt> from <tt>app/helpers/product_helper.rb</tt>
|
85
|
+
# available from all state views from our <tt>ShoppingCartCell</tt>.
|
86
|
+
#
|
87
|
+
# == Cell inheritance
|
88
|
+
#
|
89
|
+
# Unlike controllers, Cells can form a class hierarchy. When a cell class
|
90
|
+
# is inherited by another cell class, its states are inherited as regular
|
91
|
+
# methods are, but also its views are inherited. Whenever a view is looked up,
|
92
|
+
# the view finder first looks for a file in the directory belonging to the
|
93
|
+
# current cell class, but if this is not found in the application or any
|
94
|
+
# engine, the superclass' directory is checked. This continues all the
|
95
|
+
# way up until it stops at ::Cell::Base.
|
96
|
+
#
|
97
|
+
# For instance, when you have two cells:
|
98
|
+
# class MenuCell < ::Cell::Base
|
99
|
+
# def show
|
100
|
+
# end
|
101
|
+
#
|
102
|
+
# def edit
|
103
|
+
# end
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
# class MainMenuCell < MenuCell
|
107
|
+
# .. # no need to redefine show/edit if they do the same!
|
108
|
+
# end
|
109
|
+
# and the following directory structure in <tt>app/cells</tt>:
|
110
|
+
# app/cells/
|
111
|
+
# menu/
|
112
|
+
# show.html.erb
|
113
|
+
# edit.html.erb
|
114
|
+
# main_menu/
|
115
|
+
# show.html.erb
|
116
|
+
# then when you call
|
117
|
+
# render_cell :main_menu, :show
|
118
|
+
# the main menu specific show.html.erb (<tt>app/cells/main_menu/show.html.erb</tt>)
|
119
|
+
# is rendered, but when you call
|
120
|
+
# render_cell :main_menu, :edit
|
121
|
+
# cells notices that the main menu does not have a specific view for the
|
122
|
+
# <tt>edit</tt> state, so it will render the view for the parent class,
|
123
|
+
# <tt>app/cells/menu/edit.html.erb</tt>
|
124
|
+
#
|
125
|
+
#
|
126
|
+
# == Gettext support
|
127
|
+
#
|
128
|
+
# Cells support gettext, just name your views accordingly. It works exactly equivalent
|
129
|
+
# to controller views.
|
130
|
+
#
|
131
|
+
# cells/user/user_form.html.erb
|
132
|
+
# cells/user/user_form_de.html.erb
|
133
|
+
#
|
134
|
+
# If gettext is set to DE_de, the latter view will be chosen.
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Cell
|
2
|
+
module BaseMethods
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
|
6
|
+
### DISCUSS: move that to Rails?
|
7
|
+
base.class_attribute :default_template_format
|
8
|
+
base.default_template_format = :html
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def render_cell_for(controller, name, state, opts={})
|
13
|
+
create_cell_for(controller, name, opts).render_state(state) # FIXME: don't let BaseMethods know about controller's API.
|
14
|
+
end
|
15
|
+
|
16
|
+
# Creates a cell instance of the class <tt>name</tt>Cell, passing through
|
17
|
+
# <tt>opts</tt>.
|
18
|
+
def create_cell_for(controller, name, opts={})
|
19
|
+
#class_from_cell_name(name).new(controller, opts)
|
20
|
+
class_from_cell_name(name).new(controller, opts)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Return the default view for the given state on this cell subclass.
|
24
|
+
# This is a file with the name of the state under a directory with the
|
25
|
+
# name of the cell followed by a template extension.
|
26
|
+
def view_for_state(state)
|
27
|
+
"#{cell_name}/#{state}"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Find a possible template for a cell's current state. It tries to find a
|
31
|
+
# template file with the name of the state under a subdirectory
|
32
|
+
# with the name of the cell under the <tt>app/cells</tt> directory.
|
33
|
+
# If this file cannot be found, it will try to call this method on
|
34
|
+
# the superclass. This way you only have to write a state template
|
35
|
+
# once when a more specific cell does not need to change anything in
|
36
|
+
# that view.
|
37
|
+
def find_class_view_for_state(state)
|
38
|
+
return [view_for_state(state)] unless superclass.respond_to?(:find_class_view_for_state)
|
39
|
+
|
40
|
+
superclass.find_class_view_for_state(state) << view_for_state(state)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Get the name of this cell's class as an underscored string,
|
44
|
+
# with _cell removed.
|
45
|
+
#
|
46
|
+
# Example:
|
47
|
+
# UserCell.cell_name
|
48
|
+
# => "user"
|
49
|
+
def cell_name
|
50
|
+
name.underscore.sub(/_cell$/, '')
|
51
|
+
end
|
52
|
+
|
53
|
+
def class_from_cell_name(cell_name)
|
54
|
+
"#{cell_name}_cell".classify.constantize
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
attr_accessor :controller
|
63
|
+
attr_reader :state_name
|
64
|
+
|
65
|
+
def initialize(options={})
|
66
|
+
#@controller = controller
|
67
|
+
@opts = options
|
68
|
+
end
|
69
|
+
|
70
|
+
def cell_name
|
71
|
+
self.class.cell_name
|
72
|
+
end
|
73
|
+
|
74
|
+
# Invoke the state method and render the given state.
|
75
|
+
def render_state(state, controller=nil)
|
76
|
+
@cell = self
|
77
|
+
@state_name = state
|
78
|
+
|
79
|
+
dispatch_state(state)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Call the state method.
|
83
|
+
def dispatch_state(state)
|
84
|
+
send(state)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Find possible files that belong to the state. This first tries the cell's
|
88
|
+
# <tt>#view_for_state</tt> method and if that returns a true value, it
|
89
|
+
# will accept that value as a string and interpret it as a pathname for
|
90
|
+
# the view file. If it returns a falsy value, it will call the Cell's class
|
91
|
+
# method find_class_view_for_state to determine the file to check.
|
92
|
+
#
|
93
|
+
# You can override the ::Cell::Base#view_for_state method for a particular
|
94
|
+
# cell if you wish to make it decide dynamically what file to render.
|
95
|
+
def possible_paths_for_state(state)
|
96
|
+
self.class.find_class_view_for_state(state).reverse!
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|