cells 3.4.0 → 3.4.1
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/README.rdoc +9 -6
- data/lib/cell/test_case.rb +108 -0
- data/lib/cells.rb +5 -1
- data/lib/cells/version.rb +1 -1
- data/lib/generators/cells/USAGE +6 -14
- data/lib/generators/cells/templates/cell_test.rb +6 -8
- data/lib/tasks.rake +6 -0
- data/test/cell_generator_test.rb +1 -1
- data/test/cell_module_test.rb +2 -0
- data/test/dummy/tmp/test/cells/blog_cell_test.rb +9 -11
- data/test/helper_test.rb +2 -0
- data/test/rails/caching_test.rb +2 -0
- data/test/rails/cells_test.rb +15 -0
- data/test/rails/render_test.rb +2 -0
- data/test/rails/view_test.rb +2 -0
- data/test/test_case_test.rb +78 -0
- data/test/test_helper.rb +5 -7
- metadata +7 -9
- data/lib/cell/base.rb +0 -134
- data/lib/cells/assertions_helper.rb +0 -49
- data/test/assertions_helper_test.rb +0 -32
- data/test/support/internal_assertions_helper.rb +0 -69
data/README.rdoc
CHANGED
|
@@ -115,14 +115,17 @@ There are multiple advanced options for expiring your view caches, including an
|
|
|
115
115
|
|
|
116
116
|
Another big advantage compared to monolithic controller/helper/partial piles is the ability to test your cells isolated.
|
|
117
117
|
|
|
118
|
-
So what if you wanna test the cart cell? Use the generated <tt>test/cells/
|
|
118
|
+
So what if you wanna test the cart cell? Use the generated <tt>test/cells/shopping_cart_cell_test.rb</tt> test.
|
|
119
119
|
|
|
120
|
-
class
|
|
121
|
-
include Cells::AssertionsHelper
|
|
122
|
-
|
|
120
|
+
class ShoppingCartCellTest < Cell::TestCase
|
|
123
121
|
test "display" do
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
invoke :display, :user => @user_fixture
|
|
123
|
+
assert_select "#cart", "You have 3 items in your shopping cart."
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
Run your tests with
|
|
127
|
+
|
|
128
|
+
$ rake test:cells
|
|
126
129
|
|
|
127
130
|
That's easy, clean and strongly improves your component-driven software quality. How'd you do that with partials?
|
|
128
131
|
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
module Cell
|
|
2
|
+
# Test your cells.
|
|
3
|
+
#
|
|
4
|
+
# This class is roughly equal to ActionController::TestCase, exposing the same semantics. It will try
|
|
5
|
+
# to infer the tested cell name from the test name if you use declarative testing. You can also set it
|
|
6
|
+
# with TestCase.tests.
|
|
7
|
+
#
|
|
8
|
+
# A declarative test would look like
|
|
9
|
+
#
|
|
10
|
+
# class SellOutTest < Cell::TestCase
|
|
11
|
+
# tests ShoppingCartCell
|
|
12
|
+
#
|
|
13
|
+
# it "should be rendered nicely" do
|
|
14
|
+
# invoke :order_button, :items => @fixture_items
|
|
15
|
+
#
|
|
16
|
+
# assert_select "button", "Order now!"
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# You can also do stuff yourself, like
|
|
20
|
+
#
|
|
21
|
+
# it "should be rendered even nicer" do
|
|
22
|
+
# html = render_cell(:shopping_cart, :order_button, , :items => @fixture_items)
|
|
23
|
+
# assert_selector "button", "Order now!", html
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
# Or even unit test your cell:
|
|
27
|
+
#
|
|
28
|
+
# it "should provide #default_items" do
|
|
29
|
+
# assert_equal [@item1, @item2], cell(:shopping_cart).default_items
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# == Test helpers
|
|
33
|
+
#
|
|
34
|
+
# Basically, we got these new methods:
|
|
35
|
+
#
|
|
36
|
+
# +invoke+:: Renders the passed +state+ with your tested cell. You may pass options like in #render_cell.
|
|
37
|
+
# +render_cell+:: As in your views. Will return the rendered view.
|
|
38
|
+
# +assert_selector+:: Like #assert_select except that the last argument is the html markup you wanna test.
|
|
39
|
+
# +cell+:: Gives you a cell instance for unit testing and stuff.
|
|
40
|
+
class TestCase < ActiveSupport::TestCase
|
|
41
|
+
module AssertSelect
|
|
42
|
+
# Invokes assert_select for the last argument, the +content+ string.
|
|
43
|
+
#
|
|
44
|
+
# Example:
|
|
45
|
+
# assert_selector "h1", "The latest and greatest!", "<h1>The latest and greatest!</h1>"
|
|
46
|
+
#
|
|
47
|
+
# would be true.
|
|
48
|
+
def assert_selector(*args, &block)
|
|
49
|
+
rails_assert_select(HTML::Document.new(args.pop).root, *args, &block)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Invokes assert_select on the markup set by the last #invoke.
|
|
53
|
+
#
|
|
54
|
+
# Example:
|
|
55
|
+
# invoke :latest
|
|
56
|
+
# assert_select "h1", "The latest and greatest!"
|
|
57
|
+
def assert_select(*args, &block)
|
|
58
|
+
super(HTML::Document.new(last_invoke).root, *args, &block)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
module TestMethods
|
|
63
|
+
def setup
|
|
64
|
+
@controller = Class.new(ActionController::Base).new
|
|
65
|
+
@request = ::ActionController::TestRequest.new
|
|
66
|
+
@response = ::ActionController::TestResponse.new
|
|
67
|
+
@controller.request = @request
|
|
68
|
+
@controller.response = @response
|
|
69
|
+
@controller.params = {}
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Use this for functional tests of your application cells.
|
|
73
|
+
#
|
|
74
|
+
# Example:
|
|
75
|
+
# should "spit out a h1 title" do
|
|
76
|
+
# html = render_cell(:news, :latest)
|
|
77
|
+
# assert_selekt html, "h1", "The latest and greatest!"
|
|
78
|
+
def render_cell(*args)
|
|
79
|
+
@controller.render_cell(*args)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Builds an instance of <tt>name</tt>Cell for unit testing.
|
|
83
|
+
# Passes the optional block to <tt>cell.instance_eval</tt>.
|
|
84
|
+
#
|
|
85
|
+
# Example:
|
|
86
|
+
# assert_equal "Banks kill planet!" cell(:news, :topic => :terror).latest_headline
|
|
87
|
+
def cell(name, opts={}, &block)
|
|
88
|
+
cell = ::Cell::Base.create_cell_for(@controller, name, opts)
|
|
89
|
+
cell.instance_eval &block if block_given?
|
|
90
|
+
cell
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
include TestMethods
|
|
95
|
+
include ActionDispatch::Assertions::SelectorAssertions # imports "their" #assert_select.
|
|
96
|
+
alias_method :rails_assert_select, :assert_select # i hate that.
|
|
97
|
+
include AssertSelect
|
|
98
|
+
|
|
99
|
+
extend ActionController::TestCase::Behavior::ClassMethods
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
attr_reader :last_invoke
|
|
103
|
+
|
|
104
|
+
def invoke(state, *args)
|
|
105
|
+
@last_invoke = self.class.controller_class.new(@controller, *args).render_state(state)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
data/lib/cells.rb
CHANGED
|
@@ -63,7 +63,7 @@ require 'action_controller'
|
|
|
63
63
|
require 'cell'
|
|
64
64
|
require 'cells/rails'
|
|
65
65
|
require 'cell/rails'
|
|
66
|
-
|
|
66
|
+
require 'cell/test_case' if Rails.env == "test"
|
|
67
67
|
|
|
68
68
|
module Cells
|
|
69
69
|
# Any config should be placed here using +mattr_accessor+.
|
|
@@ -122,4 +122,8 @@ class Cells::Railtie < Rails::Railtie
|
|
|
122
122
|
#ActiveSupport::Dependencies.load_paths << Rails.root.join(*%w[app cells])
|
|
123
123
|
### DISCUSS: how are cell classes found by Rails?
|
|
124
124
|
end
|
|
125
|
+
|
|
126
|
+
rake_tasks do
|
|
127
|
+
load "tasks.rake"
|
|
128
|
+
end
|
|
125
129
|
end
|
data/lib/cells/version.rb
CHANGED
data/lib/generators/cells/USAGE
CHANGED
|
@@ -7,20 +7,12 @@ Description:
|
|
|
7
7
|
|
|
8
8
|
Examples:
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
rails g cells:cell ShoppingCart index --haml
|
|
11
11
|
|
|
12
|
-
This will create
|
|
12
|
+
This will create these cell assets:
|
|
13
13
|
Cell:
|
|
14
|
-
app/cells/
|
|
14
|
+
app/cells/shopping_cart_cell.rb
|
|
15
15
|
Views:
|
|
16
|
-
app/cells/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
./script/generate cell Articles popular recent --haml
|
|
20
|
-
|
|
21
|
-
This will create an Articles cell:
|
|
22
|
-
Cell:
|
|
23
|
-
app/cells/articles_cell.rb
|
|
24
|
-
Views:
|
|
25
|
-
app/cells/articles/popular.html.haml
|
|
26
|
-
app/cells/articles/recent.html.haml
|
|
16
|
+
app/cells/shopping_cart/index.html.haml
|
|
17
|
+
Test:
|
|
18
|
+
test/cells/shopping_cart_cell_test
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
require 'test_helper'
|
|
2
2
|
|
|
3
|
-
class <%= class_name %>CellTest <
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<% for state in @states -%>
|
|
3
|
+
class <%= class_name %>CellTest < Cell::TestCase
|
|
4
|
+
<% for state in @states -%>
|
|
7
5
|
test "<%= state %>" do
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
invoke :<%= state %>
|
|
7
|
+
assert_select "p"
|
|
10
8
|
end
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
end
|
|
10
|
+
<% end %>
|
|
11
|
+
end
|
data/lib/tasks.rake
ADDED
data/test/cell_generator_test.rb
CHANGED
|
@@ -20,7 +20,7 @@ class CellGeneratorTest < Rails::Generators::TestCase
|
|
|
20
20
|
assert_file "app/cells/blog/post.html.erb", %r(<p>)
|
|
21
21
|
assert_file "app/cells/blog/latest.html.erb", %r(app/cells/blog/latest\.html\.erb)
|
|
22
22
|
|
|
23
|
-
assert_file "test/cells/blog_cell_test.rb"
|
|
23
|
+
assert_file "test/cells/blog_cell_test.rb", %r(class BlogCellTest < Cell::TestCase)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
should "create haml assets with --haml" do
|
data/test/cell_module_test.rb
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
require 'test_helper'
|
|
2
2
|
|
|
3
|
-
class BlogCellTest <
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
html = render_cell(:blog, :post)
|
|
8
|
-
assert_selekt html, "p"
|
|
3
|
+
class BlogCellTest < Cell::TestCase
|
|
4
|
+
test "post" do
|
|
5
|
+
invoke :post
|
|
6
|
+
assert_select "p"
|
|
9
7
|
end
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
test "latest" do
|
|
10
|
+
invoke :latest
|
|
11
|
+
assert_select "p"
|
|
14
12
|
end
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
end
|
|
14
|
+
|
|
15
|
+
end
|
data/test/helper_test.rb
CHANGED
data/test/rails/caching_test.rb
CHANGED
data/test/rails/cells_test.rb
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
require 'test_helper'
|
|
2
2
|
|
|
3
3
|
class RailsCellsTest < ActiveSupport::TestCase
|
|
4
|
+
include Cell::TestCase::TestMethods
|
|
5
|
+
|
|
6
|
+
def swap(object, new_values)
|
|
7
|
+
old_values = {}
|
|
8
|
+
new_values.each do |key, value|
|
|
9
|
+
old_values[key] = object.send key
|
|
10
|
+
object.send :"#{key}=", value
|
|
11
|
+
end
|
|
12
|
+
yield
|
|
13
|
+
ensure
|
|
14
|
+
old_values.each do |key, value|
|
|
15
|
+
object.send :"#{key}=", value
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
4
19
|
context "A rails cell" do
|
|
5
20
|
should "respond to view_paths" do
|
|
6
21
|
assert_kind_of ActionView::PathSet, Cell::Rails.view_paths, "must be a PathSet for proper template caching/reloading (see issue#2)"
|
data/test/rails/render_test.rb
CHANGED
data/test/rails/view_test.rb
CHANGED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class TestCaseTest < Cell::TestCase
|
|
4
|
+
|
|
5
|
+
context "A TestCase" do
|
|
6
|
+
setup do
|
|
7
|
+
@test = Cell::TestCase.new(:cell_test)
|
|
8
|
+
|
|
9
|
+
BassistCell.class_eval do
|
|
10
|
+
def play; render; end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
should "respond to #render_cell" do
|
|
16
|
+
assert_equal "Doo", render_cell(:bassist, :play)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
should "respond to #assert_selector with 3 args" do
|
|
20
|
+
assert_selector "p", "Doo", "<p>Doo</p>y"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
should "respond to #cell" do
|
|
24
|
+
assert_kind_of BassistCell, cell(:bassist)
|
|
25
|
+
assert !cell(:bassist).respond_to?(:opts)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
should "respond to #cell with a block" do
|
|
29
|
+
assert_respond_to cell(:bassist) { def opts; @opts; end }, :opts
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
should "respond to #cell with options and block" do
|
|
33
|
+
assert_equal({:topic => :peace}, cell(:bassist, :topic => :peace) { def opts; @opts; end }.opts)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context "in declarative tests" do
|
|
37
|
+
should "respond to TestCase.tests" do
|
|
38
|
+
self.class.tests BassistCell
|
|
39
|
+
assert_equal BassistCell, self.class.controller_class
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
should "infer the cell name" do
|
|
43
|
+
class SingerCell < Cell::Rails
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
class SingerCellTest < Cell::TestCase
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
assert_equal SingerCell, SingerCellTest.new(:cell_test).class.controller_class
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
context "with invoke" do
|
|
53
|
+
setup do
|
|
54
|
+
self.class.tests BassistCell
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
should "provide #invoke" do
|
|
58
|
+
assert_equal "Doo", invoke(:play)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
should "provide #last_invoke" do
|
|
62
|
+
assert_equal nil, last_invoke
|
|
63
|
+
assert_equal "Doo", invoke(:play)
|
|
64
|
+
assert_equal "Doo", last_invoke
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
should "provide #invoke accepting opts" do
|
|
68
|
+
#assert_equal "Doo", invoke(:play)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
should "provide assert_select" do
|
|
72
|
+
invoke :promote
|
|
73
|
+
assert_select "a", "vd.com"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
data/test/test_helper.rb
CHANGED
|
@@ -26,14 +26,12 @@ require 'cells'
|
|
|
26
26
|
Cell::Rails.append_view_path(File.join(test_app_dir, 'cells'))
|
|
27
27
|
Cell::Rails.append_view_path(File.join(test_app_dir, 'cells', 'layouts'))
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
Dir[File.join(gem_dir, 'test', 'support', '**', '*.rb')].each { |f| require f }
|
|
31
|
-
require File.join(gem_dir, 'lib', 'cells', 'assertions_helper')
|
|
32
|
-
|
|
29
|
+
require "cell/test_case"
|
|
33
30
|
# Extend TestCase.
|
|
34
31
|
ActiveSupport::TestCase.class_eval do
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
def assert_not(assertion)
|
|
33
|
+
assert !assertion
|
|
34
|
+
end
|
|
37
35
|
end
|
|
38
36
|
|
|
39
37
|
# Enable dynamic states so we can do Cell.class_eval { def ... } at runtime.
|
|
@@ -45,4 +43,4 @@ require File.join(test_app_dir, 'cells', 'bassist_cell')
|
|
|
45
43
|
require File.join(test_app_dir, 'cells', 'bad_guitarist_cell')
|
|
46
44
|
|
|
47
45
|
require "haml"
|
|
48
|
-
require "haml/template" # Thanks, Nathan!
|
|
46
|
+
require "haml/template" # Thanks, Nathan!
|
metadata
CHANGED
|
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
|
5
5
|
segments:
|
|
6
6
|
- 3
|
|
7
7
|
- 4
|
|
8
|
-
-
|
|
9
|
-
version: 3.4.
|
|
8
|
+
- 1
|
|
9
|
+
version: 3.4.1
|
|
10
10
|
platform: ruby
|
|
11
11
|
authors:
|
|
12
12
|
- Nick Sutterer
|
|
@@ -14,7 +14,7 @@ autorequire:
|
|
|
14
14
|
bindir: bin
|
|
15
15
|
cert_chain: []
|
|
16
16
|
|
|
17
|
-
date: 2010-
|
|
17
|
+
date: 2010-10-04 00:00:00 +02:00
|
|
18
18
|
default_executable:
|
|
19
19
|
dependencies: []
|
|
20
20
|
|
|
@@ -35,11 +35,10 @@ files:
|
|
|
35
35
|
- Rakefile
|
|
36
36
|
- lib/cell.rb
|
|
37
37
|
- lib/cell/active_helper.rb
|
|
38
|
-
- lib/cell/base.rb
|
|
39
38
|
- lib/cell/caching.rb
|
|
40
39
|
- lib/cell/rails.rb
|
|
40
|
+
- lib/cell/test_case.rb
|
|
41
41
|
- lib/cells.rb
|
|
42
|
-
- lib/cells/assertions_helper.rb
|
|
43
42
|
- lib/cells/helpers.rb
|
|
44
43
|
- lib/cells/helpers/capture_helper.rb
|
|
45
44
|
- lib/cells/rails.rb
|
|
@@ -50,8 +49,8 @@ files:
|
|
|
50
49
|
- lib/generators/cells/templates/cell_test.rb
|
|
51
50
|
- lib/generators/cells/templates/view.erb
|
|
52
51
|
- lib/generators/cells/templates/view.haml
|
|
52
|
+
- lib/tasks.rake
|
|
53
53
|
- test/active_helper_test.rb
|
|
54
|
-
- test/assertions_helper_test.rb
|
|
55
54
|
- test/rails/router_test.rb
|
|
56
55
|
- test/rails/view_test.rb
|
|
57
56
|
- test/rails/capture_test.rb
|
|
@@ -61,7 +60,6 @@ files:
|
|
|
61
60
|
- test/rails/caching_test.rb
|
|
62
61
|
- test/cell_generator_test.rb
|
|
63
62
|
- test/test_helper.rb
|
|
64
|
-
- test/support/internal_assertions_helper.rb
|
|
65
63
|
- test/dummy/config/application.rb
|
|
66
64
|
- test/dummy/config/initializers/session_store.rb
|
|
67
65
|
- test/dummy/config/initializers/mime_types.rb
|
|
@@ -79,6 +77,7 @@ files:
|
|
|
79
77
|
- test/dummy/app/controllers/musician_controller.rb
|
|
80
78
|
- test/dummy/app/controllers/application_controller.rb
|
|
81
79
|
- test/dummy/app/helpers/application_helper.rb
|
|
80
|
+
- test/test_case_test.rb
|
|
82
81
|
- test/helper_test.rb
|
|
83
82
|
- test/cell_module_test.rb
|
|
84
83
|
- test/app/cells/bassist_cell.rb
|
|
@@ -120,7 +119,6 @@ specification_version: 3
|
|
|
120
119
|
summary: View Components for Rails.
|
|
121
120
|
test_files:
|
|
122
121
|
- test/active_helper_test.rb
|
|
123
|
-
- test/assertions_helper_test.rb
|
|
124
122
|
- test/rails/router_test.rb
|
|
125
123
|
- test/rails/view_test.rb
|
|
126
124
|
- test/rails/capture_test.rb
|
|
@@ -130,7 +128,6 @@ test_files:
|
|
|
130
128
|
- test/rails/caching_test.rb
|
|
131
129
|
- test/cell_generator_test.rb
|
|
132
130
|
- test/test_helper.rb
|
|
133
|
-
- test/support/internal_assertions_helper.rb
|
|
134
131
|
- test/dummy/config/application.rb
|
|
135
132
|
- test/dummy/config/initializers/session_store.rb
|
|
136
133
|
- test/dummy/config/initializers/mime_types.rb
|
|
@@ -148,6 +145,7 @@ test_files:
|
|
|
148
145
|
- test/dummy/app/controllers/musician_controller.rb
|
|
149
146
|
- test/dummy/app/controllers/application_controller.rb
|
|
150
147
|
- test/dummy/app/helpers/application_helper.rb
|
|
148
|
+
- test/test_case_test.rb
|
|
151
149
|
- test/helper_test.rb
|
|
152
150
|
- test/cell_module_test.rb
|
|
153
151
|
- test/app/cells/bassist_cell.rb
|
data/lib/cell/base.rb
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
# == Basic overview
|
|
2
|
-
#
|
|
3
|
-
# A Cell is the central notion of the cells plugin. A cell acts as a
|
|
4
|
-
# lightweight controller in the sense that it will assign variables and
|
|
5
|
-
# render a view. Cells can be rendered from other cells as well as from
|
|
6
|
-
# regular controllers and views (see ActionView::Base#render_cell and
|
|
7
|
-
# ControllerMethods#render_cell)
|
|
8
|
-
#
|
|
9
|
-
# == A render_cell() cycle
|
|
10
|
-
#
|
|
11
|
-
# A typical <tt>render_cell</tt> state rendering cycle looks like this:
|
|
12
|
-
# render_cell :blog, :newest_article, {...}
|
|
13
|
-
# - an instance of the class <tt>BlogCell</tt> is created, and a hash containing
|
|
14
|
-
# arbitrary parameters is passed
|
|
15
|
-
# - the <em>state method</em> <tt>newest_article</tt> is executed and assigns instance
|
|
16
|
-
# variables to be used in the view
|
|
17
|
-
# - Usually the state method will call #render and return
|
|
18
|
-
# - #render will retrieve the corresponding view
|
|
19
|
-
# (e.g. <tt>app/cells/blog/newest_article.html. [erb|haml|...]</tt>),
|
|
20
|
-
# renders this template and returns the markup.
|
|
21
|
-
#
|
|
22
|
-
# == Design Principles
|
|
23
|
-
# A cell is a completely autonomous object and it should not know or have to know
|
|
24
|
-
# from what controller it is being rendered. For this reason, the controller's
|
|
25
|
-
# instance variables and params hash are not directly available from the cell or
|
|
26
|
-
# its views. This is not a bug, this is a feature! It means cells are truly
|
|
27
|
-
# reusable components which can be plugged in at any point in your application
|
|
28
|
-
# without having to think about what information is available at that point.
|
|
29
|
-
# When rendering a cell, you can explicitly pass variables to the cell in the
|
|
30
|
-
# extra opts argument hash, just like you would pass locals in partials.
|
|
31
|
-
# This hash is then available inside the cell as the @opts instance variable.
|
|
32
|
-
#
|
|
33
|
-
# == Directory hierarchy
|
|
34
|
-
#
|
|
35
|
-
# To get started creating your own cells, you can simply create a new directory
|
|
36
|
-
# structure under your <tt>app</tt> directory called <tt>cells</tt>. Cells are
|
|
37
|
-
# ruby classes which end in the name Cell. So for example, if you have a
|
|
38
|
-
# cell which manages all user information, it would be called <tt>UserCell</tt>.
|
|
39
|
-
# A cell which manages a shopping cart could be called <tt>ShoppingCartCell</tt>.
|
|
40
|
-
#
|
|
41
|
-
# The directory structure of this example would look like this:
|
|
42
|
-
# app/
|
|
43
|
-
# models/
|
|
44
|
-
# ..
|
|
45
|
-
# views/
|
|
46
|
-
# ..
|
|
47
|
-
# helpers/
|
|
48
|
-
# application_helper.rb
|
|
49
|
-
# product_helper.rb
|
|
50
|
-
# ..
|
|
51
|
-
# controllers/
|
|
52
|
-
# ..
|
|
53
|
-
# cells/
|
|
54
|
-
# shopping_cart_cell.rb
|
|
55
|
-
# shopping_cart/
|
|
56
|
-
# status.html.erb
|
|
57
|
-
# product_list.html.erb
|
|
58
|
-
# empty_prompt.html.erb
|
|
59
|
-
# user_cell.rb
|
|
60
|
-
# user/
|
|
61
|
-
# login.html.erb
|
|
62
|
-
# layouts/
|
|
63
|
-
# box.html.erb
|
|
64
|
-
# ..
|
|
65
|
-
#
|
|
66
|
-
# The directory with the same name as the cell contains views for the
|
|
67
|
-
# cell's <em>states</em>. A state is an executed method along with a
|
|
68
|
-
# rendered view, resulting in content. This means that states are to
|
|
69
|
-
# cells as actions are to controllers, so each state has its own view.
|
|
70
|
-
# The use of partials is deprecated with cells, it is better to just
|
|
71
|
-
# render a different state on the same cell (which also works recursively).
|
|
72
|
-
#
|
|
73
|
-
# Anyway, <tt>render :partial </tt> in a cell view will work, if the
|
|
74
|
-
# partial is contained in the cell's view directory.
|
|
75
|
-
#
|
|
76
|
-
# As can be seen above, Cells also can make use of helpers. All Cells
|
|
77
|
-
# include ApplicationHelper by default, but you can add additional helpers
|
|
78
|
-
# as well with the ::Cell::Base.helper class method:
|
|
79
|
-
# class ShoppingCartCell < ::Cell::Base
|
|
80
|
-
# helper :product
|
|
81
|
-
# ...
|
|
82
|
-
# end
|
|
83
|
-
#
|
|
84
|
-
# This will make the <tt>ProductHelper</tt> from <tt>app/helpers/product_helper.rb</tt>
|
|
85
|
-
# available from all state views from our <tt>ShoppingCartCell</tt>.
|
|
86
|
-
#
|
|
87
|
-
# == Cell inheritance
|
|
88
|
-
#
|
|
89
|
-
# Unlike controllers, Cells can form a class hierarchy. When a cell class
|
|
90
|
-
# is inherited by another cell class, its states are inherited as regular
|
|
91
|
-
# methods are, but also its views are inherited. Whenever a view is looked up,
|
|
92
|
-
# the view finder first looks for a file in the directory belonging to the
|
|
93
|
-
# current cell class, but if this is not found in the application or any
|
|
94
|
-
# engine, the superclass' directory is checked. This continues all the
|
|
95
|
-
# way up until it stops at ::Cell::Base.
|
|
96
|
-
#
|
|
97
|
-
# For instance, when you have two cells:
|
|
98
|
-
# class MenuCell < ::Cell::Base
|
|
99
|
-
# def show
|
|
100
|
-
# end
|
|
101
|
-
#
|
|
102
|
-
# def edit
|
|
103
|
-
# end
|
|
104
|
-
# end
|
|
105
|
-
#
|
|
106
|
-
# class MainMenuCell < MenuCell
|
|
107
|
-
# .. # no need to redefine show/edit if they do the same!
|
|
108
|
-
# end
|
|
109
|
-
# and the following directory structure in <tt>app/cells</tt>:
|
|
110
|
-
# app/cells/
|
|
111
|
-
# menu/
|
|
112
|
-
# show.html.erb
|
|
113
|
-
# edit.html.erb
|
|
114
|
-
# main_menu/
|
|
115
|
-
# show.html.erb
|
|
116
|
-
# then when you call
|
|
117
|
-
# render_cell :main_menu, :show
|
|
118
|
-
# the main menu specific show.html.erb (<tt>app/cells/main_menu/show.html.erb</tt>)
|
|
119
|
-
# is rendered, but when you call
|
|
120
|
-
# render_cell :main_menu, :edit
|
|
121
|
-
# cells notices that the main menu does not have a specific view for the
|
|
122
|
-
# <tt>edit</tt> state, so it will render the view for the parent class,
|
|
123
|
-
# <tt>app/cells/menu/edit.html.erb</tt>
|
|
124
|
-
#
|
|
125
|
-
#
|
|
126
|
-
# == Gettext support
|
|
127
|
-
#
|
|
128
|
-
# Cells support gettext, just name your views accordingly. It works exactly equivalent
|
|
129
|
-
# to controller views.
|
|
130
|
-
#
|
|
131
|
-
# cells/user/user_form.html.erb
|
|
132
|
-
# cells/user/user_form_de.html.erb
|
|
133
|
-
#
|
|
134
|
-
# If gettext is set to DE_de, the latter view will be chosen.
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
require 'action_controller/test_case'
|
|
3
|
-
|
|
4
|
-
module Cells
|
|
5
|
-
module AssertionsHelper
|
|
6
|
-
# Sets up a mock controller for usage in render_cell.
|
|
7
|
-
def setup
|
|
8
|
-
@controller = Class.new(ActionController::Base).new
|
|
9
|
-
@request = ::ActionController::TestRequest.new
|
|
10
|
-
@response = ::ActionController::TestResponse.new
|
|
11
|
-
@controller.request = @request
|
|
12
|
-
@controller.response = @response
|
|
13
|
-
@controller.params = {}
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Use this for functional tests of your application cells.
|
|
17
|
-
#
|
|
18
|
-
# Example:
|
|
19
|
-
# should "spit out a h1 title" do
|
|
20
|
-
# html = render_cell(:news, :latest)
|
|
21
|
-
# assert_selekt html, "h1", "The latest and greatest!"
|
|
22
|
-
def render_cell(*args)
|
|
23
|
-
@controller.render_cell(*args)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Invokes assert_select for the passed <tt>content</tt> string.
|
|
27
|
-
#
|
|
28
|
-
# Example:
|
|
29
|
-
# html = "<h1>The latest and greatest!</h1>"
|
|
30
|
-
# assert_selekt html, "h1", "The latest and greatest!"
|
|
31
|
-
#
|
|
32
|
-
# would be true.
|
|
33
|
-
def assert_selekt(content, *args)
|
|
34
|
-
assert_select(HTML::Document.new(content).root, *args)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Builds an instance of <tt>name</tt>Cell for unit testing.
|
|
38
|
-
# Passes the optional block to <tt>cell.instance_eval</tt>.
|
|
39
|
-
#
|
|
40
|
-
# Example:
|
|
41
|
-
# assert_equal "Banks kill planet!" cell(:news, :topic => :terror).latest_headline
|
|
42
|
-
def cell(name, opts={}, &block)
|
|
43
|
-
cell = ::Cell::Base.create_cell_for(@controller, name, opts)
|
|
44
|
-
cell.instance_eval &block if block_given?
|
|
45
|
-
cell
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
require 'test_helper'
|
|
2
|
-
|
|
3
|
-
class AssertionsHelperTest < ActionController::TestCase
|
|
4
|
-
context "A TestCase" do
|
|
5
|
-
setup do
|
|
6
|
-
BassistCell.class_eval do
|
|
7
|
-
def play; render; end
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
should "respond to #render_cell" do
|
|
12
|
-
assert_equal "Doo", render_cell(:bassist, :play)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
should "respond to #assert_selekt" do
|
|
16
|
-
assert_selekt "<p>Doo</p>", "p", "Doo"
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
should "respond to #cell" do
|
|
20
|
-
assert_kind_of BassistCell, cell(:bassist)
|
|
21
|
-
assert_not cell(:bassist).respond_to? :opts
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
should "respond to #cell with a block" do
|
|
25
|
-
assert_respond_to cell(:bassist) { def opts; @opts; end }, :opts
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
should "respond to #cell with options and block" do
|
|
29
|
-
assert_equal({:topic => :peace}, cell(:bassist, :topic => :peace) { def opts; @opts; end }.opts)
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
module Cells
|
|
3
|
-
# Assertion helpers extracted from Devise by José Valim.
|
|
4
|
-
#
|
|
5
|
-
module InternalAssertionsHelper
|
|
6
|
-
def setup
|
|
7
|
-
@controller = ::MusicianController.new
|
|
8
|
-
@request = ::ActionController::TestRequest.new
|
|
9
|
-
@response = ::ActionController::TestResponse.new
|
|
10
|
-
@controller.request = @request
|
|
11
|
-
@controller.response = @response
|
|
12
|
-
@controller.params = {}
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def assert_not(assertion)
|
|
16
|
-
assert !assertion
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def assert_blank(assertion)
|
|
20
|
-
assert assertion.blank?
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def assert_not_blank(assertion)
|
|
24
|
-
assert !assertion.blank?
|
|
25
|
-
end
|
|
26
|
-
alias :assert_present :assert_not_blank
|
|
27
|
-
|
|
28
|
-
# Execute the block setting the given values and restoring old values after
|
|
29
|
-
# the block is executed.
|
|
30
|
-
#
|
|
31
|
-
# == Usage/Example:
|
|
32
|
-
#
|
|
33
|
-
# I18n.locale # => :en
|
|
34
|
-
#
|
|
35
|
-
# swap(I18n :locale => :se) do
|
|
36
|
-
# I18n.locale # => :se
|
|
37
|
-
# end
|
|
38
|
-
#
|
|
39
|
-
# I18n.locale # => :en
|
|
40
|
-
#
|
|
41
|
-
def swap(object, new_values)
|
|
42
|
-
old_values = {}
|
|
43
|
-
new_values.each do |key, value|
|
|
44
|
-
old_values[key] = object.send key
|
|
45
|
-
object.send :"#{key}=", value
|
|
46
|
-
end
|
|
47
|
-
yield
|
|
48
|
-
ensure
|
|
49
|
-
old_values.each do |key, value|
|
|
50
|
-
object.send :"#{key}=", value
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# Provides a TestCell instance. The <tt>block</tt> is passed to instance_eval and should be used
|
|
55
|
-
# to extend the mock on the fly.
|
|
56
|
-
### DISCUSS: make an anonymous subclass of TestCell?
|
|
57
|
-
def cell_mock(options={}, &block) ### DISCUSS: 2BRM.
|
|
58
|
-
cell = TestCell.new(@controller, options)
|
|
59
|
-
cell.instance_eval(&block) if block_given?
|
|
60
|
-
cell
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def bassist_mock(options={}, &block)
|
|
64
|
-
cell = BassistCell.new(@controller, options)
|
|
65
|
-
cell.instance_eval(&block) if block_given?
|
|
66
|
-
cell
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|