cells 2.3.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/CHANGES +3 -3
  2. data/MIT-LICENSE +22 -0
  3. data/README.rdoc +2 -2
  4. data/Rakefile +22 -25
  5. data/generators/cell/templates/cell.rb +1 -1
  6. data/generators/cells_install/USAGE +3 -0
  7. data/generators/cells_install/cells_install_generator.rb +12 -0
  8. data/generators/cells_install/templates/initializer.rb +9 -0
  9. data/lib/cell.rb +9 -0
  10. data/lib/cells.rb +68 -0
  11. data/lib/cells/cell.rb +15 -0
  12. data/lib/cells/cell/base.rb +461 -0
  13. data/lib/cells/cell/caching.rb +163 -0
  14. data/lib/cells/cell/view.rb +56 -0
  15. data/lib/cells/helpers.rb +7 -0
  16. data/lib/cells/helpers/capture_helper.rb +51 -0
  17. data/lib/cells/rails.rb +17 -0
  18. data/lib/cells/rails/action_controller.rb +37 -0
  19. data/lib/cells/rails/action_view.rb +37 -0
  20. data/lib/cells/version.rb +5 -0
  21. data/rails/init.rb +30 -0
  22. data/test/{cells → app/cells}/cells_test_one_cell.rb +2 -2
  23. data/test/{cells → app/cells}/cells_test_two_cell.rb +2 -0
  24. data/test/{cells → app/cells}/really_module/nested_cell.rb +1 -1
  25. data/test/app/cells/simple_cell.rb +7 -0
  26. data/test/{cells → app/cells}/test_cell.rb +3 -7
  27. data/test/app/controllers/cells_test_controller.rb +44 -0
  28. data/test/app/helpers/application_helper.rb +7 -0
  29. data/test/{helpers → app/helpers}/helper_using_cell_helper.rb +3 -1
  30. data/test/bugs_test.rb +10 -13
  31. data/test/caching_test.rb +169 -165
  32. data/test/capture_helper_test.rb +59 -0
  33. data/test/cells_test.rb +160 -158
  34. data/test/helper_test.rb +83 -104
  35. data/test/rails_test.rb +35 -0
  36. data/test/render_test.rb +163 -106
  37. data/test/support/assertions_helper.rb +60 -0
  38. data/test/test_helper.rb +67 -0
  39. metadata +35 -25
  40. data/README +0 -150
  41. data/VERSION +0 -1
  42. data/init.rb +0 -59
  43. data/lib/cell/base.rb +0 -454
  44. data/lib/cell/caching.rb +0 -151
  45. data/lib/cell/view.rb +0 -55
  46. data/lib/cells_helper.rb +0 -49
  47. data/lib/rails_extensions.rb +0 -75
  48. data/test/capture_test.rb +0 -56
  49. data/test/cell_view_test.rb +0 -9
  50. data/test/cells/simple_cell.rb +0 -5
  51. data/test/rails_extensions_test.rb +0 -25
  52. data/test/testing_helper.rb +0 -67
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+ require 'action_controller/test_case'
3
+
4
+ # Assertion helpers extracted from Devise by José Valim.
5
+ #
6
+ module Cells
7
+ module AssertionsHelper
8
+ def setup
9
+ @controller = ::CellsTestController.new
10
+ @request = ::ActionController::TestRequest.new
11
+ @response = ::ActionController::TestResponse.new
12
+ @controller.request = @request
13
+ @controller.response = @response
14
+ @controller.params = {}
15
+ end
16
+
17
+ def assert_selekt(content, *args)
18
+ assert_select(HTML::Document.new(content).root, *args)
19
+ end
20
+
21
+ def assert_not(assertion)
22
+ assert !assertion
23
+ end
24
+
25
+ def assert_blank(assertion)
26
+ assert assertion.blank?
27
+ end
28
+
29
+ def assert_not_blank(assertion)
30
+ assert !assertion.blank?
31
+ end
32
+ alias :assert_present :assert_not_blank
33
+
34
+ # Execute the block setting the given values and restoring old values after
35
+ # the block is executed.
36
+ #
37
+ # == Usage/Example:
38
+ #
39
+ # I18n.locale # => :en
40
+ #
41
+ # swap(I18n :locale => :se) do
42
+ # I18n.locale # => :se
43
+ # end
44
+ #
45
+ # I18n.locale # => :en
46
+ #
47
+ def swap(object, new_values)
48
+ old_values = {}
49
+ new_values.each do |key, value|
50
+ old_values[key] = object.send key
51
+ object.send :"#{key}=", value
52
+ end
53
+ yield
54
+ ensure
55
+ old_values.each do |key, value|
56
+ object.send :"#{key}=", value
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+ require 'rubygems'
3
+
4
+ begin
5
+ require 'test/unit'
6
+ rescue
7
+ gem 'test-unit', '1.2.3'
8
+ require 'test/unit'
9
+ end
10
+
11
+ begin
12
+ require 'active_support'
13
+ rescue
14
+ gem 'activesupport'
15
+ require 'active_support'
16
+ end
17
+
18
+ begin
19
+ require 'action_controller'
20
+ rescue
21
+ gem 'actionpack'
22
+ require 'action_controller'
23
+ end
24
+
25
+ begin
26
+ require 'action_view'
27
+ rescue
28
+ gem 'actionpack'
29
+ require 'action_view'
30
+ end
31
+
32
+ require 'active_support/test_case'
33
+
34
+ # Require app's test_helper.rb if such exists.
35
+ app_test_helper = if defined?(Rails)
36
+ Rails.root.join('test', 'test_helper')
37
+ else
38
+ # Assuming we are in something like APP_ROOT/vendor/plugins/cells that is.
39
+ File.expand_path(File.join(File.dirname(__FILE__), *%w[.. .. .. .. test test_helper])) rescue nil
40
+ end
41
+ require app_test_helper if File.exist?(app_test_helper)
42
+
43
+ ENV['RAILS_ENV'] = 'test'
44
+ test_app_path = File.expand_path(File.join(File.dirname(__FILE__), 'app').to_s)
45
+
46
+ # Important: Load any ApplicationHelper before loading cells.
47
+ Dir[File.join(test_app_path, *%w[helpers ** *.rb]).to_s].each { |f| require f }
48
+
49
+ require 'cells'
50
+
51
+ Cell::Base.add_view_path File.join(test_app_path, 'cells')
52
+ Cell::Base.add_view_path File.join(test_app_path, 'cells', 'layouts')
53
+
54
+ # Now, load the rest.
55
+ Dir[File.join(test_app_path, *%w[controllers ** *.rb]).to_s].each { |f| require f }
56
+
57
+ # We need to setup a fake route for the controller tests.
58
+ ActionController::Routing::Routes.draw do |map|
59
+ map.connect 'cells_test/:action', :controller => 'cells_test'
60
+ end
61
+
62
+ # Load test support files.
63
+ Dir[File.join(File.dirname(__FILE__), *%w[support ** *.rb]).to_s].each { |f| require f }
64
+
65
+ ActiveSupport::TestCase.class_eval do
66
+ include Cells::AssertionsHelper
67
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cells
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sutterer
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-15 00:00:00 +01:00
12
+ date: 2010-02-05 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -20,25 +20,33 @@ executables: []
20
20
  extensions: []
21
21
 
22
22
  extra_rdoc_files:
23
- - CHANGES
24
- - README
23
+ - README.rdoc
25
24
  files:
26
25
  - CHANGES
27
- - README
26
+ - MIT-LICENSE
28
27
  - README.rdoc
29
28
  - Rakefile
30
- - VERSION
31
29
  - generators/cell/USAGE
32
30
  - generators/cell/cell_generator.rb
33
31
  - generators/cell/templates/cell.rb
34
32
  - generators/cell/templates/view.html.erb
35
33
  - generators/cell/templates/view.html.haml
36
- - init.rb
37
- - lib/cell/base.rb
38
- - lib/cell/caching.rb
39
- - lib/cell/view.rb
40
- - lib/cells_helper.rb
41
- - lib/rails_extensions.rb
34
+ - generators/cells_install/USAGE
35
+ - generators/cells_install/cells_install_generator.rb
36
+ - generators/cells_install/templates/initializer.rb
37
+ - lib/cell.rb
38
+ - lib/cells.rb
39
+ - lib/cells/cell.rb
40
+ - lib/cells/cell/base.rb
41
+ - lib/cells/cell/caching.rb
42
+ - lib/cells/cell/view.rb
43
+ - lib/cells/helpers.rb
44
+ - lib/cells/helpers/capture_helper.rb
45
+ - lib/cells/rails.rb
46
+ - lib/cells/rails/action_controller.rb
47
+ - lib/cells/rails/action_view.rb
48
+ - lib/cells/version.rb
49
+ - rails/init.rb
42
50
  has_rdoc: true
43
51
  homepage: http://cells.rubyforge.org
44
52
  licenses: []
@@ -68,18 +76,20 @@ signing_key:
68
76
  specification_version: 3
69
77
  summary: Cells are lightweight controllers for Rails and can be rendered in controllers and views, providing an elegant and fast way for encapsulation and component-orientation.
70
78
  test_files:
71
- - test/capture_test.rb
72
- - test/rails_extensions_test.rb
73
- - test/bugs_test.rb
74
- - test/cells/really_module/nested_cell.rb
75
- - test/cells/cells_test_one_cell.rb
76
- - test/cells/cells_test_two_cell.rb
77
- - test/cells/simple_cell.rb
78
- - test/cells/test_cell.rb
79
- - test/render_test.rb
80
- - test/testing_helper.rb
81
- - test/cell_view_test.rb
79
+ - test/caching_test.rb
82
80
  - test/cells_test.rb
81
+ - test/test_helper.rb
82
+ - test/capture_helper_test.rb
83
+ - test/rails_test.rb
83
84
  - test/helper_test.rb
84
- - test/helpers/helper_using_cell_helper.rb
85
- - test/caching_test.rb
85
+ - test/bugs_test.rb
86
+ - test/render_test.rb
87
+ - test/support/assertions_helper.rb
88
+ - test/app/helpers/application_helper.rb
89
+ - test/app/helpers/helper_using_cell_helper.rb
90
+ - test/app/cells/cells_test_two_cell.rb
91
+ - test/app/cells/test_cell.rb
92
+ - test/app/cells/cells_test_one_cell.rb
93
+ - test/app/cells/really_module/nested_cell.rb
94
+ - test/app/cells/simple_cell.rb
95
+ - test/app/controllers/cells_test_controller.rb
data/README DELETED
@@ -1,150 +0,0 @@
1
- = Overview
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.
8
-
9
- They perfectly work together with AJAX/JavaScript, but also run fine without it,
10
- Michael.
11
-
12
- == Give me code!
13
-
14
- To quickly create the necessary files for an example cell run the generator:
15
-
16
- script/generate cell Article newest top_article
17
-
18
-
19
- The generated cell class located in <tt>app/cells/article_cell.rb</tt> could look like
20
- this, after some editing:
21
-
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
36
-
37
- The corresponding views are in <tt>app/cells/article/newest.html.erb</tt>:
38
-
39
- <h2>Hot stuff!</h2>
40
- <ul>
41
- <% @articles.each do |article| %>
42
- <li><%= article.title %></li>
43
- <% end %>
44
- </ul>
45
-
46
- The other view would be in <tt>app/cells/article/top_article_v2.html.haml</tt>:
47
-
48
- %h2
49
- = @article.title
50
- = format_and_escape(@article.text)
51
-
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
- ...
59
- end
60
- end
61
-
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.
72
-
73
- = Caching
74
-
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.
79
-
80
- cache :my_cached_state, Proc.new{|cell| Version.for(User.find(1)}
81
-
82
- This would result in re-rendering the state <tt>:my_cached_state</tt> only if the
83
- version of the user instance changes.
84
-
85
- = Compatibility with other rails plugins
86
-
87
- Cells uses the rails rendering code and thus stays completely compatible with (most?) plugins.
88
-
89
- === I18N
90
-
91
- All of Rails' new i18n features work with Cells. For example
92
-
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.
96
-
97
- === Haml
98
-
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.
101
-
102
- === Engines
103
-
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.
107
-
108
- = Installation
109
-
110
- To install, simply cd to your rails app directory and run
111
-
112
- script/plugin install git://github.com/apotonick/cells.git
113
-
114
- This release is tested and runs with Rails 2.3.
115
-
116
-
117
- = Documentation
118
-
119
- Reference documentation is found in the documentation of the Cell::Base class.
120
-
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.
124
-
125
- = LICENSE
126
-
127
- Copyright (c) 2007-2009, Nick Sutterer
128
-
129
- Copyright (c) 2007-2008, Solide ICT by Peter Bex and Bob Leers
130
-
131
- The MIT License
132
-
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
-
140
- The above copyright notice and this permission notice shall be included in
141
- all copies or substantial portions of the Software.
142
-
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.
150
-
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 2.3.0
data/init.rb DELETED
@@ -1,59 +0,0 @@
1
- # Copyright (c) 2007-2009 Nick Sutterer <apotonick@gmail.com>
2
- # Copyright (c) 2007-2008 Solide ICT by Peter Bex <peter.bex@solide-ict.nl>
3
- # and Bob Leers <bleers@fastmail.fm>
4
- # Some portions and ideas stolen ruthlessly from Ezra Zygmuntowicz <ezmobius@gmail.com>
5
- #
6
- # The MIT License
7
- #
8
- # Permission is hereby granted, free of charge, to any person obtaining a copy
9
- # of this software and associated documentation files (the "Software"), to deal
10
- # in the Software without restriction, including without limitation the rights
11
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
- # copies of the Software, and to permit persons to whom the Software is
13
- # furnished to do so, subject to the following conditions:
14
- #
15
- # The above copyright notice and this permission notice shall be included in
16
- # all copies or substantial portions of the Software.
17
- #
18
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
- # THE SOFTWARE.
25
-
26
- # load the baby:
27
- Cell::Base
28
- require 'rails_extensions'
29
-
30
-
31
- ActionController::Base.class_eval do include Cell::ActionController end
32
- ActionView::Base.class_eval do include Cell::ActionView end
33
- Cell::Base.class_eval do include Cell::Caching end
34
-
35
-
36
- ActiveSupport::Dependencies.load_paths << RAILS_ROOT+"/app/cells"
37
- Cell::Base.add_view_path "app/cells"
38
- ### DISCUSS: do we need shared layouts for different cells?
39
- Cell::Base.add_view_path "app/cells/layouts"
40
-
41
-
42
- # process cells in plugins ("engine-cells").
43
- # thanks to Tore Torell for making me aware of the initializer instance here:
44
- config.after_initialize do
45
- initializer.loaded_plugins.each do |plugin|
46
- engine_cells_dir = File.join([plugin.directory, "app/cells"])
47
- next unless plugin.engine?
48
- next unless File.exists?(engine_cells_dir)
49
-
50
- # propagate the view- and code path of this engine-cell:
51
- Cell::Base.view_paths << engine_cells_dir
52
- ActiveSupport::Dependencies.load_paths << engine_cells_dir
53
-
54
- # if a path is in +load_once_path+ it won't be reloaded between requests.
55
- unless config.reload_plugins?
56
- ActiveSupport::Dependencies.load_once_paths << engine_cells_dir
57
- end
58
- end
59
- end
data/lib/cell/base.rb DELETED
@@ -1,454 +0,0 @@
1
- module Cell
2
- # == Basic overview
3
- #
4
- # A Cell is the central notion of the cells plugin. A cell acts as a
5
- # lightweight controller in the sense that it will assign variables and
6
- # render a view. Cells can be rendered from other cells as well as from
7
- # regular controllers and views (see ActionView::Base#render_cell and
8
- # ControllerMethods#render_cell)
9
- #
10
- # == A render_cell() cycle
11
- #
12
- # A typical <tt>render_cell</tt> state rendering cycle looks like this:
13
- # render_cell :blog, :newest_article, {...}
14
- # - an instance of the class <tt>BlogCell</tt> is created, and a hash containing
15
- # arbitrary parameters is passed
16
- # - the <em>state method</em> <tt>newest_article</tt> is executed and assigns instance
17
- # variables to be used in the view
18
- # - Usually the state method will call #render and return
19
- # - #render will retrieve the corresponding view
20
- # (e.g. <tt>app/cells/blog/newest_article.html. [erb|haml|...]</tt>),
21
- # renders this template and returns the markup.
22
- #
23
- # == Design Principles
24
- # A cell is a completely autonomous object and it should not know or have to know
25
- # from what controller it is being rendered. For this reason, the controller's
26
- # instance variables and params hash are not directly available from the cell or
27
- # its views. This is not a bug, this is a feature! It means cells are truly
28
- # reusable components which can be plugged in at any point in your application
29
- # without having to think about what information is available at that point.
30
- # When rendering a cell, you can explicitly pass variables to the cell in the
31
- # extra opts argument hash, just like you would pass locals in partials.
32
- # This hash is then available inside the cell as the @opts instance variable.
33
- #
34
- # == Directory hierarchy
35
- #
36
- # To get started creating your own cells, you can simply create a new directory
37
- # structure under your <tt>app</tt> directory called <tt>cells</tt>. Cells are
38
- # ruby classes which end in the name Cell. So for example, if you have a
39
- # cell which manages all user information, it would be called <tt>UserCell</tt>.
40
- # A cell which manages a shopping cart could be called <tt>ShoppingCartCell</tt>.
41
- #
42
- # The directory structure of this example would look like this:
43
- # app/
44
- # models/
45
- # ..
46
- # views/
47
- # ..
48
- # helpers/
49
- # application_helper.rb
50
- # product_helper.rb
51
- # ..
52
- # controllers/
53
- # ..
54
- # cells/
55
- # shopping_cart_cell.rb
56
- # shopping_cart/
57
- # status.html.erb
58
- # product_list.html.erb
59
- # empty_prompt.html.erb
60
- # user_cell.rb
61
- # user/
62
- # login.html.erb
63
- # layouts/
64
- # box.html.erb
65
- # ..
66
- #
67
- # The directory with the same name as the cell contains views for the
68
- # cell's <em>states</em>. A state is an executed method along with a
69
- # rendered view, resulting in content. This means that states are to
70
- # cells as actions are to controllers, so each state has its own view.
71
- # The use of partials is deprecated with cells, it is better to just
72
- # render a different state on the same cell (which also works recursively).
73
- #
74
- # Anyway, <tt>render :partial </tt> in a cell view will work, if the
75
- # partial is contained in the cell's view directory.
76
- #
77
- # As can be seen above, Cells also can make use of helpers. All Cells
78
- # include ApplicationHelper by default, but you can add additional helpers
79
- # as well with the Cell::Base.helper class method:
80
- # class ShoppingCartCell < Cell::Base
81
- # helper :product
82
- # ...
83
- # end
84
- #
85
- # This will make the <tt>ProductHelper</tt> from <tt>app/helpers/product_helper.rb</tt>
86
- # available from all state views from our <tt>ShoppingCartCell</tt>.
87
- #
88
- # == Cell inheritance
89
- #
90
- # Unlike controllers, Cells can form a class hierarchy. When a cell class
91
- # is inherited by another cell class, its states are inherited as regular
92
- # methods are, but also its views are inherited. Whenever a view is looked up,
93
- # the view finder first looks for a file in the directory belonging to the
94
- # current cell class, but if this is not found in the application or any
95
- # engine, the superclass' directory is checked. This continues all the
96
- # way up until it stops at Cell::Base.
97
- #
98
- # For instance, when you have two cells:
99
- # class MenuCell < Cell::Base
100
- # def show
101
- # end
102
- #
103
- # def edit
104
- # end
105
- # end
106
- #
107
- # class MainMenuCell < MenuCell
108
- # .. # no need to redefine show/edit if they do the same!
109
- # end
110
- # and the following directory structure in <tt>app/cells</tt>:
111
- # app/cells/
112
- # menu/
113
- # show.html.erb
114
- # edit.html.erb
115
- # main_menu/
116
- # show.html.erb
117
- # then when you call
118
- # render_cell :main_menu, :show
119
- # the main menu specific show.html.erb (<tt>app/cells/main_menu/show.html.erb</tt>)
120
- # is rendered, but when you call
121
- # render_cell :main_menu, :edit
122
- # cells notices that the main menu does not have a specific view for the
123
- # <tt>edit</tt> state, so it will render the view for the parent class,
124
- # <tt>app/cells/menu/edit.html.erb</tt>
125
- #
126
- #
127
- # == Gettext support
128
- #
129
- # Cells support gettext, just name your views accordingly. It works exactly equivalent
130
- # to controller views.
131
- #
132
- # cells/user/user_form.html.erb
133
- # cells/user/user_form_de.html.erb
134
- #
135
- # If gettext is set to DE_de, the latter view will be chosen.
136
- class Base
137
- include ActionController::Helpers
138
- include ActionController::RequestForgeryProtection
139
-
140
- helper ApplicationHelper
141
-
142
-
143
- class << self
144
- attr_accessor :request_forgery_protection_token
145
-
146
- # A template file will be looked for in each view path. This is typically
147
- # just RAILS_ROOT/app/cells, but you might want to add e.g.
148
- # RAILS_ROOT/app/views.
149
- def add_view_path(path)
150
- self.view_paths << RAILS_ROOT + '/' + path
151
- end
152
-
153
- # Creates a cell instance of the class <tt>name</tt>Cell, passing through
154
- # <tt>opts</tt>.
155
- def create_cell_for(controller, name, opts={})
156
- class_from_cell_name(name).new(controller, opts)
157
- end
158
-
159
- # Declare a controller method as a helper. For example,
160
- # helper_method :link_to
161
- # def link_to(name, options) ... end
162
- # makes the link_to controller method available in the view.
163
- def helper_method(*methods)
164
- methods.flatten.each do |method|
165
- master_helper_module.module_eval <<-end_eval
166
- def #{method}(*args, &block)
167
- @cell.send(%(#{method}), *args, &block)
168
- end
169
- end_eval
170
- end
171
- end
172
-
173
- # Return the default view for the given state on this cell subclass.
174
- # This is a file with the name of the state under a directory with the
175
- # name of the cell followed by a template extension.
176
- def view_for_state(state)
177
- "#{cell_name}/#{state}"
178
- end
179
-
180
- # Find a possible template for a cell's current state. It tries to find a
181
- # template file with the name of the state under a subdirectory
182
- # with the name of the cell under the <tt>app/cells</tt> directory.
183
- # If this file cannot be found, it will try to call this method on
184
- # the superclass. This way you only have to write a state template
185
- # once when a more specific cell does not need to change anything in
186
- # that view.
187
- def find_class_view_for_state(state)
188
- return [view_for_state(state)] if superclass == Cell::Base
189
-
190
- superclass.find_class_view_for_state(state) << view_for_state(state)
191
- end
192
-
193
- # Get the name of this cell's class as an underscored string,
194
- # with _cell removed.
195
- #
196
- # Example:
197
- # UserCell.cell_name
198
- # => "user"
199
- def cell_name
200
- name.underscore.sub(/_cell/, '')
201
- end
202
-
203
- # Given a cell name, finds the class that belongs to it.
204
- #
205
- # Example:
206
- # Cell::Base.class_from_cell_name(:user)
207
- # => UserCell
208
- def class_from_cell_name(cell_name)
209
- "#{cell_name}_cell".classify.constantize
210
- end
211
-
212
- def state2view_cache
213
- @state2view_cache ||= {}
214
- end
215
-
216
- def cache_configured?; ::ActionController::Base.cache_configured?; end
217
- end
218
-
219
- class_inheritable_array :view_paths, :instance_writer => false
220
- self.view_paths = ActionView::PathSet.new
221
-
222
- class_inheritable_accessor :allow_forgery_protection
223
- self.allow_forgery_protection = true
224
-
225
- class_inheritable_accessor :default_template_format
226
- self.default_template_format = :html
227
-
228
-
229
- delegate :params, :session, :request, :logger, :to => :controller
230
-
231
-
232
- attr_accessor :controller
233
- attr_reader :state_name
234
-
235
-
236
- def initialize(controller, options={})
237
- @controller = controller
238
- @opts = options
239
- end
240
-
241
- def cell_name
242
- self.class.cell_name
243
- end
244
-
245
-
246
- # Render the given state. You can pass the name as either a symbol or
247
- # a string.
248
- def render_state(state)
249
- @cell = self
250
- @state_name = state
251
-
252
- content = dispatch_state(state)
253
-
254
- return content if content.kind_of? String
255
-
256
- render_view_for_backward_compat(content, state)
257
- end
258
-
259
- # Call the state method.
260
- def dispatch_state(state)
261
- send(state)
262
- end
263
-
264
- # We will soon remove the implicit call to render_view_for, but here it is for your convenience.
265
- def render_view_for_backward_compat(opts, state)
266
- ActiveSupport::Deprecation.warn "You either didn't call #render or forgot to return a string in the state method '#{state}'. However, returning nil is deprecated for the sake of explicitness"
267
-
268
- render_view_for(opts, state)
269
- end
270
-
271
-
272
- # Renders the view for the current state and returns the markup for the component.
273
- # Usually called and returned at the end of a state method.
274
- #
275
- # ==== Options
276
- # * <tt>:view</tt> - Specifies the name of the view file to render. Defaults to the current state name.
277
- # * <tt>:template_format</tt> - Allows using a format different to <tt>:html</tt>.
278
- # * <tt>:layout</tt> - If set to a valid filename inside your cell's view_paths, the current state view will be rendered inside the layout (as known from controller actions). Layouts should reside in <tt>app/cells/layouts</tt>.
279
- # * <tt>:locals</tt> - Makes the named parameters available as variables in the view.
280
- # * <tt>:text</tt> - Just renders plain text.
281
- # * <tt>:inline</tt> - Renders an inline template as state view. See ActionView::Base#render for details.
282
- # * <tt>:file</tt> - Specifies the name of the file template to render.
283
- # * <tt>:nothing</tt> - Will make the component kinda invisible and doesn't invoke the rendering cycle.
284
- # * <tt>:state</tt> - Instantly invokes another rendering cycle for the passed state and returns.
285
- # Example:
286
- # class MyCell < Cell::Base
287
- # def my_first_state
288
- # # ... do something
289
- # render
290
- # end
291
- #
292
- # will just render the view <tt>my_first_state.html</tt>.
293
- #
294
- # def my_first_state
295
- # # ... do something
296
- # render :view => :my_first_state, :layout => "metal"
297
- # end
298
- #
299
- # will also use the view <tt>my_first_state.html</tt> as template and even put it in the layout
300
- # <tt>metal</tt> that's located at <tt>$RAILS_ROOT/app/cells/layouts/metal.html.erb</tt>.
301
- #
302
- # def say_your_name
303
- # render :locals => {:name => "Nick"}
304
- # end
305
- #
306
- # will make the variable +name+ available in the view <tt>say_your_name.html</tt>.
307
- #
308
- # def say_your_name
309
- # render :nothing => true
310
- # end
311
- #
312
- # will render an empty string thus keeping your name a secret.
313
- #
314
- #
315
- # ==== Where have all the partials gone?
316
- # In Cells we abandoned the term 'partial' in favor of plain 'views' - we don't need to distinguish
317
- # between both terms. A cell view is both, a view and a kind of partial as it represents only a small
318
- # part of the page.
319
- # Just use <tt>:view</tt> and enjoy.
320
- def render(opts={})
321
- render_view_for(opts, @state_name) ### FIXME: i don't like the magic access to @state_name here. ugly!
322
- end
323
-
324
- # Render the view belonging to the given state. Will raise ActionView::MissingTemplate
325
- # if it can not find one of the requested view template. Note that this behaviour was
326
- # introduced in cells 2.3 and replaces the former warning message.
327
- def render_view_for(opts, state)
328
- return "" if opts[:nothing]
329
-
330
- action_view = setup_action_view
331
-
332
- ### TODO: dispatch dynamically:
333
- if opts[:text]
334
- elsif opts[:inline]
335
- elsif opts[:file]
336
- elsif opts[:state]
337
- opts[:text] = render_state(opts[:state])
338
- else
339
- # handle :layout, :template_format, :view
340
- opts = defaultize_render_options_for(opts, state)
341
-
342
- # set instance vars, include helpers:
343
- prepare_action_view_for(action_view, opts)
344
-
345
- template = find_family_view_for_state_with_caching(opts[:view], action_view)
346
- opts[:file] = template
347
- end
348
-
349
- opts = sanitize_render_options(opts)
350
-
351
- action_view.render_for(opts)
352
- end
353
-
354
-
355
- # Defaultize the passed options from #render.
356
- def defaultize_render_options_for(opts, state)
357
- opts[:template_format] ||= self.class.default_template_format
358
- opts[:view] ||= state
359
- opts
360
- end
361
-
362
- def prepare_action_view_for(action_view, opts)
363
- # make helpers available:
364
- include_helpers_in_class(action_view.class)
365
-
366
- action_view.assigns = assigns_for_view # make instance vars available.
367
- action_view.template_format = opts[:template_format]
368
- end
369
-
370
- def setup_action_view
371
- view_class = Class.new(Cell::View)
372
- action_view = view_class.new(self.class.view_paths, {}, @controller)
373
- action_view.cell = self
374
- action_view
375
- end
376
-
377
- # Prepares <tt>opts</tt> to be passed to ActionView::Base#render by removing
378
- # unknown parameters.
379
- def sanitize_render_options(opts)
380
- opts.except!(:view, :state)
381
- end
382
-
383
-
384
- # Climbs up the inheritance hierarchy of the Cell, looking for a view
385
- # for the current <tt>state</tt> in each level.
386
- # As soon as a view file is found it is returned as an ActionView::Template
387
- # instance.
388
- ### DISCUSS: moved to Cell::View#find_template in rainhead's fork:
389
- def find_family_view_for_state(state, action_view)
390
- missing_template_exception = nil
391
-
392
- possible_paths_for_state(state).each do |template_path|
393
- # we need to catch MissingTemplate, since we want to try for all possible
394
- # family views.
395
- begin
396
- if view = action_view.try_picking_template_for_path(template_path)
397
- return view
398
- end
399
- rescue ::ActionView::MissingTemplate => missing_template_exception
400
- end
401
- end
402
-
403
- raise missing_template_exception
404
- end
405
-
406
- # In production mode, the view for a state/template_format is cached.
407
- ### DISCUSS: ActionView::Base already caches results for #pick_template, so maybe
408
- ### we should just cache the family path for a state/format?
409
- def find_family_view_for_state_with_caching(state, action_view)
410
- return find_family_view_for_state(state, action_view) unless self.class.cache_configured?
411
-
412
- # in production mode:
413
- key = "#{state}/#{action_view.template_format}"
414
- state2view = self.class.state2view_cache
415
- state2view[key] || state2view[key] = find_family_view_for_state(state, action_view)
416
- end
417
-
418
- # Find possible files that belong to the state. This first tries the cell's
419
- # <tt>#view_for_state</tt> method and if that returns a true value, it
420
- # will accept that value as a string and interpret it as a pathname for
421
- # the view file. If it returns a falsy value, it will call the Cell's class
422
- # method find_class_view_for_state to determine the file to check.
423
- #
424
- # You can override the Cell::Base#view_for_state method for a particular
425
- # cell if you wish to make it decide dynamically what file to render.
426
- def possible_paths_for_state(state)
427
- self.class.find_class_view_for_state(state).reverse!
428
- end
429
-
430
- # Prepares the hash {instance_var => value, ...} that should be available
431
- # in the ActionView when rendering the state view.
432
- def assigns_for_view
433
- assigns = {}
434
- (self.instance_variables - ivars_to_ignore).each do |k|
435
- assigns[k[1..-1]] = instance_variable_get(k)
436
- end
437
- assigns
438
- end
439
-
440
-
441
- # When passed a copy of the ActionView::Base class, it
442
- # will mix in all helper classes for this cell in that class.
443
- def include_helpers_in_class(view_klass)
444
- view_klass.send(:include, self.class.master_helper_module)
445
- end
446
-
447
-
448
- # Defines the instance variables that should <em>not</em> be copied to the
449
- # View instance.
450
- def ivars_to_ignore; ['@controller']; end
451
-
452
-
453
- end
454
- end