Class: RVGP::Base::Reconciler

Inherits:
Object
  • Object
show all
Includes:
Utilities
Defined in:
lib/rvgp/base/reconciler.rb

Overview

See Reconcilers for extensive detail on the structure and function of reconciler yaml files, and reconciler functionality.

Defined Under Namespace

Classes: MissingFields

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Utilities

#months_through, #string_to_regex

Constructor Details

#initialize(yaml) ⇒ Reconciler

Create a Reconciler from the provided yaml

Parameters:

  • yaml (RVGP::Utilities::Yaml)

    A file containing the settings to use in the construction of this reconciler . (see above)

Raises:



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/rvgp/base/reconciler.rb', line 86

def initialize(yaml)
  @label = yaml[:label]
  @file = yaml.path
  @dependencies = yaml.dependencies

  @starts_on = yaml.key?(:starts_on) ? Date.strptime(yaml[:starts_on], '%Y-%m-%d') : nil

  missing_fields = %i[label output input from income expense].find_all { |attr| !yaml.key? attr }

  raise MissingFields.new(*missing_fields) unless missing_fields.empty?

  if RVGP.app
    @output_file = RVGP.app.config.build_path format('journals/%s', yaml[:output])
    @input_file = RVGP.app.config.project_path format('feeds/%s', yaml[:input])
  else
    # ATM this path is found in the test environment... possibly we should
    # decouple RVGP.app from this class....
    @output_file = yaml[:output]
    @input_file = yaml[:input]
  end

  @from = yaml[:from]
  @income_rules = yaml[:income]
  @expense_rules = yaml[:expense]
  @transform_commodities = yaml[:transform_commodities] || {}
  @balances = yaml[:balances]
  @disable_checks = yaml[:disable_checks]&.map(&:to_sym) if yaml.key?(:disable_checks)
  @disable_checks ||= []

  if yaml.key? :tag_accounts
    @tag_accounts = yaml[:tag_accounts]

    unless @tag_accounts.all? { |ta| %i[account tag].all? { |k| ta.key? k } }
      raise StandardError, 'One or more tag_accounts entries is missing an :account or :tag key'
    end
  end

  if yaml.key? :format
    @default_currency = yaml[:format][:default_currency] || '$'
    @reverse_order = yaml[:format][:reverse_order] if yaml[:format].key? :reverse_order

    if yaml[:format].key?(:cash_back)
      @cash_back = string_to_regex yaml[:format][:cash_back][:match]
      @cash_back_to = yaml[:format][:cash_back][:to]
    end
  end
end

Instance Attribute Details

#balancesHash<String, String> (readonly)

A hash of dates (in ‘YYYY-MM-DD’) to commodities (as string) corresponding to the balance that are expected on those dates. See Validations::BalanceValidation for details on this feature.

Returns:



31
32
33
# File 'lib/rvgp/base/reconciler.rb', line 31

def balances
  @balances
end

#cash_backRegexp (readonly)

The contents of the :match parameter, inside the yaml’s :cash_back parameter (see above)

Returns:

  • (Regexp)

    the current value of cash_back



31
32
33
# File 'lib/rvgp/base/reconciler.rb', line 31

def cash_back
  @cash_back
end

#cash_back_toString (readonly)

The contents of the :to parameter, inside the yaml’s :cash_back parameter (see above)

Returns:

  • (String)

    the current value of cash_back_to



31
32
33
# File 'lib/rvgp/base/reconciler.rb', line 31

def cash_back_to
  @cash_back_to
end

#default_currencyString (readonly)

The contents of the yaml :default_currency parameter (see above)

Returns:

  • (String)

    the current value of default_currency



31
32
33
# File 'lib/rvgp/base/reconciler.rb', line 31

def default_currency
  @default_currency
end

#disable_checksArray<String> (readonly)

The JournalValidations that are disabled on this reconciler (see above)

Returns:

  • (Array<String>)

    the current value of disable_checks



31
32
33
# File 'lib/rvgp/base/reconciler.rb', line 31

def disable_checks
  @disable_checks
end

#expense_rulesArray<Hash> (readonly)

The contents of the yaml :expense_rules parameter (see above)

Returns:

  • (Array<Hash>)

    the current value of expense_rules



31
32
33
# File 'lib/rvgp/base/reconciler.rb', line 31

def expense_rules
  @expense_rules
end

#fileString (readonly)

The full path to the reconciler yaml file this class was parsed from

Returns:

  • (String)

    the current value of file



31
32
33
# File 'lib/rvgp/base/reconciler.rb', line 31

def file
  @file
end

#fromString (readonly)

The contents of the yaml :from parameter (see above)

Returns:

  • (String)

    the current value of from



31
32
33
# File 'lib/rvgp/base/reconciler.rb', line 31

def from
  @from
end

#income_rulesArray<Hash> (readonly)

The contents of the yaml :income_rules parameter (see above)

Returns:

  • (Array<Hash>)

    the current value of income_rules



31
32
33
# File 'lib/rvgp/base/reconciler.rb', line 31

def income_rules
  @income_rules
end

#input_fileString (readonly)

The contents of the yaml :input parameter (see above)

Returns:

  • (String)

    the current value of input_file



31
32
33
# File 'lib/rvgp/base/reconciler.rb', line 31

def input_file
  @input_file
end

#labelString (readonly)

The contents of the yaml :label parameter (see above)

Returns:

  • (String)

    the current value of label



31
32
33
# File 'lib/rvgp/base/reconciler.rb', line 31

def label
  @label
end

#output_fileString (readonly)

The contents of the yaml :output parameter (see above)

Returns:

  • (String)

    the current value of output_file



31
32
33
# File 'lib/rvgp/base/reconciler.rb', line 31

def output_file
  @output_file
end

#reverse_orderTrueClass, FalseClass (readonly)

The contents of the yaml :reverse_order parameter (see above)

Returns:

  • (TrueClass, FalseClass)

    the current value of reverse_order



31
32
33
# File 'lib/rvgp/base/reconciler.rb', line 31

def reverse_order
  @reverse_order
end

#starts_onDate (readonly)

The contents of the yaml :starts_on parameter (see above)

Returns:

  • (Date)

    the current value of starts_on



31
32
33
# File 'lib/rvgp/base/reconciler.rb', line 31

def starts_on
  @starts_on
end

#tag_accountsArray<Hash> (readonly)

The contents of the yaml :tag_accounts parameter (see above)

Returns:

  • (Array<Hash>)

    the current value of tag_accounts



31
32
33
# File 'lib/rvgp/base/reconciler.rb', line 31

def tag_accounts
  @tag_accounts
end

Class Method Details

.all(directory_path) ⇒ Array<RVGP::Reconcilers::CsvReconciler, RVGP::Reconcilers::JournalReconciler>

Returns an array of all of the reconcilers found in the specified path.

Parameters:

  • directory_path (String)

    The path containing your yml reconciler files

Returns:



372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
# File 'lib/rvgp/base/reconciler.rb', line 372

def self.all(directory_path)
  # NOTE: I'm not crazy about this method. Probably we should have
  # implemented a single Reconciler class, with CSV/Journal drivers.
  # Nonetheless, this code works for now. Maybe if we add another
  # driver, we can renovate it, and add some kind of registry for drivers.

  Dir.glob(format('%s/app/reconcilers/*.yml', directory_path)).map do |path|
    yaml = RVGP::Utilities::Yaml.new path, RVGP.app.config.project_path

    raise MissingFields.new, :input unless yaml.key? :input

    # We could probably make this a registry, though, I'd like to support
    # web addresses eventually. So, probably this designe pattern would
    # have to just be reconsidered entirely around that time.
    case File.extname(yaml[:input])
    when '.csv' then RVGP::Reconcilers::CsvReconciler.new(yaml)
    when '.journal' then RVGP::Reconcilers::JournalReconciler.new(yaml)
    else
      raise StandardError, format('Unrecognized file extension for input file "%s"', yaml[:input])
    end
  end
end

Instance Method Details

#as_tasknameString

Returns the taskname to use by rake, for this reconciler

Returns:

  • (String)

    The taskname, based off the :file basename



136
137
138
# File 'lib/rvgp/base/reconciler.rb', line 136

def as_taskname
  File.basename(file, File.extname(file)).tr('^a-z0-9', '-')
end

#dependenciesArray<String>

Returns the file paths that were referenced by this reconciler in one form or another. Useful for determining build freshness.

Returns:

  • (Array<String>)

    dependent files, in this reconciler.



157
158
159
# File 'lib/rvgp/base/reconciler.rb', line 157

def dependencies
  [file, input_file] + @dependencies
end

#to_ledgerString

Builds the contents of this reconcilere’s output file, and returns it. This is the finished product of this class

Returns:

  • (String)

    a PTA journal, composed of the input_file’s transactions, after all rules are applied.



358
359
360
# File 'lib/rvgp/base/reconciler.rb', line 358

def to_ledger
  [HEADER % label, postings.map(&:to_ledger), ''].flatten.join("\n\n")
end

#to_ledger!void

This method returns an undefined value.

Writes the contents of #to_ledger, to the :output_file specified in the reconciler yaml.



364
365
366
# File 'lib/rvgp/base/reconciler.rb', line 364

def to_ledger!
  File.write output_file, to_ledger
end