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.
Files changed (103) hide show
  1. data/CHANGES +0 -8
  2. data/Gemfile +4 -1
  3. data/README.rdoc +91 -107
  4. data/Rakefile +0 -4
  5. data/lib/cell.rb +5 -6
  6. data/lib/{cells/cell → cell}/active_helper.rb +1 -1
  7. data/lib/cell/base.rb +134 -0
  8. data/lib/cell/base_methods.rb +100 -0
  9. data/lib/cell/caching.rb +153 -0
  10. data/lib/cell/rails.rb +239 -0
  11. data/lib/cells.rb +25 -3
  12. data/lib/cells/assertions_helper.rb +1 -1
  13. data/lib/cells/helpers/capture_helper.rb +3 -3
  14. data/lib/cells/rails.rb +65 -4
  15. data/lib/cells/version.rb +3 -1
  16. data/rails_generators/cell/cell_generator.rb +47 -35
  17. data/rails_generators/cell/templates/cell.rb +1 -1
  18. data/rails_generators/cells_install/cells_install_generator.rb +5 -3
  19. data/rails_generators/erb/cell_generator.rb +20 -0
  20. data/rails_generators/{cell → erb}/templates/view.html.erb +0 -0
  21. data/test/active_helper_test.rb +1 -0
  22. data/test/app/cells/bad_guitarist_cell.rb +2 -0
  23. data/test/app/cells/bassist_cell.rb +1 -1
  24. data/test/app/controllers/musician_controller.rb +16 -0
  25. data/test/assertions_helper_test.rb +8 -18
  26. data/test/base_methods_test.rb +40 -0
  27. data/test/cell_generator_test.rb +33 -21
  28. data/test/helper_test.rb +31 -123
  29. data/test/rails/caching_test.rb +215 -0
  30. data/test/rails/capture_test.rb +52 -0
  31. data/test/rails/cells_test.rb +88 -0
  32. data/test/rails/integration_test.rb +37 -0
  33. data/test/rails/render_test.rb +140 -0
  34. data/test/rails/router_test.rb +74 -0
  35. data/test/rails/view_test.rb +24 -0
  36. data/test/test_helper.rb +30 -29
  37. metadata +68 -133
  38. data/.gitignore +0 -3
  39. data/about.yml +0 -7
  40. data/cells.gemspec +0 -26
  41. data/lib/cells/cell.rb +0 -16
  42. data/lib/cells/cell/base.rb +0 -470
  43. data/lib/cells/cell/caching.rb +0 -163
  44. data/lib/cells/cell/test_case.rb +0 -158
  45. data/lib/cells/cell/view.rb +0 -55
  46. data/lib/cells/rails/action_controller.rb +0 -37
  47. data/lib/cells/rails/action_view.rb +0 -37
  48. data/rails/init.rb +0 -44
  49. data/rails_generators/cells_install/templates/tasks.rake +0 -6
  50. data/test/app/cells/a/another_state.html.erb +0 -1
  51. data/test/app/cells/a/existing_view.html.erb +0 -1
  52. data/test/app/cells/a/inherited_view.html.erb +0 -1
  53. data/test/app/cells/a/inherited_view.js.erb +0 -1
  54. data/test/app/cells/a/view_with_locals.html.erb +0 -1
  55. data/test/app/cells/a/view_with_render_call.html.erb +0 -1
  56. data/test/app/cells/b/existing_view.html.erb +0 -1
  57. data/test/app/cells/b/existing_view.js.erb +0 -1
  58. data/test/app/cells/b/layouts/metal.html.erb +0 -1
  59. data/test/app/cells/b/view_with_render_call.html.erb +0 -1
  60. data/test/app/cells/bassist/jam.html.erb +0 -3
  61. data/test/app/cells/bassist/play.html.erb +0 -1
  62. data/test/app/cells/cells_test_one/renamed_instance_view.html.erb +0 -1
  63. data/test/app/cells/cells_test_one/super_state.html.erb +0 -1
  64. data/test/app/cells/cells_test_one_cell.rb +0 -20
  65. data/test/app/cells/cells_test_two_cell.rb +0 -4
  66. data/test/app/cells/helper_using/state_using_application_helper.html.erb +0 -3
  67. data/test/app/cells/helper_using/state_with_automatic_helper_invocation.html.erb +0 -3
  68. data/test/app/cells/helper_using/state_with_helper_invocation.html.erb +0 -3
  69. data/test/app/cells/helper_using/state_with_helper_method_invocation.html.erb +0 -3
  70. data/test/app/cells/layouts/metal.html.erb +0 -1
  71. data/test/app/cells/my_child/hello.html.erb +0 -1
  72. data/test/app/cells/my_mother/bye.html.erb +0 -1
  73. data/test/app/cells/my_mother/hello.html.erb +0 -1
  74. data/test/app/cells/my_test/_broken_partial.html.erb +0 -1
  75. data/test/app/cells/my_test/_partial.html.erb +0 -1
  76. data/test/app/cells/my_test/state_with_instance_var.html.erb +0 -1
  77. data/test/app/cells/my_test/state_with_link_to.html.erb +0 -3
  78. data/test/app/cells/my_test/state_with_not_included_helper_method.html.erb +0 -8
  79. data/test/app/cells/my_test/view_containing_broken_partial.html.erb +0 -3
  80. data/test/app/cells/my_test/view_containing_nonexistant_partial.html.erb +0 -3
  81. data/test/app/cells/my_test/view_containing_partial.html.erb +0 -3
  82. data/test/app/cells/my_test/view_containing_partial_without_cell_name.html.erb +0 -3
  83. data/test/app/cells/my_test/view_in_local_test_views_dir.html.erb +0 -1
  84. data/test/app/cells/my_test/view_with_explicit_english_translation.en.html.erb +0 -1
  85. data/test/app/cells/my_test/view_with_explicit_english_translation.html.erb +0 -1
  86. data/test/app/cells/my_test/view_with_instance_var.html.erb +0 -4
  87. data/test/app/cells/really_module/nested/happy_state.html.erb +0 -1
  88. data/test/app/cells/really_module/nested_cell.rb +0 -11
  89. data/test/app/cells/simple/two_templates_state.html.mytpl +0 -1
  90. data/test/app/cells/simple_cell.rb +0 -7
  91. data/test/app/cells/test/beep.html.erb +0 -1
  92. data/test/app/cells/test/state_invoking_capture.html.erb +0 -7
  93. data/test/app/cells/test/state_invoking_content_for.html.erb +0 -7
  94. data/test/app/cells/test/state_invoking_content_for_twice.html.erb +0 -9
  95. data/test/app/cells/test/state_with_not_included_helper_method.html.erb +0 -8
  96. data/test/app/cells/two_helpers_including/state_using_another_helper.html.erb +0 -3
  97. data/test/bugs_test.rb +0 -23
  98. data/test/caching_test.rb +0 -270
  99. data/test/capture_helper_test.rb +0 -59
  100. data/test/cells_test.rb +0 -352
  101. data/test/rails_test.rb +0 -35
  102. data/test/render_test.rb +0 -305
  103. 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
@@ -1,3 +1,6 @@
1
1
  source :gemcutter
2
+ #gem "rails" , :git => "http://github.com/rails/rails.git"
3
+ gem 'sqlite3-ruby', '1.2.5', :require => 'sqlite3' # needed in router_test, whatever.
2
4
 
3
- gemspec
5
+ gem "rails" , :path => "/home/nick/projects/rails"
6
+ #gem "railties"
@@ -1,150 +1,134 @@
1
- = Overview
1
+ = Cells
2
2
 
3
- Cells are like controllers in Rails - they have methods and corresponding views.
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
- They perfectly work together with AJAX/JavaScript, but also run fine without it,
10
- Michael.
5
+ == Overview
11
6
 
12
- == Give me code!
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
- To quickly create the necessary files for an example cell run the generator:
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
- The generated cell class located in <tt>app/cells/article_cell.rb</tt> could look like
20
- this, after some editing:
13
+ == Installation
21
14
 
22
- class ArticleCell < ::Cell::Base
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
- The corresponding views are in <tt>app/cells/article/newest.html.erb</tt>:
17
+ Rails 3:
38
18
 
39
- <h2>Hot stuff!</h2>
40
- <ul>
41
- <% @articles.each do |article| %>
42
- <li><%= article.title %></li>
43
- <% end %>
44
- </ul>
19
+ gem install cells
45
20
 
46
- The other view would be in <tt>app/cells/article/top_article_v2.html.haml</tt>:
21
+ Rails 2.3:
47
22
 
48
- %h2
49
- = @article.title
50
- = format_and_escape(@article.text)
23
+ gem install cells --version 3.3.4
51
24
 
52
- You already know that from controllers, don't you? Speaking of controllers, here's
53
- how you could plug the cells into the page. In <tt>app/controllers/blog_controller.rb</tt>
54
- there could be an action
55
-
56
- class BlogController < ApplicationController
57
- def top_page
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
- where the rendered action view could be <tt>app/views/blog/top_page.html.erb</tt>:
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
- To improve performance rendered state views can be cached using Rails' caching mechanism.
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
- cache :my_cached_state, Proc.new{|cell| Version.for(User.find(1)}
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
- This would result in re-rendering the state <tt>:my_cached_state</tt> only if the
83
- version of the user instance changes.
67
+ <div id="cart">
68
+ You have <%= @items.size %> items in your shopping cart.
69
+ </div>
70
+
71
+ === Haml? Builder?
84
72
 
85
- = Compatibility with other rails plugins
73
+ Yes, Cells support all template types that are supported by Rails itself. Remember- it's a controller!
86
74
 
87
- Cells uses the rails rendering code and thus stays completely compatible with (most?) plugins.
75
+ === Helpers
88
76
 
89
- === I18N
77
+ Yes, Cells have helpers just like controllers. If you need some specific helper, do
90
78
 
91
- All of Rails' new i18n features work with Cells. For example
79
+ class ShoppingCartCell < Cell::Rails
80
+ helper MyExtraHelper
92
81
 
93
- t("Translate me, I'm a lonesome string in a cell state view!")
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
- Alternative templating engines will work seamlessly with Cells, too. Usem the markup language
100
- of your choice (.erb, .haml, ...) to write your cell views.
85
+ == Caching
101
86
 
102
- === Engines
87
+ Cells do strict view caching. No cluttered fragment caching. Add
103
88
 
104
- You can even put cells in plugins and thus maximize the modularity of your code.
105
- As soon as the plugin has an app/cells/ directory your cells will be added automatically
106
- and can be used everywhere in your application.
89
+ class ShoppingCartCell < Cell::Rails
90
+ cache :display, :expires_in => 10.minutes
107
91
 
108
- = Installation
92
+ and your cart will be re-rendered after 10 minutes.
109
93
 
110
- To install, simply cd to your rails app directory and run
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
- = Documentation
104
+ Another big advantage compared to monolithic controller/helper/partial piles is the ability to test your cells isolated.
118
105
 
119
- Reference documentation is found in the documentation of the ::Cell::Base class.
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
- See http://cells.rubyforge.org for documentation targeted at cells
122
- newbies, including an overview of what you can do with cells and a
123
- tutorial.
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
- = LICENSE
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
- Copyright (c) 2007-2008, Solide ICT by Peter Bex and Bob Leers
118
+ == More features
130
119
 
131
- The MIT License
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
- The above copyright notice and this permission notice shall be included in
141
- all copies or substantial portions of the Software.
128
+ == LICENSE
142
129
 
143
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
144
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
145
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
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
@@ -1,8 +1,4 @@
1
1
  # encoding: utf-8
2
-
3
- require 'bundler'
4
- Bundler::GemHelper.install_tasks
5
-
6
2
  require 'rake'
7
3
  require 'rake/testtask'
8
4
  require 'rake/rdoctask'
@@ -1,9 +1,8 @@
1
- require 'cells'
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 = ::Cells::Cell::Base
8
- View = ::Cells::Cell::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
@@ -1,4 +1,4 @@
1
- module Cells::Cell::ActiveHelper
1
+ module Cell::ActiveHelper
2
2
 
3
3
  def self.included(base)
4
4
  base.extend ClassMethods
@@ -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