class Rodger
Constants
- VERSION
Public Class Methods
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
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
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
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
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
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
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
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