From 4275d17b91ccebd8c210383c738176efded366f5 Mon Sep 17 00:00:00 2001 From: Hermann Mayer Date: Sun, 12 Jan 2025 09:12:43 +0100 Subject: [PATCH] Switched to Zeitwerk as autoloader. Signed-off-by: Hermann Mayer --- CHANGELOG.md | 2 +- jabber_admin.gemspec | 1 + lib/jabber_admin.rb | 187 ++++++++++-------- lib/jabber_admin/commands.rb | 11 -- lib/jabber_admin/{exceptions.rb => errors.rb} | 0 5 files changed, 103 insertions(+), 98 deletions(-) delete mode 100644 lib/jabber_admin/commands.rb rename lib/jabber_admin/{exceptions.rb => errors.rb} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a32788..50fded7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ### next -* TODO: Replace this bullet point with an actual description of a change. +* Switched to Zeitwerk as autoloader (#16) ### 1.4.0 (3 January 2025) diff --git a/jabber_admin.gemspec b/jabber_admin.gemspec index b81b587..556d1ca 100644 --- a/jabber_admin.gemspec +++ b/jabber_admin.gemspec @@ -35,4 +35,5 @@ Gem::Specification.new do |spec| spec.add_dependency 'activesupport', '>= 6.1' spec.add_dependency 'rest-client', '~> 2.1' + spec.add_dependency 'zeitwerk', '~> 2.6' end diff --git a/lib/jabber_admin.rb b/lib/jabber_admin.rb index ce52ca3..f092579 100644 --- a/lib/jabber_admin.rb +++ b/lib/jabber_admin.rb @@ -1,16 +1,11 @@ # frozen_string_literal: true +require 'zeitwerk' require 'active_support/inflector' require 'json' require 'pathname' require 'rest-client' -require 'jabber_admin/exceptions' -require 'jabber_admin/configuration' -require 'jabber_admin/commands' -require 'jabber_admin/api_call' -require 'jabber_admin/version' - # jabber_admin # # This gem allows making API calls to the ejabberd RESTful admin backend. We @@ -53,96 +48,116 @@ # @example Delete a user from the XMPP service, in fire and forget manner # JabberAdmin.unregister user: 'peter@example.com' module JabberAdmin + # Configure the relative gem code base location + root_path = Pathname.new("#{__dir__}/jabber_admin") + + # Setup a Zeitwerk autoloader instance and configure it + loader = Zeitwerk::Loader.for_gem + + # Do not auto load some parts of the gem + loader.ignore(root_path.join('errors.rb')) + + # Finish the auto loader configuration + loader.setup + + # Load standalone code + require 'jabber_admin/version' + require 'jabber_admin/errors' + + # Make sure to eager load all SDK constants + loader.eager_load + class << self attr_writer :configuration - end - # A simple getter to the global JabberAdmin configuration structure. - # - # @return [JabberAdmin::Configuration] the global JabberAdmin configuration - def self.configuration - @configuration ||= Configuration.new - end + # A simple getter to the global JabberAdmin configuration structure. + # + # @return [JabberAdmin::Configuration] the global JabberAdmin configuration + def configuration + @configuration ||= Configuration.new + end - # Class method to set and change the global configuration. This is just a - # tapped variant of the +.configuration+ method. - # - # @yield [configuration] - # @yieldparam [JabberAdmin::Configuration] configuration - def self.configure - yield(configuration) - end + # Class method to set and change the global configuration. This is just a + # tapped variant of the +.configuration+ method. + # + # @yield [configuration] + # @yieldparam [JabberAdmin::Configuration] configuration + def configure + yield(configuration) + end - # Allow an easy to use DSL on the +JabberAdmin+ module. We support predefined - # (known) commands and unknown ones in bang and non-bang variants. This - # allows maximum flexibility to the user. The bang versions perform the - # response checks and raise in case of issues. The non-bang versions skip - # this checks. For unknown commands the +JabberAdmin::ApiCall+ is directly - # utilized with the method name as command. (Without the trailling bang, when - # it is present) - # - # @param method [Symbol, String, #to_s] the name of the command to run - # @param args [Array] all additional API call payload - # @param kwargs [Hash{Symbol => Mixed}] all additional API call payload - # @return [RestClient::Response] the actual response of the command - def self.method_missing(method, *args, **kwargs) - predefined_command(method).call( - predefined_callable(method), *args, **kwargs - ) - rescue NameError - predefined_callable(method).call(method.to_s.chomp('!'), *args, **kwargs) - end + # Allow an easy to use DSL on the +JabberAdmin+ module. We support + # predefined (known) commands and unknown ones in bang and non-bang + # variants. This allows maximum flexibility to the user. The bang versions + # perform the response checks and raise in case of issues. The non-bang + # versions skip this checks. For unknown commands the + # +JabberAdmin::ApiCall+ is directly utilized with the method name as + # command. (Without the trailling bang, when it is present) + # + # @param method [Symbol, String, #to_s] the name of the command to run + # @param args [Array] all additional API call payload + # @param kwargs [Hash{Symbol => Mixed}] all additional API call payload + # @return [RestClient::Response] the actual response of the command + def method_missing(method, *args, **kwargs) + predefined_command(method).call( + predefined_callable(method), *args, **kwargs + ) + rescue NameError + predefined_callable(method).call(method.to_s.chomp('!'), *args, **kwargs) + end - # Try to find the given name as a predefined command. When there is no such - # predefined command, we raise a +NameError+. - # - # @param name [Symbol, String, #to_s] the command name to lookup - # @return [Class] the predefined command class constant - def self.predefined_command(name) - # Remove bangs and build the camel case variant - "JabberAdmin::Commands::#{name.to_s.chomp('!').camelize}".constantize - end + # Try to find the given name as a predefined command. When there is no such + # predefined command, we raise a +NameError+. + # + # @param name [Symbol, String, #to_s] the command name to lookup + # @return [Class] the predefined command class constant + def predefined_command(name) + # Remove bangs and build the camel case variant + "JabberAdmin::Commands::#{name.to_s.chomp('!').camelize}".constantize + end - # Generate a matching API call wrapper for the given command name. When we - # have to deal with a bang version, we pass the bang down to the API call - # instance. Otherwise we just run the regular +#perform+ method on the API - # call instance. - # - # @param name [Symbol, String, #to_s] the command name to match - # @return [Proc] the API call wrapper - def self.predefined_callable(name) - method = name.to_s.end_with?('!') ? 'perform!' : 'perform' - proc do |*args, **kwargs| - if kwargs.empty? - ApiCall.send(method, *args) - else - ApiCall.send(method, *args, **kwargs) + # Generate a matching API call wrapper for the given command name. When we + # have to deal with a bang version, we pass the bang down to the API call + # instance. Otherwise we just run the regular +#perform+ method on the API + # call instance. + # + # @param name [Symbol, String, #to_s] the command name to match + # @return [Proc] the API call wrapper + def predefined_callable(name) + method = name.to_s.end_with?('!') ? 'perform!' : 'perform' + proc do |*args, **kwargs| + if kwargs.empty? + ApiCall.send(method, *args) + else + ApiCall.send(method, *args, **kwargs) + end end end - end - # Determine if a room exists. This is a convenience method for the - # +JabberAdmin::Commands::GetRoomAffiliations+ command, which can be used - # to reliably determine whether a room exists or not. - # - # @param room [String] the name of the room to check - # @return [Boolean] whether the room exists or not - def self.room_exist?(room) - get_room_affiliations!(room: room) - true - rescue JabberAdmin::CommandError => e - raise e unless /room does not exist/.match? e.response.body - - false - end + # Determine if a room exists. This is a convenience method for the + # +JabberAdmin::Commands::GetRoomAffiliations+ command, which can be used + # to reliably determine whether a room exists or not. + # + # @param room [String] the name of the room to check + # @return [Boolean] whether the room exists or not + def room_exist?(room) + get_room_affiliations!(room: room) + true + rescue JabberAdmin::CommandError => e + raise e unless /room does not exist/.match? e.response.body - # We support all methods if you ask for. This is our dynamic command approach - # here to support predefined and custom commands in the same namespace. - # - # @param method [String] the method to lookup - # @param include_private [Boolean] allow the lookup of private methods - # @return [Boolean] always +true+ - def self.respond_to_missing?(_method, _include_private = false) - true + false + end + + # We support all methods if you ask for. This is our dynamic command + # approach here to support predefined and custom commands in the same + # namespace. + # + # @param method [String] the method to lookup + # @param include_private [Boolean] allow the lookup of private methods + # @return [Boolean] always +true+ + def respond_to_missing?(_method, _include_private = false) + true + end end end diff --git a/lib/jabber_admin/commands.rb b/lib/jabber_admin/commands.rb deleted file mode 100644 index 694d4c8..0000000 --- a/lib/jabber_admin/commands.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -module JabberAdmin - # Contains all predefined commands that are supported. - module Commands; end -end - -# Require all commands from the commands subfolder -Dir[Pathname.new(__dir__).join('commands', '**', '*.rb')].sort.each do |file| - require file -end diff --git a/lib/jabber_admin/exceptions.rb b/lib/jabber_admin/errors.rb similarity index 100% rename from lib/jabber_admin/exceptions.rb rename to lib/jabber_admin/errors.rb