cells 3.10.1 → 3.11.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 (64) hide show
  1. data/.travis.yml +7 -0
  2. data/CHANGES.md +18 -0
  3. data/Gemfile +1 -1
  4. data/README.md +182 -57
  5. data/TODO.md +9 -0
  6. data/cells.gemspec +3 -1
  7. data/gemfiles/Gemfile.rails4-0 +2 -1
  8. data/gemfiles/Gemfile.rails4-1 +5 -3
  9. data/lib/cell/base.rb +33 -64
  10. data/lib/cell/base/prefixes.rb +27 -0
  11. data/lib/cell/base/self_contained.rb +13 -0
  12. data/lib/cell/base/view.rb +15 -0
  13. data/lib/cell/builder.rb +52 -53
  14. data/lib/cell/caching.rb +21 -4
  15. data/lib/cell/concept.rb +85 -0
  16. data/lib/cell/rails.rb +13 -6
  17. data/lib/cell/rails/view_model.rb +47 -6
  18. data/lib/cell/rendering.rb +13 -13
  19. data/lib/cell/test_case.rb +3 -3
  20. data/lib/cell/view_model.rb +151 -0
  21. data/lib/cells.rb +0 -60
  22. data/lib/cells/rails.rb +10 -5
  23. data/lib/cells/railtie.rb +2 -5
  24. data/lib/cells/version.rb +1 -1
  25. data/lib/generators/erb/concept_generator.rb +17 -0
  26. data/lib/generators/haml/concept_generator.rb +17 -0
  27. data/lib/generators/rails/concept_generator.rb +16 -0
  28. data/lib/generators/templates/concept/cell.rb +9 -0
  29. data/lib/generators/templates/concept/view.erb +7 -0
  30. data/lib/generators/templates/concept/view.haml +4 -0
  31. data/lib/generators/trailblazer/base.rb +21 -0
  32. data/lib/generators/trailblazer/view_generator.rb +18 -0
  33. data/test/app/cells/bassist_cell.rb +1 -1
  34. data/test/app/cells/record/views/layout.haml +2 -0
  35. data/test/app/cells/record/views/show.erb +1 -0
  36. data/test/app/cells/record/views/song.erb +1 -0
  37. data/test/app/cells/song/scale.haml +1 -0
  38. data/test/cell_module_test.rb +18 -37
  39. data/test/cells_module_test.rb +1 -1
  40. data/test/concept_generator_test.rb +26 -0
  41. data/test/concept_test.rb +78 -0
  42. data/test/dummy/Rakefile +1 -1
  43. data/test/dummy/app/assets/javascripts/application.js +2 -0
  44. data/test/dummy/app/cells/album/assets/album.js +1 -0
  45. data/test/dummy/app/concepts/song/assets/songs.js +1 -0
  46. data/test/dummy/config/application.rb +11 -6
  47. data/test/dummy/label/label.gemspec +2 -2
  48. data/test/helper_test.rb +2 -2
  49. data/test/prefixes_test.rb +75 -0
  50. data/test/rails/asset_pipeline_test.rb +20 -0
  51. data/test/rails/caching_test.rb +1 -9
  52. data/test/rails/cells_test.rb +2 -17
  53. data/test/rails/forms_test.rb +2 -1
  54. data/test/rails/integration_test.rb +199 -8
  55. data/test/rails/render_test.rb +2 -10
  56. data/test/rails/view_model_test.rb +135 -60
  57. data/test/rails_helper_api_test.rb +2 -1
  58. data/test/self_contained_test.rb +9 -2
  59. data/test/test_case_test.rb +2 -2
  60. data/test/test_helper.rb +2 -3
  61. metadata +117 -33
  62. checksums.yaml +0 -7
  63. data/test/dummy/app/controllers/musician_controller.rb +0 -36
  64. data/test/rails/router_test.rb +0 -45
@@ -39,6 +39,7 @@ class FormsTest < MiniTest::Spec
39
39
  end
40
40
 
41
41
  it "renders input fields within the form tag with ERB and ViewModel" do
42
+ skip if ::Cell.rails_version.~("3.0")
42
43
 
43
44
  html = SongFormCell.new(@controller).form
44
45
  puts html.to_s
@@ -65,7 +66,7 @@ class FormsTest < MiniTest::Spec
65
66
  end
66
67
 
67
68
  it "renders input fields within the form tag with HAML and ViewModel" do
68
-
69
+ skip
69
70
  html = HamlSongFormCell.new(@controller).form
70
71
  puts html.to_s
71
72
 
@@ -1,5 +1,65 @@
1
1
  require 'test_helper'
2
2
 
3
+ class MusicianController < ActionController::Base
4
+ def index
5
+ render :text => render_cell(:bassist, :promote)
6
+ end
7
+
8
+ def promote
9
+ render :text => render_cell(:trumpeter, :promote)
10
+ end
11
+
12
+ def promotion
13
+ render :text => render_cell(:bassist, :provoke)
14
+ end
15
+
16
+ def featured
17
+ end
18
+
19
+ def featured_with_block
20
+ end
21
+
22
+ def skills
23
+ render :text => render_cell(:bassist, :listen)
24
+ end
25
+
26
+ def hamlet
27
+ end
28
+
29
+ attr_reader :flag
30
+ def promotion_with_block
31
+ html = render_cell(:bassist, :play) do |cell|
32
+ @flag = cell.class
33
+ end
34
+
35
+ render :text => html
36
+ end
37
+
38
+ def song
39
+ render :inline => %{<%= concept("view_methods_test/cell", "Up For Breakfast").call %>} # TODO: concept doesn't need .call
40
+ end
41
+
42
+ def songs
43
+ render :inline => %{<%= concept("view_methods_test/cell", :collection => %w{Alltax Ronny}) %>} # TODO: concept doesn't need .call
44
+ end
45
+
46
+ def album
47
+ render :inline => %{<%= cell("view_methods_test/album", "Dreiklang").call %>} # DISCUSS: make .call in #cell?
48
+ end
49
+
50
+ def albums
51
+ render :inline => %{<%= cell("view_methods_test/album", :collection => %w{Dreiklang Coaster}) %>}
52
+ end
53
+ end
54
+
55
+ ActionController::TestCase.class_eval do
56
+ def png_src
57
+ return "/images/me.png" if Cell.rails_version >= 4.0
58
+ return "/assets/me.png" if Cell.rails_version >= 3.1
59
+ "/images/me.png"
60
+ end
61
+ end
62
+
3
63
  class ControllerMethodsTest < ActionController::TestCase
4
64
  tests MusicianController
5
65
 
@@ -11,7 +71,7 @@ class ControllerMethodsTest < ActionController::TestCase
11
71
  fix_relative_url_root
12
72
 
13
73
  get 'promotion'
14
- assert_equal "That's me, naked <img alt=\"Me\" src=\"/images/me.png\" />", @response.body
74
+ assert_equal "That's me, naked <img alt=\"Me\" src=\"#{png_src}\" />", @response.body
15
75
  end
16
76
 
17
77
  test "#render_cell with arbitrary options" do
@@ -36,20 +96,63 @@ class ControllerMethodsTest < ActionController::TestCase
36
96
  assert_equal BassistCell, @controller.flag
37
97
  end
38
98
 
39
- test "#cell_for" do
40
- @controller.cell_for(:bassist).must_be_instance_of BassistCell
99
+ test "#cell" do
100
+ @controller.cell(:bassist).must_be_instance_of BassistCell
41
101
  end
42
102
 
43
- test "#cell_for with options" do
44
- @controller.cell_for("controller_methods_test/song", :title => "We Called It America").
103
+ test "#cell with options" do
104
+ @controller.cell("controller_methods_test/song", :title => "We Called It America").
45
105
  title.must_equal "We Called It America"
46
106
  end
47
107
 
48
- if Cell.rails4_0? or Cell.rails4_1_or_more?
108
+ if Cell.rails_version >= "5.0" # TODO: make run.
49
109
  test "#render_cell for engine" do
50
110
  @controller.render_cell(:label, :show).must_equal "Fat Wreck"
51
111
  end
52
112
  end
113
+
114
+
115
+
116
+
117
+
118
+
119
+ test "pass url_helpers to the cell instance" do
120
+ assert_equal "/musicians", BassistCell.new(@controller).musicians_path
121
+ end
122
+
123
+ test "allow cells to use url_helpers" do
124
+ get "index"
125
+ assert_response :success
126
+ assert_equal "Find me at <a href=\"/musicians\">vd.com</a>\n", @response.body
127
+ end
128
+
129
+ test "delegate #url_options to the parent_controller" do
130
+ @controller.instance_eval do
131
+ def default_url_options
132
+ {:host => "cells.rails.org"}
133
+ end
134
+ end
135
+
136
+ assert_equal "http://cells.rails.org/musicians", BassistCell.new(@controller).musicians_url
137
+ end
138
+
139
+ test "allow cells to use *_url helpers when mixing in AC::UrlFor" do
140
+ get "promote"
141
+ assert_response :success
142
+ assert_equal "Find me at <a href=\"http://test.host/musicians\">vd.com</a>\n", @response.body
143
+ end
144
+
145
+ test "allow cells to use #config" do
146
+ BassistCell.class_eval do
147
+ def provoke; render; end
148
+ end
149
+
150
+ fix_relative_url_root
151
+
152
+ get "promotion"
153
+ assert_response :success
154
+ assert_equal "That's me, naked <img alt=\"Me\" src=\"#{png_src}\" />", @response.body
155
+ end
53
156
  end
54
157
 
55
158
 
@@ -70,7 +173,7 @@ class ViewMethodsTest < ActionController::TestCase
70
173
  fix_relative_url_root
71
174
 
72
175
  get 'featured'
73
- assert_equal "That's me, naked <img alt=\"Me\" src=\"/images/me.png\" />", @response.body
176
+ assert_equal "That's me, naked <img alt=\"Me\" src=\"#{png_src}\" />", @response.body
74
177
  end
75
178
 
76
179
  test "#render_cell with a block" do
@@ -82,9 +185,97 @@ class ViewMethodsTest < ActionController::TestCase
82
185
  fix_relative_url_root
83
186
 
84
187
  get 'hamlet'
85
- assert_equal "That's me, naked <img alt=\"Me\" src=\"/images/me.png\" />\n", @response.body
188
+ assert_equal "That's me, naked <img alt=\"Me\" src=\"#{png_src}\" />\n", @response.body
86
189
  end
87
190
 
191
+
192
+
193
+ unless ::Cell.rails_version.~("3.0")
194
+
195
+ # concept -------------------
196
+ class Cell < Cell::Concept
197
+ def show
198
+ render :text => "<b>#{model}</b>"
199
+ end
200
+
201
+
202
+ class Collection < ::Cell::Concept
203
+ def show
204
+ concept("view_methods_test/cell", "Dreiklang").call
205
+ end
206
+
207
+ def collection
208
+ concept("view_methods_test/cell", :collection => %w{Dreiklang Coaster})
209
+ end
210
+ end
211
+ end
212
+
213
+ # Concept#concept(:album, "Dreiklang").call
214
+ test "Concept#cell" do # FIXME: move to HelperTest.
215
+ Cell::Collection.new(@controller).call.must_equal "<b>Dreiklang</b>"
216
+ end
217
+
218
+ # Concept#concept(:album, collection: [])
219
+ test "Concept#cell collection: []" do # FIXME: move to HelperTest.
220
+ Cell::Collection.new(@controller).call(:collection).must_equal "<b>Dreiklang</b>\n<b>Coaster</b>"
221
+ end
222
+
223
+
224
+ # concept(:song, "Alltax").call
225
+ test "#concept" do
226
+ get :song
227
+ @response.body.must_equal "<b>Up For Breakfast</b>"
228
+ end
229
+
230
+ # concept(:song, collection: [..])
231
+ test "#concept with collection" do
232
+ get :songs
233
+ @response.body.must_equal "<b>Alltax</b>\n<b>Ronny</b>"
234
+ end
235
+
236
+
237
+
238
+ # view model ------------------
239
+ class AlbumCell < ::Cell::ViewModel
240
+ def show
241
+ "<b>#{model}</b>"
242
+ end
243
+ end
244
+
245
+ class AlbumsCell < ::Cell::ViewModel
246
+ def show
247
+ cell("view_methods_test/album", "Dreiklang").call
248
+ end
249
+
250
+ def collection
251
+ cell("view_methods_test/album", :collection => %w{Dreiklang Coaster})
252
+ end
253
+ end
254
+
255
+ # ViewModel#cell(:album, "Dreiklang").call
256
+ test "ViewModel#cell" do # FIXME: move to HelperTest.
257
+ AlbumsCell.new(@controller).call.must_equal "<b>Dreiklang</b>"
258
+ end
259
+
260
+ test "ViewModel#cell collection: []" do # FIXME: move to HelperTest.
261
+ AlbumsCell.new(@controller).call(:collection).must_equal "<b>Dreiklang</b>\n<b>Coaster</b>"
262
+ end
263
+
264
+
265
+ # cell(:album, "Dreiklang").call
266
+ test "#cell for view model" do
267
+ get :album
268
+ @response.body.must_equal "<b>Dreiklang</b>"
269
+ end
270
+
271
+ # cell(:album, collection: [..])
272
+ test "#cell with collection for view model" do
273
+ get :albums
274
+ @response.body.must_equal "<b>Dreiklang</b>\n<b>Coaster</b>"
275
+ end
276
+ end
277
+
278
+
88
279
  test "make params (and friends) available in a cell" do
89
280
  BassistCell.class_eval do
90
281
  def listen
@@ -122,7 +122,7 @@ class RailsRenderTest < MiniTest::Spec
122
122
  end
123
123
 
124
124
  exception = ActionView::MissingTemplate
125
- exception = Cell::VersionStrategy::MissingTemplate if Cell.rails3_0?
125
+ exception = Cell::VersionStrategy::MissingTemplate if Cell.rails_version.~("3.0")
126
126
 
127
127
  assert_raises exception do
128
128
  render_cell(:bassist, :groove)
@@ -134,7 +134,7 @@ class RailsRenderTest < MiniTest::Spec
134
134
  def groove; render; end
135
135
  end
136
136
 
137
- if Cell.rails3_0?
137
+ if Cell.rails_version.~("3.0")
138
138
  e = assert_raises Cell::Rails::MissingTemplate do
139
139
  render_cell(:bad_guitarist, :groove)
140
140
  end
@@ -167,14 +167,6 @@ class RailsRenderTest < MiniTest::Spec
167
167
  end
168
168
  assert_equal "<h1>Laaa</h1>\n<h1>Laaa</h1>\n<h1>Laaa</h1>\n", render_cell(:bassist, :sing)
169
169
  end
170
-
171
- # inheriting
172
- it "inherit play.html.erb from BassistCell" do
173
- BassistCell.class_eval do
174
- def play; render; end
175
- end
176
- assert_equal "Doo", render_cell(:bad_guitarist, :play)
177
- end
178
170
  end
179
171
 
180
172
  describe "A cell view" do
@@ -1,24 +1,22 @@
1
1
  require 'test_helper'
2
2
 
3
- # TODO: test if nested state renders are html_safe.
3
+ if Cell.rails_version >= 3.1
4
4
 
5
- class Song < OpenStruct
6
- extend ActiveModel::Naming
5
+ class Song < OpenStruct
6
+ extend ActiveModel::Naming
7
7
 
8
- def persisted?
9
- true
10
- end
8
+ def persisted?
9
+ true
10
+ end
11
11
 
12
- def to_param
13
- id
12
+ def to_param
13
+ id
14
+ end
14
15
  end
15
- end
16
16
 
17
17
 
18
18
 
19
- class SongCell < Cell::Rails
20
- include Cell::Rails::ViewModel
21
-
19
+ class SongCell < Cell::ViewModel
22
20
  def show
23
21
  render
24
22
  end
@@ -47,6 +45,10 @@ class SongCell < Cell::Rails
47
45
  render :dashboard
48
46
  end
49
47
 
48
+ def scale
49
+ render :layout => 'b'
50
+ end
51
+
50
52
  class Lyrics < self
51
53
  def show
52
54
  render :lyrics
@@ -54,81 +56,154 @@ class SongCell < Cell::Rails
54
56
  end
55
57
 
56
58
  class PlaysCell < self
59
+ def show
60
+ render :plays
61
+ end
57
62
  end
58
63
  end
59
64
 
60
- class ViewModelTest < MiniTest::Spec
61
- # class PianoSongCell < Cell::Rails
62
- # include ViewModel
65
+ class ViewModelTest < MiniTest::Spec
66
+ # views :show, :create #=> wrap in render_state(:show, *)
67
+ let (:cell) { SongCell.new(nil, :title => "Shades Of Truth") }
63
68
 
64
- # property :title
65
- # end
69
+ it { cell.title.must_equal "Shades Of Truth" }
66
70
 
67
- # views :show, :create #=> wrap in render_state(:show, *)
68
- let (:cell) { SongCell.build_for(nil, :title => "Shades Of Truth") }
71
+ class HitCell < Cell::ViewModel
72
+ property :title, :artist
69
73
 
70
- it { cell.title.must_equal "Shades Of Truth" }
74
+ def show
75
+ "Great!"
76
+ end
71
77
 
72
- class HitCell < Cell::Base
73
- include Cell::Rails::ViewModel
74
- property :title, :artist
75
- end
78
+ def rate
79
+ "Fantastic!"
80
+ end
81
+
82
+ attr_accessor :count
83
+ cache :count
84
+ end
85
+
86
+ let (:song) { Song.new(:title => "65", artist: "Boss") }
87
+ it { HitCell.new(nil, song).title.must_equal "65" }
88
+ it { HitCell.new(nil, song).artist.must_equal "Boss" }
76
89
 
77
- let (:song) { Song.new(:title => "65", artist: "Boss") }
78
- it { HitCell.new(song).title.must_equal "65" }
79
- it { HitCell.new(song).artist.must_equal "Boss" }
80
- end
81
90
 
82
- if Cell.rails3_2_or_more?
83
- class ViewModelIntegrationTest < ActionController::TestCase
84
- tests MusicianController
91
+ describe "#call" do
92
+ let (:cell) { HitCell.new(nil, song) }
85
93
 
86
- #let (:song) { Song.new(:title => "Blindfold", :id => 1) }
87
- #let (:html) { %{<h1>Shades Of Truth</h1>\n} }
88
- #let (:cell) { }
94
+ it { cell.call.must_equal "Great!" }
95
+ it { cell.call(:rate).must_equal "Fantastic!" }
96
+
97
+ it "no caching" do
98
+ cell.instance_eval do
99
+ def cache_configured?
100
+ false
101
+ end
102
+ end
103
+
104
+ cell.count = 1
105
+ cell.call(:count).must_equal "1"
106
+ cell.count = 2
107
+ cell.call(:count).must_equal "2"
108
+ end
89
109
 
90
- setup do
91
- @cell = SongCell.build_for(@controller, :song => Song.new(:title => "Blindfold", :id => "1"))
110
+ it "with caching" do
111
+ cell.instance_eval do
112
+ self.cache_store = ActiveSupport::Cache::MemoryStore.new
113
+ self.cache_configured = true
114
+ end
92
115
 
93
- @url = "/songs/1"
94
- @url = "http://test.host/songs/1" if Cell.rails4_0?
116
+ cell.count = 1
117
+ cell.call(:count).must_equal "1"
118
+ cell.count = 2
119
+ cell.call(:count).must_equal "1"
120
+ end
95
121
  end
96
122
 
97
123
 
98
- # test "instantiating without model, but call to ::property" do
99
- # assert_raises do
100
- # @controller.cell("view_model_test/piano_song")
101
- # end
124
+ # describe "::helper" do
125
+ # it { assert_raises { HitCell.helper Module.new } }
102
126
  # end
127
+ end
128
+
103
129
 
130
+ if Cell.rails_version >= "3.2"
131
+ class ViewModelIntegrationTest < ActionController::TestCase
132
+ tests MusicianController
104
133
 
105
- test "URL helpers in view" do
106
- @cell.show.must_equal %{<h1>BLINDFOLD</h1>
134
+ #let (:song) { Song.new(:title => "Blindfold", :id => 1) }
135
+ #let (:html) { %{<h1>Shades Of Truth</h1>\n} }
136
+ #let (:cell) { }
137
+
138
+ setup do
139
+ @cell = SongCell.new(@controller, :song => Song.new(:title => "Blindfold", :id => "1"))
140
+
141
+ @url = "/songs/1"
142
+ @url = "http://test.host/songs/1" if Cell.rails_version.>=("4.0")
143
+ end
144
+
145
+
146
+ # test "instantiating without model, but call to ::property" do
147
+ # assert_raises do
148
+ # @controller.cell("view_model_test/piano_song")
149
+ # end
150
+ # end
151
+
152
+
153
+ test "URL helpers in view" do
154
+ @cell.show.must_equal %{<h1>BLINDFOLD</h1>
107
155
  <a href=\"#{@url}\">Permalink</a>
108
- } end
156
+ } end
109
157
 
110
- test "URL helper in instance" do
111
- @cell.self_url.must_equal @url
112
- end
158
+ test "URL helper in instance" do
159
+ @cell.self_url.must_equal @url
160
+ end
113
161
 
114
- test "implicit #render" do
115
- @cell.details.must_equal "<h3>BLINDFOLD</h3>\n"
116
- SongCell.build_for(@controller, :song => Song.new(:title => "Blindfold", :id => 1)).details
117
- end
162
+ test "implicit #render" do
163
+ @cell.details.must_equal "<h3>BLINDFOLD</h3>\n"
164
+ SongCell.new(@controller, :song => Song.new(:title => "Blindfold", :id => 1)).details
165
+ end
166
+
167
+ test "explicit #render with one arg" do
168
+ @cell = SongCell.new(@controller, :song => Song.new(:title => "Blindfold", :id => 1))
169
+ @cell.stats.must_equal "<h3>BLINDFOLD</h3>\n"
170
+ end
171
+
172
+ test "nested render" do
173
+ @cell.info.must_equal "<li>BLINDFOLD\n</li>\n"
174
+ end
118
175
 
119
- test "explicit #render with one arg" do
120
- @cell = SongCell.build_for(@controller, :song => Song.new(:title => "Blindfold", :id => 1))
121
- @cell.stats.must_equal "<h3>BLINDFOLD</h3>\n"
176
+ test "nested rendering method" do
177
+ @cell.dashboard.must_equal "<h1>Dashboard</h1>\n<h3>Lyrics for BLINDFOLD</h3>\n<li>\nIn the Mirror\n</li>\n<li>\nI can see\n</li>\n\nPlays: 99\n\nPlays: 99\n\n"
178
+ end
179
+
180
+ test( "layout") { @cell.scale.must_equal "<b>A Minor!\n</b>" }
181
+
182
+ # TODO: when we don't pass :song into Lyrics
122
183
  end
184
+ end
123
185
 
124
- test "nested render" do
125
- @cell.info.must_equal "<li>BLINDFOLD\n</li>\n"
186
+ class CollectionTest < MiniTest::Spec
187
+ class ReleasePartyCell < Cell::ViewModel
188
+ def show
189
+ "Party on, #{model}!"
190
+ end
191
+
192
+ def show_more
193
+ "Go nuts, #{model}!"
194
+ end
126
195
  end
127
196
 
128
- test "nested rendering method" do
129
- @cell.dashboard.must_equal "<h1>Dashboard</h1>\n<h3>Lyrics for BLINDFOLD</h3>\n<li>\nIn the Mirror\n</li>\n<li>\nI can see\n</li>\n\nPlays: 99\n\nPlays: 99\n\n"
197
+
198
+ describe "::collection" do
199
+ it { Cell::ViewModel.collection("collection_test/release_party", @controller, %w{Garth Wayne}).must_equal "Party on, Garth!\nParty on, Wayne!" }
200
+ it { Cell::ViewModel.collection("collection_test/release_party", @controller, %w{Garth Wayne}, :show_more).must_equal "Go nuts, Garth!\nGo nuts, Wayne!" }
130
201
  end
202
+ # TODO: test with builders ("polymorphic collections") and document that.
131
203
 
132
- # TODO: when we don't pass :song into Lyrics
204
+ describe "::cell" do
205
+ it { Cell::ViewModel.cell("collection_test/release_party", @controller, "Garth").call.must_equal "Party on, Garth!" }
206
+ end
133
207
  end
208
+
134
209
  end