gnucash 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -13
- data/.gitignore +0 -1
- data/Gemfile.lock +50 -0
- data/README.md +1 -1
- data/Rakefile +1 -8
- data/gnucash.gemspec +3 -6
- data/lib/gnucash.rb +9 -3
- data/lib/gnucash/account.rb +30 -18
- data/lib/gnucash/account_transaction.rb +7 -5
- data/lib/gnucash/book.rb +23 -17
- data/lib/gnucash/transaction.rb +13 -9
- data/lib/gnucash/value.rb +43 -21
- data/lib/gnucash/version.rb +1 -1
- data/spec/gnucash/account_spec.rb +12 -12
- data/spec/gnucash/book_spec.rb +8 -8
- data/spec/gnucash/transaction_spec.rb +12 -12
- data/spec/gnucash/value_spec.rb +15 -15
- data/spec/gnucash_spec.rb +2 -2
- metadata +24 -66
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
YmFmZGY1YmQ0NzkxYTRlMGEzYjBiNjVjZDE0ZTBjNDU2MGQxMGVjMQ==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f91912ae36d38bc2c602c735564159fd14114e43
|
4
|
+
data.tar.gz: c95bc53e838d5595872d3edcb16945ba84e9d0d6
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
MGNlMjU1NzE2MjdkZTVmZDdmZWM5YzkzNDU3YmM2MThhNzk0NzMyYzViMzBk
|
11
|
-
Y2E0MTM4ZTNmYWIzOGUzNzk1ZDkwYWJjMjU2ZGYyYzEwNzBhNmE=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
ZjY0NzY5YjZhN2Y0OWMyNTNmNzRmMjE3MTE0MjFhNjM0YWUzNTcxY2Y1ZmM1
|
14
|
-
ODg2Y2UzMzJhODJjODNiZDIxNDAwOTllMDFhOTVkNTZiYWEwYmIzZWRjYTZk
|
15
|
-
ZTQ1MTU4ODBlZDQ4ZTcxOTkxZWZhNjA5Y2M3ZGQzNGYwN2U0Mzg=
|
6
|
+
metadata.gz: 129f20266029b1d5e2529d3c23084b0d75f13988b87dceb8aad9b58e236ef5001a3014a857d584716aa1914543ee96d7cf449fc51226e896fd713788afe56a49
|
7
|
+
data.tar.gz: 479734374bb70a35026880996ef489923d18544c8b85fe82c2c8bdd4dbb1dba8590c6a60f72cc0edbf44b678ca3eb7593572f4a0303445901a5784314108a442
|
data/.gitignore
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
gnucash (1.2.1)
|
5
|
+
nokogiri
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
diff-lcs (1.3)
|
11
|
+
docile (1.1.5)
|
12
|
+
json (2.1.0)
|
13
|
+
mini_portile2 (2.2.0)
|
14
|
+
nokogiri (1.8.0)
|
15
|
+
mini_portile2 (~> 2.2.0)
|
16
|
+
rake (12.0.0)
|
17
|
+
rdoc (5.1.0)
|
18
|
+
rspec (3.6.0)
|
19
|
+
rspec-core (~> 3.6.0)
|
20
|
+
rspec-expectations (~> 3.6.0)
|
21
|
+
rspec-mocks (~> 3.6.0)
|
22
|
+
rspec-core (3.6.0)
|
23
|
+
rspec-support (~> 3.6.0)
|
24
|
+
rspec-expectations (3.6.0)
|
25
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
26
|
+
rspec-support (~> 3.6.0)
|
27
|
+
rspec-mocks (3.6.0)
|
28
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
29
|
+
rspec-support (~> 3.6.0)
|
30
|
+
rspec-support (3.6.0)
|
31
|
+
simplecov (0.15.0)
|
32
|
+
docile (~> 1.1.0)
|
33
|
+
json (>= 1.8, < 3)
|
34
|
+
simplecov-html (~> 0.10.0)
|
35
|
+
simplecov-html (0.10.2)
|
36
|
+
yard (0.9.9)
|
37
|
+
|
38
|
+
PLATFORMS
|
39
|
+
ruby
|
40
|
+
|
41
|
+
DEPENDENCIES
|
42
|
+
gnucash!
|
43
|
+
rake
|
44
|
+
rdoc
|
45
|
+
rspec
|
46
|
+
simplecov
|
47
|
+
yard
|
48
|
+
|
49
|
+
BUNDLED WITH
|
50
|
+
1.10.6
|
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -7,10 +7,9 @@ end
|
|
7
7
|
require "bundler/gem_tasks"
|
8
8
|
require "rake/clean"
|
9
9
|
require "rspec/core/rake_task"
|
10
|
-
require "rdoc/task"
|
11
10
|
require "yard"
|
12
11
|
|
13
|
-
CLEAN.include "
|
12
|
+
CLEAN.include "doc"
|
14
13
|
CLEAN.include "pkg"
|
15
14
|
CLEAN.include "coverage"
|
16
15
|
|
@@ -20,10 +19,4 @@ end
|
|
20
19
|
|
21
20
|
RSpec::Core::RakeTask.new("spec")
|
22
21
|
|
23
|
-
Rake::RDocTask.new(:rdoc) do |rdoc|
|
24
|
-
rdoc.rdoc_dir = 'rdoc'
|
25
|
-
rdoc.title = "Ruby library for extracting data from GnuCash data files"
|
26
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
27
|
-
end
|
28
|
-
|
29
22
|
task :default => :spec
|
data/gnucash.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |gem|
|
|
8
8
|
gem.version = Gnucash::VERSION
|
9
9
|
gem.authors = ["Josh Holtrop"]
|
10
10
|
gem.email = ["jholtrop@gmail.com"]
|
11
|
-
gem.description = %q{Ruby library for extracting data from GnuCash data files}
|
12
|
-
gem.summary = %q{Extract data from GnuCash data files}
|
11
|
+
gem.description = %q{Ruby library for extracting data from XML GnuCash data files}
|
12
|
+
gem.summary = %q{Extract data from XML GnuCash data files}
|
13
13
|
gem.homepage = "https://github.com/holtrop/ruby-gnucash"
|
14
14
|
gem.license = "MIT"
|
15
15
|
|
@@ -22,10 +22,7 @@ Gem::Specification.new do |gem|
|
|
22
22
|
|
23
23
|
gem.add_development_dependency "simplecov"
|
24
24
|
gem.add_development_dependency "rspec"
|
25
|
-
gem.add_development_dependency "rspec-core"
|
26
|
-
gem.add_development_dependency "rspec-expectations"
|
27
|
-
gem.add_development_dependency "rspec-mocks"
|
28
25
|
gem.add_development_dependency "rake"
|
29
|
-
gem.add_development_dependency "rdoc"
|
30
26
|
gem.add_development_dependency "yard"
|
27
|
+
gem.add_development_dependency "rdoc"
|
31
28
|
end
|
data/lib/gnucash.rb
CHANGED
@@ -5,12 +5,18 @@ require_relative "gnucash/transaction"
|
|
5
5
|
require_relative "gnucash/value"
|
6
6
|
require_relative "gnucash/version"
|
7
7
|
|
8
|
-
# Namespace module for gnucash gem functionality
|
8
|
+
# Namespace module for gnucash gem functionality.
|
9
9
|
module Gnucash
|
10
10
|
# Open a GnuCash book from file.
|
11
|
+
#
|
11
12
|
# The file can be either a plain-text XML file or a gzipped XML file.
|
12
|
-
#
|
13
|
-
#
|
13
|
+
#
|
14
|
+
# @param fname [String]
|
15
|
+
# The file name of the GnuCash file to open. Only XML format (or gzipped
|
16
|
+
# XML format) GnuCash data files are recognized.
|
17
|
+
#
|
18
|
+
# @return [Book]
|
19
|
+
# Gnucash::Book instance.
|
14
20
|
def self.open(fname)
|
15
21
|
Book.new(fname)
|
16
22
|
end
|
data/lib/gnucash/account.rb
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
module Gnucash
|
2
|
-
# Represent a GnuCash account object
|
2
|
+
# Represent a GnuCash account object.
|
3
3
|
class Account
|
4
|
-
#
|
4
|
+
# @return [String] The name of the account (unqualified).
|
5
5
|
attr_reader :name
|
6
6
|
|
7
|
-
#
|
7
|
+
# @return [String] The account description.
|
8
8
|
attr_reader :description
|
9
9
|
|
10
|
-
#
|
10
|
+
# @return [String] The account type (such as "EXPENSE").
|
11
11
|
attr_reader :type
|
12
12
|
|
13
|
-
#
|
13
|
+
# @return [String] The GUID of the account.
|
14
14
|
attr_reader :id
|
15
15
|
|
16
|
-
#
|
17
|
-
# account.
|
16
|
+
# @return [Array<AccountTransaction>] List of transactions associated with
|
17
|
+
# this account.
|
18
18
|
attr_reader :transactions
|
19
19
|
|
20
|
-
# Boolean
|
20
|
+
# @return [Boolean] Whether the account is a placeholder or not.
|
21
21
|
attr_reader :placeholder
|
22
22
|
|
23
23
|
# Create an Account object.
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
24
|
+
#
|
25
|
+
# @param book [Book] The {Gnucash::Book} containing the account.
|
26
|
+
# @param node [Nokogiri::XML::Node] Nokogiri XML node.
|
27
27
|
def initialize(book, node)
|
28
28
|
@book = book
|
29
29
|
@node = node
|
@@ -41,18 +41,24 @@ module Gnucash
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
# Return the fully qualified account name
|
44
|
+
# Return the fully qualified account name.
|
45
|
+
#
|
46
|
+
# @return [String] Fully qualified account name.
|
45
47
|
def full_name
|
46
48
|
@full_name ||= calculate_full_name
|
47
49
|
end
|
48
50
|
|
49
|
-
# Internal method used to associate a transaction with the account
|
51
|
+
# Internal method used to associate a transaction with the account.
|
52
|
+
#
|
53
|
+
# @return [void]
|
50
54
|
def add_transaction(act_txn)
|
51
55
|
@transactions << act_txn
|
52
56
|
end
|
53
57
|
|
54
58
|
# Internal method used to complete initialization of the Account after
|
55
59
|
# all transactions have been associated with it.
|
60
|
+
#
|
61
|
+
# @return [void]
|
56
62
|
def finalize
|
57
63
|
@transactions.sort! { |a, b| a.date <=> b.date }
|
58
64
|
balance = Value.new(0)
|
@@ -65,16 +71,21 @@ module Gnucash
|
|
65
71
|
end
|
66
72
|
end
|
67
73
|
|
68
|
-
# Return the final balance of the account as a
|
74
|
+
# Return the final balance of the account as a {Value}.
|
75
|
+
#
|
76
|
+
# @return [Value] The final balance of the account.
|
69
77
|
def final_balance
|
70
78
|
return Value.new(0) unless @balances.size > 0
|
71
79
|
@balances.last[:value]
|
72
80
|
end
|
73
81
|
|
74
|
-
# Return the balance of the account as of the date given as a
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
82
|
+
# Return the balance of the account as of the date given as a {Value}.
|
83
|
+
# Transactions that occur on the given date are included in the returned
|
84
|
+
# balance.
|
85
|
+
#
|
86
|
+
# @param date [String, Date] Date on which to query the balance.
|
87
|
+
#
|
88
|
+
# @return [Value] Balance of the account as of the date given.
|
78
89
|
def balance_on(date)
|
79
90
|
date = Date.parse(date) if date.is_a?(String)
|
80
91
|
return Value.new(0) unless @balances.size > 0
|
@@ -96,6 +107,7 @@ module Gnucash
|
|
96
107
|
|
97
108
|
private
|
98
109
|
|
110
|
+
# @return [String] Fully qualified account name.
|
99
111
|
def calculate_full_name
|
100
112
|
prefix = ""
|
101
113
|
if @parent_id
|
@@ -1,21 +1,23 @@
|
|
1
1
|
module Gnucash
|
2
2
|
# Class to link a transaction object to an Account.
|
3
3
|
class AccountTransaction
|
4
|
-
#
|
4
|
+
# @return [Value] The transaction value for the linked account.
|
5
5
|
attr_reader :value
|
6
6
|
|
7
7
|
# Construct an AccountTransaction object.
|
8
|
+
#
|
8
9
|
# This method is used internally when building a Transaction object.
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
10
|
+
#
|
11
|
+
# @param real_txn [Transaction]
|
12
|
+
# The linked Transaction object.
|
13
|
+
# @param value [Value]
|
12
14
|
# The value of the Transaction split for this account
|
13
15
|
def initialize(real_txn, value)
|
14
16
|
@real_txn = real_txn
|
15
17
|
@value = value
|
16
18
|
end
|
17
19
|
|
18
|
-
# Pass through any missing method calls to the linked Transaction object
|
20
|
+
# Pass through any missing method calls to the linked Transaction object.
|
19
21
|
def method_missing(*args)
|
20
22
|
@real_txn.send(*args)
|
21
23
|
end
|
data/lib/gnucash/book.rb
CHANGED
@@ -2,24 +2,27 @@ require "zlib"
|
|
2
2
|
require "nokogiri"
|
3
3
|
|
4
4
|
module Gnucash
|
5
|
-
# Represent a GnuCash Book
|
5
|
+
# Represent a GnuCash Book.
|
6
6
|
class Book
|
7
|
-
#
|
7
|
+
# @return [Array<Account>] Accounts in the book.
|
8
8
|
attr_reader :accounts
|
9
9
|
|
10
|
-
#
|
10
|
+
# @return [Array<Transaction>] Transactions in the book.
|
11
11
|
attr_reader :transactions
|
12
12
|
|
13
|
-
#
|
13
|
+
# @return [Date] Date of the first transaction in the book.
|
14
14
|
attr_reader :start_date
|
15
15
|
|
16
|
-
#
|
16
|
+
# @return [Date] Date of the last transaction in the book.
|
17
17
|
attr_reader :end_date
|
18
18
|
|
19
19
|
# Construct a Book object.
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
20
|
+
#
|
21
|
+
# Normally called internally by {Gnucash.open}.
|
22
|
+
#
|
23
|
+
# @param fname [String]
|
24
|
+
# The file name of the GnuCash file to open. Only XML format (or gzipped
|
25
|
+
# XML format) GnuCash data files are recognized.
|
23
26
|
def initialize(fname)
|
24
27
|
begin
|
25
28
|
@ng = Nokogiri.XML(Zlib::GzipReader.open(fname).read)
|
@@ -37,33 +40,35 @@ module Gnucash
|
|
37
40
|
end
|
38
41
|
|
39
42
|
# Return a handle to the Account object that has the given GUID.
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
43
|
+
#
|
44
|
+
# @param id [String] GUID.
|
45
|
+
#
|
46
|
+
# @return [Account, nil] Account object, or nil if not found.
|
44
47
|
def find_account_by_id(id)
|
45
48
|
@accounts.find { |a| a.id == id }
|
46
49
|
end
|
47
50
|
|
48
51
|
# Return a handle to the Account object that has the given fully-qualified
|
49
52
|
# name.
|
50
|
-
#
|
51
|
-
#
|
52
|
-
# Fully-qualified account name (ex: "Expenses::Auto::Gas")
|
53
|
-
#
|
54
|
-
#
|
53
|
+
#
|
54
|
+
# @param full_name [String]
|
55
|
+
# Fully-qualified account name (ex: "Expenses::Auto::Gas").
|
56
|
+
#
|
57
|
+
# @return [Account, nil] Account object, or nil if not found.
|
55
58
|
def find_account_by_full_name(full_name)
|
56
59
|
@accounts.find { |a| a.full_name == full_name }
|
57
60
|
end
|
58
61
|
|
59
62
|
private
|
60
63
|
|
64
|
+
# @return [void]
|
61
65
|
def build_accounts
|
62
66
|
@accounts = @book_node.xpath('gnc:account').map do |act_node|
|
63
67
|
Account.new(self, act_node)
|
64
68
|
end
|
65
69
|
end
|
66
70
|
|
71
|
+
# @return [void]
|
67
72
|
def build_transactions
|
68
73
|
@start_date = nil
|
69
74
|
@end_date = nil
|
@@ -75,6 +80,7 @@ module Gnucash
|
|
75
80
|
end
|
76
81
|
end
|
77
82
|
|
83
|
+
# @return [void]
|
78
84
|
def finalize
|
79
85
|
@accounts.sort! do |a, b|
|
80
86
|
a.full_name <=> b.full_name
|
data/lib/gnucash/transaction.rb
CHANGED
@@ -2,26 +2,27 @@ require "date"
|
|
2
2
|
|
3
3
|
module Gnucash
|
4
4
|
# Represent a GnuCash transaction.
|
5
|
+
#
|
5
6
|
# Transactions have multiple splits with individual values.
|
6
7
|
# Splits are created as AccountTransaction objects which are associated
|
7
8
|
# with an individual account.
|
8
9
|
class Transaction
|
9
|
-
#
|
10
|
+
# @return [Date] The date of the transaction.
|
10
11
|
attr_reader :date
|
11
12
|
|
12
|
-
#
|
13
|
+
# @return [String] The GUID of the transaction.
|
13
14
|
attr_reader :id
|
14
15
|
|
15
|
-
#
|
16
|
+
# @return [String] The description of the transaction.
|
16
17
|
attr_reader :description
|
17
18
|
|
18
|
-
#
|
19
|
+
# @return [Array<Hash>] Hashes with keys +:account+ and +:value+.
|
19
20
|
attr_reader :splits
|
20
21
|
|
21
|
-
# Create a new Transaction object
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
22
|
+
# Create a new Transaction object.
|
23
|
+
#
|
24
|
+
# @param book [Book] The {Gnucash::Book} containing the transaction.
|
25
|
+
# @param node [Nokogiri::XML::Node] Nokogiri XML node.
|
25
26
|
def initialize(book, node)
|
26
27
|
@book = book
|
27
28
|
@node = node
|
@@ -29,7 +30,10 @@ module Gnucash
|
|
29
30
|
@date = Date.parse(node.xpath('trn:date-posted/ts:date').text.split(' ').first)
|
30
31
|
@description = node.xpath('trn:description').text
|
31
32
|
@splits = node.xpath('trn:splits/trn:split').map do |split_node|
|
32
|
-
|
33
|
+
# Note: split:value represents the split value in the transaction's
|
34
|
+
# currency while split:quantity represents it in the currency
|
35
|
+
# associated with the account associated with this split.
|
36
|
+
value = Value.new(split_node.xpath('split:quantity').text)
|
33
37
|
account_id = split_node.xpath('split:account').text
|
34
38
|
account = @book.find_account_by_id(account_id)
|
35
39
|
unless account
|
data/lib/gnucash/value.rb
CHANGED
@@ -4,21 +4,23 @@ module Gnucash
|
|
4
4
|
class Value
|
5
5
|
include Comparable
|
6
6
|
|
7
|
-
#
|
7
|
+
# @return [Fixnum] The raw, undivided integer value.
|
8
8
|
attr_reader :val
|
9
9
|
|
10
|
-
# Create a new Value object with value 0
|
10
|
+
# Create a new Value object with value 0.
|
11
|
+
#
|
12
|
+
# @return [Value] Zero value.
|
11
13
|
def self.zero
|
12
14
|
Value.new(0)
|
13
15
|
end
|
14
16
|
|
15
|
-
# Construct a Value object
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# Either a
|
19
|
-
# raw value
|
20
|
-
#
|
21
|
-
# The divisor value to use (when +val+ is given as a
|
17
|
+
# Construct a Value object.
|
18
|
+
#
|
19
|
+
# @param val [String, Fixnum]
|
20
|
+
# Either a String in the form "1234/100" or an integer containing the
|
21
|
+
# raw value.
|
22
|
+
# @param div [Fixnum]
|
23
|
+
# The divisor value to use (when +val+ is given as a Fixnum).
|
22
24
|
def initialize(val, div = 100)
|
23
25
|
if val.is_a?(String)
|
24
26
|
if val =~ /^(-?\d+)\/(\d+)$/
|
@@ -35,8 +37,11 @@ module Gnucash
|
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
38
|
-
# Add to a Value object
|
39
|
-
#
|
40
|
+
# Add to a Value object.
|
41
|
+
#
|
42
|
+
# @param other [Value, Numeric]
|
43
|
+
#
|
44
|
+
# @return [Value] Result of addition.
|
40
45
|
def +(other)
|
41
46
|
if other.is_a?(Value)
|
42
47
|
Value.new(@val + other.val)
|
@@ -47,8 +52,11 @@ module Gnucash
|
|
47
52
|
end
|
48
53
|
end
|
49
54
|
|
50
|
-
# Subtract from a Value object
|
51
|
-
#
|
55
|
+
# Subtract from a Value object.
|
56
|
+
#
|
57
|
+
# @param other [Value, Numeric]
|
58
|
+
#
|
59
|
+
# @return [Value] Result of subtraction.
|
52
60
|
def -(other)
|
53
61
|
if other.is_a?(Value)
|
54
62
|
Value.new(@val - other.val)
|
@@ -59,13 +67,18 @@ module Gnucash
|
|
59
67
|
end
|
60
68
|
end
|
61
69
|
|
62
|
-
# Negate a Value
|
70
|
+
# Negate a Value.
|
71
|
+
#
|
72
|
+
# @return [Value] Result of negation.
|
63
73
|
def -@
|
64
74
|
Value.new(-@val, @div)
|
65
75
|
end
|
66
76
|
|
67
|
-
# Multiply a Value object
|
68
|
-
#
|
77
|
+
# Multiply a Value object.
|
78
|
+
#
|
79
|
+
# @param other [Numeric] Multiplier.
|
80
|
+
#
|
81
|
+
# @return [Value] Result of multiplication.
|
69
82
|
def *(other)
|
70
83
|
if other.is_a?(Numeric)
|
71
84
|
(to_f * other).round(2)
|
@@ -74,8 +87,11 @@ module Gnucash
|
|
74
87
|
end
|
75
88
|
end
|
76
89
|
|
77
|
-
# Divide a Value object
|
78
|
-
#
|
90
|
+
# Divide a Value object.
|
91
|
+
#
|
92
|
+
# @param other [Numeric] Divisor.
|
93
|
+
#
|
94
|
+
# @return [Value] Result of division.
|
79
95
|
def /(other)
|
80
96
|
if other.is_a?(Numeric)
|
81
97
|
(to_f / other).round(2)
|
@@ -84,17 +100,23 @@ module Gnucash
|
|
84
100
|
end
|
85
101
|
end
|
86
102
|
|
87
|
-
# Represent the Value as a string (two decimal places)
|
103
|
+
# Represent the Value as a string (two decimal places).
|
104
|
+
#
|
105
|
+
# @return [String] Representation of value.
|
88
106
|
def to_s
|
89
107
|
sprintf("%.02f", to_f)
|
90
108
|
end
|
91
109
|
|
92
|
-
# Convert the Value to a Float
|
110
|
+
# Convert the Value to a Float.
|
111
|
+
#
|
112
|
+
# @return [Float] Value of the value as a Float.
|
93
113
|
def to_f
|
94
114
|
@val / @div.to_f
|
95
115
|
end
|
96
116
|
|
97
|
-
# Compare two Value objects
|
117
|
+
# Compare two Value objects.
|
118
|
+
#
|
119
|
+
# @return [Integer] Comparison result.
|
98
120
|
def <=>(other)
|
99
121
|
@val <=> other.val
|
100
122
|
end
|
data/lib/gnucash/version.rb
CHANGED
@@ -10,44 +10,44 @@ module Gnucash
|
|
10
10
|
end
|
11
11
|
|
12
12
|
it "gives access to the account name" do
|
13
|
-
@salary.name.
|
13
|
+
expect(@salary.name).to eq "Salary"
|
14
14
|
end
|
15
15
|
|
16
16
|
it "gives access to the account description" do
|
17
|
-
@checking.description.
|
17
|
+
expect(@checking.description).to eq "Checking Account"
|
18
18
|
end
|
19
19
|
|
20
20
|
it "gives access to the fully-qualified account name" do
|
21
|
-
@checking.full_name.
|
21
|
+
expect(@checking.full_name).to eq "Assets:Current Assets:Checking Account"
|
22
22
|
end
|
23
23
|
|
24
24
|
it "gives access to the final balance" do
|
25
|
-
@checking.final_balance.
|
25
|
+
expect(@checking.final_balance).to eq Value.new(19743000)
|
26
26
|
end
|
27
27
|
|
28
28
|
describe '.balance_on' do
|
29
29
|
it "returns 0 if the given date is before the account's first transaction" do
|
30
|
-
@checking.balance_on("2006-12-12").
|
30
|
+
expect(@checking.balance_on("2006-12-12")).to eq Value.new(0)
|
31
31
|
end
|
32
32
|
|
33
33
|
it "returns the final balance if the given date is after the account's last transaction" do
|
34
|
-
@checking.balance_on("2013-10-10").
|
34
|
+
expect(@checking.balance_on("2013-10-10")).to eq @checking.final_balance
|
35
35
|
end
|
36
36
|
|
37
37
|
it "returns the balance on the given date" do
|
38
|
-
@checking.balance_on("2012-12-25").
|
38
|
+
expect(@checking.balance_on("2012-12-25")).to eq Value.new(19688000)
|
39
39
|
end
|
40
40
|
|
41
41
|
it "includes transactions that occur on the given date" do
|
42
|
-
@checking.balance_on("2007-03-27").
|
42
|
+
expect(@checking.balance_on("2007-03-27")).to eq Value.new(780000)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
46
|
it "stores whether the account was a placeholder" do
|
47
|
-
@assets.placeholder.
|
48
|
-
@checking.placeholder.
|
49
|
-
@income.placeholder.
|
50
|
-
@salary.placeholder.
|
47
|
+
expect(@assets.placeholder).to be_truthy
|
48
|
+
expect(@checking.placeholder).to be_falsey
|
49
|
+
expect(@income.placeholder).to be_truthy
|
50
|
+
expect(@salary.placeholder).to be_falsey
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
data/spec/gnucash/book_spec.rb
CHANGED
@@ -3,11 +3,11 @@ module Gnucash
|
|
3
3
|
context "with errors" do
|
4
4
|
it "raises an error for unexpected XML" do
|
5
5
|
gr = "gr"
|
6
|
-
Zlib::GzipReader.
|
7
|
-
gr.
|
6
|
+
expect(Zlib::GzipReader).to receive(:open).and_return(gr)
|
7
|
+
expect(gr).to receive(:read).and_return(nil)
|
8
8
|
ng = "ng"
|
9
|
-
Nokogiri.
|
10
|
-
ng.
|
9
|
+
expect(Nokogiri).to receive(:XML).and_return(ng)
|
10
|
+
expect(ng).to receive(:xpath).with('/gnc-v2/gnc:book').and_return([])
|
11
11
|
|
12
12
|
expect { Gnucash::Book.new('file name') }.to raise_error "Error: Expected to find one gnc:book entry"
|
13
13
|
end
|
@@ -20,19 +20,19 @@ module Gnucash
|
|
20
20
|
end
|
21
21
|
|
22
22
|
it "records the date of the earliest transaction" do
|
23
|
-
@subject.start_date.
|
23
|
+
expect(@subject.start_date).to eq Date.parse("2007-01-01")
|
24
24
|
end
|
25
25
|
|
26
26
|
it "records the date of the last transaction" do
|
27
|
-
@subject.end_date.
|
27
|
+
expect(@subject.end_date).to eq Date.parse("2012-12-28")
|
28
28
|
end
|
29
29
|
|
30
30
|
it "lets you find an account by id" do
|
31
|
-
@subject.find_account_by_id("67e6e7daadc35716eb6152769373e974").name.
|
31
|
+
expect(@subject.find_account_by_id("67e6e7daadc35716eb6152769373e974").name).to eq "Savings Account"
|
32
32
|
end
|
33
33
|
|
34
34
|
it "lets you find an account by full name" do
|
35
|
-
@subject.find_account_by_full_name("Assets:Current Assets:Savings Account").id.
|
35
|
+
expect(@subject.find_account_by_full_name("Assets:Current Assets:Savings Account").id).to eq "67e6e7daadc35716eb6152769373e974"
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -10,17 +10,17 @@ module Gnucash
|
|
10
10
|
account_text = "account_text"
|
11
11
|
date_text = "date_text"
|
12
12
|
|
13
|
-
text.
|
14
|
-
node.
|
15
|
-
date_text.
|
16
|
-
node.
|
17
|
-
value_text.
|
18
|
-
account_text.
|
19
|
-
split_node.
|
20
|
-
split_node.
|
21
|
-
node.
|
22
|
-
node.
|
23
|
-
book.
|
13
|
+
allow(text).to receive(:text) {"hi there"}
|
14
|
+
expect(node).to receive(:xpath).with('trn:id').and_return(text)
|
15
|
+
expect(date_text).to receive(:text).and_return("2014-01-20")
|
16
|
+
expect(node).to receive(:xpath).with('trn:date-posted/ts:date').and_return(date_text)
|
17
|
+
expect(value_text).to receive(:text).and_return("1177/100")
|
18
|
+
expect(account_text).to receive(:text).and_return("a1s2d3f4")
|
19
|
+
expect(split_node).to receive(:xpath).with("split:quantity").and_return(value_text)
|
20
|
+
expect(split_node).to receive(:xpath).with("split:account").and_return(account_text)
|
21
|
+
expect(node).to receive(:xpath).with('trn:description').and_return(text)
|
22
|
+
expect(node).to receive(:xpath).with('trn:splits/trn:split').and_return([split_node])
|
23
|
+
expect(book).to receive(:find_account_by_id).and_return(nil)
|
24
24
|
|
25
25
|
expect { Transaction.new(book, node) }.to raise_error /Could not find account/
|
26
26
|
end
|
@@ -33,7 +33,7 @@ module Gnucash
|
|
33
33
|
end
|
34
34
|
|
35
35
|
it "keeps track of the transaction description" do
|
36
|
-
@txn.description.
|
36
|
+
expect(@txn.description).to eq "Opening Balance"
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
data/spec/gnucash/value_spec.rb
CHANGED
@@ -2,7 +2,7 @@ module Gnucash
|
|
2
2
|
describe Value do
|
3
3
|
describe '.zero' do
|
4
4
|
it 'creates a Value object with value 0' do
|
5
|
-
Value.zero.val.
|
5
|
+
expect(Value.zero.val).to eq 0
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
@@ -15,70 +15,70 @@ module Gnucash
|
|
15
15
|
end
|
16
16
|
|
17
17
|
it "allows construction from a string" do
|
18
|
-
Value.new("5678/100").val.
|
18
|
+
expect(Value.new("5678/100").val).to eq 5678
|
19
19
|
end
|
20
20
|
|
21
21
|
it "converts the value to the expected string representation" do
|
22
|
-
Value.new("5678/100").to_s.
|
23
|
-
Value.new("1000231455/100").to_s.
|
22
|
+
expect(Value.new("5678/100").to_s).to eq "56.78"
|
23
|
+
expect(Value.new("1000231455/100").to_s).to eq "10002314.55"
|
24
24
|
end
|
25
25
|
|
26
26
|
it "allows adding two value objects" do
|
27
27
|
a = Value.new("1234/100")
|
28
28
|
b = Value.new("2345/100")
|
29
29
|
c = a + b
|
30
|
-
c.to_s.
|
30
|
+
expect(c.to_s).to eq "35.79"
|
31
31
|
end
|
32
32
|
|
33
33
|
it "allows adding a Value object to a Numeric" do
|
34
34
|
a = Value.new("1234/100")
|
35
35
|
b = 15
|
36
36
|
c = a + b
|
37
|
-
c.
|
37
|
+
expect(c).to eq 27.34
|
38
38
|
end
|
39
39
|
|
40
40
|
it "allows subtracting two value objects" do
|
41
41
|
a = Value.new("-12300/100")
|
42
42
|
b = Value.new("99/100")
|
43
43
|
c = a - b
|
44
|
-
c.to_s.
|
44
|
+
expect(c.to_s).to eq "-123.99"
|
45
45
|
end
|
46
46
|
|
47
47
|
it "allows subtracting a Numeric from a Value object" do
|
48
48
|
a = Value.new("890/100")
|
49
49
|
b = 7.8
|
50
50
|
c = a - b
|
51
|
-
c.
|
51
|
+
expect(c).to eq 1.1
|
52
52
|
end
|
53
53
|
|
54
54
|
it "allows negating a Value object" do
|
55
55
|
a = Value.new("123/100")
|
56
56
|
b = -a
|
57
|
-
b.to_s.
|
57
|
+
expect(b.to_s).to eq "-1.23"
|
58
58
|
end
|
59
59
|
|
60
60
|
it "allows multiplying a Value by a Numeric" do
|
61
61
|
a = Value.new("100/100")
|
62
62
|
b = 12
|
63
63
|
c = a * b
|
64
|
-
c.
|
64
|
+
expect(c).to eq 12.00
|
65
65
|
end
|
66
66
|
|
67
67
|
it "allows dividing a Value by a Numeric" do
|
68
68
|
a = Value.new("150000/100")
|
69
69
|
b = 150
|
70
70
|
c = a / b
|
71
|
-
c.
|
71
|
+
expect(c).to eq 10.0
|
72
72
|
end
|
73
73
|
|
74
74
|
it "formats the number with two decimal places" do
|
75
|
-
Value.new("1400/100").to_s.
|
75
|
+
expect(Value.new("1400/100").to_s).to eq "14.00"
|
76
76
|
end
|
77
77
|
|
78
78
|
it "supports comparisons between two Value objects" do
|
79
|
-
Value.new("1234/100").
|
80
|
-
(Value.new("89/100") < Value.new("100/100")).
|
81
|
-
(Value.new("1234/100") > Value.new("222/100")).
|
79
|
+
expect(Value.new("1234/100")).to eq Value.new(1234)
|
80
|
+
expect((Value.new("89/100") < Value.new("100/100"))).to be_truthy
|
81
|
+
expect((Value.new("1234/100") > Value.new("222/100"))).to be_truthy
|
82
82
|
end
|
83
83
|
|
84
84
|
context "errors" do
|
data/spec/gnucash_spec.rb
CHANGED
@@ -2,11 +2,11 @@ describe Gnucash do
|
|
2
2
|
describe '.open' do
|
3
3
|
it 'opens a gzipped gnucash book' do
|
4
4
|
book = Gnucash.open("spec/books/sample.gnucash")
|
5
|
-
book.is_a?(Gnucash::Book).
|
5
|
+
expect(book.is_a?(Gnucash::Book)).to be_truthy
|
6
6
|
end
|
7
7
|
it 'opens a plain text gnucash book' do
|
8
8
|
book = Gnucash.open("spec/books/sample-text.gnucash")
|
9
|
-
book.is_a?(Gnucash::Book).
|
9
|
+
expect(book.is_a?(Gnucash::Book)).to be_truthy
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
metadata
CHANGED
@@ -1,151 +1,110 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gnucash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Holtrop
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: simplecov
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: rspec-core
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ! '>='
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ! '>='
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: rspec-expectations
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ! '>='
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ! '>='
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rspec-mocks
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ! '>='
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ! '>='
|
52
|
+
- - ">="
|
95
53
|
- !ruby/object:Gem::Version
|
96
54
|
version: '0'
|
97
55
|
- !ruby/object:Gem::Dependency
|
98
56
|
name: rake
|
99
57
|
requirement: !ruby/object:Gem::Requirement
|
100
58
|
requirements:
|
101
|
-
- -
|
59
|
+
- - ">="
|
102
60
|
- !ruby/object:Gem::Version
|
103
61
|
version: '0'
|
104
62
|
type: :development
|
105
63
|
prerelease: false
|
106
64
|
version_requirements: !ruby/object:Gem::Requirement
|
107
65
|
requirements:
|
108
|
-
- -
|
66
|
+
- - ">="
|
109
67
|
- !ruby/object:Gem::Version
|
110
68
|
version: '0'
|
111
69
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
70
|
+
name: yard
|
113
71
|
requirement: !ruby/object:Gem::Requirement
|
114
72
|
requirements:
|
115
|
-
- -
|
73
|
+
- - ">="
|
116
74
|
- !ruby/object:Gem::Version
|
117
75
|
version: '0'
|
118
76
|
type: :development
|
119
77
|
prerelease: false
|
120
78
|
version_requirements: !ruby/object:Gem::Requirement
|
121
79
|
requirements:
|
122
|
-
- -
|
80
|
+
- - ">="
|
123
81
|
- !ruby/object:Gem::Version
|
124
82
|
version: '0'
|
125
83
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
84
|
+
name: rdoc
|
127
85
|
requirement: !ruby/object:Gem::Requirement
|
128
86
|
requirements:
|
129
|
-
- -
|
87
|
+
- - ">="
|
130
88
|
- !ruby/object:Gem::Version
|
131
89
|
version: '0'
|
132
90
|
type: :development
|
133
91
|
prerelease: false
|
134
92
|
version_requirements: !ruby/object:Gem::Requirement
|
135
93
|
requirements:
|
136
|
-
- -
|
94
|
+
- - ">="
|
137
95
|
- !ruby/object:Gem::Version
|
138
96
|
version: '0'
|
139
|
-
description: Ruby library for extracting data from GnuCash data files
|
97
|
+
description: Ruby library for extracting data from XML GnuCash data files
|
140
98
|
email:
|
141
99
|
- jholtrop@gmail.com
|
142
100
|
executables: []
|
143
101
|
extensions: []
|
144
102
|
extra_rdoc_files: []
|
145
103
|
files:
|
146
|
-
- .gitignore
|
147
|
-
- .rspec
|
104
|
+
- ".gitignore"
|
105
|
+
- ".rspec"
|
148
106
|
- Gemfile
|
107
|
+
- Gemfile.lock
|
149
108
|
- LICENSE.txt
|
150
109
|
- README.md
|
151
110
|
- Rakefile
|
@@ -175,20 +134,20 @@ require_paths:
|
|
175
134
|
- lib
|
176
135
|
required_ruby_version: !ruby/object:Gem::Requirement
|
177
136
|
requirements:
|
178
|
-
- -
|
137
|
+
- - ">="
|
179
138
|
- !ruby/object:Gem::Version
|
180
139
|
version: '0'
|
181
140
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
182
141
|
requirements:
|
183
|
-
- -
|
142
|
+
- - ">="
|
184
143
|
- !ruby/object:Gem::Version
|
185
144
|
version: '0'
|
186
145
|
requirements: []
|
187
146
|
rubyforge_project:
|
188
|
-
rubygems_version: 2.
|
147
|
+
rubygems_version: 2.6.12
|
189
148
|
signing_key:
|
190
149
|
specification_version: 4
|
191
|
-
summary: Extract data from GnuCash data files
|
150
|
+
summary: Extract data from XML GnuCash data files
|
192
151
|
test_files:
|
193
152
|
- spec/books/sample-text.gnucash
|
194
153
|
- spec/books/sample.gnucash
|
@@ -198,4 +157,3 @@ test_files:
|
|
198
157
|
- spec/gnucash/value_spec.rb
|
199
158
|
- spec/gnucash_spec.rb
|
200
159
|
- spec/spec_helper.rb
|
201
|
-
has_rdoc:
|