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
|
end
|
||||||
|
|
||||||
# Returns the value of the given attribute.
|
# Returns the value of the given attribute.
|
||||||
# The attribute gets validated against the .uses list of attributes. In the
|
# The attribute gets validated against the .uses and .optionals
|
||||||
# case than an attribute gets used that is not declared to be used
|
# lists of attributes. In the case that an attribute gets used
|
||||||
# an exception will be raised.
|
# that is not declared to be used or optional, an exception
|
||||||
|
# gets raised.
|
||||||
#
|
#
|
||||||
# @param [Symbol] attribute the attribute for which the value is requested.
|
# @param [Symbol] attribute the attribute for which the value is requested.
|
||||||
#
|
#
|
||||||
|
@ -74,6 +75,7 @@ class Sequencer
|
||||||
|
|
||||||
# Returns the value of the given attribute.
|
# Returns the value of the given attribute.
|
||||||
# The attribute DOES NOT get validated against the .uses list of attributes.
|
# 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.
|
# @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.
|
# Checks if a value for the given attribute is provided.
|
||||||
# The attribute DOES NOT get validated against the .uses list of attributes.
|
# 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.
|
# @param [Symbol] attribute the attribute which should get checked.
|
||||||
#
|
#
|
||||||
|
@ -168,7 +171,7 @@ class Sequencer
|
||||||
|
|
||||||
def available
|
def available
|
||||||
@attributes.select do |_identifier, attribute|
|
@attributes.select do |_identifier, attribute|
|
||||||
@index.between?(attribute.from, attribute.to)
|
@index.between?(attribute.from, attribute.till)
|
||||||
end.keys
|
end.keys
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -181,7 +184,9 @@ class Sequencer
|
||||||
end
|
end
|
||||||
|
|
||||||
def useable?(attribute)
|
def useable?(attribute)
|
||||||
unit.uses.include?(attribute)
|
return true if unit.uses.include?(attribute)
|
||||||
|
|
||||||
|
unit.optional.include?(attribute)
|
||||||
end
|
end
|
||||||
|
|
||||||
def set(attribute, value)
|
def set(attribute, value)
|
||||||
|
@ -230,6 +235,8 @@ class Sequencer
|
||||||
provided_attr = attribute.will_be_provided?
|
provided_attr = attribute.will_be_provided?
|
||||||
|
|
||||||
if !init_param && !provided_attr
|
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."
|
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)
|
logger.error(message)
|
||||||
raise message
|
raise message
|
||||||
|
@ -261,7 +268,7 @@ class Sequencer
|
||||||
|
|
||||||
@attributes.delete_if do |identifier, attribute|
|
@attributes.delete_if do |identifier, attribute|
|
||||||
remove = !attribute.will_be_used?
|
remove = !attribute.will_be_used?
|
||||||
remove ||= attribute.to <= @index
|
remove ||= attribute.till <= @index
|
||||||
if remove && attribute.will_be_used?
|
if remove && attribute.will_be_used?
|
||||||
logger.public_send(log_level[:cleanup][:remove]) { "Removing unneeded attribute '#{identifier}': #{@values[identifier].inspect}" }
|
logger.public_send(log_level[:cleanup][:remove]) { "Removing unneeded attribute '#{identifier}': #{@values[identifier].inspect}" }
|
||||||
end
|
end
|
||||||
|
|
|
@ -54,6 +54,53 @@ class Sequencer
|
||||||
end
|
end
|
||||||
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
|
# Creates the class macro `provides` that allows a Unit to
|
||||||
# declare the attributes it will provided via parameter or block.
|
# declare the attributes it will provided via parameter or block.
|
||||||
# On the other hand it returns the declared attributes if
|
# On the other hand it returns the declared attributes if
|
||||||
|
|
|
@ -5,12 +5,13 @@ class Sequencer
|
||||||
class IdPathMap < Sequencer::Unit::Base
|
class IdPathMap < Sequencer::Unit::Base
|
||||||
include ::Sequencer::Unit::Exchange::Folders::Mixin::Folder
|
include ::Sequencer::Unit::Exchange::Folders::Mixin::Folder
|
||||||
|
|
||||||
|
optional :ews_folder_ids
|
||||||
provides :ews_folder_id_path_map
|
provides :ews_folder_id_path_map
|
||||||
|
|
||||||
def process
|
def process
|
||||||
state.provide(:ews_folder_id_path_map) do
|
state.provide(:ews_folder_id_path_map) do
|
||||||
|
|
||||||
ids = state.optional(:ews_folder_ids)
|
ids = ews_folder_ids
|
||||||
ids ||= []
|
ids ||= []
|
||||||
|
|
||||||
ews_folder.id_folder_map.collect do |id, folder|
|
ews_folder.id_folder_map.collect do |id, folder|
|
||||||
|
|
|
@ -7,6 +7,7 @@ class Sequencer
|
||||||
class Update < Sequencer::Unit::Base
|
class Update < Sequencer::Unit::Base
|
||||||
|
|
||||||
uses :statistics_diff
|
uses :statistics_diff
|
||||||
|
optional :import_job
|
||||||
provides :statistics
|
provides :statistics
|
||||||
|
|
||||||
def process
|
def process
|
||||||
|
@ -24,7 +25,6 @@ class Sequencer
|
||||||
private
|
private
|
||||||
|
|
||||||
def statistics
|
def statistics
|
||||||
import_job = state.optional(:import_job)
|
|
||||||
return {} if import_job.nil?
|
return {} if import_job.nil?
|
||||||
|
|
||||||
import_job.result
|
import_job.result
|
||||||
|
|
|
@ -21,11 +21,13 @@ class Sequencer
|
||||||
private
|
private
|
||||||
|
|
||||||
def mapped
|
def mapped
|
||||||
|
@mapped ||= begin
|
||||||
resource_with_indifferent_access = resource.with_indifferent_access
|
resource_with_indifferent_access = resource.with_indifferent_access
|
||||||
mapping.symbolize_keys.collect do |source, local|
|
mapping.symbolize_keys.collect do |source, local|
|
||||||
[local, resource_with_indifferent_access[source]]
|
[local, resource_with_indifferent_access[source]]
|
||||||
end.to_h.with_indifferent_access
|
end.to_h.with_indifferent_access
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def mapping
|
def mapping
|
||||||
raise "Missing implementation of '#{__method__}' method for '#{self.class.name}'"
|
raise "Missing implementation of '#{__method__}' method for '#{self.class.name}'"
|
||||||
|
|
|
@ -7,13 +7,14 @@ class Sequencer
|
||||||
module ProvideMapped
|
module ProvideMapped
|
||||||
|
|
||||||
def self.included(base)
|
def self.included(base)
|
||||||
|
base.optional :mapped
|
||||||
base.provides :mapped
|
base.provides :mapped
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def existing_mapped
|
def existing_mapped
|
||||||
@existing_mapped ||= state.optional(:mapped) || ActiveSupport::HashWithIndifferentAccess.new
|
@existing_mapped ||= mapped || ActiveSupport::HashWithIndifferentAccess.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def provide_mapped
|
def provide_mapped
|
||||||
|
|
|
@ -35,11 +35,11 @@ class Sequencer
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.prepended(base)
|
def self.prepended(base)
|
||||||
|
base.optional :action
|
||||||
base.extend(ClassMethods)
|
base.extend(ClassMethods)
|
||||||
end
|
end
|
||||||
|
|
||||||
def process
|
def process
|
||||||
action = state.optional(:action)
|
|
||||||
if self.class.skip_action?(action)
|
if self.class.skip_action?(action)
|
||||||
logger.debug { "Skipping due to provided action #{action.inspect}." }
|
logger.debug { "Skipping due to provided action #{action.inspect}." }
|
||||||
else
|
else
|
||||||
|
|
|
@ -30,11 +30,11 @@ class Sequencer
|
||||||
end
|
end
|
||||||
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
|
# @example
|
||||||
# units.declarations
|
# units.declarations
|
||||||
# #=> [{uses: [:question], provides: [:answer], ...}]
|
# #=> [{uses: [:question], provides: [:answer], optional: [:facts], ...}]
|
||||||
#
|
#
|
||||||
# @return [Array<Hash{Symbol => Array<Symbol>}>] the declarations of the Units
|
# @return [Array<Hash{Symbol => Array<Symbol>}>] the declarations of the Units
|
||||||
def declarations
|
def declarations
|
||||||
|
@ -42,6 +42,7 @@ class Sequencer
|
||||||
{
|
{
|
||||||
uses: unit.uses,
|
uses: unit.uses,
|
||||||
provides: unit.provides,
|
provides: unit.provides,
|
||||||
|
optional: unit.optional,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@ class Sequencer
|
||||||
class Units < SimpleDelegator
|
class Units < SimpleDelegator
|
||||||
class Attribute
|
class Attribute
|
||||||
|
|
||||||
attr_accessor :from, :to
|
attr_accessor :from, :to, :optional
|
||||||
|
|
||||||
# Checks if the attribute will be provided by one or more Units.
|
# Checks if the attribute will be provided by one or more Units.
|
||||||
#
|
#
|
||||||
|
@ -23,7 +23,25 @@ class Sequencer
|
||||||
#
|
#
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
def will_be_used?
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -71,6 +71,10 @@ class Sequencer
|
||||||
|
|
||||||
result[attribute].from = index
|
result[attribute].from = index
|
||||||
end
|
end
|
||||||
|
|
||||||
|
unit[:optional].try(:each) do |attribute|
|
||||||
|
result[attribute].optional = index
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue