lib/jabber_admin.rb in jabber_admin-0.1.4 vs lib/jabber_admin.rb in jabber_admin-0.2.0

- old
+ new

@@ -1,61 +1,127 @@ # frozen_string_literal: true -require "active_support/inflector" -require "rest-client" +require 'active_support/inflector' +require 'json' +require 'pathname' +require 'rest-client' -require "jabber_admin/initializer" -require "jabber_admin/configuration" -require "jabber_admin/commands" -require "jabber_admin/api_call" -require "jabber_admin/version" +require 'jabber_admin/exceptions' +require 'jabber_admin/configuration' +require 'jabber_admin/commands' +require 'jabber_admin/api_call' +require 'jabber_admin/version' -## -# Jabber Admin Library +# jabber_admin # -# allows making API calls to the ejabberd RESTful admin backend -# All supported commands are available in /lib/jabber_admin/commands/ +# This gem allows making API calls to the ejabberd RESTful admin backend. We +# support a bunch of predefined commands out of the box, just have a look at +# the +lib/jabber_admin/commands/+ directory or the readme file. # -# Usage: -# All commands can be called via JabberAdmin.[method_name]! -# (Do not forget the bang at the end) +# All predefined commands can be called via +JabberAdmin.COMMAND!+ or via +# +JabberAdmin.COMMAND+. The bang variant checks the result of the command +# (successful, or not) and raise a subclass of +JabberAdmin::Exception+ in case +# of issues. The non-bang variant just sends the commands in a fire and forget +# manner. # -# @example: -# JabberAdmin.register!(user: 'peter', 'host': 'example.com', password: '123') -# JabberAdmin.unregister!(user: 'peter', 'host': 'example.com') +# When you're missing a command you want to use, you can use the +# +JabberAdmin::ApiCall+ class directly. It allows you to easily fulfill your +# custom needs with the power of error handling (if you like). +# +# You can also use your custom command directly on the +JabberAdmin+ module, in +# both banged and non-banged versions and we pass them as a shortcut to a new +# +JabberAdmin::ApiCall+ instance. +# +# @example Configure jabber_admin gem +# JabberAdmin.configure do |config| +# # The ejabberd REST API endpoint as a full URL. +# # Take care of the path part, because this is individually +# # configured on ejabberd. (See: https://bit.ly/2rBxatJ) +# config.url = 'http://jabber.local/api' +# # Provide here the full user JID in order to authenticate as +# # a administrator. +# config.username = 'admin@jabber.local' +# # The password of the administrator account. +# config.password = 'password' +# end +# +# @example Restart the ejabberd service # JabberAdmin.restart! # +# @example Register a new user to the XMPP service +# JabberAdmin.register! user: 'peter@example.com', password: '123' +# +# @example Delete a user from the XMPP service, in fire and forget manner +# JabberAdmin.unregister user: 'peter@example.com' module JabberAdmin class << self attr_writer :configuration end - # @return [JabberAdmin::Configuration] The global JabberAdmin configuration + # A simple getter to the global JabberAdmin configuration structure. + # + # @return [JabberAdmin::Configuration] the global JabberAdmin configuration def self.configuration - @configuration ||= JabberAdmin::Configuration.new + @configuration ||= Configuration.new end - # Class method to set and change the global configuration + # Class method to set and change the global configuration. This is just a + # tapped variant of the +.configuration+ method. # - # @example - # JabberAdmin.configure do |config| - # config.api_host = 'xmpp.example.com' - # config.admin = 'admin' - # config.password = 'password' - # end + # @yield [configuration] + # @yieldparam [JabberAdmin::Configuration] configuration def self.configure yield(configuration) end - def self.method_missing(method, *args, &block) - command = "jabber_admin/commands/#{method[0..-2]}".classify.constantize - args.empty? ? command.call : command.call(*args) + # 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 all additional payload to pass down to the API call + # @return [RestClient::Response] the actual response of the command + # + # rubocop:disable Style/MethodMissing we support all given methods + def self.method_missing(method, *args) + predefined_command(method).call(predefined_callable(method), *args) rescue NameError - super + predefined_callable(method).call(method.to_s.chomp('!'), *args) end + # rubocop:enable Style/MethodMissing - def self.respond_to_missing?(method, include_private = false) - "jabber_admin/commands/#{method[0..-2]}".classify.constantize && true - rescue NameError - super + # 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 + + # 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 { |*args| ApiCall.send(method, *args) } + 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 self.respond_to_missing?(_method, _include_private = false) + true end end