cells 3.3.10 → 3.4.0.beta1
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/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/.gitignore
DELETED
data/about.yml
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
author: Nick Sutterer, Peter Bex, Bob Leers
|
|
2
|
-
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.
|
|
3
|
-
homepage: http://cells.rubyforge.org
|
|
4
|
-
plugin:
|
|
5
|
-
license: MIT
|
|
6
|
-
version: 1.1
|
|
7
|
-
rails_version: 2.1
|
data/cells.gemspec
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
|
-
lib = File.expand_path('../lib/', __FILE__)
|
|
3
|
-
$:.unshift lib unless $:.include?(lib)
|
|
4
|
-
|
|
5
|
-
require 'cells/version'
|
|
6
|
-
|
|
7
|
-
Gem::Specification.new do |s|
|
|
8
|
-
s.name = "cells"
|
|
9
|
-
s.version = Cells::VERSION
|
|
10
|
-
s.platform = Gem::Platform::RUBY
|
|
11
|
-
s.authors = ["Nick Sutterer"]
|
|
12
|
-
s.email = ["apotonick@gmail.com"]
|
|
13
|
-
s.homepage = "http://cells.rubyforge.org"
|
|
14
|
-
s.summary = %q{View Components for Rails.}
|
|
15
|
-
s.description = %q{Cells are view components for Rails. They are lightweight controllers, can be rendered in views and thus provide an elegant and fast way for encapsulation and component-orientation.}
|
|
16
|
-
|
|
17
|
-
s.files = `git ls-files`.split("\n")
|
|
18
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
19
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
20
|
-
s.require_paths = ["lib"]
|
|
21
|
-
|
|
22
|
-
s.add_dependency "rails", "~> 2.3"
|
|
23
|
-
|
|
24
|
-
s.add_development_dependency "shoulda"
|
|
25
|
-
s.add_development_dependency "active_helper"
|
|
26
|
-
end
|
data/lib/cells/cell.rb
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
|
|
3
|
-
module Cells
|
|
4
|
-
module Cell
|
|
5
|
-
autoload :Base, 'cells/cell/base'
|
|
6
|
-
autoload :View, 'cells/cell/view'
|
|
7
|
-
autoload :Caching, 'cells/cell/caching'
|
|
8
|
-
autoload :ActiveHelper, 'cells/cell/active_helper'
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
# Mixin caching behaviour into +::Cell::Base+.
|
|
13
|
-
# Note: Must be done using class_eval.
|
|
14
|
-
Cells::Cell::Base.class_eval do
|
|
15
|
-
include ::Cells::Cell::Caching
|
|
16
|
-
end
|
data/lib/cells/cell/base.rb
DELETED
|
@@ -1,470 +0,0 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
require 'action_controller/base'
|
|
3
|
-
|
|
4
|
-
module Cells
|
|
5
|
-
module Cell
|
|
6
|
-
# == Basic overview
|
|
7
|
-
#
|
|
8
|
-
# A Cell is the central notion of the cells plugin. A cell acts as a
|
|
9
|
-
# lightweight controller in the sense that it will assign variables and
|
|
10
|
-
# render a view. Cells can be rendered from other cells as well as from
|
|
11
|
-
# regular controllers and views (see ActionView::Base#render_cell and
|
|
12
|
-
# ControllerMethods#render_cell)
|
|
13
|
-
#
|
|
14
|
-
# == A render_cell() cycle
|
|
15
|
-
#
|
|
16
|
-
# A typical <tt>render_cell</tt> state rendering cycle looks like this:
|
|
17
|
-
# render_cell :blog, :newest_article, {...}
|
|
18
|
-
# - an instance of the class <tt>BlogCell</tt> is created, and a hash containing
|
|
19
|
-
# arbitrary parameters is passed
|
|
20
|
-
# - the <em>state method</em> <tt>newest_article</tt> is executed and assigns instance
|
|
21
|
-
# variables to be used in the view
|
|
22
|
-
# - Usually the state method will call #render and return
|
|
23
|
-
# - #render will retrieve the corresponding view
|
|
24
|
-
# (e.g. <tt>app/cells/blog/newest_article.html. [erb|haml|...]</tt>),
|
|
25
|
-
# renders this template and returns the markup.
|
|
26
|
-
#
|
|
27
|
-
# == Design Principles
|
|
28
|
-
# A cell is a completely autonomous object and it should not know or have to know
|
|
29
|
-
# from what controller it is being rendered. For this reason, the controller's
|
|
30
|
-
# instance variables and params hash are not directly available from the cell or
|
|
31
|
-
# its views. This is not a bug, this is a feature! It means cells are truly
|
|
32
|
-
# reusable components which can be plugged in at any point in your application
|
|
33
|
-
# without having to think about what information is available at that point.
|
|
34
|
-
# When rendering a cell, you can explicitly pass variables to the cell in the
|
|
35
|
-
# extra opts argument hash, just like you would pass locals in partials.
|
|
36
|
-
# This hash is then available inside the cell as the @opts instance variable.
|
|
37
|
-
#
|
|
38
|
-
# == Directory hierarchy
|
|
39
|
-
#
|
|
40
|
-
# To get started creating your own cells, you can simply create a new directory
|
|
41
|
-
# structure under your <tt>app</tt> directory called <tt>cells</tt>. Cells are
|
|
42
|
-
# ruby classes which end in the name Cell. So for example, if you have a
|
|
43
|
-
# cell which manages all user information, it would be called <tt>UserCell</tt>.
|
|
44
|
-
# A cell which manages a shopping cart could be called <tt>ShoppingCartCell</tt>.
|
|
45
|
-
#
|
|
46
|
-
# The directory structure of this example would look like this:
|
|
47
|
-
# app/
|
|
48
|
-
# models/
|
|
49
|
-
# ..
|
|
50
|
-
# views/
|
|
51
|
-
# ..
|
|
52
|
-
# helpers/
|
|
53
|
-
# application_helper.rb
|
|
54
|
-
# product_helper.rb
|
|
55
|
-
# ..
|
|
56
|
-
# controllers/
|
|
57
|
-
# ..
|
|
58
|
-
# cells/
|
|
59
|
-
# shopping_cart_cell.rb
|
|
60
|
-
# shopping_cart/
|
|
61
|
-
# status.html.erb
|
|
62
|
-
# product_list.html.erb
|
|
63
|
-
# empty_prompt.html.erb
|
|
64
|
-
# user_cell.rb
|
|
65
|
-
# user/
|
|
66
|
-
# login.html.erb
|
|
67
|
-
# layouts/
|
|
68
|
-
# box.html.erb
|
|
69
|
-
# ..
|
|
70
|
-
#
|
|
71
|
-
# The directory with the same name as the cell contains views for the
|
|
72
|
-
# cell's <em>states</em>. A state is an executed method along with a
|
|
73
|
-
# rendered view, resulting in content. This means that states are to
|
|
74
|
-
# cells as actions are to controllers, so each state has its own view.
|
|
75
|
-
# The use of partials is deprecated with cells, it is better to just
|
|
76
|
-
# render a different state on the same cell (which also works recursively).
|
|
77
|
-
#
|
|
78
|
-
# Anyway, <tt>render :partial </tt> in a cell view will work, if the
|
|
79
|
-
# partial is contained in the cell's view directory.
|
|
80
|
-
#
|
|
81
|
-
# As can be seen above, Cells also can make use of helpers. All Cells
|
|
82
|
-
# include ApplicationHelper by default, but you can add additional helpers
|
|
83
|
-
# as well with the ::Cell::Base.helper class method:
|
|
84
|
-
# class ShoppingCartCell < ::Cell::Base
|
|
85
|
-
# helper :product
|
|
86
|
-
# ...
|
|
87
|
-
# end
|
|
88
|
-
#
|
|
89
|
-
# This will make the <tt>ProductHelper</tt> from <tt>app/helpers/product_helper.rb</tt>
|
|
90
|
-
# available from all state views from our <tt>ShoppingCartCell</tt>.
|
|
91
|
-
#
|
|
92
|
-
# == Cell inheritance
|
|
93
|
-
#
|
|
94
|
-
# Unlike controllers, Cells can form a class hierarchy. When a cell class
|
|
95
|
-
# is inherited by another cell class, its states are inherited as regular
|
|
96
|
-
# methods are, but also its views are inherited. Whenever a view is looked up,
|
|
97
|
-
# the view finder first looks for a file in the directory belonging to the
|
|
98
|
-
# current cell class, but if this is not found in the application or any
|
|
99
|
-
# engine, the superclass' directory is checked. This continues all the
|
|
100
|
-
# way up until it stops at ::Cell::Base.
|
|
101
|
-
#
|
|
102
|
-
# For instance, when you have two cells:
|
|
103
|
-
# class MenuCell < ::Cell::Base
|
|
104
|
-
# def show
|
|
105
|
-
# end
|
|
106
|
-
#
|
|
107
|
-
# def edit
|
|
108
|
-
# end
|
|
109
|
-
# end
|
|
110
|
-
#
|
|
111
|
-
# class MainMenuCell < MenuCell
|
|
112
|
-
# .. # no need to redefine show/edit if they do the same!
|
|
113
|
-
# end
|
|
114
|
-
# and the following directory structure in <tt>app/cells</tt>:
|
|
115
|
-
# app/cells/
|
|
116
|
-
# menu/
|
|
117
|
-
# show.html.erb
|
|
118
|
-
# edit.html.erb
|
|
119
|
-
# main_menu/
|
|
120
|
-
# show.html.erb
|
|
121
|
-
# then when you call
|
|
122
|
-
# render_cell :main_menu, :show
|
|
123
|
-
# the main menu specific show.html.erb (<tt>app/cells/main_menu/show.html.erb</tt>)
|
|
124
|
-
# is rendered, but when you call
|
|
125
|
-
# render_cell :main_menu, :edit
|
|
126
|
-
# cells notices that the main menu does not have a specific view for the
|
|
127
|
-
# <tt>edit</tt> state, so it will render the view for the parent class,
|
|
128
|
-
# <tt>app/cells/menu/edit.html.erb</tt>
|
|
129
|
-
#
|
|
130
|
-
#
|
|
131
|
-
# == Gettext support
|
|
132
|
-
#
|
|
133
|
-
# Cells support gettext, just name your views accordingly. It works exactly equivalent
|
|
134
|
-
# to controller views.
|
|
135
|
-
#
|
|
136
|
-
# cells/user/user_form.html.erb
|
|
137
|
-
# cells/user/user_form_de.html.erb
|
|
138
|
-
#
|
|
139
|
-
# If gettext is set to DE_de, the latter view will be chosen.
|
|
140
|
-
class Base
|
|
141
|
-
include ::ActionController::Helpers
|
|
142
|
-
include ::ActionController::RequestForgeryProtection
|
|
143
|
-
include ActiveHelper
|
|
144
|
-
|
|
145
|
-
class_inheritable_array :view_paths, :instance_writer => false
|
|
146
|
-
write_inheritable_attribute(:view_paths, ActionView::PathSet.new) # Force use of a PathSet in this attribute, self.view_paths = ActionView::PathSet.new would still yield in an array
|
|
147
|
-
|
|
148
|
-
class << self
|
|
149
|
-
attr_accessor :request_forgery_protection_token
|
|
150
|
-
|
|
151
|
-
# Use this if you want Cells to look up view templates
|
|
152
|
-
# in directories other than the default.
|
|
153
|
-
def view_paths=(paths)
|
|
154
|
-
self.view_paths.clear.concat(paths) # don't let 'em overwrite the PathSet.
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
# A template file will be looked for in each view path. This is typically
|
|
158
|
-
# just RAILS_ROOT/app/cells, but you might want to add e.g.
|
|
159
|
-
# RAILS_ROOT/app/views.
|
|
160
|
-
def add_view_path(path)
|
|
161
|
-
path = File.join(::Rails.root, path) if defined?(::Rails) and ::Rails.respond_to?(:root)
|
|
162
|
-
self.view_paths << path unless self.view_paths.include?(path)
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
# Creates a cell instance of the class <tt>name</tt>Cell, passing through
|
|
166
|
-
# <tt>opts</tt>.
|
|
167
|
-
def create_cell_for(controller, name, opts={})
|
|
168
|
-
class_from_cell_name(name).new(controller, opts)
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
# Declare a controller method as a helper. For example,
|
|
172
|
-
# helper_method :link_to
|
|
173
|
-
# def link_to(name, options) ... end
|
|
174
|
-
# makes the link_to controller method available in the view.
|
|
175
|
-
def helper_method(*methods)
|
|
176
|
-
methods.flatten.each do |method|
|
|
177
|
-
master_helper_module.module_eval <<-end_eval
|
|
178
|
-
def #{method}(*args, &block)
|
|
179
|
-
@cell.send(:#{method}, *args, &block)
|
|
180
|
-
end
|
|
181
|
-
end_eval
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
# Return the default view for the given state on this cell subclass.
|
|
186
|
-
# This is a file with the name of the state under a directory with the
|
|
187
|
-
# name of the cell followed by a template extension.
|
|
188
|
-
def view_for_state(state)
|
|
189
|
-
"#{cell_name}/#{state}"
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
# Find a possible template for a cell's current state. It tries to find a
|
|
193
|
-
# template file with the name of the state under a subdirectory
|
|
194
|
-
# with the name of the cell under the <tt>app/cells</tt> directory.
|
|
195
|
-
# If this file cannot be found, it will try to call this method on
|
|
196
|
-
# the superclass. This way you only have to write a state template
|
|
197
|
-
# once when a more specific cell does not need to change anything in
|
|
198
|
-
# that view.
|
|
199
|
-
def find_class_view_for_state(state)
|
|
200
|
-
return [view_for_state(state)] if superclass == ::Cell::Base
|
|
201
|
-
|
|
202
|
-
superclass.find_class_view_for_state(state) << view_for_state(state)
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
# Get the name of this cell's class as an underscored string,
|
|
206
|
-
# with _cell removed.
|
|
207
|
-
#
|
|
208
|
-
# Example:
|
|
209
|
-
# UserCell.cell_name
|
|
210
|
-
# => "user"
|
|
211
|
-
def cell_name
|
|
212
|
-
name.underscore.sub(/_cell/, '')
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
# Given a cell name, finds the class that belongs to it.
|
|
216
|
-
#
|
|
217
|
-
# Example:
|
|
218
|
-
# ::Cell::Base.class_from_cell_name(:user)
|
|
219
|
-
# => UserCell
|
|
220
|
-
def class_from_cell_name(cell_name)
|
|
221
|
-
"#{cell_name}_cell".classify.constantize
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
def state2view_cache
|
|
225
|
-
@state2view_cache ||= {}
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
def cache_configured?
|
|
229
|
-
::ActionController::Base.cache_configured?
|
|
230
|
-
end
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
class MissingTemplate < ActionView::ActionViewError
|
|
234
|
-
def initialize(message, possible_paths)
|
|
235
|
-
super(message + " and possible paths #{possible_paths}")
|
|
236
|
-
end
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
class_inheritable_accessor :allow_forgery_protection
|
|
240
|
-
self.allow_forgery_protection = true
|
|
241
|
-
|
|
242
|
-
class_inheritable_accessor :default_template_format
|
|
243
|
-
self.default_template_format = :html
|
|
244
|
-
|
|
245
|
-
delegate :params, :session, :request, :logger, :to => :controller
|
|
246
|
-
|
|
247
|
-
attr_accessor :controller
|
|
248
|
-
attr_reader :state_name
|
|
249
|
-
|
|
250
|
-
def initialize(controller, options={})
|
|
251
|
-
@controller = controller
|
|
252
|
-
@opts = options
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
def cell_name
|
|
256
|
-
self.class.cell_name
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
# Render the given state. You can pass the name as either a symbol or
|
|
260
|
-
# a string.
|
|
261
|
-
def render_state(state)
|
|
262
|
-
@cell = self
|
|
263
|
-
@state_name = state
|
|
264
|
-
|
|
265
|
-
content = dispatch_state(state)
|
|
266
|
-
|
|
267
|
-
return content if content.kind_of? String
|
|
268
|
-
|
|
269
|
-
render_view_for_backward_compat(content, state)
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
# Call the state method.
|
|
273
|
-
def dispatch_state(state)
|
|
274
|
-
send(state)
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
# We will soon remove the implicit call to render_view_for, but here it is for your convenience.
|
|
278
|
-
def render_view_for_backward_compat(opts, state)
|
|
279
|
-
::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"
|
|
280
|
-
|
|
281
|
-
render_view_for(opts, state)
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
# Renders the view for the current state and returns the markup for the component.
|
|
285
|
-
# Usually called and returned at the end of a state method.
|
|
286
|
-
#
|
|
287
|
-
# ==== Options
|
|
288
|
-
# * <tt>:view</tt> - Specifies the name of the view file to render. Defaults to the current state name.
|
|
289
|
-
# * <tt>:template_format</tt> - Allows using a format different to <tt>:html</tt>.
|
|
290
|
-
# * <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>.
|
|
291
|
-
# * <tt>:locals</tt> - Makes the named parameters available as variables in the view.
|
|
292
|
-
# * <tt>:text</tt> - Just renders plain text.
|
|
293
|
-
# * <tt>:inline</tt> - Renders an inline template as state view. See ActionView::Base#render for details.
|
|
294
|
-
# * <tt>:file</tt> - Specifies the name of the file template to render.
|
|
295
|
-
# * <tt>:nothing</tt> - Will make the component kinda invisible and doesn't invoke the rendering cycle.
|
|
296
|
-
# * <tt>:state</tt> - Instantly invokes another rendering cycle for the passed state and returns.
|
|
297
|
-
# Example:
|
|
298
|
-
# class MyCell < ::Cell::Base
|
|
299
|
-
# def my_first_state
|
|
300
|
-
# # ... do something
|
|
301
|
-
# render
|
|
302
|
-
# end
|
|
303
|
-
#
|
|
304
|
-
# will just render the view <tt>my_first_state.html</tt>.
|
|
305
|
-
#
|
|
306
|
-
# def my_first_state
|
|
307
|
-
# # ... do something
|
|
308
|
-
# render :view => :my_first_state, :layout => 'metal'
|
|
309
|
-
# end
|
|
310
|
-
#
|
|
311
|
-
# will also use the view <tt>my_first_state.html</tt> as template and even put it in the layout
|
|
312
|
-
# <tt>metal</tt> that's located at <tt>$RAILS_ROOT/app/cells/layouts/metal.html.erb</tt>.
|
|
313
|
-
#
|
|
314
|
-
# def say_your_name
|
|
315
|
-
# render :locals => {:name => "Nick"}
|
|
316
|
-
# end
|
|
317
|
-
#
|
|
318
|
-
# will make the variable +name+ available in the view <tt>say_your_name.html</tt>.
|
|
319
|
-
#
|
|
320
|
-
# def say_your_name
|
|
321
|
-
# render :nothing => true
|
|
322
|
-
# end
|
|
323
|
-
#
|
|
324
|
-
# will render an empty string thus keeping your name a secret.
|
|
325
|
-
#
|
|
326
|
-
#
|
|
327
|
-
# ==== Where have all the partials gone?
|
|
328
|
-
# In Cells we abandoned the term 'partial' in favor of plain 'views' - we don't need to distinguish
|
|
329
|
-
# between both terms. A cell view is both, a view and a kind of partial as it represents only a small
|
|
330
|
-
# part of the page.
|
|
331
|
-
# Just use <tt>:view</tt> and enjoy.
|
|
332
|
-
def render(opts={})
|
|
333
|
-
render_view_for(opts, @state_name) ### FIXME: i don't like the magic access to @state_name here. ugly!
|
|
334
|
-
end
|
|
335
|
-
|
|
336
|
-
# Render the view belonging to the given state. Will raise ActionView::MissingTemplate
|
|
337
|
-
# if it can not find one of the requested view template. Note that this behaviour was
|
|
338
|
-
# introduced in cells 2.3 and replaces the former warning message.
|
|
339
|
-
def render_view_for(opts, state)
|
|
340
|
-
return '' if opts[:nothing]
|
|
341
|
-
|
|
342
|
-
action_view = setup_action_view
|
|
343
|
-
|
|
344
|
-
### TODO: dispatch dynamically:
|
|
345
|
-
if opts[:text]
|
|
346
|
-
elsif opts[:inline]
|
|
347
|
-
elsif opts[:file]
|
|
348
|
-
elsif opts[:state]
|
|
349
|
-
opts[:text] = render_state(opts[:state])
|
|
350
|
-
else
|
|
351
|
-
# handle :layout, :template_format, :view
|
|
352
|
-
opts = defaultize_render_options_for(opts, state)
|
|
353
|
-
|
|
354
|
-
# set instance vars, include helpers:
|
|
355
|
-
prepare_action_view_for(action_view, opts)
|
|
356
|
-
|
|
357
|
-
template = find_family_view_for_state_with_caching(opts[:view], action_view)
|
|
358
|
-
opts[:file] = template
|
|
359
|
-
end
|
|
360
|
-
|
|
361
|
-
opts = sanitize_render_options(opts)
|
|
362
|
-
|
|
363
|
-
action_view.render_for(opts)
|
|
364
|
-
end
|
|
365
|
-
|
|
366
|
-
# Defaultize the passed options from #render.
|
|
367
|
-
def defaultize_render_options_for(opts, state)
|
|
368
|
-
opts[:template_format] ||= self.class.default_template_format
|
|
369
|
-
opts[:view] ||= state
|
|
370
|
-
opts
|
|
371
|
-
end
|
|
372
|
-
|
|
373
|
-
def prepare_action_view_for(action_view, opts)
|
|
374
|
-
# make helpers available:
|
|
375
|
-
include_helpers_in_class(action_view.class)
|
|
376
|
-
|
|
377
|
-
import_active_helpers_into(action_view) # in Cells::Cell::ActiveHelper.
|
|
378
|
-
|
|
379
|
-
action_view.assigns = assigns_for_view # make instance vars available.
|
|
380
|
-
action_view.template_format = opts[:template_format]
|
|
381
|
-
end
|
|
382
|
-
|
|
383
|
-
def setup_action_view
|
|
384
|
-
view_class = Class.new(::Cells::Cell::View)
|
|
385
|
-
action_view = view_class.new(self.class.view_paths, {}, @controller)
|
|
386
|
-
action_view.cell = self
|
|
387
|
-
action_view
|
|
388
|
-
end
|
|
389
|
-
|
|
390
|
-
# Prepares <tt>opts</tt> to be passed to ActionView::Base#render by removing
|
|
391
|
-
# unknown parameters.
|
|
392
|
-
def sanitize_render_options(opts)
|
|
393
|
-
opts.except!(:view, :state)
|
|
394
|
-
end
|
|
395
|
-
|
|
396
|
-
# Climbs up the inheritance hierarchy of the Cell, looking for a view
|
|
397
|
-
# for the current <tt>state</tt> in each level.
|
|
398
|
-
# As soon as a view file is found it is returned as an ActionView::Template
|
|
399
|
-
# instance.
|
|
400
|
-
### DISCUSS: moved to Cell::View#find_template in rainhead's fork:
|
|
401
|
-
def find_family_view_for_state(state, action_view)
|
|
402
|
-
missing_template_exception = nil
|
|
403
|
-
possible_paths = possible_paths_for_state(state)
|
|
404
|
-
|
|
405
|
-
possible_paths.each do |template_path|
|
|
406
|
-
# we need to catch MissingTemplate, since we want to try for all possible
|
|
407
|
-
# family views.
|
|
408
|
-
begin
|
|
409
|
-
if view = action_view.try_picking_template_for_path(template_path)
|
|
410
|
-
return view
|
|
411
|
-
end
|
|
412
|
-
rescue ::ActionView::MissingTemplate => missing_template_exception
|
|
413
|
-
end
|
|
414
|
-
end
|
|
415
|
-
|
|
416
|
-
raise MissingTemplate.new(missing_template_exception.message, possible_paths)
|
|
417
|
-
end
|
|
418
|
-
|
|
419
|
-
# In production mode, the view for a state/template_format is cached.
|
|
420
|
-
### DISCUSS: ActionView::Base already caches results for #pick_template, so maybe
|
|
421
|
-
### we should just cache the family path for a state/format?
|
|
422
|
-
def find_family_view_for_state_with_caching(state, action_view)
|
|
423
|
-
return find_family_view_for_state(state, action_view) unless self.class.cache_configured?
|
|
424
|
-
|
|
425
|
-
# in production mode:
|
|
426
|
-
key = "#{state}/#{action_view.template_format}"
|
|
427
|
-
state2view = self.class.state2view_cache
|
|
428
|
-
state2view[key] || state2view[key] = find_family_view_for_state(state, action_view)
|
|
429
|
-
end
|
|
430
|
-
|
|
431
|
-
# Find possible files that belong to the state. This first tries the cell's
|
|
432
|
-
# <tt>#view_for_state</tt> method and if that returns a true value, it
|
|
433
|
-
# will accept that value as a string and interpret it as a pathname for
|
|
434
|
-
# the view file. If it returns a falsy value, it will call the Cell's class
|
|
435
|
-
# method find_class_view_for_state to determine the file to check.
|
|
436
|
-
#
|
|
437
|
-
# You can override the ::Cell::Base#view_for_state method for a particular
|
|
438
|
-
# cell if you wish to make it decide dynamically what file to render.
|
|
439
|
-
def possible_paths_for_state(state)
|
|
440
|
-
self.class.find_class_view_for_state(state).reverse!
|
|
441
|
-
end
|
|
442
|
-
|
|
443
|
-
# Prepares the hash {instance_var => value, ...} that should be available
|
|
444
|
-
# in the ActionView when rendering the state view.
|
|
445
|
-
def assigns_for_view
|
|
446
|
-
assigns = {}
|
|
447
|
-
(self.instance_variables - ivars_to_ignore).each do |k|
|
|
448
|
-
assigns[k[1..-1]] = instance_variable_get(k)
|
|
449
|
-
end
|
|
450
|
-
assigns
|
|
451
|
-
end
|
|
452
|
-
|
|
453
|
-
# When passed a copy of the ActionView::Base class, it
|
|
454
|
-
# will mix in all helper classes for this cell in that class.
|
|
455
|
-
def include_helpers_in_class(view_klass)
|
|
456
|
-
view_klass.send(:include, self.class.master_helper_module)
|
|
457
|
-
end
|
|
458
|
-
|
|
459
|
-
# Defines the instance variables that should <em>not</em> be copied to the
|
|
460
|
-
# View instance.
|
|
461
|
-
def ivars_to_ignore; ['@controller']; end
|
|
462
|
-
|
|
463
|
-
### TODO: allow log levels.
|
|
464
|
-
def log(message)
|
|
465
|
-
return unless @controller.logger
|
|
466
|
-
@controller.logger.debug(message)
|
|
467
|
-
end
|
|
468
|
-
end
|
|
469
|
-
end
|
|
470
|
-
end
|