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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ad556a445c248234bf3b69666980b4eb813be8b2
4
- data.tar.gz: 4f7b1207e40e413aa6c3b8731e5763dde0583a1c
3
+ metadata.gz: c78c75ce139193f5d079d27d004b5753e929a359
4
+ data.tar.gz: bd2f0336d6869c9b207c6c202edd1eb2aa669fc6
5
5
  SHA512:
6
- metadata.gz: 3794701939adf78a543a6c81bce53e8b06e46219e522688d5b10e4a7f8de8e9d083e50bdb3425a4a8d49f290186bfc277fe1df100b769bdfc2e5d3d4a514c7fb
7
- data.tar.gz: 2130fa37267176c0a9928ccf8f8027b8f74fbb25ffb17abf12445e03fcaeb2163222225ceaa81a81fda029e50e08cf72e624df8d90ff2a61b26fa05bd62621db
6
+ metadata.gz: 52c30a7a443a6e54d3c532d8ad2df273cec319995688244ba78951bac657163856d021d795078339dd448fe503093e50718433aebd50f8372e1760c845eb5f02
7
+ data.tar.gz: e43fd99707829ccf80964f31b2c60d2052747645594623b20686ce2485e919802b40f6269a0b9d8aa3b77e40b0f2a7814ee5cfb9f4a42cf870012767ae210b7a
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ t.pattern = 'test/**/*_test.rb'
6
+ end
7
+
8
+ desc "Run tests"
9
+ task :default => :test
@@ -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,14 @@
1
+ module BeanSprout
2
+ module StructFromHashMixin
3
+ def self.included klass
4
+ klass.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def from_hash hash
9
+ new(*hash.values_at(*members))
10
+ end
11
+ end
12
+ end
13
+ end
14
+
@@ -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
+
@@ -1,3 +1,3 @@
1
1
  module BeanSprout
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
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.1
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/feidee_utils
72
+ homepage: http://github.com/muyiliqing/bean_sprout
65
73
  licenses:
66
74
  - MIT
67
75
  metadata: {}