diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0e94f1df..668381c58 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,18 +27,6 @@ jobs: fail-fast: false matrix: include: - - ruby_version: "3.0" - rails_version: "6.1" - mode: "capture_patch_enabled" - - ruby_version: "3.0" - rails_version: "6.1" - mode: "capture_patch_disabled" - - ruby_version: "3.1" - rails_version: "7.0" - mode: "capture_patch_enabled" - - ruby_version: "3.1" - rails_version: "7.0" - mode: "capture_patch_disabled" - ruby_version: "3.2" rails_version: "7.1" mode: "capture_patch_enabled" diff --git a/.gitignore b/.gitignore index 340f093f5..dfe6728fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.gem *.rbc .ruby-version +.DS_Store /.config /coverage/assets /coverage/index.html diff --git a/Appraisals b/Appraisals index 97a25f8e0..295bcd949 100644 --- a/Appraisals +++ b/Appraisals @@ -1,22 +1,5 @@ # frozen_string_literal: true -appraise "rails-6.1" do - gem "rails", "~> 6.1" - gem "tailwindcss-rails", "~> 2.0" - - # Required for Ruby 3.1.0 - gem "net-smtp", require: false - gem "net-imap", require: false - gem "net-pop", require: false - gem "turbo-rails", "~> 1" -end - -appraise "rails-7.0" do - gem "rails", "~> 7.0" - gem "tailwindcss-rails", "~> 2.0" - gem "turbo-rails", "~> 1" -end - appraise "rails-7.1" do gem "rails", "~> 7.1" gem "tailwindcss-rails", "~> 2.0" diff --git a/Gemfile b/Gemfile index 0a20ee868..0ed4f7ae3 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source "https://rubygems.org" gemspec -rails_version = (ENV["RAILS_VERSION"] || "~> 7.0.0").to_s +rails_version = (ENV["RAILS_VERSION"] || "~> 7.1.0").to_s gem "rails", (rails_version == "main") ? {git: "https://github.com/rails/rails", ref: "main"} : rails_version ruby_version = (ENV["RUBY_VERSION"] || "~> 3.3").to_s diff --git a/Gemfile.lock b/Gemfile.lock index b70346e73..dbd9018b6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,77 +2,86 @@ PATH remote: . specs: view_component (3.20.0) - activesupport (>= 5.2.0, < 8.1) + activesupport (>= 7.1.0, < 8.1) concurrent-ruby (~> 1.0) method_source (~> 1.0) GEM remote: https://rubygems.org/ specs: - actioncable (7.0.8.6) - actionpack (= 7.0.8.6) - activesupport (= 7.0.8.6) + actioncable (7.1.4) + actionpack (= 7.1.4) + activesupport (= 7.1.4) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.8.6) - actionpack (= 7.0.8.6) - activejob (= 7.0.8.6) - activerecord (= 7.0.8.6) - activestorage (= 7.0.8.6) - activesupport (= 7.0.8.6) + zeitwerk (~> 2.6) + actionmailbox (7.1.4) + actionpack (= 7.1.4) + activejob (= 7.1.4) + activerecord (= 7.1.4) + activestorage (= 7.1.4) + activesupport (= 7.1.4) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.0.8.6) - actionpack (= 7.0.8.6) - actionview (= 7.0.8.6) - activejob (= 7.0.8.6) - activesupport (= 7.0.8.6) + actionmailer (7.1.4) + actionpack (= 7.1.4) + actionview (= 7.1.4) + activejob (= 7.1.4) + activesupport (= 7.1.4) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp - rails-dom-testing (~> 2.0) - actionpack (7.0.8.6) - actionview (= 7.0.8.6) - activesupport (= 7.0.8.6) - rack (~> 2.0, >= 2.2.4) + rails-dom-testing (~> 2.2) + actionpack (7.1.4) + actionview (= 7.1.4) + activesupport (= 7.1.4) + nokogiri (>= 1.8.5) + racc + rack (>= 2.2.4) + rack-session (>= 1.0.1) rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.8.6) - actionpack (= 7.0.8.6) - activerecord (= 7.0.8.6) - activestorage (= 7.0.8.6) - activesupport (= 7.0.8.6) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + actiontext (7.1.4) + actionpack (= 7.1.4) + activerecord (= 7.1.4) + activestorage (= 7.1.4) + activesupport (= 7.1.4) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.8.6) - activesupport (= 7.0.8.6) + actionview (7.1.4) + activesupport (= 7.1.4) builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (7.0.8.6) - activesupport (= 7.0.8.6) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (7.1.4) + activesupport (= 7.1.4) globalid (>= 0.3.6) - activemodel (7.0.8.6) - activesupport (= 7.0.8.6) - activerecord (7.0.8.6) - activemodel (= 7.0.8.6) - activesupport (= 7.0.8.6) - activestorage (7.0.8.6) - actionpack (= 7.0.8.6) - activejob (= 7.0.8.6) - activerecord (= 7.0.8.6) - activesupport (= 7.0.8.6) + activemodel (7.1.4) + activesupport (= 7.1.4) + activerecord (7.1.4) + activemodel (= 7.1.4) + activesupport (= 7.1.4) + timeout (>= 0.4.0) + activestorage (7.1.4) + actionpack (= 7.1.4) + activejob (= 7.1.4) + activerecord (= 7.1.4) + activesupport (= 7.1.4) marcel (~> 1.0) - mini_mime (>= 1.1.0) - activesupport (7.0.8.6) + activesupport (7.1.4) + base64 + bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) minitest (>= 5.1) + mutex_m tzinfo (~> 2.0) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) @@ -105,6 +114,7 @@ GEM xpath (~> 3.2) coderay (1.1.3) concurrent-ruby (1.3.4) + connection_pool (2.4.1) crass (1.0.6) cuprite (0.15.1) capybara (~> 3.0) @@ -191,23 +201,28 @@ GEM puma (6.4.3) nio4r (~> 2.0) racc (1.8.1) - rack (2.2.10) + rack (2.2.9) + rack-session (1.0.2) + rack (< 3) rack-test (2.1.0) rack (>= 1.3) - rails (7.0.8.6) - actioncable (= 7.0.8.6) - actionmailbox (= 7.0.8.6) - actionmailer (= 7.0.8.6) - actionpack (= 7.0.8.6) - actiontext (= 7.0.8.6) - actionview (= 7.0.8.6) - activejob (= 7.0.8.6) - activemodel (= 7.0.8.6) - activerecord (= 7.0.8.6) - activestorage (= 7.0.8.6) - activesupport (= 7.0.8.6) + rackup (1.0.0) + rack (< 3) + webrick + rails (7.1.4) + actioncable (= 7.1.4) + actionmailbox (= 7.1.4) + actionmailer (= 7.1.4) + actionpack (= 7.1.4) + actiontext (= 7.1.4) + actionview (= 7.1.4) + activejob (= 7.1.4) + activemodel (= 7.1.4) + activerecord (= 7.1.4) + activestorage (= 7.1.4) + activesupport (= 7.1.4) bundler (>= 1.15.0) - railties (= 7.0.8.6) + railties (= 7.1.4) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -215,13 +230,14 @@ GEM rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) - railties (7.0.8.6) - actionpack (= 7.0.8.6) - activesupport (= 7.0.8.6) - method_source + railties (7.1.4) + actionpack (= 7.1.4) + activesupport (= 7.1.4) + irb + rackup (>= 1.0.0) rake (>= 12.2) - thor (~> 1.0) - zeitwerk (~> 2.5) + thor (~> 1.0, >= 1.2.2) + zeitwerk (~> 2.6) rainbow (3.1.1) rake (13.2.1) rdoc (6.7.0) @@ -356,7 +372,7 @@ DEPENDENCIES net-smtp pry (~> 0.13) puma (~> 6) - rails (~> 7.0.0) + rails (~> 7.1.0) rake (~> 13.0) rspec-rails (~> 5) rubocop-md (~> 1) diff --git a/app/helpers/preview_helper.rb b/app/helpers/preview_helper.rb index 18016ff76..a679e3318 100644 --- a/app/helpers/preview_helper.rb +++ b/app/helpers/preview_helper.rb @@ -1,10 +1,6 @@ # frozen_string_literal: true module PreviewHelper - # :nocov: - include ActionView::Helpers::AssetUrlHelper if Rails.version.to_f < 6.1 - # :nocov: - AVAILABLE_PRISM_LANGUAGES = %w[ruby erb haml] FALLBACK_LANGUAGE = "ruby" @@ -25,38 +21,10 @@ def prism_js_source_url def find_template_data(lookup_context:, template_identifier:) template = lookup_context.find_template(template_identifier) - if Rails.version.to_f >= 6.1 || template.source.present? - { - source: template.source, - prism_language_name: prism_language_name_by_template(template: template) - } - # :nocov: - else - # Fetch template source via finding it through preview paths - # to accomodate source view when exclusively using templates - # for previews for Rails < 6.1. - all_template_paths = ViewComponent::Base.config.preview_paths.map do |preview_path| - Dir.glob("#{preview_path}/**/*") - end.flatten - - # Search for templates the contain `html`. - matching_templates = all_template_paths.find_all do |path| - path =~ /#{template_identifier}*.(html)/ - end - - raise ViewComponent::NoMatchingTemplatesForPreviewError.new(template_identifier) if matching_templates.empty? - raise ViewComponent::MultipleMatchingTemplatesForPreviewError.new(template_identifier) if matching_templates.size > 1 - - template_file_path = matching_templates.first - template_source = File.read(template_file_path) - prism_language_name = prism_language_name_by_template_path(template_file_path: template_file_path) - - { - source: template_source, - prism_language_name: prism_language_name - } - end - # :nocov: + { + source: template.source, + prism_language_name: prism_language_name_by_template(template: template) + } end private diff --git a/app/views/view_components/preview.html.erb b/app/views/view_components/preview.html.erb index f364fd725..c12aa6eb0 100644 --- a/app/views/view_components/preview.html.erb +++ b/app/views/view_components/preview.html.erb @@ -1,9 +1,5 @@ <% if @render_args[:component] %> - <% if ViewComponent::Base.config.render_monkey_patch_enabled || Rails.version.to_f >= 6.1 %> - <%= render(@render_args[:component], @render_args[:args], &@render_args[:block]) %> - <% else %> - <%= render_component(@render_args[:component], &@render_args[:block]) %> - <% end %> + <%= render(@render_args[:component], @render_args[:args], &@render_args[:block]) %> <% else %> <%= render template: @render_args[:template], locals: @render_args[:locals] || {} %> <% end %> diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index c106fb61d..9287c2522 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -10,6 +10,24 @@ nav_order: 5 ## main +## 4.0.0 + +* BREAKING: Require [non-EOL](https://endoflife.date/rails) Rails (`>= 7.1.0`). + + *Joel Hawksley* + +* BREAKING: Require [non-EOL](https://www.ruby-lang.org/en/downloads/branches/) Ruby (`>= 3.2.0`). + + *Joel Hawksley* + +* BREAKING: Remove `render_component` and `render` monkey patch configured with `render_monkey_patch_enabled`. + + *Joel Hawksley* + +* BREAKING: Remove support for variant names containing `.` to be consistent with Rails. + + *Stephen Nelson* + * Ensure HTML output safety wrapper is used for all inline templates. *Joel Hawksley* diff --git a/docs/api.md b/docs/api.md index 3e18fbe58..0e4778345 100644 --- a/docs/api.md +++ b/docs/api.md @@ -243,12 +243,6 @@ Defaults to `['test/components/previews']` relative to your Rails root. The entry route for component previews. Defaults to `"/rails/view_components"`. -### `.render_monkey_patch_enabled` - -If this is disabled, use `#render_component` or -`#render_component_to_string` instead. -Defaults to `true`. - ### `.show_previews` Whether component previews are enabled. diff --git a/docs/compatibility.md b/docs/compatibility.md index ded7dfd13..19f243267 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -8,29 +8,12 @@ nav_order: 6 ## Ruby & Rails -ViewComponent supports all actively supported versions of Ruby (3.0+) and Ruby on Rails (6.1+) and is tested against a combination of these versions of Ruby on Rails. - -While EOL (end-of-life) versions of Ruby and Ruby on Rails may still work with ViewComponent, they're not actively supported and no longer tested. We will still accept patches on a case-by-case basis to support older Ruby & Rails versions based on the complexity and maintenance burden. Please open an issue before submitting such a Pull Request. +ViewComponent supports all actively supported versions of [Ruby](https://endoflife.date/ruby) (>= 3.2) and [Ruby on Rails](https://endoflife.date/rails) (>= 7.1). Changes to the minimum Ruby and Rails versions supported will only be made in major releases. ## Template languages ViewComponent is tested against ERB, Haml, and Slim, but it should support most Rails template handlers. -## Disabling the render monkey patch (Rails < 6.1) - -Since 2.13.0 -{: .label } - -To [avoid conflicts](https://github.com/viewcomponent/view_component/issues/288) between ViewComponent and other gems that also monkey patch the `render` method, it's possible to configure ViewComponent to not include the render monkey patch: - -`config.view_component.render_monkey_patch_enabled = false # defaults to true` - -With the monkey patch disabled, use `render_component` (or `render_component_to_string`) instead: - -```erb -<%= render_component Component.new(message: "bar") %> -``` - ## Bridgetown (Static Site Generator) [Bridgetown](https://www.bridgetownrb.com/) supports ViewComponent via an experimental shim provided by the [bridgetown-view-component gem](https://github.com/bridgetownrb/bridgetown-view-component). More information available [here](https://www.bridgetownrb.com/docs/components/ruby#need-compatibility-with-rails-try-viewcomponent-experimental). diff --git a/docs/index.md b/docs/index.md index c810d6471..659efa588 100644 --- a/docs/index.md +++ b/docs/index.md @@ -193,6 +193,7 @@ ViewComponent is built by over a hundred members of the community, including: + diff --git a/docs/known_issues.md b/docs/known_issues.md index ce20d6abf..ff8197168 100644 --- a/docs/known_issues.md +++ b/docs/known_issues.md @@ -55,7 +55,3 @@ Calls to form helpers such as `form_with` in ViewComponents [don't use the defau <%= f.text_field :name %> <% end %> ``` - -## Inconsistent controller rendering behavior between Rails versions - -In versions of Rails < 6.1, rendering a ViewComponent from a controller doesn't include the layout. diff --git a/gemfiles/rails_6.1.gemfile b/gemfiles/rails_6.1.gemfile deleted file mode 100644 index d78c28030..000000000 --- a/gemfiles/rails_6.1.gemfile +++ /dev/null @@ -1,12 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "rails", "~> 6.1" -gem "tailwindcss-rails", "~> 2.0" -gem "net-smtp", require: false -gem "net-imap", require: false -gem "net-pop", require: false -gem "turbo-rails", "~> 1" - -gemspec path: "../" diff --git a/gemfiles/rails_7.0.gemfile b/gemfiles/rails_7.0.gemfile deleted file mode 100644 index a703d2cc6..000000000 --- a/gemfiles/rails_7.0.gemfile +++ /dev/null @@ -1,9 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "rails", "~> 7.0" -gem "tailwindcss-rails", "~> 2.0" -gem "turbo-rails", "~> 1" - -gemspec path: "../" diff --git a/lib/view_component/base.rb b/lib/view_component/base.rb index 2cb42a545..69d8815d6 100644 --- a/lib/view_component/base.rb +++ b/lib/view_component/base.rb @@ -361,13 +361,6 @@ def safe_output_postamble # configured on a per-test basis using `with_controller_class`. # - # Set if render monkey patches should be included or not in Rails <6.1: - # - # ```ruby - # config.view_component.render_monkey_patch_enabled = false - # ``` - # - # Path for component files # # ```ruby @@ -686,8 +679,6 @@ def splatted_keyword_argument_present? def initialize_parameter_names return attribute_names.map(&:to_sym) if respond_to?(:attribute_names) - return attribute_types.keys.map(&:to_sym) if Rails::VERSION::MAJOR <= 5 && respond_to?(:attribute_types) - initialize_parameters.map(&:last) end diff --git a/lib/view_component/collection.rb b/lib/view_component/collection.rb index 798e38c25..d3c13e56a 100644 --- a/lib/view_component/collection.rb +++ b/lib/view_component/collection.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require "action_view/renderer/collection_renderer" if Rails.version.to_f >= 6.1 +require "action_view/renderer/collection_renderer" module ViewComponent class Collection diff --git a/lib/view_component/compiler.rb b/lib/view_component/compiler.rb index c4ab88df4..8e80ae026 100644 --- a/lib/view_component/compiler.rb +++ b/lib/view_component/compiler.rb @@ -169,27 +169,12 @@ def template_errors def gather_templates @templates ||= begin + path_parser = ActionView::Resolver::PathParser.new templates = @component.sidecar_files( ActionView::Template.template_handler_extensions ).map do |path| - # Extract format and variant from template filename - this_format, variant = - File - .basename(path) # "variants_component.html+mini.watch.erb" - .split(".")[1..-2] # ["html+mini", "watch"] - .join(".") # "html+mini.watch" - .split("+") # ["html", "mini.watch"] - .map(&:to_sym) # [:html, :"mini.watch"] - - out = Template.new( - component: @component, - type: :file, - path: path, - lineno: 0, - extension: path.split(".").last, - this_format: this_format.to_s.split(".").last&.to_sym, # strip locale from this_format, see #2113 - variant: variant - ) + details = path_parser.parse(path).details + out = Template::File.new(component: @component, path: path, details: details) out end @@ -201,24 +186,17 @@ def gather_templates ).flat_map { |ancestor| ancestor.instance_methods(false).grep(/^call(_|$)/) } .uniq .each do |method_name| - templates << Template.new( + templates << Template::InlineCall.new( component: @component, - type: :inline_call, - this_format: ViewComponent::Base::VC_INTERNAL_DEFAULT_FORMAT, - variant: method_name.to_s.include?("call_") ? method_name.to_s.sub("call_", "").to_sym : nil, method_name: method_name, defined_on_self: component_instance_methods_on_self.include?(method_name) ) end if @component.inline_template.present? - templates << Template.new( + templates << Template::Inline.new( component: @component, - type: :inline, - path: @component.inline_template.path, - lineno: @component.inline_template.lineno, - source: @component.inline_template.source.dup, - extension: @component.inline_template.language + inline_template: @component.inline_template ) end diff --git a/lib/view_component/config.rb b/lib/view_component/config.rb index 3edcd22d2..c2c8d6620 100644 --- a/lib/view_component/config.rb +++ b/lib/view_component/config.rb @@ -18,7 +18,6 @@ def defaults show_previews_source: false, instrumentation_enabled: false, use_deprecated_instrumentation_name: true, - render_monkey_patch_enabled: true, view_component_path: "app/components", component_parent_class: nil, show_previews: Rails.env.development? || Rails.env.test?, @@ -126,12 +125,6 @@ def defaults # Will default to `false` in next major version. # Defaults to `true`. - # @!attribute render_monkey_patch_enabled - # @return [Boolean] Whether the #render method should be monkey patched. - # If this is disabled, use `#render_component` or - # `#render_component_to_string` instead. - # Defaults to `true`. - # @!attribute view_component_path # @return [String] # The path in which components, their templates, and their sidecars should diff --git a/lib/view_component/engine.rb b/lib/view_component/engine.rb index b920eb5d8..40b9d305c 100644 --- a/lib/view_component/engine.rb +++ b/lib/view_component/engine.rb @@ -33,7 +33,6 @@ class Engine < Rails::Engine # :nodoc: options[config_option] ||= ViewComponent::Base.public_send(config_option) end options.instrumentation_enabled = false if options.instrumentation_enabled.nil? - options.render_monkey_patch_enabled = true if options.render_monkey_patch_enabled.nil? options.show_previews = (Rails.env.development? || Rails.env.test?) if options.show_previews.nil? if options.show_previews @@ -91,46 +90,6 @@ class Engine < Rails::Engine # :nodoc: end end - initializer "view_component.monkey_patch_render" do |app| - next if Rails.version.to_f >= 6.1 || !app.config.view_component.render_monkey_patch_enabled - - # :nocov: - ViewComponent::Deprecation.deprecation_warning("Monkey patching `render`", "ViewComponent 4.0 will remove the `render` monkey patch") - - ActiveSupport.on_load(:action_view) do - require "view_component/render_monkey_patch" - ActionView::Base.prepend ViewComponent::RenderMonkeyPatch - end - - ActiveSupport.on_load(:action_controller) do - require "view_component/rendering_monkey_patch" - require "view_component/render_to_string_monkey_patch" - ActionController::Base.prepend ViewComponent::RenderingMonkeyPatch - ActionController::Base.prepend ViewComponent::RenderToStringMonkeyPatch - end - # :nocov: - end - - initializer "view_component.include_render_component" do |_app| - next if Rails.version.to_f >= 6.1 - - # :nocov: - ViewComponent::Deprecation.deprecation_warning("using `render_component`", "ViewComponent 4.0 will remove `render_component`") - - ActiveSupport.on_load(:action_view) do - require "view_component/render_component_helper" - ActionView::Base.include ViewComponent::RenderComponentHelper - end - - ActiveSupport.on_load(:action_controller) do - require "view_component/rendering_component_helper" - require "view_component/render_component_to_string_helper" - ActionController::Base.include ViewComponent::RenderingComponentHelper - ActionController::Base.include ViewComponent::RenderComponentToStringHelper - end - # :nocov: - end - initializer "static assets" do |app| if serve_static_preview_assets?(app.config) app.middleware.use(::ActionDispatch::Static, "#{root}/app/assets/vendor") @@ -174,16 +133,6 @@ def serve_static_preview_assets?(app_config) end end - # :nocov: - if RUBY_VERSION < "3.2.0" - ViewComponent::Deprecation.deprecation_warning("Support for Ruby versions < 3.2.0", "ViewComponent v4 will remove support for Ruby versions < 3.2.0 no earlier than April 1, 2025") - end - - if Rails.version.to_f < 7.1 - ViewComponent::Deprecation.deprecation_warning("Support for Rails versions < 7.1", "ViewComponent v4 will remove support for Rails versions < 7.1 no earlier than April 1, 2025") - end - # :nocov: - app.executor.to_run :before do CompileCache.invalidate! unless ActionView::Base.cache_template_loading end diff --git a/lib/view_component/preview.rb b/lib/view_component/preview.rb index 2d3c84465..737b3601e 100644 --- a/lib/view_component/preview.rb +++ b/lib/view_component/preview.rb @@ -30,8 +30,6 @@ def render_with_template(template: nil, locals: {}) } end - alias_method :render_component, :render - class << self # Returns all component preview classes. def all diff --git a/lib/view_component/render_component_helper.rb b/lib/view_component/render_component_helper.rb deleted file mode 100644 index 945cd539d..000000000 --- a/lib/view_component/render_component_helper.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -module ViewComponent - module RenderComponentHelper # :nodoc: - def render_component(component, &block) - component.set_original_view_context(__vc_original_view_context) if is_a?(ViewComponent::Base) - component.render_in(self, &block) - end - end -end diff --git a/lib/view_component/render_component_to_string_helper.rb b/lib/view_component/render_component_to_string_helper.rb deleted file mode 100644 index dff55587c..000000000 --- a/lib/view_component/render_component_to_string_helper.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module ViewComponent - module RenderComponentToStringHelper # :nodoc: - def render_component_to_string(component) - component.render_in(view_context) - end - end -end diff --git a/lib/view_component/render_monkey_patch.rb b/lib/view_component/render_monkey_patch.rb deleted file mode 100644 index 0d05ac394..000000000 --- a/lib/view_component/render_monkey_patch.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -module ViewComponent - module RenderMonkeyPatch # :nodoc: - def render(options = {}, args = {}, &block) - if options.respond_to?(:render_in) - options.render_in(self, &block) - else - super - end - end - end -end diff --git a/lib/view_component/render_to_string_monkey_patch.rb b/lib/view_component/render_to_string_monkey_patch.rb deleted file mode 100644 index 325646f07..000000000 --- a/lib/view_component/render_to_string_monkey_patch.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -module ViewComponent - module RenderToStringMonkeyPatch # :nodoc: - def render_to_string(options = {}, args = {}) - if options.respond_to?(:render_in) - options.render_in(view_context) - else - super - end - end - end -end diff --git a/lib/view_component/rendering_component_helper.rb b/lib/view_component/rendering_component_helper.rb deleted file mode 100644 index dc7777efb..000000000 --- a/lib/view_component/rendering_component_helper.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module ViewComponent - module RenderingComponentHelper # :nodoc: - def render_component(component) - self.response_body = component.render_in(view_context) - end - end -end diff --git a/lib/view_component/rendering_monkey_patch.rb b/lib/view_component/rendering_monkey_patch.rb deleted file mode 100644 index ac7df3380..000000000 --- a/lib/view_component/rendering_monkey_patch.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -module ViewComponent - module RenderingMonkeyPatch # :nodoc: - def render(options = {}, args = {}) - if options.respond_to?(:render_in) - self.response_body = options.render_in(view_context) - else - super - end - end - end -end diff --git a/lib/view_component/template.rb b/lib/view_component/template.rb index f01fd9368..09d7bdc5f 100644 --- a/lib/view_component/template.rb +++ b/lib/view_component/template.rb @@ -5,56 +5,112 @@ class Template DataWithSource = Struct.new(:format, :identifier, :short_identifier, :type, keyword_init: true) DataNoSource = Struct.new(:source, :identifier, :type, keyword_init: true) - attr_reader :variant, :this_format, :type + attr_reader :details + + delegate :format, :variant, to: :details def initialize( component:, - type:, - this_format: nil, - variant: nil, + details:, lineno: nil, path: nil, - extension: nil, - source: nil, - method_name: nil, - defined_on_self: true + method_name: nil ) @component = component - @type = type - @this_format = this_format - @variant = variant&.to_sym + @details = details @lineno = lineno @path = path - @extension = extension - @source = source @method_name = method_name - @defined_on_self = defined_on_self - - @source_originally_nil = @source.nil? @call_method_name = if @method_name @method_name else out = +"call" - out << "_#{normalized_variant_name}" if @variant.present? - out << "_#{@this_format}" if @this_format.present? && @this_format != ViewComponent::Base::VC_INTERNAL_DEFAULT_FORMAT + out << "_#{normalized_variant_name}" if variant.present? + out << "_#{format}" if format.present? && format != ViewComponent::Base::VC_INTERNAL_DEFAULT_FORMAT out end end + class File < Template + def initialize(component:, details:, path:) + super( + component: component, + details: details, + path: path, + lineno: 0 + ) + end + + def type + :file + end + + # Load file each time we look up #source in case the file has been modified + def source + ::File.read(@path) + end + end + + class Inline < Template + attr_reader :source + + def initialize(component:, inline_template:) + details = ActionView::TemplateDetails.new(nil, inline_template.language.to_sym, nil, nil) + + super( + component: component, + details: details, + path: inline_template.path, + lineno: inline_template.lineno, + ) + + @source = inline_template.source.dup + end + + def type + :inline + end + end + + class InlineCall < Template + def initialize(component:, method_name:, defined_on_self:) + variant = method_name.to_s.include?("call_") ? method_name.to_s.sub("call_", "").to_sym : nil + details = ActionView::TemplateDetails.new(nil, nil, nil, variant) + + super( + component: component, + details: details, + method_name: method_name + ) + + @defined_on_self = defined_on_self + end + + def type + :inline_call + end + + def compile_to_component + @component.define_method(safe_method_name, @component.instance_method(@call_method_name)) + end + + def defined_on_self? + @defined_on_self + end + end + def compile_to_component - if !inline_call? - @component.silence_redefinition_of_method(@call_method_name) + @component.silence_redefinition_of_method(@call_method_name) - # rubocop:disable Style/EvalWithLocation - @component.class_eval <<-RUBY, @path, @lineno - def #{@call_method_name} - #{compiled_source} - end - RUBY - # rubocop:enable Style/EvalWithLocation + # rubocop:disable Style/EvalWithLocation + @component.class_eval <<-RUBY, @path, @lineno + def #{@call_method_name} + #{compiled_source} end + RUBY + # rubocop:enable Style/EvalWithLocation @component.define_method(safe_method_name, @component.instance_method(@call_method_name)) end @@ -72,19 +128,15 @@ def requires_compiled_superclass? end def inline_call? - @type == :inline_call + type == :inline_call end def inline? - @type == :inline + type == :inline end def default_format? - @this_format == ViewComponent::Base::VC_INTERNAL_DEFAULT_FORMAT - end - - def format - @this_format + format.nil? || format == ViewComponent::Base::VC_INTERNAL_DEFAULT_FORMAT end def safe_method_name @@ -92,35 +144,23 @@ def safe_method_name end def normalized_variant_name - @variant.to_s.gsub("-", "__").gsub(".", "___") - end - - def defined_on_self? - @defined_on_self + variant.to_s.gsub("-", "__") end private - def source - if @source_originally_nil - # Load file each time we look up #source in case the file has been modified - File.read(@path) - else - @source - end - end - def compiled_source - handler = ActionView::Template.handler_for_extension(@extension) + handler = details.handler_class this_source = source this_source.rstrip! if @component.strip_trailing_whitespace? short_identifier = defined?(Rails.root) ? @path.sub("#{Rails.root}/", "") : @path - type = ActionView::Template::Types[@this_format] + format = self.format || ViewComponent::Base::VC_INTERNAL_DEFAULT_FORMAT + type = ActionView::Template::Types[format] if handler.method(:call).parameters.length > 1 handler.call( - DataWithSource.new(format: @this_format, identifier: @path, short_identifier: short_identifier, type: type), + DataWithSource.new(format: format, identifier: @path, short_identifier: short_identifier, type: type), this_source ) # :nocov: diff --git a/lib/view_component/test_helpers.rb b/lib/view_component/test_helpers.rb index 3677763fb..58e4e2a4c 100644 --- a/lib/view_component/test_helpers.rb +++ b/lib/view_component/test_helpers.rb @@ -49,16 +49,7 @@ def assert_component_rendered # @return [Nokogiri::HTML] def render_inline(component, **args, &block) @page = nil - @rendered_content = - if Rails.version.to_f >= 6.1 - vc_test_controller.view_context.render(component, args, &block) - - # :nocov: - else - vc_test_controller.view_context.render_component(component, &block) - end - - # :nocov: + @rendered_content = vc_test_controller.view_context.render(component, args, &block) Nokogiri::HTML.fragment(@rendered_content) end diff --git a/test/sandbox/app/components/container_component.rb b/test/sandbox/app/components/container_component.rb index 471502918..f06f9428d 100644 --- a/test/sandbox/app/components/container_component.rb +++ b/test/sandbox/app/components/container_component.rb @@ -2,10 +2,6 @@ class ContainerComponent < ViewComponent::Base def call - if Rails.application.config.view_component.render_monkey_patch_enabled || Rails.version.to_f >= 6.1 - render HelpersProxyComponent.new - else - render_component HelpersProxyComponent.new - end + render HelpersProxyComponent.new end end diff --git a/test/sandbox/app/components/monkey_patch_disabled_component.html.erb b/test/sandbox/app/components/monkey_patch_disabled_component.html.erb deleted file mode 100644 index d2d68fe70..000000000 --- a/test/sandbox/app/components/monkey_patch_disabled_component.html.erb +++ /dev/null @@ -1 +0,0 @@ -