Class: RVGP::Base::Validation

Inherits:
Object
  • Object
show all
Includes:
Pta::AvailabilityHelper
Defined in:
lib/rvgp/base/validation.rb

Overview

This class contains methods shared by both JournalValidation and SystemValidation. Validations are run during a project build, after the reconcile tasks.

Validations are typically defined inside a .rb in your project’s app/validations folder, and should inherit from JournalValidation or SystemValidation (though not this class itself). Your validations can be customized in ruby, to add warnings or errors to your build. Warnings are non-fatal, and merely output a notice on the command line. Errors are fatal, and halt a build.

This Base class contains some common helpers for use in your validations, regardless of whether its a system or journal validation. Here are the differences between these two validation classes:

##Journal Validations Validate the output of one reconciler at a time

These validations are run immediately after the reconcile task, and before system validations are run. Each instance of these validations is applied to a reconcilers output file (typically located in build/journal). And by default, any journal validations that are defined in a project’s app/validations are instantiated against every reconciler’s output, in the project. This behavior can be overwritten, by defining a ‘disable_checks’ array in the root of the reconciler’s yaml, containing the name(s) of validations to disable for that journal. These names are expected to be the classname of the validation, underscorized, lowercase, and with the ‘Validation’ suffix removed from the class. For example, to disable the Validations::BalanceValidation in one of the reconcilers of your project, add the following lines to its yaml: “‘ disable_checks:

- balance

“‘ A JournalValidation is passed the reconciler corresponding to it’s instance in its initialize method. For further details on how these validations work, see the documentation for this class here JournalValidation or check out an example implementation. Here’s the BalanceValidation itself, which is a relatively easy example to balance_validation.rb follow.

##System Validations Validate the entire, finished, journal output for the project

Unlike Journal validations, these Validations are run without a target, and are expected to generate warnings and errors based on the state of queries spanning multiple journals.

There are no example SystemValidations included in the distribution of rvgp. However, here’s an easy one, to serve as reference. This validation ensures Transfers between accounts are always credited and debited on both sides: “‘

class TransferAccountValidation < RVGP::Base::SystemValidation
  STATUS_LABEL = 'Unbalanced inter-account transfers'
  DESCRIPTION = "Ensure that debits and credits through Transfer accounts, complete without remainders"

  def validate
    warnings = pta.balance('Transfers').accounts.map do ||
      .amounts.map do |amount|
        [ .fullname, RVGP.pastel.yellow(''), amount.to_s(commatize: true) ].join(' ')
      end
    end.compact.flatten

    warning! 'Unbalanced Transfer Encountered', warnings if warnings.length > 0
  end
end

“‘

The above validation works, if you assign transfers between accounts like so: “‘ ; This is how a Credit Card Payment looks in my Checking account, the source of funds: 2023-01-25 Payment to American Express card ending in 1234

Transfers:PersonalChecking_PersonalAmex    $ 10000.00
Personal:Assets:AcmeBank:Checking

; This is how a Credit Card Payment looks in my Amex account, the destination of funds: 2023-01-25 Payment Thank You - Web

Transfers:PersonalChecking_PersonalAmex    $ -10000.00
Personal:Liabilities:AmericanExpress

“‘

In this format of transfering money, if either the first or second transfer was omitted, the TransferAccountValidation will alert you that money has gone missing somewhere at the bank, and/or is taking longer to complete, than you expected.

##Summary of Differences SystemValidations are largely identical to JournalValidations, with, the following exceptions:

Priority Journal validations are run sooner in the rake process. Just after reconciliations have completed. System validations run immediately after all Journal validations have completed.

Input Journal validations have one input, accessible via its JournalValidation#reconciler. System validations have no preconfigured inputs at all. Journal Validations support a disable_checks attribute in the reconciler yaml, and system validations have no such directive.

Labeling With Journal validations, tasks are labeled automatically by rvgp, based on their class name. System validations are expected to define a STATUS_LABEL and DESCRIPTION constant, in order to arrive at these labels.

Note that for either type of validation, most/all of the integration functionality is provided by way of the #error! and #warning! methods, instigated in the class’ validate method.

##Error and Warning formatting The format of errors and warnings are a bit peculiar, and probably need a bit more polish to the interface. Nonetheless, it’s not complicated. Here’s the way it works, for both collections:

  • The formatting of :errors and :warnings is identical. These collections contain a hierarchy of errors, which is used to display fatal and non-fatal output to the console.

  • Every element of these collections are expected to be a two element Array. The first element of which is to be a string containing the topmost error/warning. The second element of this Array is optional. If present, this second element is expected to be an Array of Strings, which are subordinate to the message in the first element.

Direct Known Subclasses

JournalValidation, SystemValidation

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Pta::AvailabilityHelper

#hledger, #ledger, #pta

Constructor Details

#initializeValidation

Create a new Validation



126
127
128
129
# File 'lib/rvgp/base/validation.rb', line 126

def initialize
  @errors = []
  @warnings = []
end

Instance Attribute Details

#errorsArray<String,Array<String>> (readonly)

Errors encountered by this validation. See the above note on ‘Error and Warning formatting’

Returns:

  • (Array<String,Array<String>>)

    the current value of errors



117
118
119
# File 'lib/rvgp/base/validation.rb', line 117

def errors
  @errors
end

#warningsArray<String,Array<String>> (readonly)

Warnings encountered by this validation. See the above note on ‘Error and Warning formatting’

Returns:

  • (Array<String,Array<String>>)

    the current value of warnings



117
118
119
# File 'lib/rvgp/base/validation.rb', line 117

def warnings
  @warnings
end

Instance Method Details

#error!(msg, citations = nil) ⇒ Object

Add an error to our #errors collection. The format of this error is expected to match the formatting indicated in the ‘Error and Warning formatting’ above.

Parameters:

  • msg (String)

    A description of the error.

  • citations (Array<String>) (defaults to: nil)

    Supporting details, subordinate error citations, denotated ‘below’ the :msg



151
152
153
# File 'lib/rvgp/base/validation.rb', line 151

def error!(msg, citations = nil)
  @errors << format_error_or_warning(msg, citations)
end

#valid?TrueClass, FalseClass

Returns true if there are no warnings or errors present in this validation’s instance. Otherwise, returns false.

Returns:

  • (TrueClass, FalseClass)

    whether this validation has passed



133
134
135
136
137
138
# File 'lib/rvgp/base/validation.rb', line 133

def valid?
  @errors = []
  @warnings = []
  validate
  (@errors.length + @warnings.length).zero?
end

#warning!(msg, citations = nil) ⇒ Object

Add a warning to our #warnings collection. The format of this warning is expected to match the formatting indicated in the ‘Error and Warning formatting’ above.

Parameters:

  • msg (String)

    A description of the warning.

  • citations (Array<String>) (defaults to: nil)

    Supporting details, subordinate warning citations, denotated ‘below’ the :msg



160
161
162
# File 'lib/rvgp/base/validation.rb', line 160

def warning!(msg, citations = nil)
  @warnings << format_error_or_warning(msg, citations)
end