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
data/lib/cell/caching.rb DELETED
@@ -1,151 +0,0 @@
1
- # To improve performance rendered state views can be cached using Rails' caching
2
- # mechanism.
3
- # If this it configured (e.g. using our fast friend memcached) all you have to do is to
4
- # tell Cells which state you want to cache. You can further attach a proc to expire the
5
- # cached view.
6
- #
7
- # As always I stole a lot of code, this time from Lance Ivy <cainlevy@gmail.com> and
8
- # his fine components plugin at http://github.com/cainlevy/components.
9
-
10
- module Cell::Caching
11
-
12
- def self.included(base) #:nodoc:
13
- base.class_eval do
14
- # mixin Cell::Base#cache, setup vars and extend #render_state if caching's on.
15
- extend ClassMethods
16
-
17
- return unless cache_configured?
18
-
19
- alias_method_chain :render_state, :caching
20
- end
21
-
22
-
23
- end
24
-
25
-
26
-
27
- module ClassMethods
28
- # Activate caching for the state <tt>state</tt>. If no other options are passed
29
- # the view will be cached forever.
30
- #
31
- # You may pass a Proc or a Symbol as cache expiration <tt>version_proc</tt>.
32
- # This method is called every time the state is rendered, and is expected to return a
33
- # Hash containing the cache key ingredients.
34
- #
35
- # Additional options will be passed directly to the cache store when caching the state.
36
- # Useful for simply setting a TTL for a cached state.
37
- # Note that you may omit the <tt>version_proc</tt>.
38
- #
39
- #
40
- # Example:
41
- # class CachingCell < Cell::Base
42
- # cache :versioned_cached_state, Proc.new{ {:version => 0} }
43
- # would result in the complete cache key
44
- # cells/CachingCell/versioned_cached_state/version=0
45
- #
46
- # If you provide a symbol, you can access the cell instance directly in the versioning
47
- # method:
48
- #
49
- # class CachingCell < Cell::Base
50
- # cache :cached_state, :my_cache_version
51
- #
52
- # def my_cache_version
53
- # { :user => current_user.id,
54
- # :item_id => params[:item] }
55
- # }
56
- # end
57
- # results in a very specific cache key, for customized caching:
58
- # cells/CachingCell/cached_state/user=18/item_id=1
59
- #
60
- # You may also set a TTL only, e.g. when using the memcached store:
61
- #
62
- # cache :cached_state, :expires_in => 3.minutes
63
- #
64
- # Or use both, having a versioning proc <em>and</em> a TTL expiring the state as a fallback
65
- # after a certain amount of time.
66
- #
67
- # cache :cached_state, Proc.new { {:version => 0} }, :expires_in => 10.minutes
68
- #--
69
- ### TODO: implement for string, nil.
70
- ### DISCUSS: introduce return method #sweep ? so the Proc can explicitly
71
- ### delegate re-rendering to the outside.
72
- #--
73
- def cache(state, version_proc=nil, cache_opts={})
74
- if version_proc.is_a?(Hash)
75
- cache_opts = version_proc
76
- version_proc = nil
77
- end
78
-
79
- version_procs[state] = version_proc
80
- cache_options[state] = cache_opts
81
- end
82
-
83
- def version_procs; @version_procs ||= {}; end
84
- def cache_options; @cache_options ||= {}; end
85
-
86
- def cache_store #:nodoc:
87
- @cache_store ||= ActionController::Base.cache_store
88
- end
89
-
90
- def cache_key_for(cell_class, state, args = {}) #:nodoc:
91
- key_pieces = [cell_class, state]
92
-
93
- args.collect{|a,b| [a.to_s, b]}.sort.each{ |k,v| key_pieces << "#{k}=#{v}" }
94
- key = key_pieces.join('/')
95
-
96
- ActiveSupport::Cache.expand_cache_key(key, :cells)
97
- end
98
-
99
- def expire_cache_key(key, opts=nil)
100
- cache_store.delete(key, opts)
101
- end
102
- end
103
-
104
-
105
-
106
- def render_state_with_caching(state)
107
- return render_state_without_caching(state) unless state_cached?(state)
108
-
109
- key = cache_key(state, call_version_proc_for_state(state))
110
- ### DISCUSS: see sweep discussion at #cache.
111
-
112
- # cache hit:
113
- if content = read_fragment(key)
114
- return content
115
- end
116
- # re-render:
117
- return write_fragment(key, render_state_without_caching(state), cache_options[state])
118
- end
119
-
120
-
121
- def read_fragment(key, cache_options = nil) #:nodoc:
122
- returning self.class.cache_store.read(key, cache_options) do |content|
123
- @controller.logger.debug "Cell Cache hit: #{key}" unless content.blank?
124
- end
125
- end
126
-
127
- def write_fragment(key, content, cache_opts = nil) #:nodoc:
128
- @controller.logger.debug "Cell Cache miss: #{key}"
129
- self.class.cache_store.write(key, content, cache_opts)
130
- content
131
- end
132
-
133
- # Call the versioning Proc for the respective state.
134
- def call_version_proc_for_state(state)
135
- version_proc = version_procs[state]
136
-
137
- return {} unless version_proc # call to #cache was without any args.
138
-
139
- return version_proc.call(self) if version_proc.kind_of? Proc
140
- send(version_proc)
141
- end
142
-
143
- def cache_key(state, args = {}) #:nodoc:
144
- self.class.cache_key_for(self.cell_name, state, args)
145
- end
146
-
147
- def state_cached?(state); self.class.version_procs.has_key?(state); end
148
- def version_procs; self.class.version_procs; end
149
- def cache_options; self.class.cache_options; end
150
-
151
- end
data/lib/cell/view.rb DELETED
@@ -1,55 +0,0 @@
1
- module Cell
2
- class View < ::ActionView::Base
3
-
4
- attr_accessor :cell
5
-
6
- alias_method :render_for, :render
7
-
8
- # Tries to find the passed template in view_paths. Returns the view on success-
9
- # otherwise it will throw an ActionView::MissingTemplate exception.
10
- def try_picking_template_for_path(template_path)
11
- self.view_paths.find_template(template_path, template_format)
12
- end
13
-
14
- ### TODO: this should just be a thin helper.
15
- ### dear rails folks, could you guys please provide a helper #render and an internal #render_for
16
- ### so that we can overwrite the helper and cleanly reuse the internal method? using the same
17
- ### method both internally and externally sucks ass.
18
- def render(options = {}, local_assigns = {}, &block)
19
- ### TODO: delegate dynamically:
20
- ### TODO: we have to find out if this is a call to the cells #render method, or to the rails
21
- ### method (e.g. when rendering a layout). what a shit.
22
- if view = options[:view]
23
- return cell.render_view_for(options, view)
24
- end
25
-
26
-
27
- # rails compatibility we should get rid of:
28
- if partial_path = options[:partial]
29
- # adds the cell name to the partial name.
30
- options[:partial] = expand_view_path(partial_path)
31
- end
32
- #throw Exception.new
33
-
34
- super(options, local_assigns, &block)
35
- end
36
-
37
-
38
- def expand_view_path(path)
39
- path = "#{cell.cell_name}/#{path}" unless path.include?('/')
40
- path
41
- end
42
-
43
- # this prevents cell ivars from being overwritten by same-named
44
- # controller ivars.
45
- # we'll hopefully get a cleaner way, or an API, to handle this in rails 3.
46
- def _copy_ivars_from_controller #:nodoc:
47
- if @controller
48
- variables = @controller.instance_variable_names
49
- variables -= @controller.protected_instance_variables if @controller.respond_to?(:protected_instance_variables)
50
- variables -= assigns.keys.collect {|key| "@#{key}"} # cell ivars override controller ivars.
51
- variables.each { |name| instance_variable_set(name, @controller.instance_variable_get(name)) }
52
- end
53
- end
54
- end
55
- end
data/lib/cells_helper.rb DELETED
@@ -1,49 +0,0 @@
1
- # Sorry for the interface violations, but it looks as if there are
2
- # no interfaces in rails at all.
3
- module CellsHelper
4
-
5
- # Executes #capture on the global ActionView and sets <tt>name</tt> as the
6
- # instance variable name.
7
- #
8
- # Example:
9
- #
10
- # <p>
11
- # <% global_capture :greeting do
12
- # <h1>Hi, Nick!</h1>
13
- # <% end %>
14
- #
15
- # The captured markup can be accessed in your global action view or in your layout.
16
- #
17
- # <%= @greeting %>
18
- def global_capture(name, &block)
19
- global_view = controller.instance_variable_get( "@template" )
20
- content = capture &block
21
- global_view.send("instance_variable_set", "@#{name}", content)
22
- end
23
-
24
-
25
- # Executes #content_for on the global ActionView.
26
- #
27
- # Example:
28
- #
29
- # <p>
30
- # <% global_content_for :greetings do
31
- # <h1>Hi, Michal!</h1>
32
- # <% end %>
33
- #
34
- # As in global_capture, the markup can be accessed in your global action view or in your layout.
35
- #
36
- # <%= yield :greetings %>
37
- def global_content_for(name, content = nil, &block)
38
- # OMG.
39
- global_view = controller.instance_variable_get( "@template" )
40
- ivar = "@content_for_#{name}"
41
- content = capture(&block) if block_given?
42
- old_content = global_view.send("instance_variable_get", ivar)
43
-
44
-
45
- global_view.send("instance_variable_set", ivar, "#{old_content}#{content}")
46
-
47
- nil
48
- end
49
- end
@@ -1,75 +0,0 @@
1
- # The Cells plugin defines a number of new methods for ActionView::Base. These allow
2
- # you to render cells from within normal controller views as well as from Cell state views.
3
- module Cell
4
-
5
- module ActionView
6
- # Call a cell state and return its rendered view.
7
- #
8
- # ERB example:
9
- # <div id="login">
10
- # <%= render_cell :user, :login_prompt, :message => "Please login" %>
11
- # </div>
12
- #
13
- # If you have a <tt>UserCell</tt> cell in <tt>app/cells/user_cell.rb</tt>, which has a
14
- # <tt>UserCell#login_prompt</tt> method, this will call that method and then will
15
- # find the view <tt>app/cells/user/login_prompt.html.erb</tt> and render it. This is
16
- # called the <tt>:login_prompt</tt> <em>state</em> in Cells terminology.
17
- #
18
- # If this view file looks like this:
19
- # <h1><%= @opts[:message] %></h1>
20
- # <label>name: <input name="user[name]" /></label>
21
- # <label>password: <input name="user[password]" /></label>
22
- #
23
- # The resulting view in the controller will be roughly equivalent to:
24
- # <div id="login">
25
- # <h1><%= "Please login" %></h1>
26
- # <label>name: <input name="user[name]" /></label>
27
- # <label>password: <input name="user[password]" /></label>
28
- # </div>
29
- def render_cell(name, state, opts = {})
30
- cell = Cell::Base.create_cell_for(@controller, name, opts)
31
- cell.render_state(state)
32
- end
33
- end
34
-
35
-
36
- # These ControllerMethods are automatically added to all Controllers when
37
- # the cells plugin is loaded.
38
- module ActionController
39
-
40
- # Equivalent to ActionController#render_to_string, except it renders a cell
41
- # rather than a regular templates.
42
- def render_cell(name, state, opts={})
43
- cell = Cell::Base.create_cell_for(self, name, opts)
44
-
45
- return cell.render_state(state)
46
- end
47
-
48
- alias_method :render_cell_to_string, :render_cell # just for backward compatibility.
49
-
50
-
51
- # Expires the cached cell state view, similar to ActionController::expire_fragment.
52
- # Usually, this method is used in Sweepers.
53
- # Beside the obvious first two args <tt>cell_name</tt> and <tt>state</tt> you can pass
54
- # in additional cache key <tt>args</tt> and cache store specific <tt>opts</tt>.
55
- #
56
- # Example:
57
- #
58
- # class ListSweeper < ActionController::Caching::Sweeper
59
- # observe List, Item
60
- #
61
- # def after_save(record)
62
- # expire_cell_state :my_listing, :display_list
63
- # end
64
- #
65
- # will expire the view for state <tt>:display_list</tt> in the cell <tt>MyListingCell</tt>.
66
- def expire_cell_state(cell_name, state, args={}, opts=nil)
67
- key = Cell::Base.cache_key_for(cell_name, state, args)
68
- Cell::Base.expire_cache_key(key, opts)
69
- end
70
- end
71
-
72
- end
73
-
74
-
75
-
data/test/capture_test.rb DELETED
@@ -1,56 +0,0 @@
1
- require File.dirname(__FILE__) + '/../../../../test/test_helper'
2
- require File.dirname(__FILE__) + '/testing_helper'
3
-
4
- require File.dirname(__FILE__) + '/cells/test_cell'
5
-
6
- class CaptureTest < ActionController::TestCase
7
- include CellsTestMethods
8
-
9
- def setup
10
- super
11
-
12
- CellTestController.class_eval do
13
- def test_capture
14
- @cell_content = render_cell(:test, :state_invoking_capture)
15
-
16
- # captured_block comes from the cell view:
17
- render :inline => '<h3><%= @captured_block %></h3>'+@cell_content
18
- end
19
-
20
- def test_content_for
21
- @cell_content = render_cell(:test, :state_invoking_content_for)
22
-
23
- # :js comes from the cell views:
24
- render :inline => '<pre><%= yield :js %></pre>'+@cell_content
25
- end
26
- end
27
- end
28
-
29
-
30
- def test_global_capture
31
- TestCell.class_eval do
32
- helper CellsHelper
33
- def state_invoking_capture; render; end
34
- end
35
-
36
- get :test_capture
37
-
38
- assert_select "h1", ""
39
- assert_select "h2", "captured!"
40
- assert_select "h3", "captured!", "captured block not visible in controller"
41
- end
42
-
43
-
44
- def test_global_content_for
45
- TestCell.class_eval do
46
- helper CellsHelper
47
- def state_invoking_content_for; render; end
48
- def state_invoking_content_for_twice; render; end
49
- end
50
- #puts @controller.public_methods
51
- get :test_content_for
52
-
53
- assert_select "js", ""
54
- assert_select "pre", "\nfirst line\n\nsecond line\n\nthird line\n"
55
- end
56
- end
@@ -1,9 +0,0 @@
1
- require File.dirname(__FILE__) + '/../../../../test/test_helper'
2
- require File.dirname(__FILE__) + '/testing_helper'
3
-
4
- require File.dirname(__FILE__) + '/cells/test_cell'
5
-
6
- class CellViewTest < ActionController::TestCase
7
- include CellsTestMethods
8
-
9
- end
@@ -1,5 +0,0 @@
1
- class SimpleCell < Cell::Base
2
- def two_templates_state
3
- render
4
- end
5
- end
@@ -1,25 +0,0 @@
1
- require File.dirname(__FILE__) + '/../../../../test/test_helper'
2
- require File.dirname(__FILE__) + '/testing_helper'
3
-
4
- class ACell < Cell::Base
5
- def existing_view
6
- @a = "a"; render
7
- end
8
- end
9
-
10
- ### DISCUSS: rename file. just found out that rails automagically tries to load a file named
11
- ### after the test, which fails with RailsExtensions.
12
-
13
- class RenderCellTest < ActionController::TestCase
14
- include CellsTestMethods
15
- include Cell::ActionController
16
-
17
- def test_render_cell
18
- assert_equal "A/existing_view/a", render_cell(:a, :existing_view)
19
- end
20
-
21
- # #render_cell_to_string is just an alias of #render_cell
22
- def test_render_cell_to_string
23
- assert_equal render_cell_to_string(:a, :existing_view), render_cell(:a, :existing_view)
24
- end
25
- end
@@ -1,67 +0,0 @@
1
- Cell::Base.add_view_path "vendor/plugins/cells/test/cells"
2
- Cell::Base.add_view_path "vendor/plugins/cells/test/cells/layouts"
3
-
4
- module CellsTestMethods
5
-
6
- def assert_selekt(content, *args)
7
- assert_select(HTML::Document.new(content).root, *args)
8
- end
9
-
10
- def setup
11
- @controller = CellTestController.new
12
- @request = ActionController::TestRequest.new
13
- @response = ActionController::TestResponse.new
14
- @controller.request = @request
15
- @controller.response = @response
16
- @controller.params = {}
17
- end
18
-
19
- def self.views_path
20
- File.dirname(__FILE__) + '/views/'
21
- end
22
- end
23
-
24
-
25
-
26
- class CellTestController < ApplicationController
27
- def rescue_action(e) raise e end
28
-
29
- def render_cell_state
30
- cell = params[:cell]
31
- state = params[:state]
32
-
33
- render :text => render_cell_to_string(cell, state)
34
- end
35
-
36
- def call_render_cell_with_strings
37
- static = render_cell_to_string("my_test", "direct_output")
38
- render :text => static
39
- end
40
-
41
- def call_render_cell_with_syms
42
- static = render_cell_to_string(:my_test, :direct_output)
43
- render :text => static
44
- end
45
-
46
- def call_render_cell_with_state_view
47
- render :text => render_cell_to_string(:my_test, :view_with_instance_var)
48
- return
49
- end
50
-
51
- def render_view_with_render_cell_invocation
52
- render :file => "#{RAILS_ROOT}/vendor/plugins/cells/test/views/view_with_render_cell_invocation.html.erb"
53
- return
54
- end
55
-
56
- def render_just_one_view_cell
57
- static = render_cell_to_string("just_one_view", "some_state")
58
- render :text => static
59
- end
60
-
61
-
62
- def render_state_with_link_to
63
- static = render_cell_to_string("my_test", "state_with_link_to")
64
- render :text => static
65
- end
66
-
67
- end