diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3b6cf9e..2acc703 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,14 +10,23 @@ jobs: - '3.0' - '3.1' - '3.2' + - '3.3' gemfile: - gemfiles/Gemfile.rails61 - gemfiles/Gemfile.rails70 + - gemfiles/Gemfile.rails71 + - gemfiles/Gemfile.rails72 exclude: - # rails 7.0 requires ruby >= 2.7 + # rails 7.2 requires ruby >= 3.1 # https://www.fastruby.io/blog/ruby/rails/versions/compatibility-table.html - - ruby-version: '2.6' - gemfile: 'gemfiles/Gemfile.rails70' + - ruby-version: '3.0' + gemfile: 'gemfiles/Gemfile.rails72' + # rails 8.0 requires ruby >= 3.2 + # https://www.fastruby.io/blog/ruby/rails/versions/compatibility-table.html + - ruby-version: '3.0' + gemfile: 'gemfiles/Gemfile.rails80' + - ruby-version: '3.1' + gemfile: 'gemfiles/Gemfile.rails80' name: Ruby ${{ matrix.ruby-version }} / Bundle ${{ matrix.gemfile }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d49f87..bc62a11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ ## [Unreleased] +* No unreleased changes + +## 3.3.2 / 2025-06-09 +### Fixed +* Support Ruby 3.2 and 3.3 and Rails 7.1 and 7.2 + ### Added * Support Ruby 3.2. Drop support for Ruby 2.7, Rails 6.0 diff --git a/app/helpers/ndr_ui/bootstrap_helper.rb b/app/helpers/ndr_ui/bootstrap_helper.rb index 5c208f8..c47d85b 100644 --- a/app/helpers/ndr_ui/bootstrap_helper.rb +++ b/app/helpers/ndr_ui/bootstrap_helper.rb @@ -1,6 +1,6 @@ module NdrUi # Provides helper methods for the Twitter Bootstrap framework - module BootstrapHelper + module BootstrapHelper # rubocop:disable Metrics/ModuleLength include ::NdrUi::Bootstrap::BreadcrumbsHelper include ::NdrUi::Bootstrap::DropdownHelper include ::NdrUi::Bootstrap::ModalHelper @@ -594,7 +594,12 @@ def ndr_can?(action, subject, *extra_args) return true unless respond_to?(:can?) unless subject.is_a?(ActiveRecord::Base) - ActiveSupport::Deprecation.warn(<<~MSG) + deprecator = if Rails.application.respond_to?(:deprecators) + Rails.application.deprecators[:active_support] + else + ActiveSupport::Deprecation # Rails <= 7.0 + end + deprecator.warn(<<~MSG) Attempting to authorise a non-resource object causes authorisation to be skipped. In future, this behaviour may change; please use a resource where possible. MSG diff --git a/gemfiles/Gemfile.rails61 b/gemfiles/Gemfile.rails61 index e17af7b..8fdb206 100644 --- a/gemfiles/Gemfile.rails61 +++ b/gemfiles/Gemfile.rails61 @@ -4,3 +4,9 @@ gemspec path: '..' gem 'rails', '~> 6.1.0' +# Rails 6.1 does not support sqlite3 2.x; it specifies gem "sqlite3", "~> 1.4" +# in lib/active_record/connection_adapters/sqlite3_adapter.rb +gem 'sqlite3', '~> 1.7' + +# Latest concurrent-ruby breaks Rails < 7.1. See https://github.com/rails/rails/issues/54260 +gem 'concurrent-ruby', '1.3.4' diff --git a/gemfiles/Gemfile.rails70 b/gemfiles/Gemfile.rails70 index 73abd4b..a35c58c 100644 --- a/gemfiles/Gemfile.rails70 +++ b/gemfiles/Gemfile.rails70 @@ -3,3 +3,10 @@ source 'https://rubygems.org' gemspec path: '..' gem 'rails', '~> 7.0.0' + +# Rails 7.0 does not support sqlite3 2.x; it specifies gem "sqlite3", "~> 1.4" +# in lib/active_record/connection_adapters/sqlite3_adapter.rb +gem 'sqlite3', '~> 1.7' + +# Latest concurrent-ruby breaks Rails < 7.1. See https://github.com/rails/rails/issues/54260 +gem 'concurrent-ruby', '1.3.4' diff --git a/gemfiles/Gemfile.rails71 b/gemfiles/Gemfile.rails71 new file mode 100644 index 0000000..10c4cfc --- /dev/null +++ b/gemfiles/Gemfile.rails71 @@ -0,0 +1,8 @@ +source 'https://rubygems.org' + +gemspec path: '..' + +gem 'rails', '~> 7.1.0' + +# sqlite3 2.x is not supported on ruby 3.0 +gem 'sqlite3', '~> 1.7' diff --git a/gemfiles/Gemfile.rails72 b/gemfiles/Gemfile.rails72 new file mode 100644 index 0000000..474de75 --- /dev/null +++ b/gemfiles/Gemfile.rails72 @@ -0,0 +1,5 @@ +source 'https://rubygems.org' + +gemspec path: '..' + +gem 'rails', '~> 7.2.0' diff --git a/lib/ndr_ui/version.rb b/lib/ndr_ui/version.rb index 58cf003..8896c95 100644 --- a/lib/ndr_ui/version.rb +++ b/lib/ndr_ui/version.rb @@ -2,5 +2,5 @@ # This stores the current version of the NdrUi gem. Use semantic versioning http://semver.org module NdrUi - VERSION = '3.3.1' + VERSION = '3.3.2' end diff --git a/ndr_ui.gemspec b/ndr_ui.gemspec index af3419e..c20f15c 100644 --- a/ndr_ui.gemspec +++ b/ndr_ui.gemspec @@ -6,6 +6,7 @@ unless Gem::Version.new(Gem::VERSION) >= Gem::Version.new('3.0.2') raise 'Please update RubyGems to at least 3.0.2 - lower versions build a broken ndr_ui.gem!' end +# rubocop:disable Gemspec/DevelopmentDependencies Gem::Specification.new do |spec| spec.name = 'ndr_ui' spec.version = NdrUi::VERSION @@ -22,12 +23,15 @@ Gem::Specification.new do |spec| spec.required_ruby_version = '>= 3.0.0' - spec.add_dependency 'rails', '>= 6.1', '< 7.1' + spec.add_dependency 'rails', '>= 6.1', '< 7.3' spec.add_dependency 'bootstrap-sass', '~> 3.4.1' spec.add_dependency 'jquery-rails', '>= 4.1.0' spec.add_dependency 'sprockets', '>= 4.0' spec.add_dependency 'sprockets-rails', '>= 3.0.0' + # Rails 6.1 and 7.0 do not support sqlite3 2.x; they specify gem "sqlite3", "~> 1.4" + # in lib/active_record/connection_adapters/sqlite3_adapter.rb + # cf. gemfiles/Gemfile.rails70 spec.add_development_dependency 'sqlite3' spec.add_development_dependency 'mocha', '~> 2.0' @@ -38,3 +42,4 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'rake' spec.add_development_dependency 'simplecov' end +# rubocop:enable Gemspec/DevelopmentDependencies diff --git a/test/builders/ndr_ui/bootstrap_builder/error_and_warning_alert_boxes_test.rb b/test/builders/ndr_ui/bootstrap_builder/error_and_warning_alert_boxes_test.rb index 93d4e63..1cea681 100644 --- a/test/builders/ndr_ui/bootstrap_builder/error_and_warning_alert_boxes_test.rb +++ b/test/builders/ndr_ui/bootstrap_builder/error_and_warning_alert_boxes_test.rb @@ -78,7 +78,7 @@ class ErrorAndWarningAlertBoxesTest < ActionView::TestCase post.warnings.add(:somewhere2, 'Warning 2') bootstrap_form_for post do |form| - @output_buffer = form.error_and_warning_alert_boxes + @output_buffer = ActionView::OutputBuffer.new(form.error_and_warning_alert_boxes) assert_select 'div.alert', 1 assert_select 'div.alert.alert-warning' do diff --git a/test/builders/ndr_ui/bootstrap_builder/label_tooltips_test.rb b/test/builders/ndr_ui/bootstrap_builder/label_tooltips_test.rb index 1a67210..b71db6b 100644 --- a/test/builders/ndr_ui/bootstrap_builder/label_tooltips_test.rb +++ b/test/builders/ndr_ui/bootstrap_builder/label_tooltips_test.rb @@ -133,6 +133,7 @@ def setup assert_select '.question-tooltip', title: 'Time post was last updated' assert_select 'label[for=post_updated_at]', text: 'Updated' + reset_output_buffer! @output_buffer = bootstrap_form_for post do |form| form.label :updated_at, tooltip: false diff --git a/test/builders/ndr_ui/bootstrap_builder/readonly_test.rb b/test/builders/ndr_ui/bootstrap_builder/readonly_test.rb index 8fda597..8160538 100644 --- a/test/builders/ndr_ui/bootstrap_builder/readonly_test.rb +++ b/test/builders/ndr_ui/bootstrap_builder/readonly_test.rb @@ -44,7 +44,7 @@ class ReadonlyTest < ActionView::TestCase end bootstrap_form_for post do |form| - form.fields_for(:sub_records, readonly: true) do |sub_form| + form.fields_for(:sub_records, nil, readonly: true) do |sub_form| assert sub_form.readonly? refute form.readonly? end @@ -63,6 +63,7 @@ class ReadonlyTest < ActionView::TestCase assert_select 'input[type=text]#post_created_at' assert_select 'p.form-control-static', 0 + reset_output_buffer! @output_buffer = bootstrap_form_for post, readonly: true do |form| form.text_field :created_at @@ -95,6 +96,7 @@ class ReadonlyTest < ActionView::TestCase assert_select 'input[type=hidden]#post_created_at' assert_select 'p.form-control-static', 0 + reset_output_buffer! @output_buffer = bootstrap_form_for post, readonly: true do |form| form.hidden_field :created_at @@ -112,6 +114,7 @@ class ReadonlyTest < ActionView::TestCase assert_select 'label', text: I18n.t('activerecord.attributes.post.updated_at') end + reset_output_buffer! bootstrap_form_for post, readonly: true do |form| @output_buffer = form.label(:updated_at) assert_select 'label', text: I18n.t('activerecord.attributes.post.updated_at') diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb index a14250c..e0dae17 100644 --- a/test/dummy/config/application.rb +++ b/test/dummy/config/application.rb @@ -8,7 +8,7 @@ module Dummy class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. - config.load_defaults 6.1 + config.load_defaults Rails.version.match(/[0-9]*[.][0-9]*/).to_s # e.g. 7.2 # Configuration for the application, engines, and railties goes here. # diff --git a/test/helpers/ndr_ui/bootstrap/modal_helper_test.rb b/test/helpers/ndr_ui/bootstrap/modal_helper_test.rb index 9305c41..b42a1a4 100644 --- a/test/helpers/ndr_ui/bootstrap/modal_helper_test.rb +++ b/test/helpers/ndr_ui/bootstrap/modal_helper_test.rb @@ -10,6 +10,7 @@ class ModalHelperTest < ActionView::TestCase assert_select 'div.modal-content', 'Pear form' end + reset_output_buffer! @output_buffer = bootstrap_modal_dialog_tag(size: 'lg') { 'Pear form' } assert_select 'div.modal-dialog.modal-lg' do assert_select 'div.modal-content', 'Pear form' @@ -58,6 +59,7 @@ class ModalHelperTest < ActionView::TestCase text: 'Close' end + reset_output_buffer! @output_buffer = bootstrap_modal_footer_tag('Non-readonly button text', readonly: false) assert_select 'div.modal-footer' do assert_select 'button.btn.btn-default', @@ -77,6 +79,7 @@ class ModalHelperTest < ActionView::TestCase text: 'Close' end + reset_output_buffer! @output_buffer = bootstrap_modal_footer_tag(readonly: false) do button_tag('Non-readonly default', class: 'btn btn-default', "data-dismiss": 'modal') + button_tag('Non-readonly primary', class: 'btn btn-primary', "data-dismiss": 'modal') @@ -99,6 +102,7 @@ class ModalHelperTest < ActionView::TestCase text: 'Close' end + reset_output_buffer! @output_buffer = bootstrap_modal_footer_tag(readonly: false) assert_select 'div.modal-footer' do assert_select 'button.btn.btn-default', @@ -125,6 +129,7 @@ class ModalHelperTest < ActionView::TestCase end end + reset_output_buffer! @output_buffer = bootstrap_modal_box('New Pear') { 'Pear form' } assert_select 'div.modal-dialog' do assert_select 'div.modal-content' do @@ -151,6 +156,7 @@ class ModalHelperTest < ActionView::TestCase end end + reset_output_buffer! @output_buffer = bootstrap_modal_box('New Pear', 'Pear form', readonly: false) assert_select 'div.modal-dialog' do assert_select 'div.modal-content' do @@ -169,9 +175,11 @@ class ModalHelperTest < ActionView::TestCase @output_buffer = bootstrap_modal_box('New Pear', 'Pear form', size: 'lg') assert_select 'div.modal-dialog.modal-lg' + reset_output_buffer! @output_buffer = bootstrap_modal_box('New Pear', size: 'lg') { 'Pear form' } assert_select 'div.modal-dialog.modal-lg' + reset_output_buffer! @output_buffer = bootstrap_modal_box('New Pear', 'Pear form', size: 'enormous') assert_select 'div.modal-dialog.modal-enormous', 0 end diff --git a/test/helpers/ndr_ui/bootstrap_helper_test.rb b/test/helpers/ndr_ui/bootstrap_helper_test.rb index 2c82d64..f6a932c 100644 --- a/test/helpers/ndr_ui/bootstrap_helper_test.rb +++ b/test/helpers/ndr_ui/bootstrap_helper_test.rb @@ -156,6 +156,7 @@ class BootstrapHelperTest < ActionView::TestCase end assert_select 'form#preserve_me[autocomplete=off][action="/posts"]' + reset_output_buffer! @output_buffer = bootstrap_form_for( :post, url: posts_path, @@ -165,6 +166,7 @@ class BootstrapHelperTest < ActionView::TestCase end assert_select 'form#preserve_me.form-inline[autocomplete=off][action="/posts"]' + reset_output_buffer! @output_buffer = bootstrap_form_for( :post, url: posts_path, @@ -174,6 +176,7 @@ class BootstrapHelperTest < ActionView::TestCase end assert_select 'form#preserve_me[data-controller=form][autocomplete=off][action="/posts"]' + reset_output_buffer! @output_buffer = bootstrap_form_for( :post, url: posts_path, @@ -183,6 +186,7 @@ class BootstrapHelperTest < ActionView::TestCase end assert_select 'form#preserve_me[data-controller="additional form"][autocomplete=off][action="/posts"]' + reset_output_buffer! @output_buffer = bootstrap_form_for( :post, url: posts_path, @@ -210,6 +214,7 @@ class BootstrapHelperTest < ActionView::TestCase end assert_select 'form#preserve_me[autocomplete=off][action="/posts"]' + reset_output_buffer! @output_buffer = bootstrap_form_with( model: Post.new, html: { id: 'preserve_me', class: 'form-inline' } @@ -218,6 +223,7 @@ class BootstrapHelperTest < ActionView::TestCase end assert_select 'form#preserve_me.form-inline[autocomplete=off][action="/posts"]' + reset_output_buffer! @output_buffer = bootstrap_form_with( model: Post.new, html: { id: 'preserve_me' } @@ -226,6 +232,7 @@ class BootstrapHelperTest < ActionView::TestCase end assert_select 'form#preserve_me[data-controller=form][autocomplete=off][action="/posts"]' + reset_output_buffer! @output_buffer = bootstrap_form_with( model: Post.new, html: { id: 'preserve_me', 'data-controller': 'additional' } @@ -234,6 +241,7 @@ class BootstrapHelperTest < ActionView::TestCase end assert_select 'form#preserve_me[data-controller="additional form"][autocomplete=off][action="/posts"]' + reset_output_buffer! @output_buffer = bootstrap_form_with( model: Post.new, horizontal: true, html: { id: 'preserve_me' } @@ -242,6 +250,7 @@ class BootstrapHelperTest < ActionView::TestCase end assert_select 'form#preserve_me.form-horizontal[autocomplete=off][action="/posts"]' + reset_output_buffer! @output_buffer = bootstrap_form_with( url: posts_path, html: { id: 'preserve_me' } @@ -250,6 +259,7 @@ class BootstrapHelperTest < ActionView::TestCase end assert_select 'form#preserve_me[autocomplete=off][action="/posts"]' + reset_output_buffer! @output_buffer = bootstrap_form_with( url: posts_path, html: { id: 'preserve_me', class: 'form-inline' } @@ -258,6 +268,7 @@ class BootstrapHelperTest < ActionView::TestCase end assert_select 'form#preserve_me.form-inline[autocomplete=off][action="/posts"]' + reset_output_buffer! @output_buffer = bootstrap_form_with( url: posts_path, horizontal: true, html: { id: 'preserve_me' } @@ -494,13 +505,14 @@ class BootstrapHelperTest < ActionView::TestCase end test 'non authorisable link with non-resource is not deprecated' do - assert_not_deprecated { details_link('#') } + assert_not_deprecated(active_support_deprecator) { details_link('#') } end test 'authorisable link with non-resource is deprecated' do stubs(can?: true) - actual = assert_deprecated(/authorise a non-resource object/) { details_link('#') } + actual = assert_deprecated(/authorise a non-resource object/, + active_support_deprecator) { details_link('#') } expected = '' \ '' @@ -563,5 +575,11 @@ class BootstrapHelperTest < ActionView::TestCase end # TODO: bootstrap_will_paginate(collection = nil, options = {}) + + def active_support_deprecator + return nil unless Rails.application.respond_to?(:deprecators) # Rails <= 7.0 + + Rails.application.deprecators[:active_support] + end end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 176cee9..fe8b739 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -35,4 +35,12 @@ def unsafe_string end end +module ActionView + class TestCase + def reset_output_buffer! + @output_buffer = ActionView::OutputBuffer.new + end + end +end + require 'mocha/minitest'