cells 3.3.10 → 3.4.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +0 -8
- data/Gemfile +4 -1
- data/README.rdoc +91 -107
- data/Rakefile +0 -4
- data/lib/cell.rb +5 -6
- data/lib/{cells/cell → cell}/active_helper.rb +1 -1
- data/lib/cell/base.rb +134 -0
- data/lib/cell/base_methods.rb +100 -0
- data/lib/cell/caching.rb +153 -0
- data/lib/cell/rails.rb +239 -0
- data/lib/cells.rb +25 -3
- data/lib/cells/assertions_helper.rb +1 -1
- data/lib/cells/helpers/capture_helper.rb +3 -3
- data/lib/cells/rails.rb +65 -4
- data/lib/cells/version.rb +3 -1
- data/rails_generators/cell/cell_generator.rb +47 -35
- data/rails_generators/cell/templates/cell.rb +1 -1
- data/rails_generators/cells_install/cells_install_generator.rb +5 -3
- data/rails_generators/erb/cell_generator.rb +20 -0
- data/rails_generators/{cell → erb}/templates/view.html.erb +0 -0
- data/test/active_helper_test.rb +1 -0
- data/test/app/cells/bad_guitarist_cell.rb +2 -0
- data/test/app/cells/bassist_cell.rb +1 -1
- data/test/app/controllers/musician_controller.rb +16 -0
- data/test/assertions_helper_test.rb +8 -18
- data/test/base_methods_test.rb +40 -0
- data/test/cell_generator_test.rb +33 -21
- data/test/helper_test.rb +31 -123
- data/test/rails/caching_test.rb +215 -0
- data/test/rails/capture_test.rb +52 -0
- data/test/rails/cells_test.rb +88 -0
- data/test/rails/integration_test.rb +37 -0
- data/test/rails/render_test.rb +140 -0
- data/test/rails/router_test.rb +74 -0
- data/test/rails/view_test.rb +24 -0
- data/test/test_helper.rb +30 -29
- metadata +68 -133
- data/.gitignore +0 -3
- data/about.yml +0 -7
- data/cells.gemspec +0 -26
- data/lib/cells/cell.rb +0 -16
- data/lib/cells/cell/base.rb +0 -470
- data/lib/cells/cell/caching.rb +0 -163
- data/lib/cells/cell/test_case.rb +0 -158
- data/lib/cells/cell/view.rb +0 -55
- data/lib/cells/rails/action_controller.rb +0 -37
- data/lib/cells/rails/action_view.rb +0 -37
- data/rails/init.rb +0 -44
- data/rails_generators/cells_install/templates/tasks.rake +0 -6
- data/test/app/cells/a/another_state.html.erb +0 -1
- data/test/app/cells/a/existing_view.html.erb +0 -1
- data/test/app/cells/a/inherited_view.html.erb +0 -1
- data/test/app/cells/a/inherited_view.js.erb +0 -1
- data/test/app/cells/a/view_with_locals.html.erb +0 -1
- data/test/app/cells/a/view_with_render_call.html.erb +0 -1
- data/test/app/cells/b/existing_view.html.erb +0 -1
- data/test/app/cells/b/existing_view.js.erb +0 -1
- data/test/app/cells/b/layouts/metal.html.erb +0 -1
- data/test/app/cells/b/view_with_render_call.html.erb +0 -1
- data/test/app/cells/bassist/jam.html.erb +0 -3
- data/test/app/cells/bassist/play.html.erb +0 -1
- data/test/app/cells/cells_test_one/renamed_instance_view.html.erb +0 -1
- data/test/app/cells/cells_test_one/super_state.html.erb +0 -1
- data/test/app/cells/cells_test_one_cell.rb +0 -20
- data/test/app/cells/cells_test_two_cell.rb +0 -4
- data/test/app/cells/helper_using/state_using_application_helper.html.erb +0 -3
- data/test/app/cells/helper_using/state_with_automatic_helper_invocation.html.erb +0 -3
- data/test/app/cells/helper_using/state_with_helper_invocation.html.erb +0 -3
- data/test/app/cells/helper_using/state_with_helper_method_invocation.html.erb +0 -3
- data/test/app/cells/layouts/metal.html.erb +0 -1
- data/test/app/cells/my_child/hello.html.erb +0 -1
- data/test/app/cells/my_mother/bye.html.erb +0 -1
- data/test/app/cells/my_mother/hello.html.erb +0 -1
- data/test/app/cells/my_test/_broken_partial.html.erb +0 -1
- data/test/app/cells/my_test/_partial.html.erb +0 -1
- data/test/app/cells/my_test/state_with_instance_var.html.erb +0 -1
- data/test/app/cells/my_test/state_with_link_to.html.erb +0 -3
- data/test/app/cells/my_test/state_with_not_included_helper_method.html.erb +0 -8
- data/test/app/cells/my_test/view_containing_broken_partial.html.erb +0 -3
- data/test/app/cells/my_test/view_containing_nonexistant_partial.html.erb +0 -3
- data/test/app/cells/my_test/view_containing_partial.html.erb +0 -3
- data/test/app/cells/my_test/view_containing_partial_without_cell_name.html.erb +0 -3
- data/test/app/cells/my_test/view_in_local_test_views_dir.html.erb +0 -1
- data/test/app/cells/my_test/view_with_explicit_english_translation.en.html.erb +0 -1
- data/test/app/cells/my_test/view_with_explicit_english_translation.html.erb +0 -1
- data/test/app/cells/my_test/view_with_instance_var.html.erb +0 -4
- data/test/app/cells/really_module/nested/happy_state.html.erb +0 -1
- data/test/app/cells/really_module/nested_cell.rb +0 -11
- data/test/app/cells/simple/two_templates_state.html.mytpl +0 -1
- data/test/app/cells/simple_cell.rb +0 -7
- data/test/app/cells/test/beep.html.erb +0 -1
- data/test/app/cells/test/state_invoking_capture.html.erb +0 -7
- data/test/app/cells/test/state_invoking_content_for.html.erb +0 -7
- data/test/app/cells/test/state_invoking_content_for_twice.html.erb +0 -9
- data/test/app/cells/test/state_with_not_included_helper_method.html.erb +0 -8
- data/test/app/cells/two_helpers_including/state_using_another_helper.html.erb +0 -3
- data/test/bugs_test.rb +0 -23
- data/test/caching_test.rb +0 -270
- data/test/capture_helper_test.rb +0 -59
- data/test/cells_test.rb +0 -352
- data/test/rails_test.rb +0 -35
- data/test/render_test.rb +0 -305
- data/test/test_case_test.rb +0 -106
data/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)
|