Enhancement: Add support for optional Sequencer Unit attributes.
This commit is contained in:
parent
e865826810
commit
bf874d77c6
10 changed files with 100 additions and 19 deletions
|
@ -51,9 +51,10 @@ class Sequencer
|
|||
end
|
||||
|
||||
# Returns the value of the given attribute.
|
||||
# The attribute gets validated against the .uses list of attributes. In the
|
||||
# case than an attribute gets used that is not declared to be used
|
||||
# an exception will be raised.
|
||||
# The attribute gets validated against the .uses and .optionals
|
||||
# lists of attributes. In the case that an attribute gets used
|
||||
# that is not declared to be used or optional, an exception
|
||||
# gets raised.
|
||||
#
|
||||
# @param [Symbol] attribute the attribute for which the value is requested.
|
||||
#
|
||||
|
@ -74,6 +75,7 @@ class Sequencer
|
|||
|
||||
# Returns the value of the given attribute.
|
||||
# The attribute DOES NOT get validated against the .uses list of attributes.
|
||||
# Use this method only in edge cases and prefer .optional macro and state.use otherwise.
|
||||
#
|
||||
# @param [Symbol] attribute the attribute for which the value is requested.
|
||||
#
|
||||
|
@ -95,6 +97,7 @@ class Sequencer
|
|||
|
||||
# Checks if a value for the given attribute is provided.
|
||||
# The attribute DOES NOT get validated against the .uses list of attributes.
|
||||
# Use this method only in edge cases and prefer .optional macro and state.use otherwise.
|
||||
#
|
||||
# @param [Symbol] attribute the attribute which should get checked.
|
||||
#
|
||||
|
@ -168,7 +171,7 @@ class Sequencer
|
|||
|
||||
def available
|
||||
@attributes.select do |_identifier, attribute|
|
||||
@index.between?(attribute.from, attribute.to)
|
||||
@index.between?(attribute.from, attribute.till)
|
||||
end.keys
|
||||
end
|
||||
|
||||
|
@ -181,7 +184,9 @@ class Sequencer
|
|||
end
|
||||
|
||||
def useable?(attribute)
|
||||
unit.uses.include?(attribute)
|
||||
return true if unit.uses.include?(attribute)
|
||||
|
||||
unit.optional.include?(attribute)
|
||||
end
|
||||
|
||||
def set(attribute, value)
|
||||
|
@ -230,6 +235,8 @@ class Sequencer
|
|||
provided_attr = attribute.will_be_provided?
|
||||
|
||||
if !init_param && !provided_attr
|
||||
next if attribute.optional?
|
||||
|
||||
message = "Attribute '#{identifier}' is used in Unit '#{unit(attribute.to).name}' (index: #{attribute.to}) but is not provided or given via initial parameters."
|
||||
logger.error(message)
|
||||
raise message
|
||||
|
@ -261,7 +268,7 @@ class Sequencer
|
|||
|
||||
@attributes.delete_if do |identifier, attribute|
|
||||
remove = !attribute.will_be_used?
|
||||
remove ||= attribute.to <= @index
|
||||
remove ||= attribute.till <= @index
|
||||
if remove && attribute.will_be_used?
|
||||
logger.public_send(log_level[:cleanup][:remove]) { "Removing unneeded attribute '#{identifier}': #{@values[identifier].inspect}" }
|
||||
end
|
||||
|
|
|
@ -54,6 +54,53 @@ class Sequencer
|
|||
end
|
||||
end
|
||||
|
||||
# Creates the class macro `optional` that allows a Unit to
|
||||
# declare the attributes it will use via parameter or block.
|
||||
# On the other hand it returns the declared attributes if
|
||||
# called without parameters.
|
||||
#
|
||||
# This method can be called multiple times and will add the
|
||||
# given attributes to the list. It takes care of handling
|
||||
# duplicates so no uniq check is required. It's safe to use
|
||||
# for inheritance structures and modules.
|
||||
#
|
||||
# It additionally creates a getter instance method for each declared
|
||||
# attribute like e.g. attr_reader does. This allows direct access
|
||||
# to an attribute via `attribute_name`. See examples.
|
||||
#
|
||||
# @param [Array<Symbol>] attributes an optional list of attributes that the Unit optional
|
||||
#
|
||||
# @yield [] A block returning a list of attributes
|
||||
#
|
||||
# @example Via regular Array<Symbol> parameter
|
||||
# optional :instance, :action, :connection
|
||||
#
|
||||
# @example Via block
|
||||
# optional do
|
||||
# additional = method(parameter)
|
||||
# [:some, additional]
|
||||
# end
|
||||
#
|
||||
# @example Listing declared attributes
|
||||
# Unit::Name.optional
|
||||
# # => [:instance, :action, :connection, :some, :suprise]
|
||||
#
|
||||
# @example Using declared attribute in the Unit via state object
|
||||
# state.use(:instance).id
|
||||
#
|
||||
# @example Using declared attribute in the Unit via getter
|
||||
# instance.id
|
||||
#
|
||||
# @return [Array<Symbol>] the list of all declared optionals of a Unit.
|
||||
def self.optional(*attributes, &block)
|
||||
declaration_accessor(
|
||||
key: __method__,
|
||||
attributes: attributes(*attributes, &block)
|
||||
) do |attribute|
|
||||
use_getter(attribute)
|
||||
end
|
||||
end
|
||||
|
||||
# Creates the class macro `provides` that allows a Unit to
|
||||
# declare the attributes it will provided via parameter or block.
|
||||
# On the other hand it returns the declared attributes if
|
||||
|
|
|
@ -5,12 +5,13 @@ class Sequencer
|
|||
class IdPathMap < Sequencer::Unit::Base
|
||||
include ::Sequencer::Unit::Exchange::Folders::Mixin::Folder
|
||||
|
||||
optional :ews_folder_ids
|
||||
provides :ews_folder_id_path_map
|
||||
|
||||
def process
|
||||
state.provide(:ews_folder_id_path_map) do
|
||||
|
||||
ids = state.optional(:ews_folder_ids)
|
||||
ids = ews_folder_ids
|
||||
ids ||= []
|
||||
|
||||
ews_folder.id_folder_map.collect do |id, folder|
|
||||
|
|
|
@ -7,6 +7,7 @@ class Sequencer
|
|||
class Update < Sequencer::Unit::Base
|
||||
|
||||
uses :statistics_diff
|
||||
optional :import_job
|
||||
provides :statistics
|
||||
|
||||
def process
|
||||
|
@ -24,7 +25,6 @@ class Sequencer
|
|||
private
|
||||
|
||||
def statistics
|
||||
import_job = state.optional(:import_job)
|
||||
return {} if import_job.nil?
|
||||
|
||||
import_job.result
|
||||
|
|
|
@ -21,11 +21,13 @@ class Sequencer
|
|||
private
|
||||
|
||||
def mapped
|
||||
@mapped ||= begin
|
||||
resource_with_indifferent_access = resource.with_indifferent_access
|
||||
mapping.symbolize_keys.collect do |source, local|
|
||||
[local, resource_with_indifferent_access[source]]
|
||||
end.to_h.with_indifferent_access
|
||||
end
|
||||
end
|
||||
|
||||
def mapping
|
||||
raise "Missing implementation of '#{__method__}' method for '#{self.class.name}'"
|
||||
|
|
|
@ -7,13 +7,14 @@ class Sequencer
|
|||
module ProvideMapped
|
||||
|
||||
def self.included(base)
|
||||
base.optional :mapped
|
||||
base.provides :mapped
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def existing_mapped
|
||||
@existing_mapped ||= state.optional(:mapped) || ActiveSupport::HashWithIndifferentAccess.new
|
||||
@existing_mapped ||= mapped || ActiveSupport::HashWithIndifferentAccess.new
|
||||
end
|
||||
|
||||
def provide_mapped
|
||||
|
|
|
@ -35,11 +35,11 @@ class Sequencer
|
|||
end
|
||||
|
||||
def self.prepended(base)
|
||||
base.optional :action
|
||||
base.extend(ClassMethods)
|
||||
end
|
||||
|
||||
def process
|
||||
action = state.optional(:action)
|
||||
if self.class.skip_action?(action)
|
||||
logger.debug { "Skipping due to provided action #{action.inspect}." }
|
||||
else
|
||||
|
|
|
@ -30,11 +30,11 @@ class Sequencer
|
|||
end
|
||||
end
|
||||
|
||||
# Provides an Array of :uses and :provides declarations for each Unit.
|
||||
# Provides an Array of :uses, :provides and :optional declarations for each Unit.
|
||||
#
|
||||
# @example
|
||||
# units.declarations
|
||||
# #=> [{uses: [:question], provides: [:answer], ...}]
|
||||
# #=> [{uses: [:question], provides: [:answer], optional: [:facts], ...}]
|
||||
#
|
||||
# @return [Array<Hash{Symbol => Array<Symbol>}>] the declarations of the Units
|
||||
def declarations
|
||||
|
@ -42,6 +42,7 @@ class Sequencer
|
|||
{
|
||||
uses: unit.uses,
|
||||
provides: unit.provides,
|
||||
optional: unit.optional,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@ class Sequencer
|
|||
class Units < SimpleDelegator
|
||||
class Attribute
|
||||
|
||||
attr_accessor :from, :to
|
||||
attr_accessor :from, :to, :optional
|
||||
|
||||
# Checks if the attribute will be provided by one or more Units.
|
||||
#
|
||||
|
@ -23,7 +23,25 @@ class Sequencer
|
|||
#
|
||||
# @return [Boolean]
|
||||
def will_be_used?
|
||||
!to.nil?
|
||||
till.present?
|
||||
end
|
||||
|
||||
def optional?
|
||||
to.nil? && !optional.nil?
|
||||
end
|
||||
|
||||
def cleanup?(index)
|
||||
return true if !will_be_used?
|
||||
|
||||
till <= index
|
||||
end
|
||||
|
||||
def available?(index)
|
||||
index.between?(from, till)
|
||||
end
|
||||
|
||||
def till
|
||||
[to, optional].compact.max
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -71,6 +71,10 @@ class Sequencer
|
|||
|
||||
result[attribute].from = index
|
||||
end
|
||||
|
||||
unit[:optional].try(:each) do |attribute|
|
||||
result[attribute].optional = index
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue