bean_sprout 0.0.1 → 0.0.2
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 +4 -4
- data/Rakefile +9 -0
- data/lib/bean_sprout.rb +10 -0
- data/lib/bean_sprout/account.rb +28 -0
- data/lib/bean_sprout/accounting_entry.rb +25 -0
- data/lib/bean_sprout/glass_jar.rb +100 -0
- data/lib/bean_sprout/struct_archive_mixin.rb +16 -0
- data/lib/bean_sprout/struct_from_hash_mixin.rb +14 -0
- data/lib/bean_sprout/transaction.rb +28 -0
- data/lib/bean_sprout/version.rb +1 -1
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c78c75ce139193f5d079d27d004b5753e929a359
|
4
|
+
data.tar.gz: bd2f0336d6869c9b207c6c202edd1eb2aa669fc6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52c30a7a443a6e54d3c532d8ad2df273cec319995688244ba78951bac657163856d021d795078339dd448fe503093e50718433aebd50f8372e1760c845eb5f02
|
7
|
+
data.tar.gz: e43fd99707829ccf80964f31b2c60d2052747645594623b20686ce2485e919802b40f6269a0b9d8aa3b77e40b0f2a7814ee5cfb9f4a42cf870012767ae210b7a
|
data/Rakefile
ADDED
data/lib/bean_sprout.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'bean_sprout/account'
|
2
|
+
require 'bean_sprout/accounting_entry'
|
3
|
+
require 'bean_sprout/glass_jar'
|
4
|
+
require 'bean_sprout/struct_archive_mixin'
|
5
|
+
require 'bean_sprout/struct_from_hash_mixin'
|
6
|
+
require 'bean_sprout/transaction'
|
7
|
+
require 'bean_sprout/version'
|
8
|
+
|
9
|
+
module BeanSprout
|
10
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'bean_sprout/struct_from_hash_mixin'
|
2
|
+
require 'bean_sprout/struct_archive_mixin'
|
3
|
+
|
4
|
+
module BeanSprout
|
5
|
+
class Account < Struct.new(:currency, :other_data)
|
6
|
+
include StructFromHashMixin
|
7
|
+
include StructArchiveMixin
|
8
|
+
|
9
|
+
def initialize *fields
|
10
|
+
super *fields
|
11
|
+
@entries = []
|
12
|
+
@balances = [0]
|
13
|
+
end
|
14
|
+
|
15
|
+
def append_entry entry
|
16
|
+
@entries.push entry
|
17
|
+
@balances.push balance + entry.accurate_amount
|
18
|
+
end
|
19
|
+
|
20
|
+
def entries
|
21
|
+
@entries.clone
|
22
|
+
end
|
23
|
+
|
24
|
+
def balance
|
25
|
+
@balances.last
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'bean_sprout/struct_from_hash_mixin'
|
2
|
+
require 'bean_sprout/struct_archive_mixin'
|
3
|
+
require 'bigdecimal'
|
4
|
+
require 'bigdecimal/util'
|
5
|
+
|
6
|
+
module BeanSprout
|
7
|
+
# AccountingEntry is made up of the following fields:
|
8
|
+
# 1. The account owns the entry, the currency of which is defined as the local
|
9
|
+
# currency;
|
10
|
+
# 2. The amount to be added to the account balance, in local currency;
|
11
|
+
# 3. Convention rate from local currency to the base currency;
|
12
|
+
# 4. Other arbitrary data.
|
13
|
+
class AccountingEntry < Struct.new(:account, :amount, :rate, :other_data)
|
14
|
+
include StructFromHashMixin
|
15
|
+
include StructArchiveMixin
|
16
|
+
|
17
|
+
def rate_or_one
|
18
|
+
rate or 1
|
19
|
+
end
|
20
|
+
|
21
|
+
def accurate_amount
|
22
|
+
@accurate_amount ||= amount.to_d
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module BeanSprout
|
2
|
+
class GlassJar
|
3
|
+
attr_reader :base_currency
|
4
|
+
|
5
|
+
def initialize base_currency
|
6
|
+
@base_currency = base_currency
|
7
|
+
|
8
|
+
@accounts = {}
|
9
|
+
@account_id = 0
|
10
|
+
|
11
|
+
@transactions = {}
|
12
|
+
@transaction_id = 0
|
13
|
+
|
14
|
+
@entries = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_account account
|
18
|
+
account.archive_in_glass_jar self, next_account_id
|
19
|
+
@accounts[account.id] = account
|
20
|
+
end
|
21
|
+
|
22
|
+
def accounts
|
23
|
+
@accounts.values
|
24
|
+
end
|
25
|
+
|
26
|
+
# External ID is not supported. Clients must implement
|
27
|
+
# external ID to internal ID mapping.
|
28
|
+
def account id
|
29
|
+
@accounts[id]
|
30
|
+
end
|
31
|
+
|
32
|
+
def transactions
|
33
|
+
@transactions.values
|
34
|
+
end
|
35
|
+
|
36
|
+
def transaction id
|
37
|
+
@transactions[id]
|
38
|
+
end
|
39
|
+
|
40
|
+
def entries
|
41
|
+
@entries.values
|
42
|
+
end
|
43
|
+
|
44
|
+
def entry id
|
45
|
+
@entries[id]
|
46
|
+
end
|
47
|
+
|
48
|
+
AccountEntitySizeBits = 30
|
49
|
+
def commit_transaction trans
|
50
|
+
raise "Creating transaction with no entries." if trans.entries.empty?
|
51
|
+
if trans.entries.size >= (1 << AccountEntitySizeBits)
|
52
|
+
raise "Creating transaction with too many entries."
|
53
|
+
end
|
54
|
+
|
55
|
+
# Validate trans status.
|
56
|
+
trans.entries.each do |entry|
|
57
|
+
valid_account! entry.account
|
58
|
+
valid_rate! entry
|
59
|
+
end
|
60
|
+
trans.balanced!
|
61
|
+
|
62
|
+
trans.archive_in_glass_jar self, next_transaction_id
|
63
|
+
trans.entries.each_with_index do |entry, index|
|
64
|
+
entry_id = (trans.id << AccountEntitySizeBits) + index
|
65
|
+
entry.archive_in_glass_jar self, entry_id
|
66
|
+
|
67
|
+
@entries[entry_id] = entry
|
68
|
+
account(entry.account).append_entry(entry)
|
69
|
+
end
|
70
|
+
@transactions[trans.id] = trans
|
71
|
+
end
|
72
|
+
|
73
|
+
def create_transaction *entries, other_data: nil
|
74
|
+
trans = Transaction.new(entries, other_data)
|
75
|
+
commit_transaction(trans)
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
def next_account_id
|
80
|
+
@account_id += 1
|
81
|
+
end
|
82
|
+
|
83
|
+
def next_transaction_id
|
84
|
+
@transaction_id += 1
|
85
|
+
end
|
86
|
+
|
87
|
+
def valid_account! account
|
88
|
+
if not @accounts.has_key? account
|
89
|
+
raise "Unkown account #{account} refered."
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def valid_rate! entry
|
94
|
+
if not (entry.rate or account(entry.account).currency == base_currency)
|
95
|
+
raise "Rate must be specified if entry is not in base currency " +
|
96
|
+
"#{base_currency}.\n Entry is #{entry}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module BeanSprout
|
2
|
+
module StructArchiveMixin
|
3
|
+
def self.included klass
|
4
|
+
klass.class_eval do
|
5
|
+
attr_reader :id
|
6
|
+
attr_reader :glass_jar
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def archive_in_glass_jar glass_jar, id
|
11
|
+
@glass_jar = glass_jar
|
12
|
+
@id = id
|
13
|
+
freeze
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'bean_sprout/struct_archive_mixin'
|
2
|
+
|
3
|
+
module BeanSprout
|
4
|
+
class Transaction < Struct.new(:entries, :other_data)
|
5
|
+
include StructArchiveMixin
|
6
|
+
|
7
|
+
alias entries_data entries
|
8
|
+
private :entries_data
|
9
|
+
|
10
|
+
public
|
11
|
+
def balanced?
|
12
|
+
balance = 0
|
13
|
+
entries_data.each do |entry|
|
14
|
+
balance += entry.accurate_amount / entry.rate_or_one
|
15
|
+
end
|
16
|
+
balance == 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def balanced!
|
20
|
+
raise "#{entries_data} is not balanced." unless balanced?
|
21
|
+
end
|
22
|
+
|
23
|
+
def entries
|
24
|
+
entries_data.clone
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
data/lib/bean_sprout/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bean_sprout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Liqing Muyi
|
@@ -60,8 +60,16 @@ extra_rdoc_files: []
|
|
60
60
|
files:
|
61
61
|
- Gemfile
|
62
62
|
- MIT-LICENSE
|
63
|
+
- Rakefile
|
64
|
+
- lib/bean_sprout.rb
|
65
|
+
- lib/bean_sprout/account.rb
|
66
|
+
- lib/bean_sprout/accounting_entry.rb
|
67
|
+
- lib/bean_sprout/glass_jar.rb
|
68
|
+
- lib/bean_sprout/struct_archive_mixin.rb
|
69
|
+
- lib/bean_sprout/struct_from_hash_mixin.rb
|
70
|
+
- lib/bean_sprout/transaction.rb
|
63
71
|
- lib/bean_sprout/version.rb
|
64
|
-
homepage: http://github.com/muyiliqing/
|
72
|
+
homepage: http://github.com/muyiliqing/bean_sprout
|
65
73
|
licenses:
|
66
74
|
- MIT
|
67
75
|
metadata: {}
|