From 94e5f7b0fa0050457cc928cd7800c796018567ab Mon Sep 17 00:00:00 2001 From: Alfonso Uceda Date: Tue, 12 Nov 2024 16:26:16 +0100 Subject: [PATCH 01/13] Benchmarks folder is removed --- benchmarks/class_builder.rb | 37 ----------------------------- benchmarks/collection.rb | 47 ------------------------------------- 2 files changed, 84 deletions(-) delete mode 100644 benchmarks/class_builder.rb delete mode 100644 benchmarks/collection.rb diff --git a/benchmarks/class_builder.rb b/benchmarks/class_builder.rb deleted file mode 100644 index bc1ae5b0..00000000 --- a/benchmarks/class_builder.rb +++ /dev/null @@ -1,37 +0,0 @@ -require 'bundler/setup' -require 'benchmark/ips' -require "cells" -require 'cell/view_model' - -class ACell < Cell::ViewModel - def show - "" - end -end - -class ACellWithBuilder < Cell::ViewModel - include Cell::Builder - - def show - "" - end -end - -Benchmark.ips do |x| - x.report("ACell") { ACell.().() } - x.report("ACellWithBuilder") { ACellWithBuilder.().() } - x.compare! -end - -__END__ - -Calculating ------------------------------------- - ACell 25.710k i/100ms - ACellWithBuilder 19.948k i/100ms -------------------------------------------------- - ACell 419.631k (± 5.0%) i/s - 2.108M - ACellWithBuilder 291.924k (± 5.7%) i/s - 1.476M - -Comparison: - ACell: 419630.8 i/s - ACellWithBuilder: 291923.5 i/s - 1.44x slower diff --git a/benchmarks/collection.rb b/benchmarks/collection.rb deleted file mode 100644 index dafcd118..00000000 --- a/benchmarks/collection.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'test_helper' -require 'benchmark' -require 'benchmark/ips' - -Song = Struct.new(:title) - - -class SongCell < Cell::ViewModel - self.view_paths = ['test/fixtures'] - property :title - - def show - render - end -end - -ary = 1000.times.collect { |i| Song.new(i) } - -Benchmark.ips do |x| - x.report("collection, call") { SongCell.(collection: ary).() } - x.report("collection, join") { SongCell.(collection: ary).join { |cell, i| cell.() } } - # x.report("collection, joinstr") { SongCell.(collection: ary).joinstr { |cell, i| cell.() } } - # x.report("collection, joincollect") { SongCell.(collection: ary).joincollect { |cell, i| cell.() } } - # x.report("ACellWithBuilder") { ACellWithBuilder.().() } - x.compare! -end - -__END__ - -Calculating ------------------------------------- - collection, call 3.000 i/100ms - collection, join 3.000 i/100ms -------------------------------------------------- - collection, call 33.403 (± 3.0%) i/s - 168.000 - collection, join 33.248 (± 3.0%) i/s - 168.000 - -Comparison: - collection, call: 33.4 i/s - collection, join: 33.2 i/s - 1.00x slower - - - -Comparison: - collection, join: 32.8 i/s - collection, call: 32.6 i/s - 1.01x slower - collection, joinstr: 32.6 i/s - 1.01x slower -collection, joincollect: 32.4 i/s - 1.01x slower # each_with_index.collect.join From d34f56bddecdc04532a6a3a6c72661beec36e3ec Mon Sep 17 00:00:00 2001 From: Alfonso Uceda Date: Tue, 12 Nov 2024 16:27:23 +0100 Subject: [PATCH 02/13] Github action CI workflow is added --- .github/workflows/ci.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..7d3fbb70 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,17 @@ +name: CI +on: [push, pull_request] +jobs: + test: + strategy: + fail-fast: false + matrix: + # Due to https://github.com/actions/runner/issues/849, we have to use quotes for '3.0' + ruby: [2.5, 2.6, 2.7, '3.0', 3.1, 3.2, 3.3, head] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true # runs 'bundle install' and caches installed gems automatically + - run: bundle exec rake From f08b01f02091e715f2b0f7bd37a57e4c67514c77 Mon Sep 17 00:00:00 2001 From: Alfonso Uceda Date: Tue, 12 Nov 2024 16:27:41 +0100 Subject: [PATCH 03/13] Travis is removed --- .travis.yml | 16 ---------------- README.md | 3 ++- 2 files changed, 2 insertions(+), 17 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 2e52d378..00000000 --- a/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -language: ruby -rvm: - #- ruby-head - - 2.3.1 - - 2.2.2 - -sudo: false -cache: bundler - -matrix: - fast_finish: true - allow_failures: - - rvm: ruby-head - -before_install: - - gem update bundler diff --git a/README.md b/README.md index 7cff4448..2e3d86d1 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,8 @@ [![Gitter Chat](https://badges.gitter.im/trailblazer/chat.svg)](https://gitter.im/trailblazer/chat) [![TRB Newsletter](https://img.shields.io/badge/TRB-newsletter-lightgrey.svg)](http://trailblazer.to/newsletter/) [![Build -Status](https://travis-ci.org/apotonick/cells.svg)](https://travis-ci.org/apotonick/cells) +Status](https://github.com/trailblazer/cells/actions/workflows/ci.yml/badge.svg +)] [![Gem Version](https://badge.fury.io/rb/cells.svg)](http://badge.fury.io/rb/cells) ## Overview From 5814effcbf140f7fa459da6d0c1c5fb8f075b50c Mon Sep 17 00:00:00 2001 From: Alfonso Uceda Date: Tue, 12 Nov 2024 16:31:36 +0100 Subject: [PATCH 04/13] MiniTest is replaced with Minitest --- test/builder_test.rb | 2 +- test/cache_test.rb | 1 - test/cell_test.rb | 2 +- test/concept_test.rb | 4 ++-- test/context_test.rb | 2 +- test/layout_test.rb | 2 +- test/partial_test.rb | 2 +- test/prefixes_test.rb | 4 ++-- test/property_test.rb | 4 ++-- test/public_test.rb | 2 +- test/render_test.rb | 2 +- test/templates_test.rb | 4 ++-- test/test_helper.rb | 2 +- test/testing_test.rb | 4 ++-- test/twin_test.rb | 2 +- 15 files changed, 19 insertions(+), 20 deletions(-) diff --git a/test/builder_test.rb b/test/builder_test.rb index f28b953d..63a54570 100644 --- a/test/builder_test.rb +++ b/test/builder_test.rb @@ -1,6 +1,6 @@ require 'test_helper' -class BuilderTest < MiniTest::Spec +class BuilderTest < Minitest::Spec Song = Struct.new(:title) Hit = Struct.new(:title) diff --git a/test/cache_test.rb b/test/cache_test.rb index 66b1a670..d0ca4e5f 100644 --- a/test/cache_test.rb +++ b/test/cache_test.rb @@ -29,4 +29,3 @@ class Index < Cell::ViewModel Index.new(2).().must_equal("1") end end - diff --git a/test/cell_test.rb b/test/cell_test.rb index d9476dd6..6a0de12c 100644 --- a/test/cell_test.rb +++ b/test/cell_test.rb @@ -1,6 +1,6 @@ require 'test_helper' -class CellTest < MiniTest::Spec +class CellTest < Minitest::Spec class SongCell < Cell::ViewModel self.view_paths = ['test/fixtures'] diff --git a/test/concept_test.rb b/test/concept_test.rb index cfed5c14..a1ad150b 100644 --- a/test/concept_test.rb +++ b/test/concept_test.rb @@ -46,7 +46,7 @@ class Song < ::Cell::Concept # app/cells/comment/views/form inherit_views Comment::Cell, render form/show -class ConceptTest < MiniTest::Spec +class ConceptTest < Minitest::Spec describe "::controller_path" do it { Record::Cell.new.class.controller_path.must_equal "record" } it { Record::Cell::Song.new.class.controller_path.must_equal "record/song" } @@ -81,7 +81,7 @@ class ConceptTest < MiniTest::Spec # concept(.., collection: ..) it do Cell::Concept.cell("record/cell", nil, context: { controller: Object }). - concept("record/cell", collection: [1,2], tracks: 24).(:description).must_equal "A Tribute To Rancid, with 24 songs! [{:controller=>Object}]A Tribute To Rancid, with 24 songs! [{:controller=>Object}]" + concept("record/cell", collection: [1,2], tracks: 24).(:description).must_equal "A Tribute To Rancid, with 24 songs! [{:controller=>Object}]A Tribute To Rancid, with 24 songs! [{:controller=>Object}]" end end end diff --git a/test/context_test.rb b/test/context_test.rb index 280aa180..5c992815 100644 --- a/test/context_test.rb +++ b/test/context_test.rb @@ -1,6 +1,6 @@ require "test_helper" -class ContextTest < MiniTest::Spec +class ContextTest < Minitest::Spec class ParentCell < Cell::ViewModel def user context[:user] diff --git a/test/layout_test.rb b/test/layout_test.rb index 36cc7aa4..5543962b 100644 --- a/test/layout_test.rb +++ b/test/layout_test.rb @@ -39,7 +39,7 @@ def show_with_layout end end -class LayoutTest < MiniTest::Spec +class LayoutTest < Minitest::Spec # render show.haml calling method. # same context as content view as layout call method. it { SongWithLayoutCell.new(nil).show.must_equal "Merry Xmas, Papertiger" } diff --git a/test/partial_test.rb b/test/partial_test.rb index 2df6ed58..332925e4 100644 --- a/test/partial_test.rb +++ b/test/partial_test.rb @@ -1,7 +1,7 @@ require "test_helper" require "cell/partial" -class PartialTest < MiniTest::Spec +class PartialTest < Minitest::Spec class WithPartial < Cell::ViewModel self.view_paths = ['test/fixtures'] # doesn't exist. include ::Cell::Erb diff --git a/test/prefixes_test.rb b/test/prefixes_test.rb index 274fe6f4..e0883215 100644 --- a/test/prefixes_test.rb +++ b/test/prefixes_test.rb @@ -18,7 +18,7 @@ class EngineCell < Cell::ViewModel class InheritingFromEngineCell < EngineCell end -class PrefixesTest < MiniTest::Spec +class PrefixesTest < Minitest::Spec class SingerCell < Cell::ViewModel end @@ -81,7 +81,7 @@ def self._local_prefixes # it { Record::Cell.new(@controller).render_state(:show).must_equal "Rock on!" } end -class InheritViewsTest < MiniTest::Spec +class InheritViewsTest < Minitest::Spec class SlapperCell < Cell::ViewModel self.view_paths = ['test/fixtures'] # todo: REMOVE! include Cell::Erb diff --git a/test/property_test.rb b/test/property_test.rb index 0e51a802..160e3bde 100644 --- a/test/property_test.rb +++ b/test/property_test.rb @@ -1,6 +1,6 @@ require "test_helper" -class PropertyTest < MiniTest::Spec +class PropertyTest < Minitest::Spec class SongCell < Cell::ViewModel property :title @@ -15,7 +15,7 @@ def title end -class EscapedPropertyTest < MiniTest::Spec +class EscapedPropertyTest < Minitest::Spec class SongCell < Cell::ViewModel include Escaped property :title diff --git a/test/public_test.rb b/test/public_test.rb index 0d16dc91..857d3ddc 100644 --- a/test/public_test.rb +++ b/test/public_test.rb @@ -1,6 +1,6 @@ require 'test_helper' -class PublicTest < MiniTest::Spec +class PublicTest < Minitest::Spec class SongCell < Cell::ViewModel def initialize(*args) @initialize_args = *args diff --git a/test/render_test.rb b/test/render_test.rb index 078b5082..7729bf9b 100644 --- a/test/render_test.rb +++ b/test/render_test.rb @@ -57,7 +57,7 @@ def title end end -class RenderTest < MiniTest::Spec +class RenderTest < Minitest::Spec # render show.haml calling method, implicit render. it { SongCell.new(nil).show.must_equal "Papertiger" } diff --git a/test/templates_test.rb b/test/templates_test.rb index 44cb1db5..95b49372 100644 --- a/test/templates_test.rb +++ b/test/templates_test.rb @@ -1,7 +1,7 @@ require 'test_helper' -class TemplatesTest < MiniTest::Spec +class TemplatesTest < Minitest::Spec Templates = Cell::Templates # existing. @@ -18,7 +18,7 @@ class TemplatesTest < MiniTest::Spec end -class TemplatesCachingTest < MiniTest::Spec +class TemplatesCachingTest < Minitest::Spec class SongCell < Cell::ViewModel self.view_paths = ['test/fixtures'] # include Cell::Erb diff --git a/test/test_helper.rb b/test/test_helper.rb index 1577db18..e5210524 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -4,7 +4,7 @@ Cell::ViewModel.send(:include, Cell::Erb) if Cell.const_defined?(:Erb) # FIXME: should happen in inititalizer. -MiniTest::Spec.class_eval do +Minitest::Spec.class_eval do include Cell::Testing end diff --git a/test/testing_test.rb b/test/testing_test.rb index d78b35db..e5cd3384 100644 --- a/test/testing_test.rb +++ b/test/testing_test.rb @@ -1,6 +1,6 @@ require 'test_helper' -class TestCaseTest < MiniTest::Spec +class TestCaseTest < Minitest::Spec class SongCell < Cell::ViewModel def show "Give It All!" @@ -36,7 +36,7 @@ class Cell < Cell::Concept # capybara support require "capybara" -class CapybaraTest < MiniTest::Spec +class CapybaraTest < Minitest::Spec class CapybaraCell < Cell::ViewModel def show "Grunt" diff --git a/test/twin_test.rb b/test/twin_test.rb index b14cb675..7b14cb17 100644 --- a/test/twin_test.rb +++ b/test/twin_test.rb @@ -1,7 +1,7 @@ # require 'test_helper' # require 'cell/twin' -# class TwinTest < MiniTest::Spec +# class TwinTest < Minitest::Spec # class SongCell < Cell::ViewModel # class Twin < Disposable::Twin # property :title From 56ab21771975e266d586e2af62ad03d9a4fd1d39 Mon Sep 17 00:00:00 2001 From: Alfonso Uceda Date: Tue, 12 Nov 2024 16:32:15 +0100 Subject: [PATCH 05/13] Debug gem is added to tests --- cells.gemspec | 1 + test/test_helper.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/cells.gemspec b/cells.gemspec index 61af5bcc..102c53bb 100644 --- a/cells.gemspec +++ b/cells.gemspec @@ -27,4 +27,5 @@ Gem::Specification.new do |spec| spec.add_development_dependency "rake" spec.add_development_dependency "capybara" spec.add_development_dependency "cells-erb", ">= 0.0.4" + spec.add_development_dependency 'debug' end diff --git a/test/test_helper.rb b/test/test_helper.rb index e5210524..cf6f8a5a 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,6 +1,7 @@ require "minitest/autorun" require "cells" require "cells-erb" +require "debug" Cell::ViewModel.send(:include, Cell::Erb) if Cell.const_defined?(:Erb) # FIXME: should happen in inititalizer. From 6ce4b4b4d7bbe3c78aeb1d81a52351fda8c37e80 Mon Sep 17 00:00:00 2001 From: Alfonso Uceda Date: Tue, 12 Nov 2024 16:40:13 +0100 Subject: [PATCH 06/13] Cell::ViewModel#state_for_implicit_render is fixed for ruby 3.4.0 Ruby 3.4 has added to Kernel#caller the class and the method, e.g. Object#foo, before the method was only displayed. --- lib/cell/view_model.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cell/view_model.rb b/lib/cell/view_model.rb index 2ea62c77..64bc213f 100644 --- a/lib/cell/view_model.rb +++ b/lib/cell/view_model.rb @@ -199,7 +199,7 @@ def process_options!(options) # Computes the view name from the call stack in which `render` was invoked. def state_for_implicit_render(options) _caller = RUBY_VERSION < "2.0" ? caller(3) : caller(3, 1) # TODO: remove case in 5.0 when dropping 1.9. - _caller[0].match(/`(\w+)/)[1] + _caller[0].match(/`(\w+)|#(\w+)'/).captures.compact.first end include Layout From e64017b0bbc896d84bdb9b824be950de75da45ec Mon Sep 17 00:00:00 2001 From: Alfonso Uceda Date: Tue, 12 Nov 2024 16:49:52 +0100 Subject: [PATCH 07/13] Test fixed that require new lines --- test/layout_test.rb | 10 ++++------ test/render_test.rb | 14 +++++++------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/test/layout_test.rb b/test/layout_test.rb index 5543962b..37faf36c 100644 --- a/test/layout_test.rb +++ b/test/layout_test.rb @@ -42,7 +42,7 @@ def show_with_layout class LayoutTest < Minitest::Spec # render show.haml calling method. # same context as content view as layout call method. - it { SongWithLayoutCell.new(nil).show.must_equal "Merry Xmas, Papertiger" } + it { SongWithLayoutCell.new(nil).show.must_equal "Merry Xmas, Papertiger\n" } # raises exception when layout not found! @@ -51,7 +51,7 @@ class LayoutTest < Minitest::Spec it { } # with ::layout. - it { SongWithLayoutOnClassCell.new(nil).show.must_equal "Merry Xmas, Papertiger" } + it { SongWithLayoutOnClassCell.new(nil).show.must_equal "Merry Xmas, Papertiger\n" } # with ::layout and :layout, :layout wins. it { SongWithLayoutOnClassCell.new(nil).show_with_layout.must_equal "Happy Friday!" } @@ -75,14 +75,12 @@ class LayoutCell < Cell::ViewModel class ExternalLayoutTest < Minitest::Spec it do Comment::ShowCell.new(nil, layout: Comment::LayoutCell, context: { beer: true }). - ().must_equal "$layout.erb{$show.erb, {:beer=>true}$show.erb, {:beer=>true}, {:beer=>true}} -" + ().must_equal "$layout.erb{$show.erb, {:beer=>true}\n$show.erb, {:beer=>true}\n, {:beer=>true}}\n" end # collection :layout it do Cell::ViewModel.cell("comment/show", collection: [Object, Module], layout: Comment::LayoutCell).(). - must_equal "$layout.erb{$show.erb, nil$show.erb, nil$show.erb, nil$show.erb, nil, nil} -" + must_equal "$layout.erb{$show.erb, nil\n$show.erb, nil\n$show.erb, nil\n$show.erb, nil\n, nil}\n" end end diff --git a/test/render_test.rb b/test/render_test.rb index 7729bf9b..f700e759 100644 --- a/test/render_test.rb +++ b/test/render_test.rb @@ -59,19 +59,19 @@ def title class RenderTest < Minitest::Spec # render show.haml calling method, implicit render. - it { SongCell.new(nil).show.must_equal "Papertiger" } + it { SongCell.new(nil).show.must_equal "Papertiger\n" } # render ivar.haml using instance variable. - it { SongCell.new(nil).ivar.must_equal "Carnage" } + it { SongCell.new(nil).ivar.must_equal "Carnage\n" } # render string. it { SongCell.new(nil).string.must_equal "Right" } # #call renders :show - it { SongCell.new(nil).call.must_equal "Papertiger" } + it { SongCell.new(nil).call.must_equal "Papertiger\n" } # call(:form) renders :form - it { SongCell.new(nil).call(:with_view_name).must_equal "Man Of Steel" } + it { SongCell.new(nil).call(:with_view_name).must_equal "Man Of Steel\n" } # works with state called `send` it { SongCell.new(nil).call(:send).must_equal "send" } @@ -83,10 +83,10 @@ class RenderTest < Minitest::Spec end # allows locals - it { SongCell.new(nil).with_locals.must_equal "Shot Across The Bow280" } + it { SongCell.new(nil).with_locals.must_equal "Shot Across The Bow\n280\n" } # render :form is a shortcut. - it { SongCell.new(nil).with_view_name.must_equal "Man Of Steel" } + it { SongCell.new(nil).with_view_name.must_equal "Man Of Steel\n" } # :template_engine renders ERB. # it { SongCell.new(nil).with_erb.must_equal "ERB:\n\n Papertiger\n" } @@ -102,7 +102,7 @@ class RenderTest < Minitest::Spec it { SongCell.new(nil).call(:with_html).must_equal "

Yew!

" } # render {} with block - it { SongCell.new(nil).with_block.must_equal "Yo! Clean Sheets

Yew!

" } + it { SongCell.new(nil).with_block.must_equal "Yo! Clean Sheets

Yew!

\n" } end # test inheritance From b35cac2c569c2ffae29b3cde047c0ddccc205170 Mon Sep 17 00:00:00 2001 From: Alfonso Uceda Date: Tue, 12 Nov 2024 16:57:38 +0100 Subject: [PATCH 08/13] Must matchers are covnerted to assertion matchers --- test/builder_test.rb | 16 +++++------ test/cache_test.rb | 4 +-- test/cell_test.rb | 4 +-- test/concept_test.rb | 42 +++++++++++------------------ test/context_test.rb | 22 ++++++++-------- test/layout_test.rb | 17 +++++------- test/partial_test.rb | 12 ++++----- test/prefixes_test.rb | 55 ++++++++++++++++++-------------------- test/property_test.rb | 13 +++++---- test/public_test.rb | 60 +++++++++++++++++++----------------------- test/render_test.rb | 43 ++++++++++-------------------- test/templates_test.rb | 14 +++------- test/testing_test.rb | 18 ++++++------- 13 files changed, 136 insertions(+), 184 deletions(-) diff --git a/test/builder_test.rb b/test/builder_test.rb index 63a54570..fc495ed4 100644 --- a/test/builder_test.rb +++ b/test/builder_test.rb @@ -36,28 +36,28 @@ class EvergreenCell < SongCell end # the original class is used when no builder matches. - it { SongCell.(Song.new("Nation States"), {}).must_be_instance_of SongCell } + it { assert_instance_of SongCell, SongCell.(Song.new("Nation States"), {}) } it do cell = SongCell.(Hit.new("New York"), {}) - cell.must_be_instance_of HitCell - cell.options.must_equal({}) + assert_instance_of HitCell, cell + assert_equal({}, cell.options) end it do cell = SongCell.(Song.new("San Francisco"), evergreen: true) - cell.must_be_instance_of EvergreenCell - cell.options.must_equal({evergreen:true}) + assert_instance_of EvergreenCell, cell + assert_equal({evergreen: true}, cell.options) end # without arguments. - it { SongCell.(Hit.new("Frenzy")).must_be_instance_of HitCell } + it { assert_instance_of HitCell, SongCell.(Hit.new("Frenzy")) } # with collection. - it { SongCell.(collection: [Song.new("Nation States"), Hit.new("New York")]).().must_equal "* Nation States* **New York**" } + it { assert_equal "* Nation States* **New York**", SongCell.(collection: [Song.new("Nation States"), Hit.new("New York")]).() } # with Concept class Track < Cell::Concept end - it { Track.().must_be_instance_of Track } + it { assert_instance_of Track, Track.() } end diff --git a/test/cache_test.rb b/test/cache_test.rb index d0ca4e5f..0aba853e 100644 --- a/test/cache_test.rb +++ b/test/cache_test.rb @@ -25,7 +25,7 @@ class Index < Cell::ViewModel end it do - Index.new(1).().must_equal("1") - Index.new(2).().must_equal("1") + assert_equal "1", Index.new(1).() + assert_equal "1", Index.new(2).() end end diff --git a/test/cell_test.rb b/test/cell_test.rb index 6a0de12c..6e1b7ff3 100644 --- a/test/cell_test.rb +++ b/test/cell_test.rb @@ -13,8 +13,8 @@ def show_with_block(&block) end # #options - it { SongCell.new(nil, genre: "Punkrock").send(:options)[:genre].must_equal "Punkrock" } + it { assert_equal "Punkrock", SongCell.new(nil, genre: "Punkrock").send(:options)[:genre] } # #block - it { SongCell.new(nil, genre: "Punkrock").(:show_with_block) { "hello" }.must_equal "hello\n" } + it { assert_equal "hello\n", SongCell.new(nil, genre: "Punkrock").(:show_with_block) { "hello" } } end diff --git a/test/concept_test.rb b/test/concept_test.rb index a1ad150b..3eb6ebcd 100644 --- a/test/concept_test.rb +++ b/test/concept_test.rb @@ -25,7 +25,6 @@ class Hit < ::Cell::Concept inherit_views Record::Cell end - def description "A Tribute To Rancid, with #{@options[:tracks]} songs! [#{context}]" end @@ -41,47 +40,38 @@ class Song < ::Cell::Concept end end -# app/cells/comment/views -# app/cells/comment/form/views -# app/cells/comment/views/form inherit_views Comment::Cell, render form/show - - class ConceptTest < Minitest::Spec describe "::controller_path" do - it { Record::Cell.new.class.controller_path.must_equal "record" } - it { Record::Cell::Song.new.class.controller_path.must_equal "record/song" } - it { Record::Cells::Cell.new.class.controller_path.must_equal "record/cells" } - it { Record::Cells::Cell::Song.new.class.controller_path.must_equal "record/cells/song" } + it { assert_equal "record", Record::Cell.new.class.controller_path } + it { assert_equal "record/song", Record::Cell::Song.new.class.controller_path } + it { assert_equal "record/cells", Record::Cells::Cell.new.class.controller_path } + it { assert_equal "record/cells/song", Record::Cells::Cell::Song.new.class.controller_path } end - describe "#_prefixes" do - it { Record::Cell.new._prefixes.must_equal ["test/fixtures/concepts/record/views"] } - it { Record::Cell::Song.new._prefixes.must_equal ["test/fixtures/concepts/record/song/views", "test/fixtures/concepts/record/views"] } - it { Record::Cell::Hit.new._prefixes.must_equal ["test/fixtures/concepts/record/hit/views", "test/fixtures/concepts/record/views"] } # with inherit_views. + it { assert_equal ["test/fixtures/concepts/record/views"], Record::Cell.new._prefixes } + it { assert_equal ["test/fixtures/concepts/record/song/views", "test/fixtures/concepts/record/views"], Record::Cell::Song.new._prefixes } + it { assert_equal ["test/fixtures/concepts/record/hit/views", "test/fixtures/concepts/record/views"], Record::Cell::Hit.new._prefixes } # with inherit_views. end - it { Record::Cell.new("Wayne").call(:show).must_equal "Party on, Wayne!" } - + it { assert_equal "Party on, Wayne!", Record::Cell.new("Wayne").call(:show) } describe "::cell" do - it { Cell::Concept.cell("record/cell").must_be_instance_of( Record::Cell) } - it { Cell::Concept.cell("record/cell/song").must_be_instance_of Record::Cell::Song } - # cell("song", concept: "record/compilation") # record/compilation/cell/song + it { assert_instance_of Record::Cell, Cell::Concept.cell("record/cell") } + it { assert_instance_of Record::Cell::Song, Cell::Concept.cell("record/cell/song") } end describe "#render" do - it { Cell::Concept.cell("record/cell/song").show.must_equal "Lalala" } + it { assert_equal "Lalala", Cell::Concept.cell("record/cell/song").show } end describe "#cell (in state)" do - # test with controller, but remove tests when we don't need it anymore. - it { Cell::Concept.cell("record/cell", nil, context: { controller: Object }).cell("record/cell", nil).must_be_instance_of Record::Cell } - it { Cell::Concept.cell("record/cell", nil, context: { controller: Object }).concept("record/cell", nil, tracks: 24).(:description).must_equal "A Tribute To Rancid, with 24 songs! [{:controller=>Object}]" } - # concept(.., collection: ..) + it { assert_instance_of Record::Cell, Cell::Concept.cell("record/cell", nil, context: { controller: Object }).cell("record/cell", nil) } + it { assert_equal "A Tribute To Rancid, with 24 songs! [{:controller=>Object}]", Cell::Concept.cell("record/cell", nil, context: { controller: Object }).concept("record/cell", nil, tracks: 24).(:description) } + it do - Cell::Concept.cell("record/cell", nil, context: { controller: Object }). - concept("record/cell", collection: [1,2], tracks: 24).(:description).must_equal "A Tribute To Rancid, with 24 songs! [{:controller=>Object}]A Tribute To Rancid, with 24 songs! [{:controller=>Object}]" + assert_equal "A Tribute To Rancid, with 24 songs! [{:controller=>Object}]A Tribute To Rancid, with 24 songs! [{:controller=>Object}]", + Cell::Concept.cell("record/cell", nil, context: { controller: Object }).concept("record/cell", collection: [1,2], tracks: 24).(:description) end end end diff --git a/test/context_test.rb b/test/context_test.rb index 5c992815..83948ef3 100644 --- a/test/context_test.rb +++ b/test/context_test.rb @@ -18,27 +18,27 @@ def controller let (:parent) { ParentCell.(model, admin: true, context: { user: user, controller: controller }) } it do - parent.model.must_equal model - parent.controller.must_equal controller - parent.user.must_equal user + assert_equal model, parent.model + assert_equal controller, parent.controller + assert_equal user, parent.user # nested cell child = parent.cell("context_test/parent", "") - child.model.must_equal "" - child.controller.must_equal controller - child.user.must_equal user + assert_equal "", child.model + assert_equal controller, child.controller + assert_equal user, child.user end # child can add to context it do child = parent.cell(ParentCell, nil, context: { "is_child?" => true }) - assert_nil(parent.context["is_child?"]) + assert_nil parent.context["is_child?"] - assert_nil(child.model) - child.controller.must_equal controller - child.user.must_equal user - child.context["is_child?"].must_equal true + assert_nil child.model + assert_equal controller, child.controller + assert_equal user, child.user + assert_equal true, child.context["is_child?"] end end diff --git a/test/layout_test.rb b/test/layout_test.rb index 37faf36c..4a9efafb 100644 --- a/test/layout_test.rb +++ b/test/layout_test.rb @@ -42,19 +42,16 @@ def show_with_layout class LayoutTest < Minitest::Spec # render show.haml calling method. # same context as content view as layout call method. - it { SongWithLayoutCell.new(nil).show.must_equal "Merry Xmas, Papertiger\n" } + it { assert_equal "Merry Xmas, Papertiger\n", SongWithLayoutCell.new(nil).show } # raises exception when layout not found! - it { assert_raises(Cell::TemplateMissingError) { SongWithLayoutCell.new(nil).unknown } } - # assert message of exception. - it { } # with ::layout. - it { SongWithLayoutOnClassCell.new(nil).show.must_equal "Merry Xmas, Papertiger\n" } + it { assert_equal "Merry Xmas, Papertiger\n", SongWithLayoutOnClassCell.new(nil).show } # with ::layout and :layout, :layout wins. - it { SongWithLayoutOnClassCell.new(nil).show_with_layout.must_equal "Happy Friday!" } + it { assert_equal "Happy Friday!", SongWithLayoutOnClassCell.new(nil).show_with_layout } end module Comment @@ -74,13 +71,13 @@ class LayoutCell < Cell::ViewModel class ExternalLayoutTest < Minitest::Spec it do - Comment::ShowCell.new(nil, layout: Comment::LayoutCell, context: { beer: true }). - ().must_equal "$layout.erb{$show.erb, {:beer=>true}\n$show.erb, {:beer=>true}\n, {:beer=>true}}\n" + result = Comment::ShowCell.new(nil, layout: Comment::LayoutCell, context: { beer: true }).() + assert_equal "$layout.erb{$show.erb, {:beer=>true}\n$show.erb, {:beer=>true}\n, {:beer=>true}}\n", result end # collection :layout it do - Cell::ViewModel.cell("comment/show", collection: [Object, Module], layout: Comment::LayoutCell).(). - must_equal "$layout.erb{$show.erb, nil\n$show.erb, nil\n$show.erb, nil\n$show.erb, nil\n, nil}\n" + result = Cell::ViewModel.cell("comment/show", collection: [Object, Module], layout: Comment::LayoutCell).() + assert_equal "$layout.erb{$show.erb, nil\n$show.erb, nil\n$show.erb, nil\n$show.erb, nil\n, nil}\n", result end end diff --git a/test/partial_test.rb b/test/partial_test.rb index 332925e4..fdcc753b 100644 --- a/test/partial_test.rb +++ b/test/partial_test.rb @@ -25,11 +25,11 @@ class WithPartialAndManyViewPaths < WithPartial self.view_paths << ['app/views'] end - it { WithPartial.new(nil).show.must_equal "I Am Wrong And I Am Right" } - it { WithPartial.new(nil).show_with_format.must_equal "I Am Wrong And I Am Right" } - it { WithPartial.new(nil).show_without_partial.must_equal "Adenosine Breakdown" } + it { assert_equal "I Am Wrong And I Am Right", WithPartial.new(nil).show } + it { assert_equal "I Am Wrong And I Am Right", WithPartial.new(nil).show_with_format } + it { assert_equal "Adenosine Breakdown", WithPartial.new(nil).show_without_partial } - it { WithPartialAndManyViewPaths.new(nil).show.must_equal "I Am Wrong And I Am Right" } - it { WithPartialAndManyViewPaths.new(nil).show_with_format.must_equal "I Am Wrong And I Am Right" } - it { WithPartialAndManyViewPaths.new(nil).show_without_partial.must_equal "Adenosine Breakdown" } + it { assert_equal "I Am Wrong And I Am Right", WithPartialAndManyViewPaths.new(nil).show } + it { assert_equal "I Am Wrong And I Am Right", WithPartialAndManyViewPaths.new(nil).show_with_format } + it { assert_equal "Adenosine Breakdown", WithPartialAndManyViewPaths.new(nil).show_without_partial } end diff --git a/test/prefixes_test.rb b/test/prefixes_test.rb index e0883215..9e6a8627 100644 --- a/test/prefixes_test.rb +++ b/test/prefixes_test.rb @@ -40,45 +40,43 @@ def self._local_prefixes end end - describe "::controller_path" do - it { ::BassistCell.new(@controller).class.controller_path.must_equal "bassist" } - it { SingerCell.new(@controller).class.controller_path.must_equal "prefixes_test/singer" } + it { assert_equal "bassist", ::BassistCell.new(@controller).class.controller_path } + it { assert_equal "prefixes_test/singer", SingerCell.new(@controller).class.controller_path } end describe "#_prefixes" do - it { ::BassistCell.new(@controller)._prefixes.must_equal ["test/fixtures/bassist"] } - it { ::BassistCell::FenderCell.new(@controller)._prefixes.must_equal ["app/cells/bassist_cell/fender"] } - it { ::BassistCell::IbanezCell.new(@controller)._prefixes.must_equal ["test/fixtures/bassist_cell/ibanez", "test/fixtures/bassist"] } + it { assert_equal ["test/fixtures/bassist"], ::BassistCell.new(@controller)._prefixes } + it { assert_equal ["app/cells/bassist_cell/fender"], ::BassistCell::FenderCell.new(@controller)._prefixes } + it { assert_equal ["test/fixtures/bassist_cell/ibanez", "test/fixtures/bassist"], ::BassistCell::IbanezCell.new(@controller)._prefixes } - it { SingerCell.new(@controller)._prefixes.must_equal ["app/cells/prefixes_test/singer"] } - it { BackgroundVocalsCell.new(@controller)._prefixes.must_equal ["app/cells/prefixes_test/background_vocals", "app/cells/prefixes_test/singer"] } - it { ChorusCell.new(@controller)._prefixes.must_equal ["app/cells/prefixes_test/chorus", "app/cells/prefixes_test/background_vocals", "app/cells/prefixes_test/singer"] } + it { assert_equal ["app/cells/prefixes_test/singer"], SingerCell.new(@controller)._prefixes } + it { assert_equal ["app/cells/prefixes_test/background_vocals", "app/cells/prefixes_test/singer"], BackgroundVocalsCell.new(@controller)._prefixes } + it { assert_equal ["app/cells/prefixes_test/chorus", "app/cells/prefixes_test/background_vocals", "app/cells/prefixes_test/singer"], ChorusCell.new(@controller)._prefixes } - it { GuitaristCell.new(@controller)._prefixes.must_equal ["stringer", "app/cells/prefixes_test/singer"] } - it { BassistCell.new(@controller)._prefixes.must_equal ["app/cells/prefixes_test/bassist", "basser", "app/cells/prefixes_test/singer"] } - # it { DrummerCell.new(@controller)._prefixes.must_equal ["drummer", "stringer", "prefixes_test/singer"] } + it { assert_equal ["stringer", "app/cells/prefixes_test/singer"], GuitaristCell.new(@controller)._prefixes } + it { assert_equal ["app/cells/prefixes_test/bassist", "basser", "app/cells/prefixes_test/singer"], BassistCell.new(@controller)._prefixes } # multiple view_paths. - it { EngineCell.prefixes.must_equal ["app/cells/engine", "/var/engine/app/cells/engine"] } + it { assert_equal ["app/cells/engine", "/var/engine/app/cells/engine"], EngineCell.prefixes } it do - InheritingFromEngineCell.prefixes.must_equal [ + expected = [ "app/cells/inheriting_from_engine", "/var/engine/app/cells/inheriting_from_engine", - "app/cells/engine", "/var/engine/app/cells/engine"] + "app/cells/engine", "/var/engine/app/cells/engine" + ] + assert_equal expected, InheritingFromEngineCell.prefixes end # ::_prefixes is cached. it do - WannabeCell.prefixes.must_equal ["test/fixtures/wannabe", "test/fixtures/bassist_cell/ibanez", "test/fixtures/bassist"] + assert_equal ["test/fixtures/wannabe", "test/fixtures/bassist_cell/ibanez", "test/fixtures/bassist"], WannabeCell.prefixes WannabeCell.instance_eval { def _local_prefixes; ["more"] end } # _prefixes is cached. - WannabeCell.prefixes.must_equal ["test/fixtures/wannabe", "test/fixtures/bassist_cell/ibanez", "test/fixtures/bassist"] + assert_equal ["test/fixtures/wannabe", "test/fixtures/bassist_cell/ibanez", "test/fixtures/bassist"], WannabeCell.prefixes # superclasses don't get disturbed. - ::BassistCell.prefixes.must_equal ["test/fixtures/bassist"] + assert_equal ["test/fixtures/bassist"], ::BassistCell.prefixes end end - - # it { Record::Cell.new(@controller).render_state(:show).must_equal "Rock on!" } end class InheritViewsTest < Minitest::Spec @@ -96,13 +94,12 @@ def play class FunkerCell < SlapperCell end - it { SlapperCell.new(nil)._prefixes.must_equal ["test/fixtures/inherit_views_test/slapper", "test/fixtures/bassist"] } - it { FunkerCell.new(nil)._prefixes.must_equal ["test/fixtures/inherit_views_test/funker", "test/fixtures/inherit_views_test/slapper", "test/fixtures/bassist"] } + it { assert_equal ["test/fixtures/inherit_views_test/slapper", "test/fixtures/bassist"], SlapperCell.new(nil)._prefixes } + it { assert_equal ["test/fixtures/inherit_views_test/funker", "test/fixtures/inherit_views_test/slapper", "test/fixtures/bassist"], FunkerCell.new(nil)._prefixes } # test if normal cells inherit views. - it { cell('inherit_views_test/slapper').play.must_equal 'Doo' } - it { cell('inherit_views_test/funker').play.must_equal 'Doo' } - + it { assert_equal 'Doo', cell('inherit_views_test/slapper').play } + it { assert_equal 'Doo', cell('inherit_views_test/funker').play } # TapperCell class TapperCell < Cell::ViewModel @@ -122,12 +119,12 @@ class PopperCell < TapperCell end # Tapper renders its play - it { cell('inherit_views_test/tapper').call(:play).must_equal 'Dooom!' } + it { assert_equal 'Dooom!', cell('inherit_views_test/tapper').call(:play) } # Tapper renders its tap - it { cell('inherit_views_test/tapper').call(:tap).must_equal 'Tap tap tap!' } + it { assert_equal 'Tap tap tap!', cell('inherit_views_test/tapper').call(:tap) } # Popper renders Tapper's play - it { cell('inherit_views_test/popper').call(:play).must_equal 'Dooom!' } + it { assert_equal 'Dooom!', cell('inherit_views_test/popper').call(:play) } # Popper renders its tap - it { cell('inherit_views_test/popper').call(:tap).must_equal "TTttttap I'm not good enough!" } + it { assert_equal "TTttttap I'm not good enough!", cell('inherit_views_test/popper').call(:tap) } end diff --git a/test/property_test.rb b/test/property_test.rb index 160e3bde..d6adbd6e 100644 --- a/test/property_test.rb +++ b/test/property_test.rb @@ -11,10 +11,9 @@ def title let (:song) { Struct.new(:title).new("She Sells And Sand Sandwiches") } # ::property creates automatic accessor. - it { SongCell.(song).title.must_equal "She Sells And Sand Sandwiches" } + it { assert_equal "She Sells And Sand Sandwiches", SongCell.(song).title } end - class EscapedPropertyTest < Minitest::Spec class SongCell < Cell::ViewModel include Escaped @@ -38,11 +37,11 @@ def raw_title end # ::property escapes, everywhere. - it { SongCell.(song).title.must_equal "<b>She Sells And Sand Sandwiches" } - it { SongCell.(song).copyright.must_equal "<a>Copy</a>" } - it { SongCell.(song).lyrics.must_equal "<i>Words</i>" } + it { assert_equal "<b>She Sells And Sand Sandwiches", SongCell.(song).title } + it { assert_equal "<a>Copy</a>", SongCell.(song).copyright } + it { assert_equal "<i>Words</i>", SongCell.(song).lyrics } # no escaping for non-strings. - it { SongCell.(song).artist.must_equal Object } + it { assert_equal Object, SongCell.(song).artist } # no escaping when escape: false - it { SongCell.(song).raw_title.must_equal "She Sells And Sand Sandwiches" } + it { assert_equal "She Sells And Sand Sandwiches", SongCell.(song).raw_title } end diff --git a/test/public_test.rb b/test/public_test.rb index 857d3ddc..0ff2326c 100644 --- a/test/public_test.rb +++ b/test/public_test.rb @@ -16,84 +16,78 @@ def detail end end - class Songs < Cell::Concept - end + class Songs < Cell::Concept + end # ViewModel.cell returns the cell instance. - it { Cell::ViewModel.cell("public_test/song").must_be_instance_of SongCell } - it { Cell::ViewModel.cell(PublicTest::SongCell).must_be_instance_of SongCell } + it { assert_instance_of SongCell, Cell::ViewModel.cell("public_test/song") } + it { assert_instance_of SongCell, Cell::ViewModel.cell(PublicTest::SongCell) } # Concept.cell simply camelizes the string before constantizing. - it { Cell::Concept.cell("public_test/songs").must_be_instance_of Songs } - - it { Cell::Concept.cell(PublicTest::Songs).must_be_instance_of Songs } + it { assert_instance_of Songs, Cell::Concept.cell("public_test/songs") } + it { assert_instance_of Songs, Cell::Concept.cell(PublicTest::Songs) } # ViewModel.cell passes options to cell. - it { Cell::ViewModel.cell("public_test/song", Object, genre: "Metal").initialize_args.must_equal [Object, {genre:"Metal"}] } + it { assert_equal [Object, {genre:"Metal"}], Cell::ViewModel.cell("public_test/song", Object, genre: "Metal").initialize_args } # ViewModel.cell(collection: []) renders cells. - it { Cell::ViewModel.cell("public_test/song", collection: [Object, Module]).to_s.must_equal '[Object, {}][Module, {}]' } + it { assert_equal '[Object, {}][Module, {}]', Cell::ViewModel.cell("public_test/song", collection: [Object, Module]).to_s } # DISCUSS: should cell.() be the default? # ViewModel.cell(collection: []) renders cells with custom join. it do Gem::Deprecate::skip_during do - Cell::ViewModel.cell("public_test/song", collection: [Object, Module]).join('
') do |cell| - cell.() - end.must_equal '[Object, {}]
[Module, {}]' + result = Cell::ViewModel.cell("public_test/song", collection: [Object, Module]).join('
') do |cell| + cell.() + end + assert_equal '[Object, {}]
[Module, {}]', result end end # ViewModel.cell(collection: []) passes generic options to cell. - it { Cell::ViewModel.cell("public_test/song", collection: [Object, Module], genre: 'Metal', context: { ready: true }).to_s.must_equal "[Object, {:genre=>\"Metal\", :context=>{:ready=>true}}][Module, {:genre=>\"Metal\", :context=>{:ready=>true}}]" } + it { assert_equal "[Object, {:genre=>\"Metal\", :context=>{:ready=>true}}][Module, {:genre=>\"Metal\", :context=>{:ready=>true}}]", Cell::ViewModel.cell("public_test/song", collection: [Object, Module], genre: 'Metal', context: { ready: true }).to_s } # ViewModel.cell(collection: [], method: :detail) invokes #detail instead of #show. # TODO: remove in 5.0. it do Gem::Deprecate::skip_during do - Cell::ViewModel.cell("public_test/song", collection: [Object, Module], method: :detail).to_s.must_equal '* [Object, {}]* [Module, {}]' + assert_equal '* [Object, {}]* [Module, {}]', Cell::ViewModel.cell("public_test/song", collection: [Object, Module], method: :detail).to_s end end # ViewModel.cell(collection: []).() invokes #show. - it { Cell::ViewModel.cell("public_test/song", collection: [Object, Module]).().must_equal '[Object, {}][Module, {}]' } + it { assert_equal '[Object, {}][Module, {}]', Cell::ViewModel.cell("public_test/song", collection: [Object, Module]).() } # ViewModel.cell(collection: []).(:detail) invokes #detail instead of #show. - it { Cell::ViewModel.cell("public_test/song", collection: [Object, Module]).(:detail).must_equal '* [Object, {}]* [Module, {}]' } + it { assert_equal '* [Object, {}]* [Module, {}]', Cell::ViewModel.cell("public_test/song", collection: [Object, Module]).(:detail) } # #cell(collection: [], genre: "Fusion").() doesn't change options hash. it do - Cell::ViewModel.cell("public_test/song", options = { genre: "Fusion", collection: [Object] }).() - options.to_s.must_equal "{:genre=>\"Fusion\", :collection=>[Object]}" + options = { genre: "Fusion", collection: [Object] } + Cell::ViewModel.cell("public_test/song", options).() + assert_equal "{:genre=>\"Fusion\", :collection=>[Object]}", options.to_s end - # it do - # content = "" - # Cell::ViewModel.cell("public_test/song", collection: [Object, Module]).each_with_index do |cell, i| - # content += (i == 1 ? cell.(:detail) : cell.()) - # end - - # content.must_equal '[Object, {}]* [Module, {}]' - # end - # cell(collection: []).join captures return value and joins it for you. it do - Cell::ViewModel.cell("public_test/song", collection: [Object, Module]).join do |cell, i| + result = Cell::ViewModel.cell("public_test/song", collection: [Object, Module]).join do |cell, i| i == 1 ? cell.(:detail) : cell.() - end.must_equal '[Object, {}]* [Module, {}]' + end + assert_equal '[Object, {}]* [Module, {}]', result end # cell(collection: []).join("<") captures return value and joins it for you with join. it do - Cell::ViewModel.cell("public_test/song", collection: [Object, Module]).join(">") do |cell, i| + result = Cell::ViewModel.cell("public_test/song", collection: [Object, Module]).join(">") do |cell, i| i == 1 ? cell.(:detail) : cell.() - end.must_equal '[Object, {}]>* [Module, {}]' + end + assert_equal '[Object, {}]>* [Module, {}]', result end # 'join' can be used without a block: it do - Cell::ViewModel.cell( + assert_equal '[Object, {}]---[Module, {}]', Cell::ViewModel.cell( "public_test/song", collection: [Object, Module] - ).join('---').must_equal('[Object, {}]---[Module, {}]') + ).join('---') end end diff --git a/test/render_test.rb b/test/render_test.rb index f700e759..915c9182 100644 --- a/test/render_test.rb +++ b/test/render_test.rb @@ -21,7 +21,6 @@ def string "Right" end - # TODO: just pass hash. def with_locals render locals: {length: 280, title: "Shot Across The Bow"} end @@ -59,57 +58,43 @@ def title class RenderTest < Minitest::Spec # render show.haml calling method, implicit render. - it { SongCell.new(nil).show.must_equal "Papertiger\n" } + it { assert_equal "Papertiger\n", SongCell.new(nil).show } # render ivar.haml using instance variable. - it { SongCell.new(nil).ivar.must_equal "Carnage\n" } + it { assert_equal "Carnage\n", SongCell.new(nil).ivar } # render string. - it { SongCell.new(nil).string.must_equal "Right" } + it { assert_equal "Right", SongCell.new(nil).string } # #call renders :show - it { SongCell.new(nil).call.must_equal "Papertiger\n" } + it { assert_equal "Papertiger\n", SongCell.new(nil).call } # call(:form) renders :form - it { SongCell.new(nil).call(:with_view_name).must_equal "Man Of Steel\n" } + it { assert_equal "Man Of Steel\n", SongCell.new(nil).call(:with_view_name) } # works with state called `send` - it { SongCell.new(nil).call(:send).must_equal "send" } + it { assert_equal "send", SongCell.new(nil).call(:send) } # throws an exception when not found. it do exception = assert_raises(Cell::TemplateMissingError) { SongCell.new(nil).unknown } - exception.message.must_equal "Template missing: view: `unknown.erb` prefixes: [\"test/fixtures/song\"]" + assert_equal "Template missing: view: `unknown.erb` prefixes: [\"test/fixtures/song\"]", exception.message end # allows locals - it { SongCell.new(nil).with_locals.must_equal "Shot Across The Bow\n280\n" } + it { assert_equal "Shot Across The Bow\n280\n", SongCell.new(nil).with_locals } # render :form is a shortcut. - it { SongCell.new(nil).with_view_name.must_equal "Man Of Steel\n" } - - # :template_engine renders ERB. - # it { SongCell.new(nil).with_erb.must_equal "ERB:\n\n Papertiger\n" } - - # view: "show.html" + it { assert_equal "Man Of Steel\n", SongCell.new(nil).with_view_name } # allows passing in options DISCUSS: how to handle that in cache block/builder? - it { SongCell.new(nil).receiving_options.must_equal "default" } - it { SongCell.new(nil).receiving_options(:fancy).must_equal "fancy" } - it { SongCell.new(nil).call(:receiving_options, :fancy).must_equal "fancy" } + it { assert_equal "default", SongCell.new(nil).receiving_options } + it { assert_equal "fancy", SongCell.new(nil).receiving_options(:fancy) } + it { assert_equal "fancy", SongCell.new(nil).call(:receiving_options, :fancy) } # doesn't escape HTML. - it { SongCell.new(nil).call(:with_html).must_equal "

Yew!

" } + it { assert_equal "

Yew!

", SongCell.new(nil).call(:with_html) } # render {} with block - it { SongCell.new(nil).with_block.must_equal "Yo! Clean Sheets

Yew!

\n" } + it { assert_equal "Yo! Clean Sheets

Yew!

\n", SongCell.new(nil).with_block } end - -# test inheritance - -# test view: :bla and :bla -# with layout and locals. -# with layout and :text - -# render with format (e.g. when using ERB for one view) -# should we allow changing the format "per run", so a cell can do .js and .haml? or should that be configurable on class level? diff --git a/test/templates_test.rb b/test/templates_test.rb index 95b49372..43c14c7a 100644 --- a/test/templates_test.rb +++ b/test/templates_test.rb @@ -1,23 +1,15 @@ require 'test_helper' - class TemplatesTest < Minitest::Spec Templates = Cell::Templates # existing. - it { Templates.new[['test/fixtures/bassist'], 'play.erb', {template_class: Cell::Erb::Template}].file.must_equal 'test/fixtures/bassist/play.erb' } + it { assert_equal 'test/fixtures/bassist/play.erb', Templates.new[['test/fixtures/bassist'], 'play.erb', {template_class: Cell::Erb::Template}].file } # not existing. it { assert_nil(Templates.new[['test/fixtures/bassist'], 'not-here.erb', {}]) } - - - # different caches for different classes - - # same cache for subclasses - end - class TemplatesCachingTest < Minitest::Spec class SongCell < Cell::ViewModel self.view_paths = ['test/fixtures'] @@ -32,13 +24,13 @@ def show it do cell = cell("templates_caching_test/song") - cell.call(:show).must_equal 'The Great Mind Eraser' + assert_equal 'The Great Mind Eraser', cell.call(:show) SongCell.templates.instance_eval do def create; raise; end end # cached, NO new tilt template. - cell.call(:show).must_equal 'The Great Mind Eraser' + assert_equal 'The Great Mind Eraser', cell.call(:show) end end diff --git a/test/testing_test.rb b/test/testing_test.rb index e5cd3384..8c2298a7 100644 --- a/test/testing_test.rb +++ b/test/testing_test.rb @@ -18,18 +18,17 @@ class Cell < Cell::Concept describe "#cell" do subject { cell("test_case_test/song", song) } - it { subject.must_be_instance_of SongCell } - it { subject.model.must_equal song } + it { assert_instance_of SongCell, subject } + it { assert_equal song, subject.model } - it { cell("test_case_test/song", collection: [song, song]).().must_equal "Give It All!Give It All!" } + it { assert_equal "Give It All!Give It All!", cell("test_case_test/song", collection: [song, song]).() } end - describe "#concept" do subject { concept("test_case_test/song/cell", song) } - it { subject.must_be_instance_of Song::Cell } - it { subject.model.must_equal song } + it { assert_instance_of Song::Cell, subject } + it { assert_equal song, subject.model } end end @@ -49,11 +48,10 @@ def show before { Cell::Testing.capybara = true } # yes, a global switch! after { Cell::Testing.capybara = false } - it { subject.(:show).has_selector?('b').must_equal true } - - it { cell("capybara_test/capybara", collection: [1, 2]).().has_selector?('b').must_equal true } + it { assert subject.(:show).has_selector?('b') } + it { assert cell("capybara_test/capybara", collection: [1, 2]).().has_selector?('b') } # FIXME: this kinda sucks, what if you want the string in a Capybara environment? - it { subject.(:show).to_s.must_match "Grunt" } + it { assert_match "Grunt", subject.(:show).to_s } end end From 05970fffc90115ae83380f5c5cb77ee4a2808ca2 Mon Sep 17 00:00:00 2001 From: Alfonso Uceda Date: Tue, 12 Nov 2024 16:58:20 +0100 Subject: [PATCH 09/13] Twin test is not used --- test/twin_test.rb | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 test/twin_test.rb diff --git a/test/twin_test.rb b/test/twin_test.rb deleted file mode 100644 index 7b14cb17..00000000 --- a/test/twin_test.rb +++ /dev/null @@ -1,26 +0,0 @@ -# require 'test_helper' -# require 'cell/twin' - -# class TwinTest < Minitest::Spec -# class SongCell < Cell::ViewModel -# class Twin < Disposable::Twin -# property :title -# option :online? -# end - -# include Cell::Twin -# twin Twin - -# def show -# "#{title} is #{online?}" -# end - -# def title -# super.downcase -# end -# end - -# let (:model) { OpenStruct.new(title: "Kenny") } - -# it { SongCell.new( model, :online? => true).call.must_equal "kenny is true" } -# end From 88ceb32be6b418b5c8ff4063f9317b926a32e6de Mon Sep 17 00:00:00 2001 From: Alfonso Uceda Date: Tue, 12 Nov 2024 17:01:50 +0100 Subject: [PATCH 10/13] Rakefile is cleaned --- Rakefile | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Rakefile b/Rakefile index a838ead1..575f6573 100644 --- a/Rakefile +++ b/Rakefile @@ -10,19 +10,5 @@ Rake::TestTask.new(:test) do |test| test.libs << 'test' test.pattern = 'test/*_test.rb' test.verbose = true - # Ruby built-in warnings contain way too much noise to be useful. Consider turning them on again when the following issues are accepted in ruby: - # * https://bugs.ruby-lang.org/issues/10967 (remove warning: private attribute?) - # * https://bugs.ruby-lang.org/issues/12299 (customized warning handling) test.warning = false end - -# Rake::TestTask.new(:rails) do |test| -# test.libs << 'test/rails' -# test.test_files = FileList['test/rails4.2/*_test.rb'] -# test.verbose = true -# end - -# rails_task = Rake::Task["rails"] -# test_task = Rake::Task["test"] -# default_task.enhance { test_task.invoke } -# default_task.enhance { rails_task.invoke } From a67a273b0dc5f75929f352fa501886d5fdb09c0e Mon Sep 17 00:00:00 2001 From: Alfonso Uceda Date: Tue, 12 Nov 2024 17:10:09 +0100 Subject: [PATCH 11/13] Tests reliying in Hash#inspect are fixed for ruby 3.4.0 --- test/concept_test.rb | 19 ++++++++++++++++--- test/layout_test.rb | 7 ++++++- test/public_test.rb | 17 +++++++++++++++-- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/test/concept_test.rb b/test/concept_test.rb index 3eb6ebcd..884d4e6b 100644 --- a/test/concept_test.rb +++ b/test/concept_test.rb @@ -67,11 +67,24 @@ class ConceptTest < Minitest::Spec describe "#cell (in state)" do it { assert_instance_of Record::Cell, Cell::Concept.cell("record/cell", nil, context: { controller: Object }).cell("record/cell", nil) } - it { assert_equal "A Tribute To Rancid, with 24 songs! [{:controller=>Object}]", Cell::Concept.cell("record/cell", nil, context: { controller: Object }).concept("record/cell", nil, tracks: 24).(:description) } + it do + result = Cell::Concept.cell("record/cell", nil, context: { controller: Object }).concept("record/cell", nil, tracks: 24).(:description) + + if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.4.0') + assert_equal "A Tribute To Rancid, with 24 songs! [{:controller=>Object}]", result + else + assert_equal "A Tribute To Rancid, with 24 songs! [{controller: Object}]", result + end + end it do - assert_equal "A Tribute To Rancid, with 24 songs! [{:controller=>Object}]A Tribute To Rancid, with 24 songs! [{:controller=>Object}]", - Cell::Concept.cell("record/cell", nil, context: { controller: Object }).concept("record/cell", collection: [1,2], tracks: 24).(:description) + result = Cell::Concept.cell("record/cell", nil, context: { controller: Object }).concept("record/cell", collection: [1,2], tracks: 24).(:description) + + if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.4.0') + assert_equal "A Tribute To Rancid, with 24 songs! [{:controller=>Object}]A Tribute To Rancid, with 24 songs! [{:controller=>Object}]", result + else + assert_equal "A Tribute To Rancid, with 24 songs! [{controller: Object}]A Tribute To Rancid, with 24 songs! [{controller: Object}]", result + end end end end diff --git a/test/layout_test.rb b/test/layout_test.rb index 4a9efafb..9d1bd080 100644 --- a/test/layout_test.rb +++ b/test/layout_test.rb @@ -72,7 +72,12 @@ class LayoutCell < Cell::ViewModel class ExternalLayoutTest < Minitest::Spec it do result = Comment::ShowCell.new(nil, layout: Comment::LayoutCell, context: { beer: true }).() - assert_equal "$layout.erb{$show.erb, {:beer=>true}\n$show.erb, {:beer=>true}\n, {:beer=>true}}\n", result + + if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.4.0') + assert_equal "$layout.erb{$show.erb, {:beer=>true}\n$show.erb, {:beer=>true}\n, {:beer=>true}}\n", result + else + assert_equal "$layout.erb{$show.erb, {beer: true}\n$show.erb, {beer: true}\n, {beer: true}}\n", result + end end # collection :layout diff --git a/test/public_test.rb b/test/public_test.rb index 0ff2326c..d7e7c0e9 100644 --- a/test/public_test.rb +++ b/test/public_test.rb @@ -45,7 +45,15 @@ class Songs < Cell::Concept end # ViewModel.cell(collection: []) passes generic options to cell. - it { assert_equal "[Object, {:genre=>\"Metal\", :context=>{:ready=>true}}][Module, {:genre=>\"Metal\", :context=>{:ready=>true}}]", Cell::ViewModel.cell("public_test/song", collection: [Object, Module], genre: 'Metal', context: { ready: true }).to_s } + it do + result = Cell::ViewModel.cell("public_test/song", collection: [Object, Module], genre: 'Metal', context: { ready: true }).to_s + + if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.4.0') + assert_equal "[Object, {:genre=>\"Metal\", :context=>{:ready=>true}}][Module, {:genre=>\"Metal\", :context=>{:ready=>true}}]", result + else + assert_equal "[Object, {genre: \"Metal\", context: {ready: true}}][Module, {genre: \"Metal\", context: {ready: true}}]", result + end + end # ViewModel.cell(collection: [], method: :detail) invokes #detail instead of #show. # TODO: remove in 5.0. @@ -65,7 +73,12 @@ class Songs < Cell::Concept it do options = { genre: "Fusion", collection: [Object] } Cell::ViewModel.cell("public_test/song", options).() - assert_equal "{:genre=>\"Fusion\", :collection=>[Object]}", options.to_s + + if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.4.0') + assert_equal "{:genre=>\"Fusion\", :collection=>[Object]}", options.to_s + else + assert_equal "{genre: \"Fusion\", collection: [Object]}", options.to_s + end end # cell(collection: []).join captures return value and joins it for you. From 65a0b0743fbaae915f38665af395ee091c49f4b4 Mon Sep 17 00:00:00 2001 From: Alfonso Uceda Date: Tue, 12 Nov 2024 17:20:34 +0100 Subject: [PATCH 12/13] Gemfile is cleaned up and drop ruby support below 2.5 version --- Gemfile | 7 ------ cells.gemspec | 51 ++++++++++++++++++++++++------------------ lib/cell/view_model.rb | 3 +-- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/Gemfile b/Gemfile index 93f5d477..b4e2a20b 100644 --- a/Gemfile +++ b/Gemfile @@ -1,10 +1,3 @@ source "https://rubygems.org" -gem "minitest", "~> 5.2" -gem "cells-erb"#, path: "../cells-erb" -gem "benchmark-ips" -gem "minitest-line" - gemspec - -# gem "uber", path: "../uber" diff --git a/cells.gemspec b/cells.gemspec index 102c53bb..4df26a76 100644 --- a/cells.gemspec +++ b/cells.gemspec @@ -1,31 +1,38 @@ -lib = File.expand_path("../lib/", __FILE__) -$:.unshift lib unless $:.include?(lib) - -require "cell/version" +require_relative 'lib/cell/version' Gem::Specification.new do |spec| - spec.name = "cells" + spec.name = 'cells' spec.version = Cell::VERSION - spec.platform = Gem::Platform::RUBY - spec.authors = ["Nick Sutterer"] - spec.email = ["apotonick@gmail.com"] - spec.homepage = "https://github.com/apotonick/cells" - spec.summary = %q{View Models for Ruby and Rails.} - spec.description = %q{View Models for Ruby and Rails, replacing helpers and partials while giving you a clean view architecture with proper encapsulation.} - spec.license = "MIT" + spec.authors = ['Nick Sutterer'] + spec.email = ['apotonick@gmail.com'] + spec.homepage = 'https://github.com/trailblazer/cells' + spec.summary = 'View Models for Ruby and Rails.' + spec.description = 'View Models for Ruby and Rails, replacing helpers and partials while giving you a clean view architecture with proper encapsulation.' + spec.license = 'MIT' + + spec.metadata['bug_tracker_uri'] = "#{spec.homepage}/issues" + spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/HEAD/CHANGES.md" + spec.metadata['documentation_uri'] = 'https://trailblazer.to/2.1/docs/cells' + spec.metadata['homepage_uri'] = spec.homepage + spec.metadata['source_code_uri'] = spec.homepage + spec.metadata['wiki_uri'] = "#{spec.homepage}/wiki" - spec.files = `git ls-files`.split("\n") - spec.test_files = `git ls-files -- {test}/*`.split("\n") - spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } - spec.require_paths = ["lib"] + spec.files = Dir.chdir(__dir__) do + `git ls-files -z`.split("\x0").reject do |file| + file.start_with?(*%w[.git Gemfile Rakefile TODO test]) + end + end + spec.require_paths = ['lib'] + spec.required_ruby_version = '>= 2.5' - spec.add_dependency "uber", "< 0.2.0" + spec.add_dependency 'declarative-builder', '~> 0.2.0' + spec.add_dependency 'tilt', '>= 1.4', '< 3' spec.add_dependency "declarative-option", "< 0.2.0" - spec.add_dependency "declarative-builder", "< 0.2.0" - spec.add_dependency "tilt", ">= 1.4", "< 3" + spec.add_dependency 'uber', '< 0.2.0' - spec.add_development_dependency "rake" - spec.add_development_dependency "capybara" - spec.add_development_dependency "cells-erb", ">= 0.0.4" + spec.add_development_dependency 'capybara' + spec.add_development_dependency 'cells-erb', '>= 0.1.0' + spec.add_development_dependency 'minitest' + spec.add_development_dependency 'rake' spec.add_development_dependency 'debug' end diff --git a/lib/cell/view_model.rb b/lib/cell/view_model.rb index 64bc213f..eebeb703 100644 --- a/lib/cell/view_model.rb +++ b/lib/cell/view_model.rb @@ -198,8 +198,7 @@ def process_options!(options) # Computes the view name from the call stack in which `render` was invoked. def state_for_implicit_render(options) - _caller = RUBY_VERSION < "2.0" ? caller(3) : caller(3, 1) # TODO: remove case in 5.0 when dropping 1.9. - _caller[0].match(/`(\w+)|#(\w+)'/).captures.compact.first + caller(3, 1)[0].match(/`(\w+)|#(\w+)'/).captures.compact.first end include Layout From f4139668cd8dc305c4bf9f2bc17c428066fc6363 Mon Sep 17 00:00:00 2001 From: Alfonso Uceda Date: Tue, 12 Nov 2024 17:28:14 +0100 Subject: [PATCH 13/13] README links are corrected --- README.md | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 2e3d86d1..c6e4ded2 100644 --- a/README.md +++ b/README.md @@ -2,24 +2,24 @@ *View Components for Ruby and Rails.* -[![Gitter Chat](https://badges.gitter.im/trailblazer/chat.svg)](https://gitter.im/trailblazer/chat) -[![TRB Newsletter](https://img.shields.io/badge/TRB-newsletter-lightgrey.svg)](http://trailblazer.to/newsletter/) -[![Build +[![Zulip Chat](https://badges.gitter.im/trailblazer/chat.svg)](https://trailblazer.zulipchat.com/login/) +[![TRB Newsletter](https://img.shields.io/badge/TRB-newsletter-lightgrey.svg)](https://trailblazer.to/2.1/#callout-section) +![Build Status](https://github.com/trailblazer/cells/actions/workflows/ci.yml/badge.svg -)] +) [![Gem Version](https://badge.fury.io/rb/cells.svg)](http://badge.fury.io/rb/cells) ## Overview Cells allow you to encapsulate parts of your UI into components into _view models_. View models, or cells, are simple ruby classes that can render templates. -Nevertheless, a cell gives you more than just a template renderer. They allow proper OOP, polymorphic builders, [nesting](#nested-cells), view inheritance, using Rails helpers, [asset packaging](http://trailblazer.to/gems/cells/rails.html#asset-pipeline) to bundle JS, CSS or images, simple distribution via gems or Rails engines, encapsulated testing, [caching](#caching), and [integrate with Trailblazer](https://github.com/trailblazer/trailblazer-cells). +Nevertheless, a cell gives you more than just a template renderer. They allow proper OOP, polymorphic builders, [nesting](#nested-cells), view inheritance, using Rails helpers, [asset packaging](https://trailblazer.to/2.1/docs/cells.html#cells-rails-asset-pipeline) to bundle JS, CSS or images, simple distribution via gems or Rails engines, encapsulated testing, [caching](#caching), and [integrate with Trailblazer](https://github.com/trailblazer/trailblazer-cells). ## Full Documentation -Cells is part of the Trailblazer framework. [Full documentation](http://trailblazer.to/gems/cells) is available on the project site. +Cells is part of the Trailblazer framework. [Full documentation](https://trailblazer.to/2.1/docs/cells/) is available on the project site. -Cells is completely decoupled from Rails. However, Rails-specific functionality is to be found [here](http://trailblazer.to/gems/cells/rails.html). +Cells is completely decoupled from Rails. However, Rails-specific functionality is to be found [here](https://trailblazer.to/2.1/docs/cells/#cells-4-rails). ## Rendering Cells @@ -152,7 +152,7 @@ Capybara.string(html).must_have_css "h3" It is completely up to you how you test, whether it's RSpec, MiniTest or whatever. All the cell does is return HTML. -[In Rails, there's support](http://trailblazer.to/gems/cells/testing.html) for TestUnit, MiniTest and RSpec available, along with Capybara integration. +[In Rails, there's support](https://trailblazer.to/2.1/docs/cells/#cells-4-overview-testing) for TestUnit, MiniTest and RSpec available, along with Capybara integration. ## Properties @@ -183,7 +183,7 @@ song.title #=> "" Comment::Cell.(song).title #=> <script>Dangerous</script> ``` -Properties and escaping are [documented here](http://trailblazer.to/gems/cells/api.html#html-escaping). +Properties and escaping are [documented here](https://trailblazer.to/2.1/docs/cells/#cells-4-api-html-escaping). ## Installation @@ -271,7 +271,7 @@ end ## Asset Packaging -Cells can easily ship with their own JavaScript, CSS and more and be part of Rails' asset pipeline. Bundling assets into a cell allows you to implement super encapsulated widgets that are stand-alone. Asset pipeline is [documented here](http://trailblazer.to/gems/cells/rails.html#asset-pipeline). +Cells can easily ship with their own JavaScript, CSS and more and be part of Rails' asset pipeline. Bundling assets into a cell allows you to implement super encapsulated widgets that are stand-alone. Asset pipeline is [documented here](https://trailblazer.to/2.1/docs/cells/#cells-4-rails-asset-pipeline). ## Render API @@ -345,7 +345,7 @@ This works both in cell views and on the instance, in states. ## View Inheritance -You can not only inherit code across cell classes, but also views. This is extremely helpful if you want to override parts of your UI, only. It's [documented here](http://trailblazer.to/gems/cells/api.html#view-inheritance). +You can not only inherit code across cell classes, but also views. This is extremely helpful if you want to override parts of your UI, only. It's [documented here](https://trailblazer.to/2.1/docs/cells/#cells-4-api-view-inheritance). ## Collections @@ -358,7 +358,7 @@ cell(:comment, collection: comments).() This will invoke `cell(:comment, comment).()` three times and concatenate the rendered output automatically. -Learn more [about collections here](http://trailblazer.to/gems/cells/api.html#collection). +Learn more [about collections here](https://trailblazer.to/2.1/docs/cells/#cells-4-api-collection). ## Builder @@ -383,7 +383,7 @@ The `#cell` helper takes care of instantiating the right cell class for you. cell(:comment, Post.find(1)) #=> creates a PostCell. ``` -Learn more [about builders here](http://trailblazer.to/gems/cells/api.html#builder). +Learn more [about builders here](https://trailblazer.to/2.1/docs/cells/#cells-4-api-builder). ## Caching @@ -402,16 +402,14 @@ The `::cache` method will forward options to the caching engine. cache :show, expires_in: 10.minutes ``` -You can also compute your own cache key, use dynamic keys, cache tags, and conditionals using `:if`. Caching is documented [here](http://trailblazer.to/gems/cells/api.html#caching) and in chapter 8 of the [Trailblazer book](http://leanpub.com/trailblazer). +You can also compute your own cache key, use dynamic keys, cache tags, and conditionals using `:if`. Caching is documented [here](https://trailblazer.to/2.1/docs/cells/#cells-4-api-caching) and in chapter 8 of the [Trailblazer book](http://leanpub.com/trailblazer). ## The Book Cells is part of the [Trailblazer project](https://github.com/apotonick/trailblazer). Please [buy my book](https://leanpub.com/trailblazer) to support the development and to learn all the cool stuff about Cells. The book discusses many use cases of Cells. - -![](https://raw.githubusercontent.com/apotonick/trailblazer/master/doc/trb.jpg) - +[![trb](https://raw.githubusercontent.com/apotonick/trailblazer/master/doc/trb.jpg)](https://leanpub.com/trailblazer) * Basic view models, replacing helpers, and how to structure your view into cell components (chapter 2 and 4). * Advanced Cells API (chapter 4 and 6). @@ -423,11 +421,11 @@ The book picks up where the README leaves off. Go grab a copy and support us - i ## This is not Cells 3.x! -Temporary note: This is the README and API for Cells 4. Many things have improved. If you want to upgrade, [follow this guide](https://github.com/apotonick/cells/wiki/From-Cells-3-to-Cells-4---Upgrading-Guide). When in trouble, join the [Gitter channel](https://gitter.im/trailblazer/chat). +Temporary note: This is the README and API for Cells 4. Many things have improved. If you want to upgrade, [follow this guide](https://github.com/apotonick/cells/wiki/From-Cells-3-to-Cells-4---Upgrading-Guide). When in trouble, join the [Zulip channel](https://trailblazer.zulipchat.com/login/). ## LICENSE -Copyright (c) 2007-2015, Nick Sutterer +Copyright (c) 2007-2024, Nick Sutterer Copyright (c) 2007-2008, Solide ICT by Peter Bex and Bob Leers