Module: Simple::Service
- Defined in:
- lib/simple/service.rb,
lib/simple/service.rb,
lib/simple/service/action.rb,
lib/simple/service/action.rb,
lib/simple/service/errors.rb,
lib/simple/service/version.rb
Overview
The Simple::Service interface
This module implements the main API of the Simple::Service ruby gem.
-
Marking a service module: To turn a target module as a service module one must include
Simple::Service
into the target. This serves as a marker that this module is actually intended to provide one or more services. Example:module GodMode include Simple::Service # Build a universe. # # This comment will become part of the full description of the # "build_universe" service def build_universe(name, c: , pi: 3.14, e: 2.781) # at this point I realize that *I* am not God. 42 # Best try approach end end
-
Discover services: To discover services in a service module use the #actions method. This returns a Hash of actions.
Simple::Service.actions(GodMode) => {:build_universe=>#<Simple::Service::Action...>, ...}
TODO: why a Hash? It feels much better if Simple::Service.actions returns an array of names.
-
Invoke a service: run
Simple::Service.invoke3
orSimple::Service.invoke
.Simple::Service.invoke3(GodMode, :build_universe, "TestWorld", c: 1e9) => 42
Defined Under Namespace
Modules: ClassMethods, GemHelper, ServiceExpectations Classes: Action, ArgumentError, ContextReadOnlyError, ExtraArgumentError, MissingArgumentError, NoSuchActionError, UnknownFlagError
Constant Summary collapse
Class Method Summary collapse
-
.action(service, name) ⇒ Object
returns the action with the given name.
-
.actions(service) ⇒ Object
returns a Hash with all actions in the
service
module. - .included(klass) ⇒ Object
-
.invoke(service, name, args: {}, flags: {}) ⇒ Object
invokes an action with a given
name
. -
.invoke3(service, name, *args, **flags) ⇒ Object
invokes an action with a given
name
in a service withargs
andflags
. -
.verify_service!(service) ⇒ Object
Raises an error if the passed in object is not a Simple::Service.
Class Method Details
.action(service, name) ⇒ Object
returns the action with the given name.
84 85 86 87 88 89 90 91 |
# File 'lib/simple/service.rb', line 84 def self.action(service, name) expect! name => Symbol actions = self.actions(service) actions[name] || begin raise ::Simple::Service::NoSuchActionError.new(service, name) end end |
.actions(service) ⇒ Object
returns a Hash with all actions in the service
module
77 78 79 80 81 |
# File 'lib/simple/service.rb', line 77 def self.actions(service) verify_service!(service) service.__simple_service_actions__ end |
.included(klass) ⇒ Object
59 60 61 62 |
# File 'lib/simple/service.rb', line 59 def self.included(klass) # @private klass.extend ClassMethods klass.include ServiceExpectations end |
.invoke(service, name, args: {}, flags: {}) ⇒ Object
invokes an action with a given name
.
This is the general form of invoking a service. It accepts the following arguments:
-
args: an Array of positional arguments OR a Hash of named arguments.
-
flags: a Hash of flags.
Note that the keys in both the flags
and the args
Hash must be strings.
The service is being called with a parameters built out of those like this:
-
The service’s positional arguments are being built from the
args
array parameter or from thenamed_args
hash parameter. -
The service’s keyword arguments are being built from the
named_args
andflags
arguments.
In other words:
-
You cannot set both
args
andnamed_args
at the same time. -
The
flags
arguments are only being used to determine the service’s keyword parameters.
So, if the service X implements an action “def foo(bar, baz:)”, the following would all invoke that service:
-
Service.invoke3(X, :foo, “bar-value”, baz: “baz-value”), or
-
Service.invoke3(X, :foo, bar: “bar-value”, baz: “baz-value”), or
-
Service.invoke(X, :foo, args: [“bar-value”], flags: { “baz” => “baz-value” }), or
-
Service.invoke(X, :foo, args: { “bar” => “bar-value”, “baz” => “baz-value” }).
(see spec/service_spec.rb)
When there are not enough positional arguments to match the number of required positional arguments of the method we raise an ArgumentError.
When there are more positional arguments provided than the number accepted by the method we raise an ArgumentError.
Entries in the named_args
Hash that are not defined in the action itself are ignored.
153 154 155 156 157 158 159 |
# File 'lib/simple/service.rb', line 153 def self.invoke(service, name, args: {}, flags: {}) expect! args => [Hash, Array], flags: Hash args.each_key { |key| expect! key => String } if args.is_a?(Hash) flags.each_key { |key| expect! key => String } action(service, name).invoke(args: args, flags: flags) end |
.invoke3(service, name, *args, **flags) ⇒ Object
invokes an action with a given name
in a service with args
and flags
.
This is a helper method which one can use to easily call an action from ruby source code.
As the main purpose of this module is to call services with outside data, the .invoke
action is usually preferred.
100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/simple/service.rb', line 100 def self.invoke3(service, name, *args, **flags) # The following checks if flags is empty. This might be intentional, but might also mean that # the caller is sending in kwargs as last arguments of the args array. # # This is supported in 2.7.*, but no longer works with ruby 3. if flags.empty? && args.last.is_a?(Hash) flags = args.pop end flags = flags.transform_keys(&:to_s) invoke service, name, args: args, flags: flags end |
.verify_service!(service) ⇒ Object
Raises an error if the passed in object is not a Simple::Service
65 66 67 68 69 70 71 72 73 74 |
# File 'lib/simple/service.rb', line 65 def self.verify_service!(service) # @private expect! service => Module # rubocop:disable Style/GuardClause unless service.include?(::Simple::Service) raise ::ArgumentError, "#{service.name} is not a Simple::Service, did you 'include Simple::Service'" end # rubocop:enable Style/GuardClause end |