simple_command_dispatcher 3.0.4 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile CHANGED
@@ -2,19 +2,11 @@
2
2
 
3
3
  require 'bundler/gem_tasks'
4
4
  require 'rspec/core/rake_task'
5
- require 'yard'
6
5
 
7
6
  # Rspec
8
7
  RSpec::Core::RakeTask.new(:spec)
9
8
  #task default: :spec
10
9
 
11
- # Yard
12
- YARD::Rake::YardocTask.new do |t|
13
- t.files = ['lib/**/*.rb']
14
- t.options = ['--no-cache', '--protected', '--private']
15
- t.stats_options = ['--list-undoc']
16
- end
17
-
18
10
  # Load our custom rake tasks.
19
11
  Gem.find_files('tasks/**/*.rake').each { |path| import path }
20
12
 
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kernel
4
+ # Returns the eigenclass (singleton class) of the current object.
5
+ # This allows classes to reference their own class-level methods and variables.
6
+ #
7
+ # @return [Class] the eigenclass of the current object
8
+ #
9
+ # @example
10
+ # class MyClass
11
+ # def self.test
12
+ # eigenclass
13
+ # end
14
+ # end
15
+ # MyClass.test # => #<Class:MyClass>
16
+ #
17
+ def eigenclass
18
+ class << self
19
+ self
20
+ end
21
+ end
22
+ end
@@ -1,44 +1,46 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module SimpleCommand
4
- module Dispatcher
5
- # Gem configuration settings class. Use this class to configure this gem.
3
+ # This is the configuration for SimpleCommandDispatcher.
4
+ module SimpleCommandDispatcher
5
+ class << self
6
+ attr_reader :configuration
7
+
8
+ # Configures SimpleCommandDispatcher by yielding the configuration object to the block.
6
9
  #
7
- # To configure this gem in your application, simply add the following code in your application and set the
8
- # appropriate configuration settings.
10
+ # @yield [Configuration] yields the configuration object to the block
11
+ # @return [Configuration] returns the configuration object
9
12
  #
10
13
  # @example
11
14
  #
12
- # SimpleCommand::Dispatcher.configure do |config|
13
- # config.allow_custom_commands = true
14
- # end
15
- #
16
- class Configuration
17
- # Gets/sets the *allow_custom_commands* configuration setting (defaults to false).
18
- # If this setting is set to *false*, only command classes that prepend the *SimpleCommand* module
19
- # will be considered acceptable to run, all other command classes will fail to run. If this
20
- # setting is set to *true*, any command class will be considered acceptable to run, regardless of
21
- # whether or not the class prepends the *SimpleCommand* module.
22
- #
23
- # For information about the simple_command gem, visit {https://rubygems.org/gems/simple_command}
24
- #
25
- # @return [Boolean] the value.
26
- #
27
- attr_accessor :allow_custom_commands
28
-
29
- def initialize
30
- # The default is to use any command that exposes a ::call class method.
31
- reset
32
- end
33
-
34
- # Resets the configuration to use the default values.
35
- #
36
- # @return [nil] returns nil.
37
- #
38
- def reset
39
- @allow_custom_commands = false
40
- nil
41
- end
15
+ # SimpleCommandDispatcher.configure do |config|
16
+ # config.some_option = 'some value'
17
+ # end
18
+ def configure
19
+ self.configuration ||= Configuration.new
20
+
21
+ yield(configuration) if block_given?
22
+
23
+ configuration
24
+ end
25
+
26
+ private
27
+
28
+ attr_writer :configuration
29
+ end
30
+
31
+ # This class encapsulates the configuration properties for this gem and
32
+ # provides methods and attributes that allow for management of the same.
33
+ class Configuration
34
+ # TODO: Add attr_xxx here
35
+
36
+ # Initializes a new Configuration instance with default values
37
+ def initialize
38
+ reset
39
+ end
40
+
41
+ # Resets all configuration attributes to their default values
42
+ def reset
43
+ # TODO: Reset our attributes here e.g. @attr = nil
42
44
  end
43
45
  end
44
46
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleCommandDispatcher
4
+ module Errors
5
+ # This error is raised when a command class constant is not found or invalid.
6
+ class InvalidClassConstantError < StandardError
7
+ # Initializes a new InvalidClassConstantError
8
+ #
9
+ # @param constantized_class_string [String] the class string that failed to constantize
10
+ # @param error_message [String] the underlying error message
11
+ def initialize(constantized_class_string, error_message)
12
+ super("\"#{constantized_class_string}\" is not a valid class constant. Error message: \"#{error_message}\".")
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleCommandDispatcher
4
+ module Errors
5
+ # This error is raised when a required class method is missing on the command class.
6
+ class RequiredClassMethodMissingError < StandardError
7
+ # Initializes a new RequiredClassMethodMissingError
8
+ #
9
+ # @param command_class_constant [Class] the command class that is missing the required method
10
+ def initialize(command_class_constant)
11
+ super("Class \"#{command_class_constant}\" does not respond_to? class method \"call\".")
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'errors/invalid_class_constant_error'
4
+ require_relative 'errors/required_class_method_missing_error'
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'trim_all'
4
+
5
+ module SimpleCommandDispatcher
6
+ module Helpers
7
+ module Camelize
8
+ include TrimAll
9
+
10
+ # Transforms a RESTful route into a Ruby constant string for instantiation
11
+ #
12
+ # @param token [String] the route path to be camelized
13
+ # @return [String] the camelized constant name
14
+ #
15
+ # @example
16
+ #
17
+ # camelize("/api/users/v1") # => "Api::Users::V1"
18
+ # # Then: Api::Users::V1.new.call
19
+ #
20
+ def camelize(token)
21
+ raise ArgumentError, 'Token is not a String' unless token.instance_of? String
22
+
23
+ return if token.empty?
24
+
25
+ # For RESTful paths → Ruby constants, use Rails' proven methods
26
+ # They're fast, reliable, and handle edge cases that matter for constants
27
+ result = trim_all(token)
28
+ .gsub(%r{[/\-\.\s:]+}, '/') # Normalize separators to /
29
+ .split('/') # Split into path segments
30
+ .reject(&:empty?) # Remove empty segments
31
+ .map { |segment| segment.underscore.camelize } # Rails camelization
32
+ .join('::') # Join as Ruby namespace
33
+
34
+ result.empty? ? '' : result
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ # Usage example:
41
+ # "/api/user_sessions/v1" → "Api::UserSessions::V1"
42
+ #
43
+ # Then in your dispatcher:
44
+ # constant_name = camelize(request.path)
45
+ # command_class = Object.const_get(constant_name)
46
+ # command_class.new.call
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleCommandDispatcher
4
+ module Helpers
5
+ module TrimAll
6
+ # Removes all whitespace from the given string, including Unicode whitespace
7
+ #
8
+ # @param string [String] the string to remove whitespace from
9
+ # @return [String] the string with all whitespace removed
10
+ def trim_all(string)
11
+ # Using Unicode property \p{Space} to match all Unicode whitespace characters
12
+ string.gsub(/\p{Space}+/, '')
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../helpers/camelize'
4
+ require_relative '../helpers/trim_all'
5
+
6
+ module SimpleCommandDispatcher
7
+ module Services
8
+ # Returns a string of modules that can be subsequently prepended to a class, to create a fully qualified,
9
+ # constantized class.
10
+ #
11
+ # The command_namespace is provided during initialization and can be a Hash, Array, or String.
12
+ #
13
+ # @return [String] a string of modules that can be subsequently prepended to a class, to create a
14
+ # constantized class.
15
+ #
16
+ # @raise [ArgumentError] if the command_namespace is not of type String, Hash or Array.
17
+ #
18
+ # @example
19
+ #
20
+ # to_class_modules_string("Api") # => "Api::"
21
+ # to_class_modules_string([:Api, :AppName, :V1]) # => "Api::AppName::V1::"
22
+ # to_class_modules_string({ api: :Api, app_name: :AppName, api_version: :V1 }) # => "Api::AppName::V1::"
23
+ # to_class_modules_string({ api: :api, app_name: :app_name, api_version: :v1 }, { titleize_module: true })
24
+ # # => "Api::AppName::V1::"
25
+ #
26
+ class CommandNamespaceService
27
+ include Helpers::Camelize
28
+ include Helpers::TrimAll
29
+
30
+ def initialize(command_namespace:)
31
+ @command_namespace = command_namespace
32
+ end
33
+
34
+ # Handles command module transformations from String, Hash or Array into
35
+ # a fully qualified class modules string (e.g. "A::B::C::").
36
+ def to_class_modules_string
37
+ return '' if command_namespace.blank?
38
+
39
+ class_modules_string = join_class_modules_if(command_namespace:)
40
+ class_modules_string = trim_all(camelize(class_modules_string))
41
+ "#{class_modules_string}::"
42
+ end
43
+
44
+ private
45
+
46
+ attr_reader :command_namespace
47
+
48
+ def join_class_modules_if(command_namespace:)
49
+ case command_namespace
50
+ when String
51
+ command_namespace
52
+ when Array
53
+ command_namespace.join('::')
54
+ when Hash
55
+ command_namespace.values.join('::')
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../errors'
4
+ require_relative '../helpers/camelize'
5
+ require_relative 'command_namespace_service'
6
+
7
+ module SimpleCommandDispatcher
8
+ module Services
9
+ # Handles class and module transformations and instantiation.
10
+ class CommandService
11
+ include Helpers::Camelize
12
+
13
+ def initialize(command:, command_namespace: {})
14
+ @command = validate_command(command:)
15
+ @command_namespace = validate_command_namespace(command_namespace:)
16
+ end
17
+
18
+ # Returns a constantized class (as a Class constant), given the command and command_namespace
19
+ # that were provided during initialization.
20
+ #
21
+ # @return [Class] the class constant.
22
+ #
23
+ # @raise [Errors::InvalidClassConstantError] if the constantized class string cannot be constantized; that is,
24
+ # if it is not a valid class constant.
25
+ #
26
+ # @example
27
+ #
28
+ # to_class("Authenticate", "Api") # => Api::Authenticate
29
+ # to_class(:Authenticate, [:Api, :AppName, :V1]) # => Api::AppName::V1::Authenticate
30
+ # to_class(:Authenticate, { :api :Api, app_name: :AppName, api_version: :V2 })
31
+ # # => Api::AppName::V2::Authenticate
32
+ # to_class("authenticate", { :api :api, app_name: :app_name, api_version: :v1 },
33
+ # { titleize_class: true, titleize_module: true }) # => Api::AppName::V1::Authenticate
34
+ #
35
+ def to_class
36
+ qualified_class_string = to_qualified_class_string(command, command_namespace)
37
+
38
+ begin
39
+ qualified_class_string.constantize
40
+ rescue StandardError => e
41
+ raise Errors::InvalidClassConstantError.new(qualified_class_string, e.message)
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ attr_accessor :command, :command_namespace
48
+
49
+ # Returns a fully-qualified constantized class (as a string), given the command and command_namespace.
50
+ # Both parameters are automatically camelized/titleized during processing.
51
+ #
52
+ # @param command [Symbol, String] the class name.
53
+ # @param command_namespace [Hash, Array, String] the modules command belongs to.
54
+ #
55
+ # @return [String] the fully qualified class, which includes module(s) and class name.
56
+ #
57
+ # @example
58
+ #
59
+ # to_qualified_class_string("authenticate", "api") # => "Api::Authenticate"
60
+ # to_qualified_class_string(:Authenticate, [:Api, :AppName, :V1]) # => "Api::AppName::V1::Authenticate"
61
+ # to_qualified_class_string(:authenticate, { api: :api, app_name: :app_name, api_version: :v1 })
62
+ # # => "Api::AppName::V1::Authenticate"
63
+ #
64
+ def to_qualified_class_string(command, command_namespace)
65
+ class_modules_string = CommandNamespaceService.new(command_namespace:).to_class_modules_string
66
+ class_string = to_class_string(command:)
67
+ "#{class_modules_string}#{class_string}"
68
+ end
69
+
70
+ # Returns the command as a string after transformations have been applied.
71
+ # The command is automatically camelized/titleized during processing.
72
+ #
73
+ # @param command [Symbol, String] the class name to be transformed.
74
+ #
75
+ # @return [String] the transformed class as a string.
76
+ #
77
+ # @example
78
+ #
79
+ # to_class_string(command: "MyClass") # => "MyClass"
80
+ # to_class_string(command: "my_class") # => "MyClass"
81
+ # to_class_string(command: :MyClass) # => "MyClass"
82
+ # to_class_string(command: :my_class) # => "MyClass"
83
+ #
84
+ def to_class_string(command:)
85
+ camelize(command)
86
+ end
87
+
88
+ # @!visibility public
89
+ #
90
+ # Validates command and returns command as a string after all blanks have been removed using
91
+ # command.gsub(/\s+/, "").
92
+ #
93
+ # @param [Symbol or String] command the class name to be validated. command cannot be empty?
94
+ #
95
+ # @return [String] the validated class as a string with blanks removed.
96
+ #
97
+ # @raise [ArgumentError] if the command is empty? or not of type String or Symbol.
98
+ #
99
+ # @example
100
+ #
101
+ # validate_command(" My Class ") # => "MyClass"
102
+ # validate_command(:MyClass) # => "MyClass"
103
+ #
104
+ def validate_command(command:)
105
+ unless command.is_a?(Symbol) || command.is_a?(String)
106
+ raise ArgumentError,
107
+ 'command is not a String or Symbol. command must equal the class name of the ' \
108
+ 'command to call in the form of a String or Symbol.'
109
+ end
110
+
111
+ command = command.to_s.strip
112
+
113
+ raise ArgumentError, 'command is empty?' if command.empty?
114
+
115
+ command
116
+ end
117
+
118
+ # @!visibility public
119
+ #
120
+ # Validates and returns command_namespace.
121
+ #
122
+ # @param [Hash, Array or String] command_namespace the module(s) to be validated.
123
+ #
124
+ # @return [Hash, Array or String] the validated module(s).
125
+ #
126
+ # @raise [ArgumentError] if the command_namespace is not of type String, Hash or Array.
127
+ #
128
+ # @example
129
+ #
130
+ # validate_command_namespace(" Module ") # => " Module "
131
+ # validate_command_namespace(:Module) # => :Module
132
+ # validate_command_namespace("ModuleA::ModuleB") # => "ModuleA::ModuleB"
133
+ #
134
+ def validate_command_namespace(command_namespace:)
135
+ return {} if command_namespace.blank?
136
+
137
+ unless valid_command_namespace_type?(command_namespace:)
138
+ raise ArgumentError,
139
+ 'Argument command_namespace is not a String, Hash or Array.'
140
+ end
141
+
142
+ command_namespace
143
+ end
144
+
145
+ def valid_command_namespace_type?(command_namespace:)
146
+ command_namespace.instance_of?(String) ||
147
+ command_namespace.instance_of?(Hash) ||
148
+ command_namespace.instance_of?(Array)
149
+ end
150
+ end
151
+ end
152
+ end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module SimpleCommand
4
- module Dispatcher
5
- VERSION = '3.0.4'
6
- end
3
+ module SimpleCommandDispatcher
4
+ VERSION = '4.0.0'
7
5
  end
@@ -1,135 +1,83 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'simple_command_dispatcher/version'
4
- require 'simple_command_dispatcher/klass_transform'
5
- require 'simple_command'
3
+ require 'active_support/core_ext/object/blank'
6
4
  require 'active_support/core_ext/string/inflections'
7
- require 'simple_command_dispatcher/configure'
8
-
9
- module Kernel
10
- def eigenclass
11
- class << self
12
- self
13
- end
14
- end
15
- end
5
+ require 'core_ext/kernel'
6
+ require 'simple_command_dispatcher/configuration'
7
+ require 'simple_command_dispatcher/errors'
8
+ require 'simple_command_dispatcher/services/command_service'
9
+ require 'simple_command_dispatcher/version'
16
10
 
17
- module SimpleCommand
18
- # Provides a way to call SimpleCommands or your own custom commands in a more dymanic manner.
19
- #
20
- # For information about the simple_command gem, visit {https://rubygems.org/gems/simple_command}
11
+ module SimpleCommandDispatcher
12
+ # Provides a way to call your custom commands dynamically.
21
13
  #
22
- module Dispatcher
23
- class << self
24
- include SimpleCommand::KlassTransform
14
+ class << self
15
+ # Calls a *Command* given the command name, the namespace (modules) the command belongs to
16
+ # and the (request) parameters to pass to the command.
17
+ #
18
+ # @param command [Symbol, String] the name of the Command to call.
19
+ #
20
+ # @param command_namespace [Hash, Array] the ruby modules that qualify the Command to call.
21
+ # When passing a Hash, the Hash keys serve as documentation only.
22
+ # For example, ['Api', 'AppName', 'V1'] and { :api :Api, app_name: :AppName, api_version: :V1 }
23
+ # will both produce 'Api::AppName::V1', this string will be prepended to the command to form the Command
24
+ # to call (e.g. 'Api::AppName::V1::MySimpleCommand' = Api::AppName::V1::MySimpleCommand.call(*request_params)).
25
+ #
26
+ # @param request_params [Hash, Array, Object] the parameters to pass to the call method of the Command. This
27
+ # parameter is simply passed through to the call method of the Command. Hash parameters are passed as
28
+ # keyword arguments, Array parameters are passed as positional arguments, and other objects are passed
29
+ # as a single argument.
30
+ #
31
+ # @return [Object] the Object returned as a result of calling the Command#call method.
32
+ #
33
+ # @example
34
+ #
35
+ # # Below call equates to the following:
36
+ # # Api::Carz4Rent::V1::Authenticate.call({ email: 'sam@gmail.com', password: 'AskM3!' })
37
+ # SimpleCommandDispatcher.call(command: :Authenticate,
38
+ # command_namespace: { api: :Api, app_name: :Carz4Rent, api_version: :V1 },
39
+ # request_params: { email: 'sam@gmail.com', password: 'AskM3!' } ) # => Command result
40
+ #
41
+ # # Below equates to the following: Api::Carz4Rent::V2::Authenticate.call('sam@gmail.com', 'AskM3!')
42
+ # SimpleCommandDispatcher.call(command: :Authenticate,
43
+ # command_namespace: ['Api', 'Carz4Rent', 'V2'],
44
+ # request_params: ['sam@gmail.com', 'AskM3!']) # => Command result
45
+ #
46
+ # # Below equates to the following:
47
+ # # Api::Auth::JazzMeUp::V1::Authenticate.call('jazz_me@gmail.com', 'JazzM3!')
48
+ # SimpleCommandDispatcher.call(command: :Authenticate,
49
+ # command_namespace: ['Api::Auth::JazzMeUp', :V1],
50
+ # request_params: ['jazz_me@gmail.com', 'JazzM3!']) # => Command result
51
+ #
52
+ def call(command:, command_namespace: {}, request_params: nil)
53
+ # Create a constantized class from our command and command_namespace...
54
+ constantized_class_object = Services::CommandService.new(command:, command_namespace:).to_class
55
+ validate_command!(constantized_class_object)
25
56
 
26
- # Calls a *SimpleCommand* or *Command* given the command name, the modules the command belongs to
27
- # and the parameters to pass to the command.
28
- #
29
- # @param command [Symbol, String] the name of the SimpleCommand or Command to call.
30
- #
31
- # @param command_modules [Hash, Array] the ruby modules that qualify the SimpleCommand to call. When
32
- # passing a Hash, the Hash keys serve as documentation only. For example, ['Api', 'AppName', 'V1']
33
- # and { :api :Api, app_name: :AppName, api_version: :V1 } will both produce 'Api::AppName::V1',
34
- # this string will be prepended to the command to form the SimpleCommand to call
35
- # (e.g. 'Api::AppName::V1::MySimpleCommand' = Api::AppName::V1::MySimpleCommand.call(*command_parameters)).
36
- #
37
- # @param [Hash] options the options that determine how command and command_module are transformed.
38
- # @option options [Boolean] :camelize (false) determines whether or not both class and module names should be
39
- # camelized.
40
- # @option options [Boolean] :titleize (false) determines whether or not both class and module names should be
41
- # titleized.
42
- # @option options [Boolean] :class_titleize (false) determines whether or not class names should be titleized.
43
- # @option options [Boolean] :class_camelized (false) determines whether or not class names should be camelized.
44
- # @option options [Boolean] :module_titleize (false) determines whether or not module names should be titleized.
45
- # @option options [Boolean] :module_camelized (false) determines whether or not module names should be camelized.
46
- #
47
- # @param command_parameters [Array<Symbol>] the parameters to pass to the call method of the SimpleCommand.
48
- # This parameter is simplypassed through to the call method of the SimpleCommand/Command.
49
- #
50
- # @return [SimpleCommand, Object] the SimpleCommand or Object returned as a result of calling the
51
- # SimpleCommand#call method or the Command#call method respectfully.
52
- #
53
- # @example
54
- #
55
- # # Below call equates to the following:
56
- # # Api::Carz4Rent::V1::Authenticate.call({ email: 'sam@gmail.com', password: 'AskM3!' })
57
- # SimpleCommand::Dispatcher.call(:Authenticate,
58
- # { api: :Api, app_name: :Carz4Rent, api_version: :V1 },
59
- # { email: 'sam@gmail.com', password: 'AskM3!' } ) # => SimpleCommand result
60
- #
61
- # # Below equates to the following: Api::Carz4Rent::V2::Authenticate.call('sam@gmail.com', 'AskM3!')
62
- # SimpleCommand::Dispatcher.call(:Authenticate,
63
- # ['Api', 'Carz4Rent', 'V2'], 'sam@gmail.com', 'AskM3!') # => SimpleCommand result
64
- #
65
- # # Below equates to the following:
66
- # # Api::Auth::JazzMeUp::V1::Authenticate.call('jazz_me@gmail.com', 'JazzM3!')
67
- # SimpleCommand::Dispatcher.call(:Authenticate, ['Api::Auth::JazzMeUp', :V1],
68
- # 'jazz_me@gmail.com', 'JazzM3!') # => SimpleCommand result
69
- #
70
- def call(command = '', command_modules = {}, options = {}, *command_parameters)
71
- # Create a constantized class from our command and command_modules...
72
- command_class_constant = to_constantized_class(command, command_modules, options)
57
+ # We know we have a valid command class object if we get here. All we need to do is call the .call
58
+ # class method, pass the request_params arguments depending on the request_params data type, and
59
+ # return the results.
73
60
 
74
- # If we're NOT allowing custom commands, make sure we're dealing with a a command class
75
- # that prepends the SimpleCommand module.
76
- if !SimpleCommand::Dispatcher.configuration.allow_custom_commands && !simple_command?(command_class_constant)
77
- raise ArgumentError,
78
- "Class \"#{command_class_constant}\" " \
79
- 'must prepend module SimpleCommand if Configuration#allow_custom_commands is true.'
80
- end
81
-
82
- if valid_command?(command_class_constant)
83
- # We know we have a valid SimpleCommand; all we need to do is call #call,
84
- # pass the command_parameter variable arguments to the call, and return the results.
85
- run_command(command_class_constant, command_parameters)
86
- else
87
- raise NameError, "Class \"#{command_class_constant}\" does not respond_to? method ::call."
88
- end
89
- end
90
-
91
- private
61
+ call_command(constantized_class_object:, request_params:)
62
+ end
92
63
 
93
- # Returns true or false depending on whether or not the class constant has a public
94
- # class method named ::call defined. Commands that do not have a public class method
95
- # named ::call, are considered invalid.
96
- #
97
- # @param klass_constant [String] a class constant that will be validated to see whether or not the
98
- # class is a valid command.
99
- #
100
- # @return [Boolean] true if klass_constant has a public class method named ::call defined,
101
- # false otherwise.
102
- #
103
- # @!visibility public
104
- def valid_command?(klass_constant)
105
- klass_constant.eigenclass.public_method_defined?(:call)
106
- end
64
+ private
107
65
 
108
- # Returns true or false depending on whether or not the class constant prepends module
109
- # SimpleCommand::ClassMethods.
110
- #
111
- # @param klass_constant [String] a class constant that will be validated to see whether
112
- # or not the class prepends module SimpleCommand::ClassMethods.
113
- #
114
- # @return [Boolean] true if klass_constant prepends Module SimpleCommand::ClassMethods, false otherwise.
115
- #
116
- # @!visibility public
117
- def simple_command?(klass_constant)
118
- klass_constant.eigenclass.included_modules.include? SimpleCommand::ClassMethods
66
+ def call_command(constantized_class_object:, request_params:)
67
+ if request_params.is_a?(Hash)
68
+ constantized_class_object.call(**request_params)
69
+ elsif request_params.is_a?(Array)
70
+ constantized_class_object.call(*request_params)
71
+ elsif request_params.present?
72
+ constantized_class_object.call(request_params)
73
+ else
74
+ constantized_class_object.call
119
75
  end
76
+ end
120
77
 
121
- # Runs the command given the parameters and returns the result.
122
- #
123
- # @param klass_constant [String] a class constant that will be called.
124
- # @param parameters [Array] an array of parameters to pass to the command that will be called.
125
- #
126
- # @return [Object] returns the object (if any) that results from calling the command.
127
- #
128
- # @!visibility public
129
- def run_command(klass_constant, parameters)
130
- klass_constant.call(*parameters)
131
- # rescue NameError
132
- # raise NameError.new("Class \"#{klass_constant}\" does not respond_to? method ::call.")
78
+ def validate_command!(constantized_class_object)
79
+ unless constantized_class_object.eigenclass.public_method_defined?(:call)
80
+ raise Errors::RequiredClassMethodMissingError, constantized_class_object
133
81
  end
134
82
  end
135
83
  end