class Rodger

Constants

VERSION

Public Class Methods

new(options = {}) click to toggle source

Initialize with the name of the filename and an optional path to the ledger binary

options is a hash like :file => path to the ledger file :bin => path to the ledger binary. Defaults to 'ledger' so not required if ledger is in your path

# File lib/rodger.rb, line 48
def initialize(options = {})
  @filename = options[:file]
  @ledger = options[:bin] || 'ledger'
end

Public Instance Methods

accounts() click to toggle source

Public: Builds a AccountTree of the accounts as reported by ledger. It populates each account with the canonical name and balance of the account returns a Hash like {“Assets” => {:name => “Assets”, :balance => <balance>, “Fixed Assets” => {:name => “Assets:FixedAssets”, :bal…}}}

# File lib/rodger.rb, line 55
def accounts
  ahash = (cmd "accounts | sort").split("\n")
  ahash.reduce(AccountTree.new) do |s, h|
    a = recurse_accounts(h.split(":"))            # recursion is awsm!
    s.deep_merge(a)
  end
end
balance(account) click to toggle source

Public: Returns the account balance for a given account on a given date Need to give the full name of the account, not a regexp to match against

# File lib/rodger.rb, line 73
def balance(account)
  return balances[account] || infer_balance(account) # need to infer the balance if the account is not in ledger's output
end
balances() click to toggle source

Public: Returns a hash of all the account names and their balances. Is the “flat” version of the accounts tree above however, it does not include any accounts which do not have any journal entries in them.

# File lib/rodger.rb, line 65
def balances
  return @balances_hash if @balances_hash
  ledger_balances = cmd 'bal --balance-format "%A | %(display_total)\n"'
  @balances_hash = Hash[*(ledger_balances.split("\n")).map{|line| parse_account_line(line)}.flatten]
end

Private Instance Methods

cmd(extra_args) click to toggle source

Builds the command using the provided switches and any extra arguments used here

# File lib/rodger.rb, line 80
def cmd(extra_args)
  `#{@ledger} -f #{@filename} #{extra_args}`
end
infer_balance(account) click to toggle source

If the given account is not found in the balance report, we have to infer the balance from the subaccounts Please refer to the specs for more information

account is an account name

# File lib/rodger.rb, line 114
def infer_balance(account)
  sub_accounts = balances.keys.compact.map{|k| k.match(/#{account}:[^:]*/)}.compact
  relevant_accounts = sub_accounts.map(&:to_s).uniq
  relevant_account_balances = relevant_accounts.map{|a| balance(a)}
  balance = relevant_account_balances.reduce({:amount => 0, :currency => nil}){|s,h| {:amount => s[:amount] + h[:amount], :currency => h[:currency]}}
end
parse_account_line(line) click to toggle source

Private: takes a line from ledger balance output and returns the account, amount and currency

# File lib/rodger.rb, line 103
def parse_account_line(line)
  account = line.split("|")[0].strip rescue nil
  amount  = line.scan(/\-{0,1}\d+[\.\d+]*/)[0].to_f rescue nil
  currency = line.scan(/[A-Z]{3,7}/)[-1] rescue nil
  [account,{:amount => amount, :currency => currency}]
end
recurse_accounts(accounts_array, prenom = "") click to toggle source

given an array like [Assets][Furniture], returns a Hash like {“Assets” => {:name => “Assets”, :balance => <balance>, “FixedAssets” => {…}…}…} by querying the given ledger for balances, etc.

# File lib/rodger.rb, line 87
def recurse_accounts(accounts_array, prenom = "")
  result = AccountTree.new
  prenom = prenom.empty? ? accounts_array[0] : "#{prenom}:#{accounts_array[0]}"
  if accounts_array.class == Array
    if accounts_array.size == 1
      result[accounts_array[0]] = AccountTree.new(:name => prenom, :balance => balance(prenom))
    else
      r = recurse_accounts(accounts_array[1..-1], prenom)
      result[accounts_array[0]] = r.merge(:name => prenom, :balance => balance(prenom))
    end
  end
  result
end