cells 3.4.3 → 3.4.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.textile +8 -0
- data/Gemfile +3 -2
- data/README.rdoc +23 -0
- data/lib/cell.rb +45 -2
- data/lib/cell/rails.rb +1 -5
- data/lib/cell/test_case.rb +22 -0
- data/lib/cells.rb +4 -24
- data/lib/cells/version.rb +1 -1
- data/test/cell_module_test.rb +90 -0
- data/test/cells_module_test.rb +21 -0
- data/test/rails/view_test.rb +8 -10
- data/test/test_case_test.rb +19 -1
- metadata +5 -3
data/CHANGES.textile
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
h2. 3.4.4
|
2
|
+
|
3
|
+
h3. Changes
|
4
|
+
* Cells.setup now yields Cell::Base, so you can really call append_view_path and friends here.
|
5
|
+
* added Cell::Base.build for streamlining the process of deciders around #render_cell, "see here":http://nicksda.apotomo.de/2010/12/pragmatic-rails-thoughts-on-views-inheritance-view-inheritance-and-rails-304
|
6
|
+
* added TestCase#in_view to test helpers in a real cell view.
|
7
|
+
|
8
|
+
|
1
9
|
h2. 3.4.3
|
2
10
|
|
3
11
|
h3. Changes
|
data/Gemfile
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
source :gemcutter
|
2
2
|
gem 'sqlite3-ruby', '1.2.5', :require => 'sqlite3' # needed in router_test, whatever.
|
3
3
|
|
4
|
-
#gem "rails" , :path => "/home/nick/projects/
|
5
|
-
gem "rails", '3.0
|
4
|
+
#gem "rails" , :path => "/home/nick/projects/rayls"
|
5
|
+
gem "rails", '~> 3.0'
|
6
6
|
gem "haml"
|
7
7
|
|
8
8
|
group :test do
|
9
9
|
gem "shoulda"
|
10
10
|
end
|
11
|
+
gem "rack", :git => "git://github.com/rack/rack.git"
|
data/README.rdoc
CHANGED
@@ -94,6 +94,29 @@ The distinction between partials and views is making things more complex, so why
|
|
94
94
|
= render :view => 'items'
|
95
95
|
|
96
96
|
|
97
|
+
== View Inheritance
|
98
|
+
|
99
|
+
This is where OOP comes back to your view.
|
100
|
+
|
101
|
+
* <b>Inherit code</b> into your cells by deriving more abstract cells.
|
102
|
+
* <b>Inherit views</b> from ancesting cells.
|
103
|
+
|
104
|
+
=== Builders
|
105
|
+
|
106
|
+
Let +render_cell+ take care of creating the right cell. Just configure your super-cell properly.
|
107
|
+
|
108
|
+
class LoginCell < Cell::Rails
|
109
|
+
build do
|
110
|
+
UnauthorizedUserCell unless logged_in?
|
111
|
+
end
|
112
|
+
|
113
|
+
A call to
|
114
|
+
|
115
|
+
render_cell(:login, :box)
|
116
|
+
|
117
|
+
will render the configured +UnauthorizedUserCell+ instead of the original +LoginCell+ if the login test fails.
|
118
|
+
|
119
|
+
|
97
120
|
== Caching
|
98
121
|
|
99
122
|
Cells do strict view caching. No cluttered fragment caching. Add
|
data/lib/cell.rb
CHANGED
@@ -10,9 +10,52 @@ module Cell
|
|
10
10
|
cell.render_state(state)
|
11
11
|
end
|
12
12
|
|
13
|
-
# Creates a cell instance.
|
13
|
+
# Creates a cell instance. Note that this method calls builders which were attached to the
|
14
|
+
# class with Cell::Base.build - this might lead to a different cell being returned.
|
14
15
|
def create_cell_for(controller, name, opts={})
|
15
|
-
class_from_cell_name(name)
|
16
|
+
build_class_for(controller, class_from_cell_name(name), opts).
|
17
|
+
new(controller, opts)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Adds a builder to the cell class. Builders are used in #render_cell to find out the concrete
|
21
|
+
# class for rendering. This is helpful if you frequently want to render subclasses according
|
22
|
+
# to different circumstances (e.g. login situations) and you don't want to place these deciders in
|
23
|
+
# your view code.
|
24
|
+
#
|
25
|
+
# Passes the opts hash from #render_cell into the block. The block is executed in controller context.
|
26
|
+
# Multiple build blocks are ORed, if no builder matches the building cell is used.
|
27
|
+
#
|
28
|
+
# Example:
|
29
|
+
#
|
30
|
+
# Consider two different user box cells in your app.
|
31
|
+
#
|
32
|
+
# class AuthorizedUserBox < UserInfoBox
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# class AdminUserBox < UserInfoBox
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# Now you don't want to have deciders all over your views - use a declarative builder.
|
39
|
+
#
|
40
|
+
# UserInfoBox.build do |opts|
|
41
|
+
# AuthorizedUserBox if user_signed_in?
|
42
|
+
# AdminUserBox if admin_signed_in?
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# In your view #render_cell will instantiate the right cell for you now.
|
46
|
+
def build(&block)
|
47
|
+
builders << block
|
48
|
+
end
|
49
|
+
|
50
|
+
def build_class_for(controller, target_class, opts)
|
51
|
+
target_class.builders.each do |blk|
|
52
|
+
res = controller.instance_exec(opts, &blk) and return res
|
53
|
+
end
|
54
|
+
target_class
|
55
|
+
end
|
56
|
+
|
57
|
+
def builders
|
58
|
+
@builders ||= []
|
16
59
|
end
|
17
60
|
|
18
61
|
# Return the default view path for +state+. Override this if you cell has a differing naming style.
|
data/lib/cell/rails.rb
CHANGED
@@ -48,8 +48,6 @@ module Cell
|
|
48
48
|
include Rendering
|
49
49
|
include Caching
|
50
50
|
|
51
|
-
|
52
|
-
cattr_accessor :url_helpers ### TODO: discuss if we really need that or can handle that in cells.rb already.
|
53
51
|
attr_reader :parent_controller
|
54
52
|
|
55
53
|
abstract!
|
@@ -67,12 +65,10 @@ module Cell
|
|
67
65
|
|
68
66
|
View.class_eval do
|
69
67
|
include controller._helpers
|
70
|
-
include
|
68
|
+
include controller._routes.url_helpers
|
71
69
|
end
|
72
70
|
|
73
|
-
|
74
71
|
@view_context_class ||= View
|
75
|
-
### DISCUSS: copy behaviour from abstract_controller/rendering-line 49? (helpers)
|
76
72
|
end
|
77
73
|
|
78
74
|
def self.controller_path
|
data/lib/cell/test_case.rb
CHANGED
@@ -89,6 +89,27 @@ module Cell
|
|
89
89
|
cell.instance_eval &block if block_given?
|
90
90
|
cell
|
91
91
|
end
|
92
|
+
|
93
|
+
# Execute the passed +block+ in a real view context of +cell_class+.
|
94
|
+
# Usually you'd test helpers here.
|
95
|
+
#
|
96
|
+
# Example:
|
97
|
+
#
|
98
|
+
# assert_equal("<h1>Modularity rocks.</h1>", in_view do content_tag(:h1, "Modularity rocks."))
|
99
|
+
def in_view(cell_class, &block)
|
100
|
+
subject = cell(cell_class, :block => block)
|
101
|
+
setup_test_states_in(subject) # add #in_view to subject cell.
|
102
|
+
subject.render_state(:in_view)
|
103
|
+
end
|
104
|
+
|
105
|
+
protected
|
106
|
+
def setup_test_states_in(cell)
|
107
|
+
cell.instance_eval do
|
108
|
+
def in_view
|
109
|
+
render :inline => "<%= instance_exec(&block) %>", :locals => {:block => @opts[:block]}
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
92
113
|
end
|
93
114
|
|
94
115
|
include TestMethods
|
@@ -97,6 +118,7 @@ module Cell
|
|
97
118
|
include AssertSelect
|
98
119
|
|
99
120
|
extend ActionController::TestCase::Behavior::ClassMethods
|
121
|
+
class_attribute :_controller_class
|
100
122
|
|
101
123
|
|
102
124
|
attr_reader :last_invoke
|
data/lib/cells.rb
CHANGED
@@ -66,40 +66,22 @@ require 'cell/rails'
|
|
66
66
|
require 'cell/test_case' if Object.const_defined?("Rails") and Rails.env == "test"
|
67
67
|
|
68
68
|
module Cells
|
69
|
-
# Any config should be placed here using +mattr_accessor+.
|
70
|
-
|
71
69
|
# Default view paths for Cells.
|
72
70
|
DEFAULT_VIEW_PATHS = [
|
73
71
|
File.join('app', 'cells'),
|
74
72
|
File.join('app', 'cells', 'layouts')
|
75
73
|
]
|
76
74
|
|
77
|
-
|
78
|
-
# Holds paths in which Cells should look for cell views (i.e. view template files).
|
79
|
-
#
|
80
|
-
# == Default:
|
81
|
-
#
|
82
|
-
# * +app/cells+
|
83
|
-
# * +app/cells/layouts+
|
84
|
-
#
|
85
|
-
def self.view_paths
|
86
|
-
::Cell::Base.view_paths
|
87
|
-
end
|
88
|
-
def self.view_paths=(paths)
|
89
|
-
::Cell::Base.view_paths = paths
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
# Cells setup/configuration helper for initializer.
|
75
|
+
# Setup your special needs for Cells here. Use this to add new view paths.
|
94
76
|
#
|
95
|
-
#
|
77
|
+
# Example:
|
96
78
|
#
|
97
79
|
# Cells.setup do |config|
|
98
|
-
# config.
|
80
|
+
# config.append_view_path << "app/view_models"
|
99
81
|
# end
|
100
82
|
#
|
101
83
|
def self.setup
|
102
|
-
yield(
|
84
|
+
yield(Cell::Base)
|
103
85
|
end
|
104
86
|
end
|
105
87
|
|
@@ -115,8 +97,6 @@ class Cells::Railtie < Rails::Railtie
|
|
115
97
|
Cell::Rails.class_eval do
|
116
98
|
include app.routes.url_helpers
|
117
99
|
end
|
118
|
-
|
119
|
-
Cell::Base.url_helpers = app.routes.url_helpers
|
120
100
|
end
|
121
101
|
|
122
102
|
rake_tasks do
|
data/lib/cells/version.rb
CHANGED
data/test/cell_module_test.rb
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
+
class MusicianCell < Cell::Base
|
4
|
+
|
5
|
+
end
|
6
|
+
|
7
|
+
class PianistCell < MusicianCell
|
8
|
+
end
|
9
|
+
|
10
|
+
class SingerCell < MusicianCell
|
11
|
+
end
|
12
|
+
|
13
|
+
|
3
14
|
class CellModuleTest < ActiveSupport::TestCase
|
4
15
|
include Cell::TestCase::TestMethods
|
5
16
|
|
@@ -20,9 +31,88 @@ class CellModuleTest < ActiveSupport::TestCase
|
|
20
31
|
assert_equal "Doo", html
|
21
32
|
assert flag
|
22
33
|
end
|
34
|
+
|
35
|
+
|
23
36
|
end
|
24
37
|
|
38
|
+
context "create_cell_for" do
|
39
|
+
should "call the cell's builders, eventually returning a different class" do
|
40
|
+
class DrummerCell < BassistCell
|
41
|
+
build do
|
42
|
+
BassistCell
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
assert_instance_of BassistCell, Cell::Base.create_cell_for(@controller, "cell_module_test/drummer", :play)
|
47
|
+
end
|
48
|
+
end
|
25
49
|
|
50
|
+
context "calling build" do
|
51
|
+
setup do
|
52
|
+
@controller.class_eval do
|
53
|
+
attr_accessor :bassist
|
54
|
+
end
|
55
|
+
|
56
|
+
MusicianCell.build do
|
57
|
+
BassistCell if bassist
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
teardown do
|
62
|
+
MusicianCell.class_eval do
|
63
|
+
@builders = false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
should "execute the block in controller context" do
|
68
|
+
@controller.bassist = true
|
69
|
+
assert_equal BassistCell, Cell::Base.build_class_for(@controller, MusicianCell, {})
|
70
|
+
end
|
71
|
+
|
72
|
+
should "limit the builder to the receiving class" do
|
73
|
+
assert_equal PianistCell, Cell::Base.build_class_for(@controller, PianistCell, {}) # don't inherit anything.
|
74
|
+
@controller.bassist = true
|
75
|
+
assert_equal BassistCell, Cell::Base.build_class_for(@controller, MusicianCell, {})
|
76
|
+
end
|
77
|
+
|
78
|
+
should "chain build blocks and execute them by ORing them in the same order" do
|
79
|
+
MusicianCell.build do
|
80
|
+
PianistCell unless bassist
|
81
|
+
end
|
82
|
+
|
83
|
+
MusicianCell.build do
|
84
|
+
UnknownCell # should never be executed.
|
85
|
+
end
|
86
|
+
|
87
|
+
assert_equal PianistCell, Cell::Base.build_class_for(@controller, MusicianCell, {}) # bassist is false.
|
88
|
+
@controller.bassist = true
|
89
|
+
assert_equal BassistCell, Cell::Base.build_class_for(@controller, MusicianCell, {})
|
90
|
+
end
|
91
|
+
|
92
|
+
should "use the original cell if no builder matches" do
|
93
|
+
assert_equal MusicianCell, Cell::Base.build_class_for(@controller, MusicianCell, {}) # bassist is false.
|
94
|
+
end
|
95
|
+
|
96
|
+
should "stop at the first builder returning a valid cell" do
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
should "pass options to the block" do
|
101
|
+
BassistCell.build do |opts|
|
102
|
+
SingerCell if opts[:sing_the_song]
|
103
|
+
end
|
104
|
+
assert_equal BassistCell, Cell::Base.build_class_for(@controller, BassistCell, {})
|
105
|
+
assert_equal SingerCell, Cell::Base.build_class_for(@controller, BassistCell, {:sing_the_song => true})
|
106
|
+
end
|
107
|
+
|
108
|
+
should "create the original target class if no block matches" do
|
109
|
+
assert_equal PianistCell, Cell::Base.build_class_for(@controller, PianistCell, {})
|
110
|
+
end
|
111
|
+
|
112
|
+
should "builders should return an empty array per default" do
|
113
|
+
assert_equal [], PianistCell.builders
|
114
|
+
end
|
115
|
+
end
|
26
116
|
|
27
117
|
should "provide possible_paths_for_state" do
|
28
118
|
assert_equal ["bad_guitarist/play", "bassist/play", "cell/rails/play"], cell(:bad_guitarist).possible_paths_for_state(:play)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CellsModuleTest < ActiveSupport::TestCase
|
4
|
+
context "Cells" do
|
5
|
+
setup do
|
6
|
+
@old_view_paths = Cell::Base.view_paths.clone
|
7
|
+
end
|
8
|
+
|
9
|
+
should "provide .setup" do
|
10
|
+
Cells.setup do |c|
|
11
|
+
c.append_view_path "/road/to/nowhere"
|
12
|
+
end
|
13
|
+
|
14
|
+
assert_equal "/road/to/nowhere", Cell::Base.view_paths.last.to_s
|
15
|
+
end
|
16
|
+
|
17
|
+
teardown do
|
18
|
+
Cell::Base.view_paths = @old_view_paths
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/test/rails/view_test.rb
CHANGED
@@ -5,18 +5,16 @@ class RailsViewTest < ActiveSupport::TestCase
|
|
5
5
|
|
6
6
|
context "A cell view" do
|
7
7
|
context "calling render :partial" do
|
8
|
-
should "render the cell partial in bassist/dii" do
|
9
|
-
|
10
|
-
|
11
|
-
end
|
12
|
-
assert_equal "Dumm Dii", render_cell(:bassist, :compose)
|
8
|
+
should "render the local cell partial in bassist/dii" do
|
9
|
+
assert_equal("Dii", in_view(:bassist) do
|
10
|
+
render :partial => 'dii'
|
11
|
+
end)
|
13
12
|
end
|
14
13
|
|
15
|
-
should "render the cell partial in bad_guitarist/dii" do
|
16
|
-
|
17
|
-
|
18
|
-
end
|
19
|
-
assert_equal "Dumm Dooom", render_cell(:bassist, :compose)
|
14
|
+
should "render the foreign cell partial in bad_guitarist/dii" do
|
15
|
+
assert_equal("Dooom", in_view(:bassist) do
|
16
|
+
render :partial => "bad_guitarist/dii"
|
17
|
+
end)
|
20
18
|
end
|
21
19
|
end
|
22
20
|
|
data/test/test_case_test.rb
CHANGED
@@ -49,7 +49,7 @@ class TestCaseTest < Cell::TestCase
|
|
49
49
|
assert_equal SingerCell, SingerCellTest.new(:cell_test).class.controller_class
|
50
50
|
end
|
51
51
|
|
52
|
-
context "with invoke" do
|
52
|
+
context "with #invoke" do
|
53
53
|
setup do
|
54
54
|
self.class.tests BassistCell
|
55
55
|
end
|
@@ -73,6 +73,24 @@ class TestCaseTest < Cell::TestCase
|
|
73
73
|
assert_select "a", "vd.com"
|
74
74
|
end
|
75
75
|
end
|
76
|
+
|
77
|
+
context "#setup_test_states_in" do
|
78
|
+
should "add the :in_view state" do
|
79
|
+
c = cell(:bassist, :block => lambda{"Cells rock."})
|
80
|
+
assert_not c.respond_to?(:in_view)
|
81
|
+
|
82
|
+
setup_test_states_in(c)
|
83
|
+
assert_equal "Cells rock.", c.render_state(:in_view)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "#in_view" do
|
88
|
+
should "execute the block in a real view" do
|
89
|
+
content = "Cells rule."
|
90
|
+
@test.setup
|
91
|
+
assert_equal("<h1>Cells rule.</h1>", @test.in_view(:bassist) do content_tag("h1", content) end)
|
92
|
+
end
|
93
|
+
end
|
76
94
|
end
|
77
95
|
end
|
78
96
|
end
|
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
|
+
- 4
|
9
|
+
version: 3.4.4
|
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:
|
17
|
+
date: 2011-01-02 00:00:00 +01:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -88,6 +88,7 @@ files:
|
|
88
88
|
- test/dummy/app/views/musician/hamlet.html.haml
|
89
89
|
- test/dummy/app/views/musician/featured.html.erb
|
90
90
|
- test/dummy/app/helpers/application_helper.rb
|
91
|
+
- test/cells_module_test.rb
|
91
92
|
- test/test_case_test.rb
|
92
93
|
- test/helper_test.rb
|
93
94
|
- test/cell_module_test.rb
|
@@ -184,6 +185,7 @@ test_files:
|
|
184
185
|
- test/dummy/app/views/musician/hamlet.html.haml
|
185
186
|
- test/dummy/app/views/musician/featured.html.erb
|
186
187
|
- test/dummy/app/helpers/application_helper.rb
|
188
|
+
- test/cells_module_test.rb
|
187
189
|
- test/test_case_test.rb
|
188
190
|
- test/helper_test.rb
|
189
191
|
- test/cell_module_test.rb
|