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/lib/cell/caching.rb
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
# To improve performance rendered state views can be cached using Rails' caching
|
|
4
|
+
# mechanism.
|
|
5
|
+
# If this it configured (e.g. using our fast friend memcached) all you have to do is to
|
|
6
|
+
# tell Cells which state to cache. You can further attach a proc to expire the
|
|
7
|
+
# cached view.
|
|
8
|
+
#
|
|
9
|
+
# As always I stole a lot of code, this time from Lance Ivy <cainlevy@gmail.com> and
|
|
10
|
+
# his fine components plugin at http://github.com/cainlevy/components.
|
|
11
|
+
|
|
12
|
+
module Cell
|
|
13
|
+
module Caching
|
|
14
|
+
|
|
15
|
+
def self.included(base) #:nodoc:
|
|
16
|
+
base.class_eval do
|
|
17
|
+
extend ClassMethods
|
|
18
|
+
|
|
19
|
+
alias_method_chain :render_state, :caching
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module ClassMethods
|
|
24
|
+
# Activate caching for the state <tt>state</tt>. If no other options are passed
|
|
25
|
+
# the view will be cached forever.
|
|
26
|
+
#
|
|
27
|
+
# You may pass a Proc or a Symbol as cache expiration <tt>version_proc</tt>.
|
|
28
|
+
# This method is called every time the state is rendered, and is expected to return a
|
|
29
|
+
# Hash containing the cache key ingredients.
|
|
30
|
+
#
|
|
31
|
+
# Additional options will be passed directly to the cache store when caching the state.
|
|
32
|
+
# Useful for simply setting a TTL for a cached state.
|
|
33
|
+
# Note that you may omit the <tt>version_proc</tt>.
|
|
34
|
+
#
|
|
35
|
+
#
|
|
36
|
+
# Example:
|
|
37
|
+
# class CachingCell < ::Cell::Base
|
|
38
|
+
# cache :versioned_cached_state, Proc.new{ {:version => 0} }
|
|
39
|
+
# would result in the complete cache key
|
|
40
|
+
# cells/CachingCell/versioned_cached_state/version=0
|
|
41
|
+
#
|
|
42
|
+
# If you provide a symbol, you can access the cell instance directly in the versioning
|
|
43
|
+
# method:
|
|
44
|
+
#
|
|
45
|
+
# class CachingCell < ::Cell::Base
|
|
46
|
+
# cache :cached_state, :my_cache_version
|
|
47
|
+
#
|
|
48
|
+
# def my_cache_version
|
|
49
|
+
# { :user => current_user.id,
|
|
50
|
+
# :item_id => params[:item] }
|
|
51
|
+
# }
|
|
52
|
+
# end
|
|
53
|
+
# results in a very specific cache key, for customized caching:
|
|
54
|
+
# cells/CachingCell/cached_state/user=18/item_id=1
|
|
55
|
+
#
|
|
56
|
+
# You may also set a TTL only, e.g. when using the memcached store:
|
|
57
|
+
#
|
|
58
|
+
# cache :cached_state, :expires_in => 3.minutes
|
|
59
|
+
#
|
|
60
|
+
# Or use both, having a versioning proc <em>and</em> a TTL expiring the state as a fallback
|
|
61
|
+
# after a certain amount of time.
|
|
62
|
+
#
|
|
63
|
+
# cache :cached_state, Proc.new { {:version => 0} }, :expires_in => 10.minutes
|
|
64
|
+
#--
|
|
65
|
+
### TODO: implement for string, nil.
|
|
66
|
+
### DISCUSS: introduce return method #sweep ? so the Proc can explicitly
|
|
67
|
+
### delegate re-rendering to the outside.
|
|
68
|
+
#--
|
|
69
|
+
def cache(state, version_proc=nil, cache_opts={})
|
|
70
|
+
if version_proc.is_a?(Hash)
|
|
71
|
+
cache_opts = version_proc
|
|
72
|
+
version_proc = nil
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
version_procs[state] = version_proc
|
|
76
|
+
cache_options[state] = cache_opts
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def version_procs
|
|
80
|
+
@version_procs ||= {}
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def cache_options
|
|
84
|
+
@cache_options ||= {}
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def cache_store #:nodoc:
|
|
88
|
+
::ActionController::Base.cache_store
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def cache_key_for(cell_class, state, args = {}) #:nodoc:
|
|
92
|
+
key_pieces = [cell_class, state]
|
|
93
|
+
|
|
94
|
+
args.collect{|a,b| [a.to_s, b]}.sort.each{ |k,v| key_pieces << "#{k}=#{v}" }
|
|
95
|
+
key = key_pieces.join('/')
|
|
96
|
+
|
|
97
|
+
::ActiveSupport::Cache.expand_cache_key(key, :cells)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def expire_cache_key(key, opts=nil)
|
|
101
|
+
cache_store.delete(key, opts)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def cache_configured?
|
|
105
|
+
::ActionController::Base.cache_configured?
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def render_state_with_caching(state, request=ActionDispatch::Request.new({}))
|
|
110
|
+
return render_state_without_caching(state, request) unless state_cached?(state)
|
|
111
|
+
|
|
112
|
+
key = cache_key(state, call_version_proc_for_state(state))
|
|
113
|
+
### DISCUSS: see sweep discussion at #cache.
|
|
114
|
+
|
|
115
|
+
# cache hit:
|
|
116
|
+
if content = read_fragment(key)
|
|
117
|
+
return content
|
|
118
|
+
end
|
|
119
|
+
# re-render:
|
|
120
|
+
return write_fragment(key, render_state_without_caching(state, request), self.class.cache_options[state])
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def read_fragment(key, cache_options = nil) #:nodoc:
|
|
124
|
+
returning self.class.cache_store.read(key, cache_options) do |content|
|
|
125
|
+
log "Cell Cache hit: #{key}" unless content.blank?
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def write_fragment(key, content, cache_opts = nil) #:nodoc:
|
|
130
|
+
log "Cell Cache miss: #{key}"
|
|
131
|
+
self.class.cache_store.write(key, content, cache_opts)
|
|
132
|
+
content
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Call the versioning Proc for the respective state.
|
|
136
|
+
def call_version_proc_for_state(state)
|
|
137
|
+
version_proc = self.class.version_procs[state]
|
|
138
|
+
|
|
139
|
+
return {} unless version_proc # call to #cache was without any args.
|
|
140
|
+
|
|
141
|
+
return version_proc.call(self) if version_proc.kind_of?(Proc)
|
|
142
|
+
send(version_proc)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def cache_key(state, args = {}) #:nodoc:
|
|
146
|
+
self.class.cache_key_for(self.cell_name, state, args)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def state_cached?(state)
|
|
150
|
+
self.class.version_procs.has_key?(state)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
data/lib/cell/rails.rb
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
require 'abstract_controller'
|
|
2
|
+
require 'action_controller'
|
|
3
|
+
|
|
4
|
+
module Cell
|
|
5
|
+
class Rails < ActionController::Metal
|
|
6
|
+
include BaseMethods
|
|
7
|
+
include AbstractController
|
|
8
|
+
include Rendering, Layouts, Helpers, Callbacks, Translation
|
|
9
|
+
include ActionController::RequestForgeryProtection
|
|
10
|
+
#include AbstractController::Logger
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
#include Cell::ActiveHelper
|
|
14
|
+
cattr_accessor :url_helpers ### TODO: discuss if we really need that or can handle that in cells.rb already.
|
|
15
|
+
|
|
16
|
+
abstract!
|
|
17
|
+
|
|
18
|
+
### DISCUSS: should we pass the parent_controller here?
|
|
19
|
+
def initialize(parent_controller=nil, options={}) ### FIXME: move to BaseMethods.
|
|
20
|
+
@parent_controller = parent_controller
|
|
21
|
+
@opts = @options = options
|
|
22
|
+
end
|
|
23
|
+
attr_reader :parent_controller
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def log(*args); end
|
|
27
|
+
|
|
28
|
+
class View < ActionView::Base
|
|
29
|
+
def render(options = {}, locals = {}, &block)
|
|
30
|
+
if options[:state] or options[:view]
|
|
31
|
+
return @_controller.render(options, &block)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
super
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.view_context_class
|
|
39
|
+
controller = self
|
|
40
|
+
# Unfortunately, there is currently an abstraction leak between AC::Base
|
|
41
|
+
# and AV::Base which requires having the URL helpers in both AC and AV.
|
|
42
|
+
# To do this safely at runtime for tests, we need to bump up the helper serial
|
|
43
|
+
# to that the old AV subclass isn't cached.
|
|
44
|
+
#
|
|
45
|
+
# TODO: Make this unnecessary
|
|
46
|
+
#if @controller
|
|
47
|
+
# @controller.singleton_class.send(:include, _routes.url_helpers)
|
|
48
|
+
# @controller.view_context_class = Class.new(@controller.view_context_class) do
|
|
49
|
+
# include _routes.url_helpers
|
|
50
|
+
|
|
51
|
+
View.class_eval do
|
|
52
|
+
|
|
53
|
+
include controller._helpers
|
|
54
|
+
|
|
55
|
+
include Cell::Base.url_helpers if Cell::Rails.respond_to?(:url_helpers) and Cell::Rails.url_helpers
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@view_context_class ||= View
|
|
60
|
+
### DISCUSS: copy behaviour from abstract_controller/rendering-line 49? (helpers)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.controller_path
|
|
64
|
+
@controller_path ||= name.sub(/Cell$/, '').underscore unless anonymous?
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def process(*) # defined in AC::Metal.
|
|
68
|
+
self.response_body = super ### TODO: discuss with yehuda.
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
#attr_internal :request
|
|
72
|
+
delegate :request, :to => :parent_controller
|
|
73
|
+
delegate :config, :to => :parent_controller # DISCUSS: what if a cell has its own config (eg for assets, cells/bassist/images)?
|
|
74
|
+
# DISCUSS: let @controller point to @parent_controller in views, and @cell is the actual real controller?
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def render_state(state, request=ActionDispatch::Request.new({})) ### FIXME: where to set Request if none given? leave blank?
|
|
78
|
+
rack_response = dispatch(state, parent_controller.request)
|
|
79
|
+
|
|
80
|
+
return rack_response[2].last if rack_response[2].kind_of?(Array) ### FIXME: HACK for testing, wtf is going on here?
|
|
81
|
+
rack_response[2] ### TODO: discuss with yehuda.
|
|
82
|
+
# rack_response in test mode: [nil, nil, ["Doo"]]
|
|
83
|
+
# rack_response in dev mode: [nil, nil, "<div>..."]
|
|
84
|
+
end
|
|
85
|
+
include Cell::Caching
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class << self
|
|
91
|
+
def state2view_cache
|
|
92
|
+
@state2view_cache ||= {}
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
# Renders the view for the current state and returns the markup for the component.
|
|
98
|
+
# Usually called and returned at the end of a state method.
|
|
99
|
+
#
|
|
100
|
+
# ==== Options
|
|
101
|
+
# * <tt>:view</tt> - Specifies the name of the view file to render. Defaults to the current state name.
|
|
102
|
+
# * <tt>:template_format</tt> - Allows using a format different to <tt>:html</tt>.
|
|
103
|
+
# * <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>.
|
|
104
|
+
# * <tt>:locals</tt> - Makes the named parameters available as variables in the view.
|
|
105
|
+
# * <tt>:text</tt> - Just renders plain text.
|
|
106
|
+
# * <tt>:inline</tt> - Renders an inline template as state view. See ActionView::Base#render for details.
|
|
107
|
+
# * <tt>:file</tt> - Specifies the name of the file template to render.
|
|
108
|
+
# * <tt>:nothing</tt> - Will make the component kinda invisible and doesn't invoke the rendering cycle.
|
|
109
|
+
# * <tt>:state</tt> - Instantly invokes another rendering cycle for the passed state and returns.
|
|
110
|
+
# Example:
|
|
111
|
+
# class MyCell < ::Cell::Base
|
|
112
|
+
# def my_first_state
|
|
113
|
+
# # ... do something
|
|
114
|
+
# render
|
|
115
|
+
# end
|
|
116
|
+
#
|
|
117
|
+
# will just render the view <tt>my_first_state.html</tt>.
|
|
118
|
+
#
|
|
119
|
+
# def my_first_state
|
|
120
|
+
# # ... do something
|
|
121
|
+
# render :view => :my_first_state, :layout => 'metal'
|
|
122
|
+
# end
|
|
123
|
+
#
|
|
124
|
+
# will also use the view <tt>my_first_state.html</tt> as template and even put it in the layout
|
|
125
|
+
# <tt>metal</tt> that's located at <tt>$RAILS_ROOT/app/cells/layouts/metal.html.erb</tt>.
|
|
126
|
+
#
|
|
127
|
+
# def say_your_name
|
|
128
|
+
# render :locals => {:name => "Nick"}
|
|
129
|
+
# end
|
|
130
|
+
#
|
|
131
|
+
# will make the variable +name+ available in the view <tt>say_your_name.html</tt>.
|
|
132
|
+
#
|
|
133
|
+
# def say_your_name
|
|
134
|
+
# render :nothing => true
|
|
135
|
+
# end
|
|
136
|
+
#
|
|
137
|
+
# will render an empty string thus keeping your name a secret.
|
|
138
|
+
#
|
|
139
|
+
#
|
|
140
|
+
# ==== Where have all the partials gone?
|
|
141
|
+
# In Cells we abandoned the term 'partial' in favor of plain 'views' - we don't need to distinguish
|
|
142
|
+
# between both terms. A cell view is both, a view and a kind of partial as it represents only a small
|
|
143
|
+
# part of the page.
|
|
144
|
+
# Just use <tt>:view</tt> and enjoy.
|
|
145
|
+
def render(opts={})
|
|
146
|
+
render_view_for(opts, self.action_name)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
# Climbs up the inheritance hierarchy of the Cell, looking for a view
|
|
152
|
+
# for the current <tt>state</tt> in each level.
|
|
153
|
+
# As soon as a view file is found it is returned as an ActionView::Template
|
|
154
|
+
# instance.
|
|
155
|
+
### DISCUSS: moved to Cell::View#find_template in rainhead's fork:
|
|
156
|
+
def find_family_view_for_state(state)
|
|
157
|
+
missing_template_exception = nil
|
|
158
|
+
|
|
159
|
+
possible_paths_for_state(state).each do |template_path|
|
|
160
|
+
# we need to catch MissingTemplate, since we want to try for all possible family views.
|
|
161
|
+
begin
|
|
162
|
+
template = find_template(template_path)
|
|
163
|
+
return template if template
|
|
164
|
+
rescue ::ActionView::MissingTemplate => missing_template_exception
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
raise missing_template_exception
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# In production mode, the view for a state/template_format is cached.
|
|
172
|
+
### DISCUSS: ActionView::Base already caches results for #pick_template, so maybe
|
|
173
|
+
### we should just cache the family path for a state/format?
|
|
174
|
+
def find_family_view_for_state_with_caching(state)
|
|
175
|
+
return find_family_view_for_state(state) unless self.class.cache_configured?
|
|
176
|
+
|
|
177
|
+
# in production mode:
|
|
178
|
+
key = "#{state}/#{action_view.template_format}"
|
|
179
|
+
state2view = self.class.state2view_cache
|
|
180
|
+
state2view[key] || state2view[key] = find_family_view_for_state(state, action_view)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
# Render the view belonging to the given state. Will raise ActionView::MissingTemplate
|
|
188
|
+
# if it can not find one of the requested view template. Note that this behaviour was
|
|
189
|
+
# introduced in cells 2.3 and replaces the former warning message.
|
|
190
|
+
def render_view_for(opts, state)
|
|
191
|
+
return '' if opts[:nothing]
|
|
192
|
+
|
|
193
|
+
### TODO: dispatch dynamically:
|
|
194
|
+
if opts[:text] ### FIXME: generic option?
|
|
195
|
+
elsif opts[:inline]
|
|
196
|
+
elsif opts[:file]
|
|
197
|
+
elsif opts[:state] ### FIXME: generic option
|
|
198
|
+
opts[:text] = render_state(opts[:state])
|
|
199
|
+
else
|
|
200
|
+
# handle :layout, :template_format, :view
|
|
201
|
+
opts = defaultize_render_options_for(opts, state)
|
|
202
|
+
|
|
203
|
+
# set instance vars, include helpers:
|
|
204
|
+
#prepare_action_view_for(action_view, opts)
|
|
205
|
+
|
|
206
|
+
#template = find_family_view_for_state_with_caching(opts[:view], action_view)
|
|
207
|
+
template = find_family_view_for_state(opts[:view])
|
|
208
|
+
opts[:template] = template
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
opts = sanitize_render_options(opts)
|
|
212
|
+
|
|
213
|
+
render_to_string(opts)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# Defaultize the passed options from #render.
|
|
217
|
+
def defaultize_render_options_for(opts, state)
|
|
218
|
+
opts[:template_format] ||= self.class.default_template_format
|
|
219
|
+
opts[:view] ||= state
|
|
220
|
+
opts
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def prepare_action_view_for(action_view, opts)
|
|
224
|
+
# make helpers available:
|
|
225
|
+
include_helpers_in_class(action_view.class)
|
|
226
|
+
|
|
227
|
+
import_active_helpers_into(action_view) # in Cells::Cell::ActiveHelper.
|
|
228
|
+
|
|
229
|
+
action_view.assigns = assigns_for_view # make instance vars available.
|
|
230
|
+
action_view.template_format = opts[:template_format]
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Prepares <tt>opts</tt> to be passed to ActionView::Base#render by removing
|
|
234
|
+
# unknown parameters.
|
|
235
|
+
def sanitize_render_options(opts)
|
|
236
|
+
opts.except!(:view, :state)
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
data/lib/cells.rb
CHANGED
|
@@ -21,9 +21,14 @@ rescue
|
|
|
21
21
|
require 'action_view'
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
require '
|
|
25
|
-
|
|
24
|
+
require 'cell/base_methods'
|
|
25
|
+
|
|
26
26
|
require 'cell'
|
|
27
|
+
require 'cells/rails' # helper.
|
|
28
|
+
require 'cell/rails'
|
|
29
|
+
|
|
30
|
+
require 'cells/helpers'
|
|
31
|
+
|
|
27
32
|
|
|
28
33
|
module Cells
|
|
29
34
|
# Any config should be placed here using +mattr_accessor+.
|
|
@@ -63,7 +68,24 @@ module Cells
|
|
|
63
68
|
end
|
|
64
69
|
end
|
|
65
70
|
|
|
71
|
+
Cell::Base = Cell::Rails
|
|
72
|
+
|
|
66
73
|
Cell::Base.view_paths = Cells::DEFAULT_VIEW_PATHS if Cell::Base.view_paths.blank?
|
|
67
74
|
|
|
68
75
|
require 'cells/rails'
|
|
69
|
-
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
require "rails/railtie"
|
|
79
|
+
class Cells::Railtie < Rails::Railtie
|
|
80
|
+
initializer "cells.attach_router" do |app|
|
|
81
|
+
Cell::Rails.class_eval do
|
|
82
|
+
include app.routes.url_helpers
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
Cell::Base.url_helpers = app.routes.url_helpers
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
initializer "cells.add_load_path" do |app|
|
|
89
|
+
#ActiveSupport::Dependencies.load_paths << Rails.root.join(*%w[app cells])
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -40,7 +40,7 @@ module Cells
|
|
|
40
40
|
# Example:
|
|
41
41
|
# assert_equal "Banks kill planet!" cell(:news, :topic => :terror).latest_headline
|
|
42
42
|
def cell(name, opts={}, &block)
|
|
43
|
-
cell = Cell::Base.create_cell_for(@controller, name, opts)
|
|
43
|
+
cell = ::Cell::Base.create_cell_for(@controller, name, opts)
|
|
44
44
|
cell.instance_eval &block if block_given?
|
|
45
45
|
cell
|
|
46
46
|
end
|
|
@@ -19,7 +19,7 @@ module Cells
|
|
|
19
19
|
#
|
|
20
20
|
# <%= @greeting %>
|
|
21
21
|
def global_capture(name, &block)
|
|
22
|
-
global_view = controller.
|
|
22
|
+
global_view = controller.parent_controller.view_context
|
|
23
23
|
content = capture(&block)
|
|
24
24
|
global_view.send(:instance_variable_set, :"@#{name}", content)
|
|
25
25
|
end
|
|
@@ -38,8 +38,8 @@ module Cells
|
|
|
38
38
|
#
|
|
39
39
|
# <%= yield :greetings %>
|
|
40
40
|
def global_content_for(name, content = nil, &block)
|
|
41
|
-
# OMG.
|
|
42
|
-
global_view = controller.
|
|
41
|
+
# OMG. that SUCKS.
|
|
42
|
+
global_view = controller.parent_controller.view_context
|
|
43
43
|
ivar = :"@content_for_#{name}"
|
|
44
44
|
content = capture(&block) if block_given?
|
|
45
45
|
old_content = global_view.send(:'instance_variable_get', ivar)
|