lib/simple/service/action.rb in simple-service-0.1.4 vs lib/simple/service/action.rb in simple-service-0.1.5
- old
+ new
@@ -3,17 +3,15 @@
end
end
require_relative "./action/comment"
require_relative "./action/parameter"
-require_relative "./action/indie_hash"
module Simple::Service
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/PerceivedComplexity
# rubocop:disable Metrics/CyclomaticComplexity
- # rubocop:disable Style/GuardClause
# rubocop:disable Metrics/ClassLength
class Action
IDENTIFIER_PATTERN = "[a-z][a-z0-9_]*" # @private
IDENTIFIER_REGEXP = Regexp.compile("\\A#{IDENTIFIER_PATTERN}\\z") # @private
@@ -69,34 +67,15 @@
def source_location
@service.instance_method(name).source_location
end
- # build a service_instance and run the action, with arguments constructed from
- # args_hsh and params_hsh.
- def invoke(*args, **named_args)
- # convert Array arguments into a Hash of named arguments. This is strictly
- # necessary to be able to apply default value-based type conversions. (On
- # the downside this also means we convert an array to a hash and then back
- # into an array. This, however, should only be an issue for CLI based action
- # invocations, because any other use case (that I can think of) should allow
- # us to provide arguments as a Hash.
- args = convert_argument_array_to_hash(args)
- named_args = named_args.merge(args)
-
- invoke2(args: named_args, flags: {})
- end
-
# invokes an action with a given +name+ in a service with a Hash of arguments.
#
# You cannot call this method if the context is not set.
- def invoke2(args:, flags:)
- # args and flags are being stringified. This is necessary to not allow any
- # unchecked input to DOS this process by just providing always changing
- # key values.
- args = IndieHash.new(args)
- flags = IndieHash.new(flags)
+ def invoke(args:, flags:)
+ args = convert_argument_array_to_hash(args) if args.is_a?(Array)
verify_required_args!(args, flags)
positionals = build_positional_arguments(args, flags)
keywords = build_keyword_arguments(args.merge(flags))
@@ -143,11 +122,11 @@
@variadic_parameter = parameters.detect(&:variadic?)
end
def positional_names
- @positional_names ||= parameters.select(&:positional?).map(&:name)
+ @positional_names ||= parameters.select(&:positional?).map(&:name).map(&:to_s)
end
# Enumerating all parameters it collects all positional parameters into
# an Array.
def build_positional_arguments(args, flags)
@@ -175,28 +154,36 @@
end
def convert_argument_array_to_hash(ary)
expect! ary => Array
- hsh = {}
-
- if variadic_parameter
- hsh[variadic_parameter.name] = []
- end
-
- if ary.length > positional_names.length
+ # +ary* might contain more, less, or the exact number of positional
+ # arguments. If the number is less, we return a hash with only whart
+ # exists in ary - the action might define default values after all.
+ #
+ # If it contains more the action better supports a variadic parameter;
+ # we otherwise raise a ExtraArguments exception.
+ case ary.length <=> positional_names.length
+ when 1 # i.e. ary.length > positional_names.length
extra_arguments = ary[positional_names.length..-1]
+ ary = ary[0..positional_names.length]
- if variadic_parameter
- hsh[variadic_parameter.name] = extra_arguments
- else
+ if !extra_arguments.empty? && !variadic_parameter
raise ::Simple::Service::ExtraArguments.new(self, extra_arguments)
end
- end
- ary.zip(positional_names).each do |value, parameter_name|
- hsh[parameter_name] = value
+ existing_positional_names = positional_names
+ when 0 # i.e. ary.length == positional_names.length
+ existing_positional_names = positional_names
+ when -1 # i.e. ary.length < positional_names.length
+ existing_positional_names = positional_names[0, ary.length]
end
+
+ # Build a hash with the existing_positional_names and the values from the array.
+ hsh = Hash[existing_positional_names.zip(ary)]
+
+ # Add the variadic_parameter, if any.
+ hsh[variadic_parameter.name] = extra_arguments if variadic_parameter
hsh
end
end
end