cells 3.8.8 → 3.9.0

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.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -1
  3. data/.travis.yml +5 -2
  4. data/CHANGES.textile +23 -15
  5. data/Gemfile +1 -1
  6. data/README.md +412 -0
  7. data/Rakefile +2 -2
  8. data/cells.gemspec +5 -6
  9. data/gemfiles/Gemfile.rails3-0 +2 -2
  10. data/gemfiles/Gemfile.rails3-1 +1 -1
  11. data/gemfiles/Gemfile.rails3-2 +1 -2
  12. data/gemfiles/Gemfile.rails4-0 +7 -0
  13. data/lib/cell.rb +27 -0
  14. data/lib/cell/base.rb +31 -18
  15. data/lib/cell/builder.rb +11 -10
  16. data/lib/cell/dsl.rb +7 -0
  17. data/lib/cell/rack.rb +5 -9
  18. data/lib/cell/rails.rb +19 -11
  19. data/lib/cell/rails/view_model.rb +115 -0
  20. data/lib/cell/rails3_0_strategy.rb +1 -1
  21. data/lib/cell/rails3_1_strategy.rb +1 -1
  22. data/lib/cell/rails4_0_strategy.rb +1 -2
  23. data/lib/cell/test_case.rb +11 -11
  24. data/lib/cells.rb +4 -3
  25. data/lib/cells/rails.rb +16 -3
  26. data/lib/cells/version.rb +1 -1
  27. data/test/app/cells/bassist_cell.rb +9 -1
  28. data/test/app/cells/rails_helper_api_test/bassist/edit.html.erb +3 -3
  29. data/test/app/cells/song/dashboard.haml +7 -0
  30. data/test/app/cells/song/details.html.haml +1 -0
  31. data/test/app/cells/song/info.html.haml +1 -0
  32. data/test/app/cells/song/lyrics.html.haml +6 -0
  33. data/test/app/cells/song/plays.haml +1 -0
  34. data/test/app/cells/song/show.html.haml +3 -0
  35. data/test/app/cells/song/title.html.haml +1 -0
  36. data/test/app/cells/view_model_test/comments/show.haml +7 -0
  37. data/test/cell_module_test.rb +39 -41
  38. data/test/cell_test.rb +28 -0
  39. data/test/dummy/app/views/musician/featured_with_block.html.erb +1 -1
  40. data/test/dummy/app/views/musician/title.erb +1 -0
  41. data/test/dummy/config/routes.rb +1 -0
  42. data/test/helper_test.rb +13 -10
  43. data/test/rails/caching_test.rb +75 -73
  44. data/test/rails/cells_test.rb +25 -23
  45. data/test/rails/integration_test.rb +80 -61
  46. data/test/rails/view_model_test.rb +119 -0
  47. data/test/rails_helper_api_test.rb +11 -13
  48. metadata +41 -61
  49. data/README.rdoc +0 -279
  50. data/about.yml +0 -7
  51. data/test/app/cells/producer/capture.html.erb +0 -1
  52. data/test/app/cells/producer/content_for.html.erb +0 -2
  53. data/test/rails/capture_test.rb +0 -70
@@ -69,7 +69,7 @@ module Cells
69
69
  module Engines
70
70
  module VersionStrategy
71
71
  def registered_engines
72
- ::Rails::Application.railties.engines
72
+ ::Rails.application.railties.engines
73
73
  end
74
74
 
75
75
  def existent_directories_for(path)
@@ -27,7 +27,7 @@ module Cells
27
27
  module Engines
28
28
  module VersionStrategy
29
29
  def registered_engines
30
- ::Rails::Application::Railties.engines
30
+ ::Rails.application.railties.engines
31
31
  end
32
32
 
33
33
  def existent_directories_for(path)
@@ -27,8 +27,7 @@ module Cells
27
27
  module Engines
28
28
  module VersionStrategy
29
29
  def registered_engines
30
- #::Rails::Railties.engines
31
- []
30
+ ::Rails::Engine::Railties.engines
32
31
  end
33
32
 
34
33
  def existent_directories_for(path)
@@ -58,36 +58,36 @@ module Cell
58
58
  super(HTML::Document.new(last_invoke).root, *args, &block)
59
59
  end
60
60
  end
61
-
61
+
62
62
  module CommonTestMethods
63
63
  def setup
64
- @controller = Class.new(ActionController::Base).new
65
- @request = ::ActionController::TestRequest.new
64
+ @controller ||= Class.new(ActionController::Base).new
65
+ @request ||= ::ActionController::TestRequest.new
66
66
  @response = ::ActionController::TestResponse.new
67
67
  @controller.request = @request
68
68
  @controller.response = @response
69
69
  @controller.params = {}
70
70
  end
71
-
72
- # Runs the block while computing the instance variables diff from before and after.
71
+
72
+ # Runs the block while computing the instance variables diff from before and after.
73
73
  def extract_state_ivars_for(cell)
74
74
  before = cell.instance_variables
75
- yield
75
+ yield
76
76
  after = cell.instance_variables
77
-
77
+
78
78
  Hash[(after - before).collect do |var|
79
79
  next if var =~ /^@_/
80
80
  [var[1, var.length].to_sym, cell.instance_variable_get(var)]
81
81
  end.compact]
82
82
  end
83
83
  end
84
-
84
+
85
85
 
86
86
  module TestMethods
87
87
  include CommonTestMethods
88
-
88
+
89
89
  attr_reader :last_invoke, :subject_cell, :view_assigns
90
-
90
+
91
91
  # Use this for functional tests of your application cells.
92
92
  #
93
93
  # Example:
@@ -100,7 +100,7 @@ module Cell
100
100
  @view_assigns = extract_state_ivars_for(@subject_cell) do
101
101
  @last_invoke = @subject_cell.render_state(state, *args)
102
102
  end
103
-
103
+
104
104
  @last_invoke
105
105
  end
106
106
 
data/lib/cells.rb CHANGED
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # Cells are view components for Rails. Being lightweight controllers with actions and views, cells are the
4
4
  # answer to <tt>DoubleRenderError</tt>s and the long awaited ability to render actions within actions.
5
- #
5
+ #
6
6
  # == Directory structure
7
7
  #
8
8
  # Cells live in +app/cells/+ and have a similar file layout as controllers.
@@ -17,7 +17,7 @@
17
17
  # box.html.erb
18
18
  #
19
19
  # == Cell nesting
20
- #
20
+ #
21
21
  # Is is good practice to split up complex cell views into multiple states or views. Remember, you can always use
22
22
  # <tt>render :view => ...</tt> and <tt>render :state => ...</tt> in your views.
23
23
  #
@@ -42,7 +42,7 @@
42
42
  # = @item.title
43
43
  #
44
44
  # render :state => :order_button
45
- #
45
+ #
46
46
  # which is more than just a partial, as you may execute additional code in the state method.
47
47
  #
48
48
  # == View inheritance
@@ -72,6 +72,7 @@ module Cells
72
72
  end
73
73
  end
74
74
 
75
+ require 'cell'
75
76
  require 'cell/rails'
76
77
  require 'cells/rails'
77
78
  require 'cell/deprecations'
data/lib/cells/rails.rb CHANGED
@@ -3,9 +3,14 @@
3
3
  module Cells
4
4
  module Rails
5
5
  module ActionController
6
+ def cell_for(name, *args, &block)
7
+ ::Cell::Base.cell_for(name, self, *args, &block)
8
+ end
9
+ alias_method :cell, :cell_for # DISCUSS: make this configurable?
10
+
6
11
  # Renders the cell state and returns the content. You may pass options here, too. They will be
7
12
  # around in @opts.
8
- #
13
+ #
9
14
  # Example:
10
15
  #
11
16
  # @box = render_cell(:posts, :latest, :user => current_user)
@@ -41,19 +46,27 @@ module Cells
41
46
  ActiveSupport::Deprecation.warn "Please pass the cell class into #expire_cell_state, as in expire_cell_state(DirectorCell, :count, :user_id => 1)"
42
47
  cell_class = Cell::Rails.class_from_cell_name(cell_class)
43
48
  end
44
-
49
+
45
50
  key = cell_class.state_cache_key(state, args)
46
51
  cell_class.expire_cache_key(key, opts)
47
52
  end
48
53
  end
49
54
 
50
55
  module ActionView
56
+ # Returns the cell instance for +name+. You may pass arbitrary options to your
57
+ # cell.
58
+ #
59
+ # = cell(:song, :title => "Creeping Out Sara").render(:show)
60
+ def cell_for(name, *args, &block)
61
+ controller.cell_for(name, *args, &block)
62
+ end
63
+ alias_method :cell, :cell_for # DISCUSS: make this configurable?
64
+
51
65
  # See Cells::Rails::ActionController#render_cell.
52
66
  def render_cell(name, state, *args, &block)
53
67
  ::Cell::Rails.render_cell_for(name, state, controller, *args, &block)
54
68
  end
55
69
  end
56
-
57
70
  end
58
71
  end
59
72
 
data/lib/cells/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Cells
2
- VERSION = '3.8.8'
2
+ VERSION = '3.9.0'
3
3
  end
@@ -1,8 +1,16 @@
1
1
  class BassistCell < Cell::Rails
2
- def play; render; end
2
+ def play
3
+ render
4
+ end
3
5
 
4
6
  def shout(args)
5
7
  @words = args[:words]
6
8
  render
7
9
  end
10
+
11
+ def provoke
12
+ controller.config.relative_url_root = "" if Cell.rails3_0?
13
+
14
+ render
15
+ end
8
16
  end
@@ -1,5 +1,5 @@
1
- <%= simple_form_for @fruit do |f| %>
2
- <%= f.input :title %>
1
+ <%= form_for @fruit do |f| %>
2
+ <%= f.text_field :title %>
3
3
  <%= f.button :submit %>
4
- <% end %>
4
+ <% end %>
5
5
  <%= url_for(:host => "apotomo.de") %>
@@ -0,0 +1,7 @@
1
+ %h1 Dashboard
2
+
3
+ = SongCell::Lyrics.new(controller, :song => song, :phrases => ["In the Mirror", "I can see"]).show
4
+
5
+ = SongCell::PlaysCell.new(controller, :song => song).call
6
+
7
+ = cell("song_cell/plays").call
@@ -0,0 +1 @@
1
+ %h3 #{title}
@@ -0,0 +1 @@
1
+ %li #{render :title}
@@ -0,0 +1,6 @@
1
+ -# notice how we use title from the superclass here.
2
+ %h3 Lyrics for #{title}
3
+
4
+ - phrases.each do |ln|
5
+ %li
6
+ = ln
@@ -0,0 +1 @@
1
+ Plays: 99
@@ -0,0 +1,3 @@
1
+ %h1 #{title}
2
+
3
+ = link_to "Permalink", song
@@ -0,0 +1 @@
1
+ = title
@@ -0,0 +1,7 @@
1
+ %h1 "Comments from #{link_to title, Musician.new}"
2
+
3
+ = local
4
+
5
+ =# form
6
+
7
+ =# comment.created_at
@@ -18,25 +18,23 @@ end
18
18
 
19
19
 
20
20
  class CellBaseTest < MiniTest::Spec
21
- describe "Cell::Base" do
22
- it "still have a working #url_for" do
23
- cell = Cell::Base.new
24
- cell.instance_eval do
25
- # You can use #default_url_options.
26
- def default_url_options
27
- {:host => "cells-project.org"}
28
- end
29
-
21
+ it "still have a working #url_for" do
22
+ cell = Cell::Base.new
23
+ cell.instance_eval do
24
+ # You can use #default_url_options.
25
+ def default_url_options
26
+ {:host => "cells-project.org"}
30
27
  end
31
- # You could also use a *_url or *_path helper method here.
32
- assert_equal "http://cells-project.org/dashboard/show", cell.url_for(:action => :show, :controller => :dashboard)
28
+
33
29
  end
34
-
35
- describe ".render_cell_for" do
36
- it "invokes controller-less cell" do
37
- Cell::Base.view_paths= ["test/app/cells"]
38
- assert_equal "YAAAaaargh!\n", Cell::Base.render_cell_for(:shouter, :sing, "Y")
39
- end
30
+ # You could also use a *_url or *_path helper method here.
31
+ assert_equal "http://cells-project.org/dashboard/show", cell.url_for(:action => :show, :controller => :dashboard)
32
+ end
33
+
34
+ describe ".render_cell_for" do
35
+ it "invokes controller-less cell" do
36
+ Cell::Base.view_paths= ["test/app/cells"]
37
+ assert_equal "YAAAaaargh!\n", Cell::Base.render_cell_for(:shouter, :sing, "Y")
40
38
  end
41
39
  end
42
40
  end
@@ -50,19 +48,19 @@ class CellModuleTest < MiniTest::Spec
50
48
  it "render the actual cell" do
51
49
  assert_equal "Doo", Cell::Rails.render_cell_for(:bassist, :play, @controller)
52
50
  end
53
-
51
+
54
52
  it "accept a block, passing the cell instance" do
55
53
  flag = false
56
54
  html = Cell::Rails.render_cell_for(:bassist, :play, @controller) do |cell|
57
55
  assert_equal BassistCell, cell.class
58
56
  flag = true
59
57
  end
60
-
58
+
61
59
  assert_equal "Doo", html
62
60
  assert flag
63
61
  end
64
62
  end
65
-
63
+
66
64
  describe "create_cell_for" do
67
65
  it "call the cell's builders, eventually returning a different class" do
68
66
  class DrummerCell < BassistCell
@@ -70,22 +68,22 @@ class CellModuleTest < MiniTest::Spec
70
68
  BassistCell
71
69
  end
72
70
  end
73
-
71
+
74
72
  assert_instance_of BassistCell, Cell::Rails.create_cell_for("cell_module_test/drummer", :play, @controller)
75
73
  end
76
74
  end
77
-
75
+
78
76
  describe "#create_cell_for with #build" do
79
77
  before do
80
78
  @controller.class_eval do
81
79
  attr_accessor :bassist
82
80
  end
83
-
81
+
84
82
  MusicianCell.build do
85
83
  BassistCell if bassist
86
84
  end
87
85
  end
88
-
86
+
89
87
  after do
90
88
  MusicianCell.class_eval do
91
89
  @builders = false
@@ -94,40 +92,40 @@ class CellModuleTest < MiniTest::Spec
94
92
  @builders = false
95
93
  end
96
94
  end
97
-
95
+
98
96
  it "execute the block in controller describe" do
99
97
  @controller.bassist = true
100
98
  assert_is_a BassistCell, Cell::Rails.create_cell_for(:musician, @controller)
101
99
  end
102
-
100
+
103
101
  it "limit the builder to the receiving class" do
104
102
  assert_is_a PianistCell, Cell::Rails.create_cell_for(:pianist, @controller) # don't inherit anything.
105
103
  @controller.bassist = true
106
104
  assert_is_a BassistCell, Cell::Rails.create_cell_for(:musician, @controller)
107
105
  end
108
-
106
+
109
107
  it "chain build blocks and execute them by ORing them in the same order" do
110
108
  MusicianCell.build do
111
109
  PianistCell unless bassist
112
110
  end
113
-
111
+
114
112
  MusicianCell.build do
115
113
  UnknownCell # it never be executed.
116
114
  end
117
-
115
+
118
116
  assert_is_a PianistCell, Cell::Rails.create_cell_for(:musician, @controller) # bassist is false.
119
117
  @controller.bassist = true
120
118
  assert_is_a BassistCell, Cell::Rails.create_cell_for(:musician, @controller)
121
119
  end
122
-
120
+
123
121
  it "use the original cell if no builder matches" do
124
122
  assert_is_a MusicianCell, Cell::Rails.create_cell_for(:musician, @controller) # bassist is false.
125
123
  end
126
-
124
+
127
125
  it "stop at the first builder returning a valid cell" do
128
-
126
+
129
127
  end
130
-
128
+
131
129
  it "pass options to the block" do
132
130
  BassistCell.build do |opts|
133
131
  SingerCell if opts[:sing_the_song]
@@ -135,38 +133,38 @@ class CellModuleTest < MiniTest::Spec
135
133
  assert_kind_of BassistCell, Cell::Rails.create_cell_for(:bassist, @controller, {})
136
134
  assert_kind_of SingerCell, Cell::Rails.create_cell_for(:bassist, @controller, {:sing_the_song => true})
137
135
  end
138
-
136
+
139
137
  it "create the original target class if no block matches" do
140
138
  assert_kind_of PianistCell, Cell::Rails.create_cell_for(:pianist, @controller)
141
139
  end
142
-
140
+
143
141
  it "builders it return an empty array per default" do
144
142
  assert_equal [], PianistCell.send(:builders)
145
143
  end
146
144
  end
147
-
145
+
148
146
  it "provide class_from_cell_name" do
149
147
  assert_equal BassistCell, ::Cell::Rails.class_from_cell_name('bassist')
150
148
  end
151
-
149
+
152
150
  if Cell.rails3_0?
153
151
  it "provide possible_paths_for_state" do
154
152
  assert_equal ["bad_guitarist/play", "bassist/play"], cell(:bad_guitarist).send(:possible_paths_for_state, :play)
155
153
  end
156
-
154
+
157
155
  it "provide Cell.cell_name" do
158
156
  assert_equal 'bassist', cell(:bassist).class.cell_name
159
157
  end
160
-
158
+
161
159
  it "provide cell_name for modules, too" do
162
160
  class SingerCell < Cell::Rails
163
161
  end
164
-
162
+
165
163
  assert_equal "cell_module_test/singer", CellModuleTest::SingerCell.cell_name
166
164
  end
167
165
  end
168
166
  end
169
-
167
+
170
168
  it "respond to #rails3_1_or_more?" do
171
169
  if Rails::VERSION::MAJOR == 3
172
170
  if Rails::VERSION::MINOR == 0
data/test/cell_test.rb ADDED
@@ -0,0 +1,28 @@
1
+ require "test_helper"
2
+
3
+ class CellTest < MiniTest::Spec
4
+ class ArtistCell < Cell::Rails
5
+ end
6
+ class SongCell < Cell::Base
7
+ include Cell::OptionsConstructor
8
+ end
9
+
10
+ describe "#initialize" do
11
+ it { Class.new(Cell::Base) { include Cell::OptionsConstructor }.new(:song => song=Object.new).song.must_equal song }
12
+ it { Class.new(Cell::Rack) { include Cell::OptionsConstructor }.new(Object, :song => song=Object.new).song.must_equal song }
13
+ it { Class.new(Cell::Rails) { include Cell::OptionsConstructor }.new(Object, :song => song=Object.new).song.must_equal song }
14
+ end
15
+
16
+ describe "::create_cell_for" do
17
+ it { Cell::Base.create_cell_for("cell_test/song", :song => song=Object.new).song.must_equal song }
18
+ end
19
+
20
+ describe "#cell" do
21
+ it { Cell::Rails.new(Object).cell("cell_test/artist").must_be_instance_of ArtistCell }
22
+ it { Cell::Base.new.cell("cell_test/song").must_be_instance_of SongCell }
23
+ end
24
+ end
25
+
26
+ class OptionsConstructorTest < MiniTest::Spec
27
+ it { Class.new(Cell::Base) { include Cell::OptionsConstructor }.new(:song => song=Object.new).song.must_equal song }
28
+ end