cells 3.11.3 → 4.0.0.beta1

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 (204) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.travis.yml +15 -13
  4. data/Appraisals +23 -0
  5. data/CHANGES.md +20 -3
  6. data/Gemfile +5 -7
  7. data/README.md +317 -236
  8. data/Rakefile +1 -1
  9. data/TODO.md +3 -0
  10. data/cells.gemspec +19 -28
  11. data/gemfiles/rails3.2.gemfile +14 -0
  12. data/gemfiles/rails4.0.gemfile +14 -0
  13. data/gemfiles/rails4.1.gemfile +15 -0
  14. data/gemfiles/rails4.2.gemfile +14 -0
  15. data/lib/cell.rb +28 -21
  16. data/lib/cell/caching.rb +10 -22
  17. data/lib/cell/caching/notification.rb +15 -0
  18. data/lib/cell/concept.rb +4 -69
  19. data/lib/cell/development.rb +11 -0
  20. data/lib/{cells → cell}/engines.rb +1 -1
  21. data/lib/cell/layout.rb +20 -0
  22. data/lib/cell/partial.rb +17 -0
  23. data/lib/cell/{base/prefixes.rb → prefixes.rb} +1 -1
  24. data/lib/cell/rails.rb +58 -50
  25. data/lib/cell/railtie.rb +60 -0
  26. data/lib/cell/{base/self_contained.rb → self_contained.rb} +1 -1
  27. data/lib/cell/templates.rb +60 -0
  28. data/lib/cell/test_case.rb +4 -162
  29. data/lib/cell/testing.rb +15 -0
  30. data/lib/cell/twin.rb +11 -29
  31. data/lib/cell/version.rb +10 -0
  32. data/lib/cell/view_model.rb +196 -88
  33. data/lib/cells.rb +1 -20
  34. data/lib/rails/generators/cell/cell_generator.rb +43 -0
  35. data/lib/rails/generators/cell/templates/cell.rb.erb +8 -0
  36. data/lib/{generators/templates/concept → rails/generators/cell/templates}/view.erb +0 -0
  37. data/lib/{generators/templates/concept → rails/generators/cell/templates}/view.haml +0 -0
  38. data/lib/rails/generators/cell/templates/view.slim +2 -0
  39. data/lib/rails/generators/concept/concept_generator.rb +38 -0
  40. data/lib/{generators/templates/concept/cell.rb → rails/generators/concept/templates/concept.rb.erb} +2 -2
  41. data/lib/{generators → rails/generators/concept}/templates/view.erb +0 -0
  42. data/lib/{generators → rails/generators/concept}/templates/view.haml +0 -0
  43. data/lib/rails/generators/concept/templates/view.slim +2 -0
  44. data/lib/rails/generators/test_unit/cell/cell_generator.rb +21 -0
  45. data/lib/{generators/templates/cell_test.rb → rails/generators/test_unit/cell/templates/unit_test.rb.erb} +3 -3
  46. data/lib/rails/generators/test_unit/concept/concept_generator.rb +21 -0
  47. data/lib/rails/generators/test_unit/concept/templates/unit_test.rb.erb +11 -0
  48. data/lib/{cells → tasks}/cells.rake +0 -0
  49. data/test/builder_test.rb +58 -0
  50. data/test/caching_test.rb +298 -0
  51. data/test/cell_benchmark.rb +32 -0
  52. data/test/cell_generator_test.rb +51 -82
  53. data/test/cell_test.rb +8 -23
  54. data/test/concept_generator_test.rb +22 -13
  55. data/test/concept_test.rb +41 -75
  56. data/test/dummy/app/views/musician/hamlet.html.erb +1 -0
  57. data/test/dummy/config/application.rb +21 -8
  58. data/test/{app/cells/bassist/play.html.erb → fixtures/bassist/play.erb} +0 -0
  59. data/test/fixtures/concepts/record/views/layout.erb +1 -0
  60. data/test/{app → fixtures}/concepts/record/views/show.erb +0 -0
  61. data/test/{app → fixtures}/concepts/record/views/song.erb +0 -0
  62. data/test/fixtures/inherit_views_test/popper/tap.erb +1 -0
  63. data/test/fixtures/inherit_views_test/tapper/play.erb +1 -0
  64. data/test/fixtures/inherit_views_test/tapper/tap.erb +1 -0
  65. data/test/fixtures/partial_test/with_partial/show.erb +1 -0
  66. data/test/fixtures/partials/_show.html.erb +1 -0
  67. data/test/fixtures/partials/_show.xml.erb +1 -0
  68. data/test/fixtures/song/ivar.erb +1 -0
  69. data/test/fixtures/song/show.erb +1 -0
  70. data/test/fixtures/song/with_erb.erb +4 -0
  71. data/test/fixtures/song/with_html.erb +1 -0
  72. data/test/fixtures/song/with_locals.erb +2 -0
  73. data/test/fixtures/song_with_layout/happy.erb +1 -0
  74. data/test/fixtures/song_with_layout/merry.erb +1 -0
  75. data/test/fixtures/song_with_layout/show.erb +1 -0
  76. data/test/fixtures/song_with_layout/show_with_layout.erb +1 -0
  77. data/test/fixtures/templates_caching_test/song/show.erb +1 -0
  78. data/test/fixtures/url_helper_test/song/edit.erb +8 -0
  79. data/test/fixtures/url_helper_test/song/with_block.erb +2 -0
  80. data/test/fixtures/url_helper_test/song/with_capture.erb +4 -0
  81. data/test/fixtures/url_helper_test/song/with_content_tag.erb +6 -0
  82. data/test/fixtures/url_helper_test/song/with_form_for_block.erb +3 -0
  83. data/test/fixtures/url_helper_test/song/with_link_to.erb +3 -0
  84. data/test/layout_test.rb +57 -0
  85. data/test/partial_test.rb +27 -0
  86. data/test/prefixes_test.rb +36 -10
  87. data/test/public_test.rb +42 -0
  88. data/test/rails_extensions_test.rb +51 -0
  89. data/test/render_test.rb +103 -0
  90. data/test/templates_test.rb +45 -0
  91. data/test/test_case_test.rb +21 -122
  92. data/test/test_helper.rb +37 -33
  93. data/test/twin_test.rb +3 -7
  94. data/test/url_helper_test.rb +89 -0
  95. metadata +92 -357
  96. data/gemfiles/Gemfile.rails3-0 +0 -7
  97. data/gemfiles/Gemfile.rails3-1 +0 -7
  98. data/gemfiles/Gemfile.rails3-2 +0 -7
  99. data/gemfiles/Gemfile.rails4-0 +0 -12
  100. data/gemfiles/Gemfile.rails4-1 +0 -12
  101. data/lib/cell/base.rb +0 -82
  102. data/lib/cell/base/view.rb +0 -15
  103. data/lib/cell/builder.rb +0 -71
  104. data/lib/cell/deprecations.rb +0 -41
  105. data/lib/cell/dsl.rb +0 -7
  106. data/lib/cell/rack.rb +0 -32
  107. data/lib/cell/rails/helper_api.rb +0 -37
  108. data/lib/cell/rails/view_model.rb +0 -159
  109. data/lib/cell/rails3_0_strategy.rb +0 -82
  110. data/lib/cell/rails3_1_strategy.rb +0 -40
  111. data/lib/cell/rails4_0_strategy.rb +0 -39
  112. data/lib/cell/rails4_1_strategy.rb +0 -40
  113. data/lib/cell/rendering.rb +0 -109
  114. data/lib/cells/rails.rb +0 -86
  115. data/lib/cells/railtie.rb +0 -38
  116. data/lib/cells/version.rb +0 -3
  117. data/lib/generators/USAGE +0 -30
  118. data/lib/generators/cells/base.rb +0 -22
  119. data/lib/generators/cells/cell_generator.rb +0 -15
  120. data/lib/generators/cells/view_generator.rb +0 -18
  121. data/lib/generators/erb/cell_generator.rb +0 -15
  122. data/lib/generators/erb/concept_generator.rb +0 -17
  123. data/lib/generators/haml/cell_generator.rb +0 -17
  124. data/lib/generators/haml/concept_generator.rb +0 -17
  125. data/lib/generators/rails/cell_generator.rb +0 -16
  126. data/lib/generators/rails/concept_generator.rb +0 -16
  127. data/lib/generators/slim/cell_generator.rb +0 -17
  128. data/lib/generators/templates/cell.rb +0 -9
  129. data/lib/generators/templates/view.slim +0 -4
  130. data/lib/generators/test_unit/cell_generator.rb +0 -14
  131. data/lib/generators/trailblazer/base.rb +0 -21
  132. data/lib/generators/trailblazer/view_generator.rb +0 -18
  133. data/test/app/cells/album/views/cover.haml +0 -1
  134. data/test/app/cells/bad_guitarist/_dii.html.erb +0 -1
  135. data/test/app/cells/bad_guitarist_cell.rb +0 -2
  136. data/test/app/cells/bassist/_dii.html.erb +0 -1
  137. data/test/app/cells/bassist/ahem.html.erb +0 -1
  138. data/test/app/cells/bassist/compose.html.erb +0 -1
  139. data/test/app/cells/bassist/contact_form.html.erb +0 -1
  140. data/test/app/cells/bassist/form_for.erb +0 -3
  141. data/test/app/cells/bassist/form_for_in_haml.haml +0 -2
  142. data/test/app/cells/bassist/jam.html.erb +0 -3
  143. data/test/app/cells/bassist/play.js.erb +0 -1
  144. data/test/app/cells/bassist/pose.html.erb +0 -1
  145. data/test/app/cells/bassist/promote.html.erb +0 -1
  146. data/test/app/cells/bassist/provoke.html.erb +0 -1
  147. data/test/app/cells/bassist/shout.html.erb +0 -1
  148. data/test/app/cells/bassist/sing.html.haml +0 -1
  149. data/test/app/cells/bassist/slap.html.erb +0 -1
  150. data/test/app/cells/bassist/yell.en.html.erb +0 -1
  151. data/test/app/cells/bassist_cell.rb +0 -25
  152. data/test/app/cells/club_security.rb +0 -2
  153. data/test/app/cells/club_security/guard/help.html.erb +0 -1
  154. data/test/app/cells/club_security/guard_cell.rb +0 -6
  155. data/test/app/cells/club_security/medic/help.html.erb +0 -1
  156. data/test/app/cells/club_security/medic_cell.rb +0 -8
  157. data/test/app/cells/layouts/b.erb +0 -1
  158. data/test/app/cells/layouts/metal.html.erb +0 -1
  159. data/test/app/cells/rails_helper_api_test/bassist/edit.html.erb +0 -5
  160. data/test/app/cells/shouter/sing.html.erb +0 -1
  161. data/test/app/cells/song/dashboard.haml +0 -7
  162. data/test/app/cells/song/details.html.haml +0 -1
  163. data/test/app/cells/song/info.html.haml +0 -1
  164. data/test/app/cells/song/lyrics.html.haml +0 -6
  165. data/test/app/cells/song/plays.haml +0 -1
  166. data/test/app/cells/song/scale.haml +0 -1
  167. data/test/app/cells/song/show.html.haml +0 -3
  168. data/test/app/cells/song/title.html.haml +0 -1
  169. data/test/app/cells/trumpeter/promote.html.erb +0 -1
  170. data/test/app/cells/trumpeter_cell.rb +0 -8
  171. data/test/app/cells/view_model_test/comments/show.haml +0 -7
  172. data/test/app/concepts/record/views/layout.haml +0 -2
  173. data/test/app/views/shared/_dong.html.erb +0 -1
  174. data/test/cell_module_test.rb +0 -170
  175. data/test/cells_module_test.rb +0 -27
  176. data/test/deprecations_test.rb +0 -101
  177. data/test/dummy/app/helpers/application_helper.rb +0 -2
  178. data/test/dummy/app/views/musician/hamlet.html.haml +0 -1
  179. data/test/dummy/config/environments/development.rb +0 -16
  180. data/test/dummy/config/environments/production.rb +0 -46
  181. data/test/dummy/config/environments/test.rb +0 -33
  182. data/test/dummy/db/test.sqlite3 +0 -0
  183. data/test/dummy/label/app/cells/label/show.erb +0 -1
  184. data/test/dummy/label/app/cells/label_cell.rb +0 -5
  185. data/test/dummy/label/label.gemspec +0 -20
  186. data/test/dummy/label/lib/label.rb +0 -4
  187. data/test/dummy/label/lib/label/version.rb +0 -3
  188. data/test/dummy/public/404.html +0 -26
  189. data/test/dummy/public/422.html +0 -26
  190. data/test/dummy/public/500.html +0 -26
  191. data/test/dummy/public/favicon.ico +0 -0
  192. data/test/dummy/public/stylesheets/.gitkeep +0 -0
  193. data/test/helper_test.rb +0 -81
  194. data/test/rack_test.rb +0 -32
  195. data/test/rails/asset_pipeline_test.rb +0 -20
  196. data/test/rails/caching_test.rb +0 -456
  197. data/test/rails/cells_test.rb +0 -119
  198. data/test/rails/forms_test.rb +0 -75
  199. data/test/rails/integration_test.rb +0 -299
  200. data/test/rails/render_test.rb +0 -189
  201. data/test/rails/view_model_test.rb +0 -226
  202. data/test/rails/view_test.rb +0 -49
  203. data/test/rails_helper_api_test.rb +0 -58
  204. data/test/self_contained_test.rb +0 -31
@@ -1,20 +1 @@
1
- module Cells
2
- # Setup your special needs for Cells here. Use this to add new view paths.
3
- #
4
- # Example:
5
- #
6
- # Cells.setup do |config|
7
- # config.append_view_path "app/view_models"
8
- # end
9
- #
10
- def self.setup
11
- yield(Cell::Rails)
12
- end
13
- end
14
-
15
- require 'cell'
16
- require 'cell/rails'
17
- require 'cells/rails'
18
- require 'cell/deprecations'
19
- require 'cells/engines'
20
- require 'cells/railtie'
1
+ require 'cell'
@@ -0,0 +1,43 @@
1
+ module Rails
2
+ module Generators
3
+ class CellGenerator < NamedBase
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ class_option :parent, type: :string, desc: 'The parent class for the generated cell'
7
+ class_option :e, type: :string, desc: 'The template engine'
8
+
9
+ check_class_collision suffix: 'Cell'
10
+
11
+ argument :actions, type: :array, default: [], banner: 'action action2'
12
+
13
+ def create_cell_file
14
+ template 'cell.rb.erb', File.join('app/cells', class_path, "#{file_name}_cell.rb")
15
+ end
16
+
17
+ def create_view_files
18
+ states.each do |state|
19
+ @state = state
20
+ @path = File.join('app/cells', class_path, file_name, "#{state}.#{template_engine}")
21
+ template "view.#{template_engine}", @path
22
+ end
23
+ end
24
+
25
+ hook_for :test_framework
26
+
27
+ private
28
+
29
+ def parent_class_name
30
+ options[:parent] || 'Cell::ViewModel'
31
+ end
32
+
33
+ # The show state is included by default
34
+ def states
35
+ (['show'] + actions).uniq
36
+ end
37
+
38
+ def template_engine
39
+ (options[:e] || Rails.application.config.app_generators.rails[:template_engine] || 'erb').to_s
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,8 @@
1
+ class <%= class_name %>Cell < <%= parent_class_name %>
2
+ <% states.each do |state| -%>
3
+ def <%= state %>
4
+ render
5
+ end
6
+
7
+ <% end -%>
8
+ end
@@ -0,0 +1,2 @@
1
+ h1 <%= class_name %>#<%= @state %>
2
+ p Find me in <%= @path %>
@@ -0,0 +1,38 @@
1
+ module Rails
2
+ module Generators
3
+ class ConceptGenerator < NamedBase
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ class_option :e, type: :string, desc: 'The template engine'
7
+ argument :actions, type: :array, default: [], banner: 'action action2'
8
+
9
+ check_class_collision suffix: 'Concept'
10
+
11
+
12
+ def create_concept
13
+ template 'concept.rb.erb', File.join('app/concepts', class_path, file_name, 'cell.rb')
14
+ end
15
+
16
+ def create_views
17
+ states.each do |state|
18
+ @state = state
19
+ @path = File.join('app/concepts', class_path, file_name, 'views', "#{state}.#{template_engine}")
20
+ template "view.#{template_engine}", @path
21
+ end
22
+ end
23
+
24
+ hook_for :test_framework
25
+
26
+ private
27
+
28
+ def template_engine
29
+ (options[:e] || Rails.application.config.app_generators.rails[:template_engine] || 'erb').to_s
30
+ end
31
+
32
+ # The show state is included by default
33
+ def states
34
+ (['show'] + actions).uniq
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,6 +1,6 @@
1
1
  class <%= class_name %>::Cell < Cell::Concept
2
- <% for action in actions -%>
3
- def <%= action %>
2
+ <% states.each do |state| -%>
3
+ def <%= state %>
4
4
  render
5
5
  end
6
6
  <% end -%>
@@ -0,0 +1,2 @@
1
+ h1 <%= class_name %>#<%= @state %>
2
+ p Find me in <%= @path %>
@@ -0,0 +1,21 @@
1
+ require 'rails/generators/test_unit'
2
+
3
+ module TestUnit # :nodoc:
4
+ module Generators # :nodoc:
5
+ class CellGenerator < Base # :nodoc:
6
+ source_root File.expand_path('../templates', __FILE__)
7
+ argument :actions, type: :array, default: []
8
+ check_class_collision suffix: 'CellTest'
9
+
10
+ def create_test_file
11
+ template 'unit_test.rb.erb', File.join('test/cells', class_path, "#{file_name}_cell_test.rb")
12
+ end
13
+
14
+ private
15
+
16
+ def states
17
+ (['show'] + actions).uniq
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,11 +1,11 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class <%= class_name %>CellTest < Cell::TestCase
4
- <% for state in @states -%>
4
+ <% states.each do |state| -%>
5
5
  test "<%= state %>" do
6
6
  invoke :<%= state %>
7
- assert_select "p"
7
+ assert_select 'p'
8
8
  end
9
-
9
+
10
10
  <% end %>
11
11
  end
@@ -0,0 +1,21 @@
1
+ require 'rails/generators/test_unit'
2
+
3
+ module TestUnit # :nodoc:
4
+ module Generators # :nodoc:
5
+ class ConceptGenerator < Base # :nodoc:
6
+ source_root File.expand_path('../templates', __FILE__)
7
+ argument :actions, type: :array, default: []
8
+ check_class_collision suffix: 'ConceptTest'
9
+
10
+ def create_test_file
11
+ template 'unit_test.rb.erb', File.join('test/concepts', class_path, file_name, 'cell_test.rb')
12
+ end
13
+
14
+ private
15
+
16
+ def states
17
+ (['show'] + actions).uniq
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ require 'test_helper'
2
+
3
+ class <%= class_name %>ConceptTest < Cell::TestCase
4
+ <% states.each do |state| -%>
5
+ test "<%= state %>" do
6
+ invoke :<%= state %>
7
+ assert_select 'p'
8
+ end
9
+
10
+ <% end %>
11
+ end
File without changes
@@ -0,0 +1,58 @@
1
+ require 'test_helper'
2
+
3
+ class BuilderTest < MiniTest::Spec
4
+ Song = Struct.new(:title)
5
+ Hit = Struct.new(:title)
6
+
7
+ class SongCell < Cell::ViewModel
8
+ builds do |model, options|
9
+ if model.is_a? Hit
10
+ HitCell
11
+ elsif options[:evergreen]
12
+ EvergreenCell
13
+ end
14
+ end
15
+
16
+ def options
17
+ @options
18
+ end
19
+
20
+ def show
21
+ "* #{title}"
22
+ end
23
+
24
+ property :title
25
+ end
26
+
27
+ class HitCell < SongCell
28
+ def show
29
+ "* **#{title}**"
30
+ end
31
+ end
32
+
33
+ class EvergreenCell < SongCell
34
+ end
35
+
36
+ # the original class is used when no builder matches.
37
+ it { Cell::ViewModel.cell("builder_test/song", nil, Song.new("Nation States"), {}).must_be_instance_of BuilderTest::SongCell }
38
+
39
+ it do
40
+ cell = Cell::ViewModel.cell("builder_test/song", nil, Hit.new("New York"), {})
41
+ cell.must_be_instance_of BuilderTest::HitCell
42
+ cell.options.must_equal({})
43
+ end
44
+
45
+ it do
46
+ cell = Cell::ViewModel.cell("builder_test/song", nil, Song.new("San Francisco"), evergreen: true)
47
+ cell.must_be_instance_of BuilderTest::EvergreenCell
48
+ cell.options.must_equal({:evergreen=>true})
49
+ end
50
+
51
+ # with collection.
52
+ it { Cell::ViewModel.cell("builder_test/song", nil, collection: [Song.new("Nation States"), Hit.new("New York")]).must_equal "* Nation States* **New York**" }
53
+
54
+ # with Concept
55
+ class Track < Cell::Concept
56
+ end
57
+ it { Cell::Concept.cell("builder_test/track", nil).must_be_instance_of Track }
58
+ end
@@ -0,0 +1,298 @@
1
+ # encoding: utf-8
2
+ require 'test_helper'
3
+
4
+ class DirectorCell < Cell::ViewModel
5
+ attr_reader :count
6
+
7
+ def initialize(*)
8
+ super
9
+ @count = 0
10
+ end
11
+
12
+ cache :tock
13
+
14
+ def tock
15
+ @count += 1
16
+ end
17
+ end
18
+
19
+
20
+ class CachingUnitTest < MiniTest::Spec
21
+ before :each do
22
+ ActionController::Base.cache_store.clear
23
+ ActionController::Base.perform_caching = true
24
+ end
25
+
26
+ let (:director) { DirectorCell }
27
+ let (:cellule) { DirectorCell.new(nil) }
28
+
29
+
30
+ describe "::state_cache_key" do
31
+ # accepts state name, only.
32
+ it { director.state_cache_key(:count).must_equal "cells/director/count/" }
33
+
34
+ # accepts hash as key parts
35
+ if Cell.rails_version >= Gem::Version.new('4.0')
36
+ it { director.state_cache_key(:count, b: 2, a: 1).must_equal "cells/director/count/b/2/a/1" }
37
+ else
38
+ it { director.state_cache_key(:count, b: 2, a: 1).must_equal "cells/director/count/a=1&b=2" }
39
+ end
40
+
41
+ # accepts array as key parts
42
+ it { director.state_cache_key(:count, [1, 2, 3]).must_equal "cells/director/count/1/2/3" }
43
+
44
+ # accepts string as key parts
45
+ it { director.state_cache_key(:count, "1/2").must_equal "cells/director/count/1/2" }
46
+
47
+ # accepts nil as key parts
48
+ it { director.state_cache_key(:count, nil).must_equal "cells/director/count/" }
49
+ end
50
+
51
+
52
+ describe "#state_cached?" do
53
+ # true for cached
54
+ it { cellule.send(:state_cached?, :tock).must_equal true }
55
+
56
+ # false otherwise
57
+ it { cellule.send(:state_cached?, :sing).must_equal false }
58
+ end
59
+
60
+
61
+ describe "#cache?" do
62
+ # true for cached
63
+ it { cellule.cache?(:tock).must_equal true }
64
+
65
+ # false otherwise
66
+ it { cellule.cache?(:sing).must_equal false }
67
+
68
+ describe "perform_caching turned off" do
69
+ after do
70
+ ::ActionController::Base.perform_caching = true
71
+ end
72
+
73
+ # always false
74
+ it do
75
+ ::ActionController::Base.perform_caching = false
76
+ cellule.cache?(:sing).must_equal false
77
+ cellule.cache?(:sing).must_equal false
78
+ end
79
+ end
80
+
81
+ describe "#cache_store" do
82
+ # rails cache store per default.
83
+ it { cellule.cache_store.must_equal ActionController::Base.cache_store }
84
+ end
85
+ end
86
+
87
+
88
+ # describe ".expire_cache_key" do
89
+ # before :each do
90
+ # @key = @class.state_cache_key(:tock)
91
+ # puts "====== key is #{@key}"
92
+ # assert_equal "1", render_cell(:director, :tock)
93
+ # assert_equal "1", @class.cache_store.read(@key)
94
+ # end
95
+
96
+ # it "delete the state from cache" do
97
+ # @class.expire_cache_key(@key)
98
+ # assert_not @class.cache_store.read(@key)
99
+ # end
100
+
101
+ # it "be available in controllers for sweepers" do
102
+ # MusicianController.new.expire_cell_state(DirectorCell, :tock)
103
+ # assert_not @class.cache_store.read(@key)
104
+ # end
105
+
106
+ # it "accept cache options" do
107
+ # key = @class.state_cache_key(:tock, :volume => 9)
108
+ # assert Cell::Rails.cache_store.write(key, 'ONE!')
109
+
110
+ # MusicianController.new.expire_cell_state(DirectorCell, :tock, :volume => 9)
111
+ # assert_equal "1", @class.cache_store.read(@key)
112
+ # assert_not ::Cell::Rails.cache_store.read(key)
113
+ # end
114
+ # end
115
+ end
116
+
117
+
118
+ class CachingTest < MiniTest::Spec
119
+ class DirectorCell < Cell::ViewModel
120
+ def initialize(controller, counter=0)
121
+ super
122
+ @counter = counter
123
+ end
124
+
125
+ def show # public method.
126
+ @counter
127
+ end
128
+
129
+
130
+ cache :utf8
131
+
132
+ def utf8
133
+ "æøå" # or any other UTF-8 string
134
+ end
135
+ end
136
+
137
+ before :each do
138
+ ActionController::Base.cache_store.clear
139
+ ActionController::Base.perform_caching = true
140
+ end
141
+
142
+ # let (:cell) { DirectorCell.new(nil) }
143
+ def cellule(*args)
144
+ DirectorCell.new(nil, *args)
145
+ end
146
+
147
+ # no caching when turned off.
148
+ it do
149
+ cellule.class.cache :show
150
+ ActionController::Base.perform_caching = false
151
+
152
+ cellule(1).call.must_equal "1"
153
+ cellule(2).call.must_equal "2"
154
+ end
155
+
156
+ # cache forever when no options.
157
+ it do
158
+ cellule.class.cache :show
159
+ cellule(1).call.must_equal "1"
160
+ cellule(2).call.must_equal "1"
161
+ end
162
+
163
+
164
+ # no caching when state not configured.
165
+ it do
166
+ cellule.class.class_eval do
167
+ def dictate
168
+ @counter
169
+ end
170
+ end
171
+
172
+ cellule(1).call(:dictate).must_equal "1"
173
+ cellule(2).call(:dictate).must_equal "2"
174
+ end
175
+
176
+ # compute key with cell properties from #initialize.
177
+ it do
178
+ cellule.class.cache :show do
179
+ @counter < 3 ? {:count => "<"} : {:count => ">"}
180
+ end
181
+
182
+ cellule(1).call.must_equal "1"
183
+ cellule(2).call.must_equal "1"
184
+ cellule(3).call.must_equal "3"
185
+ cellule(4).call.must_equal "3"
186
+ end
187
+
188
+ # compute key with instance method
189
+ it do
190
+ cellule.class.cache :show, :version
191
+ cellule.class.class_eval do
192
+ def version
193
+ @counter < 3 ? {:count => "<"} : {:count => ">"}
194
+ end
195
+ end
196
+
197
+ cellule(1).call.must_equal "1"
198
+ cellule(2).call.must_equal "1"
199
+ cellule(3).call.must_equal "3"
200
+ cellule(4).call.must_equal "3"
201
+ end
202
+
203
+ # allow returning strings for key
204
+ it do
205
+ cellule.class.cache :show do
206
+ @counter < 3 ? "<" : ">"
207
+ end
208
+
209
+ cellule(1).call.must_equal "1"
210
+ cellule(2).call.must_equal "1"
211
+ cellule(3).call.must_equal "3"
212
+ cellule(4).call.must_equal "3"
213
+ end
214
+
215
+ # allows conditional ifs.
216
+ it do
217
+ cellule.class.cache :show, if: lambda { @counter < 3 }
218
+
219
+ cellule(1).call.must_equal "1"
220
+ cellule(2).call.must_equal "1"
221
+ cellule(3).call.must_equal "3"
222
+ cellule(4).call.must_equal "4"
223
+ end
224
+
225
+ # allows conditional ifs with instance method.
226
+ it do
227
+ cellule.class.class_eval do
228
+ cache :show, if: :smaller?
229
+
230
+ def smaller?
231
+ @counter < 3
232
+ end
233
+ end
234
+
235
+ cellule(1).call.must_equal "1"
236
+ cellule(2).call.must_equal "1"
237
+ cellule(3).call.must_equal "3"
238
+ cellule(4).call.must_equal "4"
239
+ end
240
+
241
+
242
+ unless ::ActionPack::VERSION::MAJOR == 3 and ::ActionPack::VERSION::MINOR >= 2 # bug in 3.2.
243
+ describe "utf-8" do
244
+ before do
245
+ @key = cellule.class.state_cache_key(:utf8)
246
+ end
247
+
248
+ it "has the correct encoding when reading from cache" do
249
+ assert_equal "UTF-8", cellule.call(:utf8).encoding.to_s
250
+ assert_equal "UTF-8", cellule.cache_store.read(@key).encoding.to_s
251
+ end
252
+ end
253
+ end
254
+
255
+ # options are passed through to cache store.
256
+ # :expires_in.
257
+ # :tags => lambda { |one, two, three| "#{one},#{two},#{three}" }
258
+ class CacheStore
259
+ attr_reader :fetch_args
260
+
261
+ def fetch(*args)
262
+ @fetch_args = args
263
+ end
264
+ end
265
+
266
+ it do
267
+ cellule = self.cellule
268
+
269
+ cellule.instance_eval do
270
+ def cache_store;
271
+ @cache_store ||= CacheStore.new;
272
+ end
273
+ end
274
+
275
+ cellule.class.cache :show, expires_in: 1.minutes, tags: lambda { self.class.to_s }
276
+ cellule.call
277
+ cellule.cache_store.fetch_args.must_equal ["cells/caching_test/director/show/", {expires_in: 60, tags: "CachingTest::DirectorCell"}]
278
+ end
279
+ end
280
+
281
+
282
+ class CachingInheritanceTest < CachingTest
283
+ class DirectorCell < ::DirectorCell
284
+ cache :show, :expires_in => 10.minutes do
285
+ "v1"
286
+ end
287
+ end
288
+
289
+ class DirectorsSonCell < DirectorCell
290
+ end
291
+
292
+ class DirectorsDaughterCell < ::DirectorCell
293
+ cache :show, :expires_in => 9.minutes do
294
+ "v2"
295
+ end
296
+ end
297
+
298
+ end