From 017ac627eeab8fe155698dd2f99e1fb41cb0e537 Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 1 Oct 2024 17:18:05 +0200 Subject: [PATCH] Replace StrictHashConfiguration by Grape::Util::ApiDescription Add Grape::Util::ApiDescription Remove options from ApiDescription Remove const Update api_description.rb FIx rubocop Renamed `to_h` by `settings` --- CHANGELOG.md | 1 + lib/grape/dsl/desc.rb | 73 ++---------- lib/grape/util/api_description.rb | 56 +++++++++ lib/grape/util/strict_hash_configuration.rb | 108 ------------------ .../util/strict_hash_configuration_spec.rb | 34 ------ 5 files changed, 65 insertions(+), 207 deletions(-) create mode 100644 lib/grape/util/api_description.rb delete mode 100644 lib/grape/util/strict_hash_configuration.rb delete mode 100644 spec/grape/util/strict_hash_configuration_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index eb7c5f0d5..5c34e326f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * [#2572](https://github.com/ruby-grape/grape/pull/2572): Drop support ruby 2.7 and active_support 6.1 - [@ericproulx](https://github.com/ericproulx). * [#2573](https://github.com/ruby-grape/grape/pull/2573): Clean up deprecated code - [@ericproulx](https://github.com/ericproulx). +* [#2575](https://github.com/ruby-grape/grape/pull/2575): Refactor Api description class - [@ericproulx](https://github.com/ericproulx). * Your contribution here. #### Fixes diff --git a/lib/grape/dsl/desc.rb b/lib/grape/dsl/desc.rb index 954820bdd..127b70c9b 100644 --- a/lib/grape/dsl/desc.rb +++ b/lib/grape/dsl/desc.rb @@ -3,26 +3,7 @@ module Grape module DSL module Desc - ROUTE_ATTRIBUTES = %i[ - body_name - consumes - default - deprecated - description - detail - entity - headers - hidden - http_codes - is_array - named - nickname - params - produces - security - summary - tags - ].freeze + extend Grape::DSL::Settings # Add a description to the next namespace or function. # @param description [String] descriptive string for this endpoint @@ -68,54 +49,16 @@ module Desc # # ... # end # - def desc(description, options = nil, &config_block) - opts = + def desc(description, options = {}, &config_block) + settings = if config_block - desc_container(endpoint_configuration).then do |config_class| - config_class.configure do - description(description) - end - - config_class.configure(&config_block) - config_class.settings - end + endpoint_config = defined?(configuration) ? configuration : nil + Grape::Util::ApiDescription.new(description, endpoint_config, &config_block).settings else - options&.merge(description: description) || { description: description } - end - - namespace_setting :description, opts - route_setting :description, opts - end - - # Returns an object which configures itself via an instance-context DSL. - def desc_container(endpoint_configuration) - Module.new do - include Grape::Util::StrictHashConfiguration.module(*ROUTE_ATTRIBUTES) - config_context.define_singleton_method(:configuration) do - endpoint_configuration - end - - def config_context.success(*args) - entity(*args) + options.merge(description: description) end - - def config_context.failure(*args) - http_codes(*args) - end - end - end - - private - - def endpoint_configuration - return {} unless defined?(configuration) - - if configuration.respond_to?(:evaluate) - configuration.evaluate - # Within `given` or `mounted blocks` the configuration is already evaluated - elsif configuration.is_a?(Hash) - configuration - end + namespace_setting :description, settings + route_setting :description, settings end end end diff --git a/lib/grape/util/api_description.rb b/lib/grape/util/api_description.rb new file mode 100644 index 000000000..6246f67d1 --- /dev/null +++ b/lib/grape/util/api_description.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +module Grape + module Util + class ApiDescription + def initialize(description, endpoint_configuration, &block) + @endpoint_configuration = endpoint_configuration + @attributes = { description: description } + instance_eval(&block) + end + + %i[ + body_name + consumes + default + deprecated + detail + entity + headers + hidden + http_codes + is_array + named + nickname + params + produces + security + summary + tags + ].each do |attribute| + define_method attribute do |value| + @attributes[attribute] = value + end + end + + alias success entity + alias failure http_codes + + def configuration + @configuration ||= eval_endpoint_config(@endpoint_configuration) + end + + def settings + @attributes + end + + private + + def eval_endpoint_config(configuration) + return configuration if configuration.is_a?(Hash) + + configuration.evaluate + end + end + end +end diff --git a/lib/grape/util/strict_hash_configuration.rb b/lib/grape/util/strict_hash_configuration.rb deleted file mode 100644 index 4ac105856..000000000 --- a/lib/grape/util/strict_hash_configuration.rb +++ /dev/null @@ -1,108 +0,0 @@ -# frozen_string_literal: true - -module Grape - module Util - module StrictHashConfiguration - extend ActiveSupport::Concern - - module DSL - extend ActiveSupport::Concern - - module ClassMethods - def settings - config_context.to_hash - end - - def configure(&block) - config_context.instance_exec(&block) - end - end - end - - class SettingsContainer - def initialize - @settings = {} - @contexts = {} - end - - def to_hash - @settings.to_hash - end - end - - def self.config_class(*args) - new_config_class = Class.new(SettingsContainer) - - args.each do |setting_name| - if setting_name.respond_to? :values - nested_settings_methods(setting_name, new_config_class) - else - simple_settings_methods(setting_name, new_config_class) - end - end - - new_config_class - end - - def self.simple_settings_methods(setting_name, new_config_class) - setting_name_sym = setting_name.to_sym - new_config_class.class_eval do - define_method setting_name do |new_value| - @settings[setting_name_sym] = new_value - end - end - end - - def self.nested_settings_methods(setting_name, new_config_class) - new_config_class.class_eval do - setting_name.each_pair do |key, value| - define_method :"#{key}_context" do - @contexts[key] ||= Grape::Util::StrictHashConfiguration.config_class(*value).new - end - - define_method key do |&block| - send(:"#{key}_context").instance_exec(&block) - end - end - - define_method :to_hash do - @settings.to_hash.merge( - setting_name.each_key.with_object({}) do |k, merge_hash| - merge_hash[k] = send(:"#{k}_context").to_hash - end - ) - end - end - end - - def self.module(*args) - new_module = Module.new do - extend ActiveSupport::Concern - include DSL - end - - new_module.tap do |mod| - class_mod = create_class_mod(args) - - mod.const_set(:ClassMethods, class_mod) - end - end - - def self.create_class_mod(args) - new_module = Module.new do - def config_context - @config_context ||= config_class.new - end - end - - new_module.tap do |class_mod| - new_config_class = config_class(*args) - - class_mod.send(:define_method, :config_class) do - @config_class ||= new_config_class - end - end - end - end - end -end diff --git a/spec/grape/util/strict_hash_configuration_spec.rb b/spec/grape/util/strict_hash_configuration_spec.rb deleted file mode 100644 index 300986860..000000000 --- a/spec/grape/util/strict_hash_configuration_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -describe Grape::Util::StrictHashConfiguration do - subject do - Class.new do - include Grape::Util::StrictHashConfiguration.module(:config1, :config2, config3: [:config4], config5: [config6: %i[config7 config8]]) - end - end - - it 'set nested configs' do - subject.configure do - config1 'alpha' - config2 'beta' - - config3 do - config4 'gamma' - end - - local_var = 8 - - config5 do - config6 do - config7 7 - config8 local_var - end - end - end - - expect(subject.settings).to eq(config1: 'alpha', - config2: 'beta', - config3: { config4: 'gamma' }, - config5: { config6: { config7: 7, config8: 8 } }) - end -end