subledger 0.7.7
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.
- data/.gitignore +9 -0
- data/LICENSE.txt +12 -0
- data/README.md +136 -0
- data/Rakefile +5 -0
- data/bin/subledger +6 -0
- data/lib/subledger/actor.rb +32 -0
- data/lib/subledger/collection_name.rb +25 -0
- data/lib/subledger/domain/account.rb +168 -0
- data/lib/subledger/domain/balance.rb +102 -0
- data/lib/subledger/domain/book.rb +111 -0
- data/lib/subledger/domain/category.rb +157 -0
- data/lib/subledger/domain/control.rb +180 -0
- data/lib/subledger/domain/formatters.rb +31 -0
- data/lib/subledger/domain/identity.rb +159 -0
- data/lib/subledger/domain/journal_entry.rb +293 -0
- data/lib/subledger/domain/key.rb +113 -0
- data/lib/subledger/domain/line.rb +272 -0
- data/lib/subledger/domain/org.rb +110 -0
- data/lib/subledger/domain/report.rb +247 -0
- data/lib/subledger/domain/report_rendering.rb +233 -0
- data/lib/subledger/domain/roles/activatable.rb +11 -0
- data/lib/subledger/domain/roles/archivable.rb +11 -0
- data/lib/subledger/domain/roles/attributable.rb +14 -0
- data/lib/subledger/domain/roles/collectable.rb +175 -0
- data/lib/subledger/domain/roles/creatable.rb +58 -0
- data/lib/subledger/domain/roles/describable.rb +33 -0
- data/lib/subledger/domain/roles/describable_report_rendering.rb +50 -0
- data/lib/subledger/domain/roles/identifiable.rb +15 -0
- data/lib/subledger/domain/roles/postable.rb +54 -0
- data/lib/subledger/domain/roles/progressable.rb +11 -0
- data/lib/subledger/domain/roles/readable.rb +34 -0
- data/lib/subledger/domain/roles/restable.rb +69 -0
- data/lib/subledger/domain/roles/storable.rb +30 -0
- data/lib/subledger/domain/roles/timeable.rb +18 -0
- data/lib/subledger/domain/roles/updatable.rb +35 -0
- data/lib/subledger/domain/roles/versionable.rb +35 -0
- data/lib/subledger/domain/roles.rb +16 -0
- data/lib/subledger/domain/value/credit.rb +16 -0
- data/lib/subledger/domain/value/debit.rb +16 -0
- data/lib/subledger/domain/value/zero.rb +24 -0
- data/lib/subledger/domain/value.rb +111 -0
- data/lib/subledger/domain.rb +95 -0
- data/lib/subledger/exception_handler.rb +65 -0
- data/lib/subledger/interface/client.rb +295 -0
- data/lib/subledger/interface/dispatcher.rb +20 -0
- data/lib/subledger/interface.rb +2 -0
- data/lib/subledger/path.rb +106 -0
- data/lib/subledger/rest.rb +128 -0
- data/lib/subledger/server.rb +3 -0
- data/lib/subledger/store/api/errors.rb +95 -0
- data/lib/subledger/store/api/roles/activate.rb +21 -0
- data/lib/subledger/store/api/roles/archive.rb +21 -0
- data/lib/subledger/store/api/roles/balance.rb +39 -0
- data/lib/subledger/store/api/roles/categories.rb +51 -0
- data/lib/subledger/store/api/roles/collect.rb +58 -0
- data/lib/subledger/store/api/roles/create.rb +26 -0
- data/lib/subledger/store/api/roles/create_and_post.rb +35 -0
- data/lib/subledger/store/api/roles/create_identity.rb +39 -0
- data/lib/subledger/store/api/roles/create_line.rb +24 -0
- data/lib/subledger/store/api/roles/first_and_last_line.rb +31 -0
- data/lib/subledger/store/api/roles/post.rb +25 -0
- data/lib/subledger/store/api/roles/progress.rb +21 -0
- data/lib/subledger/store/api/roles/read.rb +19 -0
- data/lib/subledger/store/api/roles/reports.rb +77 -0
- data/lib/subledger/store/api/roles/update.rb +24 -0
- data/lib/subledger/store/api/store.rb +103 -0
- data/lib/subledger/store/api.rb +20 -0
- data/lib/subledger/store.rb +236 -0
- data/lib/subledger/supervisor.rb +21 -0
- data/lib/subledger/uuid.rb +52 -0
- data/lib/subledger/version.rb +4 -0
- data/lib/subledger.rb +234 -0
- data/spec/spec_helper.rb +77 -0
- data/spec/subledger_account_spec.rb +354 -0
- data/spec/subledger_book_spec.rb +130 -0
- data/spec/subledger_category_spec.rb +203 -0
- data/spec/subledger_control_spec.rb +43 -0
- data/spec/subledger_identity_spec.rb +47 -0
- data/spec/subledger_journal_entry_spec.rb +417 -0
- data/spec/subledger_key_spec.rb +43 -0
- data/spec/subledger_org_spec.rb +68 -0
- data/spec/subledger_report_spec.rb +295 -0
- data/spec/subledger_spec.rb +101 -0
- data/subledger.gemspec +52 -0
- metadata +205 -0
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            module Subledger
         | 
| 2 | 
            +
              module Domain
         | 
| 3 | 
            +
                class Zero
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                  include Value
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  def self.type
         | 
| 8 | 
            +
                    'zero'
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def rest_hash
         | 
| 12 | 
            +
                    { 'type' => 'zero', 'amount' => amount_to_s(@amount) }
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  private
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def validate_sign arg_amount
         | 
| 18 | 
            +
                    unless arg_amount.zero?
         | 
| 19 | 
            +
                      raise ValueError, 'Amount must be zero'
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
            end
         | 
| @@ -0,0 +1,111 @@ | |
| 1 | 
            +
            # additional requires at bottom
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Subledger
         | 
| 4 | 
            +
              module Domain
         | 
| 5 | 
            +
                class ValueError < Error; end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                module Value
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def self.included base
         | 
| 10 | 
            +
                    base.extend ValueClass
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  module ValueClass
         | 
| 14 | 
            +
                    def raise_unless_creatable args
         | 
| 15 | 
            +
                      value = args[:value]
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                      if value.nil? or not value.kind_of? Value
         | 
| 18 | 
            +
                        raise ValueError, ':value is required and must be a Value'
         | 
| 19 | 
            +
                      end
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  attr_reader :amount
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  def initialize arg_amount=0
         | 
| 26 | 
            +
                    if arg_amount.nil?
         | 
| 27 | 
            +
                      raise ValueError, 'amount may not be nil'
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    validate_amount(arg_amount) if arg_amount.respond_to?(:match)
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    big_amount = BigDecimal arg_amount
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                    validate_sign big_amount
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                    validate_amount( amount_to_s big_amount )
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                    @amount = big_amount
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  def + other
         | 
| 42 | 
            +
                    (Balance.new + value + other.value).value
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  def == other
         | 
| 46 | 
            +
                    self.value.class == other.value.class and amount == other.amount
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  def value
         | 
| 50 | 
            +
                    self
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  def to_s
         | 
| 54 | 
            +
                    "#{self.class.type}: #{amount_to_s @amount}"
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  alias :inspect :to_s
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  private
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  def amount_to_s arg_amount
         | 
| 62 | 
            +
                    if arg_amount.zero?
         | 
| 63 | 
            +
                      '0'
         | 
| 64 | 
            +
                    else
         | 
| 65 | 
            +
                      arg_amount.to_s( 'F' ).chomp( '.0' ).sub( /^0+/, '' )
         | 
| 66 | 
            +
                    end
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  def validate_sign arg_amount
         | 
| 70 | 
            +
                    unless arg_amount > 0
         | 
| 71 | 
            +
                      raise ValueError, 'amount must be positive'
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  ERROR_TEXT = 'amount is limited to 15 whole digits and 12 fractional digits'
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                  def validate_amount arg_amount
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                    unless arg_amount.match /^\d*[.]?\d*$/
         | 
| 80 | 
            +
                      raise ValueError, "amount (#{arg_amount}) must be numeric"
         | 
| 81 | 
            +
                    end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                    return if BigDecimal(arg_amount).zero?
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                    arg_amount.sub! /^0+/, ''
         | 
| 86 | 
            +
                    arg_amount.sub! /[.](\d)*0+$/, '.\\1'
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                    if arg_amount.include? '.'
         | 
| 89 | 
            +
                      whole, fraction = arg_amount.split '.'
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                      whole    ||= ''
         | 
| 92 | 
            +
                      fraction ||= ''
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                      if whole.length > 15 or fraction.length > 12
         | 
| 95 | 
            +
                        raise ValueError, ERROR_TEXT
         | 
| 96 | 
            +
                      end
         | 
| 97 | 
            +
                    else
         | 
| 98 | 
            +
                      if arg_amount.length > 15
         | 
| 99 | 
            +
                        raise ValueError, ERROR_TEXT
         | 
| 100 | 
            +
                      end
         | 
| 101 | 
            +
                    end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                  end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
              end
         | 
| 107 | 
            +
            end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            require 'subledger/domain/value/credit'
         | 
| 110 | 
            +
            require 'subledger/domain/value/debit'
         | 
| 111 | 
            +
            require 'subledger/domain/value/zero'
         | 
| @@ -0,0 +1,95 @@ | |
| 1 | 
            +
            require 'bcrypt'
         | 
| 2 | 
            +
            require 'grape-entity'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            # additional requires at bottom
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Subledger
         | 
| 7 | 
            +
              module Domain
         | 
| 8 | 
            +
                class ActivatableError                < Error; end
         | 
| 9 | 
            +
                class ArchivableError                 < Error; end
         | 
| 10 | 
            +
                class AttributableError               < Error; end
         | 
| 11 | 
            +
                class CollectableError                < Error; end
         | 
| 12 | 
            +
                class CreatableError                  < Error; end
         | 
| 13 | 
            +
                class DescribableError                < Error; end
         | 
| 14 | 
            +
                class DescribableReportRenderingError < Error; end
         | 
| 15 | 
            +
                class IdentifiableError               < Error; end
         | 
| 16 | 
            +
                class PostableError                   < Error; end
         | 
| 17 | 
            +
                class ProgressableError               < Error; end
         | 
| 18 | 
            +
                class ReadableError                   < Error; end
         | 
| 19 | 
            +
                class RestableError                   < Error; end
         | 
| 20 | 
            +
                class StorableError                   < Error; end
         | 
| 21 | 
            +
                class TimeableError                   < Error; end
         | 
| 22 | 
            +
                class UpdatableError                  < Error; end
         | 
| 23 | 
            +
                class VersionableError                < Error; end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def self.included base
         | 
| 26 | 
            +
                  base.extend DomainClass
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                module DomainClass
         | 
| 30 | 
            +
                  def keys
         | 
| 31 | 
            +
                    self::Entity.exposures.keys
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  def entity_name
         | 
| 35 | 
            +
                    self::Entity.instance_variable_get( :@root ).to_sym
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def collection_name
         | 
| 39 | 
            +
                    self::Entity.instance_variable_get( :@collection_root ).to_sym
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  def raise_unless_creatable args
         | 
| 43 | 
            +
                    raise NoMethodError, 'subclasses must provide self.raise_unless_creatable'
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def == other
         | 
| 48 | 
            +
                  if respond_to?( :id )       and
         | 
| 49 | 
            +
                     other.respond_to?( :id ) and
         | 
| 50 | 
            +
                     ( ( not id.nil? ) and ( not other.id.nil? ) )
         | 
| 51 | 
            +
                    id == other.id
         | 
| 52 | 
            +
                  else
         | 
| 53 | 
            +
                    super
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                def collection_name
         | 
| 58 | 
            +
                  self.class.collection_name
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                def entity_name
         | 
| 62 | 
            +
                  self.class.entity_name
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                def to_s
         | 
| 66 | 
            +
                  "#{entity_name}: #{ MultiJson.dump serializable_hash }"
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                alias :inspect :to_s
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                private
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                def short_klass_name
         | 
| 74 | 
            +
                  self.class.name.match( /[^:]+$/ )[0] + ': '
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
            end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            require 'subledger/domain/formatters'
         | 
| 80 | 
            +
            require 'subledger/domain/roles'
         | 
| 81 | 
            +
             | 
| 82 | 
            +
            require 'subledger/domain/value'
         | 
| 83 | 
            +
             | 
| 84 | 
            +
            require 'subledger/domain/account'
         | 
| 85 | 
            +
            require 'subledger/domain/balance'
         | 
| 86 | 
            +
            require 'subledger/domain/book'
         | 
| 87 | 
            +
            require 'subledger/domain/category'
         | 
| 88 | 
            +
            require 'subledger/domain/control'
         | 
| 89 | 
            +
            require 'subledger/domain/identity'
         | 
| 90 | 
            +
            require 'subledger/domain/journal_entry'
         | 
| 91 | 
            +
            require 'subledger/domain/key'
         | 
| 92 | 
            +
            require 'subledger/domain/line'
         | 
| 93 | 
            +
            require 'subledger/domain/org'
         | 
| 94 | 
            +
            require 'subledger/domain/report'
         | 
| 95 | 
            +
            require 'subledger/domain/report_rendering'
         | 
| @@ -0,0 +1,65 @@ | |
| 1 | 
            +
            module Subledger
         | 
| 2 | 
            +
              class ExceptionHandler
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                # attempts   seconds
         | 
| 5 | 
            +
                #        1      no point!
         | 
| 6 | 
            +
                #        2      0.15+
         | 
| 7 | 
            +
                #        3      0.35+
         | 
| 8 | 
            +
                #        4      0.75+
         | 
| 9 | 
            +
                #        5      1.55+
         | 
| 10 | 
            +
                #        6      3.15+
         | 
| 11 | 
            +
                #        7      6.35+
         | 
| 12 | 
            +
                #        8     12.75+
         | 
| 13 | 
            +
                #        9     25.55+ default max_attempts
         | 
| 14 | 
            +
                #       10     51.15
         | 
| 15 | 
            +
                #
         | 
| 16 | 
            +
                # attempts 11 and up are 2 seconds apart
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def initialize args
         | 
| 19 | 
            +
                  @name          = args[:name]
         | 
| 20 | 
            +
                  @exception     = args[:exception]     || Exception
         | 
| 21 | 
            +
                  @max_attempts  = args[:max_attempts]  || 10
         | 
| 22 | 
            +
                  @initial_delay = args[:initial_delay] || 0
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def with_retry
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  attempts = 1
         | 
| 28 | 
            +
                  total    = 0
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  sleep @initial_delay
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  begin
         | 
| 33 | 
            +
                    yield
         | 
| 34 | 
            +
                  rescue @exception => e
         | 
| 35 | 
            +
                    if is_internal?( e ) or ( attempts >= @max_attempts )
         | 
| 36 | 
            +
                      raise e, "FAILURE: #{@name}, attempts: #{attempts}, total: #{total}, #{e}"
         | 
| 37 | 
            +
                    elsif attempts < @max_attempts
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                      if attempts < 11
         | 
| 40 | 
            +
                        delay = 2 ** attempts * 0.05
         | 
| 41 | 
            +
                      else
         | 
| 42 | 
            +
                        delay += 2
         | 
| 43 | 
            +
                      end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                      if attempts > 8
         | 
| 46 | 
            +
                        LOG.warn "RETRY: #{@name}, attempts: #{attempts}, delay: #{delay}, #{e}"
         | 
| 47 | 
            +
                      end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                      sleep delay
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                      total    += delay
         | 
| 52 | 
            +
                      attempts += 1
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                      retry
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                private
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                def is_internal? e
         | 
| 62 | 
            +
                  e.class.name.to_s =~ /^Subledger::/
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
            end
         | 
| @@ -0,0 +1,295 @@ | |
| 1 | 
            +
            module Subledger
         | 
| 2 | 
            +
              module Interface
         | 
| 3 | 
            +
                class ClientError < Error; end
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                class Client
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  private
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  attr_reader :client_args
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  COLLECTIONS = { :identity                    => { :klass           => Domain::Identity,
         | 
| 12 | 
            +
                                                                    :root_collection => :identities,
         | 
| 13 | 
            +
                                                                    :state           => :active },
         | 
| 14 | 
            +
                                  :identities                  => { :klass           => Domain::Identity,
         | 
| 15 | 
            +
                                                                    :root_collection => :identities,
         | 
| 16 | 
            +
                                                                    :state           => :active },
         | 
| 17 | 
            +
                                  :archived_identity           => { :klass           => Domain::ArchivedIdentity,
         | 
| 18 | 
            +
                                                                    :root_collection => :identities,
         | 
| 19 | 
            +
                                                                    :state           => :archived },
         | 
| 20 | 
            +
                                  :archived_identities         => { :klass           => Domain::ArchivedIdentity,
         | 
| 21 | 
            +
                                                                    :root_collection => :identities,
         | 
| 22 | 
            +
                                                                    :state           => :archived },
         | 
| 23 | 
            +
                                  :active_identity             => { :klass           => Domain::ActiveIdentity,
         | 
| 24 | 
            +
                                                                    :root_collection => :identities,
         | 
| 25 | 
            +
                                                                    :state           => :active },
         | 
| 26 | 
            +
                                  :active_identities           => { :klass           => Domain::ActiveIdentity,
         | 
| 27 | 
            +
                                                                    :root_collection => :identities,
         | 
| 28 | 
            +
                                                                    :state           => :active },
         | 
| 29 | 
            +
                                  :key                         => { :klass           => Domain::Key,
         | 
| 30 | 
            +
                                                                    :root_collection => :keys,
         | 
| 31 | 
            +
                                                                    :state           => :active },
         | 
| 32 | 
            +
                                  :keys                        => { :klass           => Domain::Key,
         | 
| 33 | 
            +
                                                                    :root_collection => :keys,
         | 
| 34 | 
            +
                                                                    :state           => :active },
         | 
| 35 | 
            +
                                  :archived_key                => { :klass           => Domain::ArchivedKey,
         | 
| 36 | 
            +
                                                                    :root_collection => :keys,
         | 
| 37 | 
            +
                                                                    :state           => :archived },
         | 
| 38 | 
            +
                                  :archived_keys               => { :klass           => Domain::ArchivedKey,
         | 
| 39 | 
            +
                                                                    :root_collection => :keys,
         | 
| 40 | 
            +
                                                                    :state           => :archived },
         | 
| 41 | 
            +
                                  :active_key                  => { :klass           => Domain::ActiveKey,
         | 
| 42 | 
            +
                                                                    :root_collection => :keys,
         | 
| 43 | 
            +
                                                                    :state           => :active },
         | 
| 44 | 
            +
                                  :active_keys                 => { :klass           => Domain::ActiveKey,
         | 
| 45 | 
            +
                                                                    :root_collection => :keys,
         | 
| 46 | 
            +
                                                                    :state           => :active },
         | 
| 47 | 
            +
                                  :control                     => { :klass           => Domain::Control,
         | 
| 48 | 
            +
                                                                    :root_collection => :controls,
         | 
| 49 | 
            +
                                                                    :state           => :active },
         | 
| 50 | 
            +
                                  :controls                    => { :klass           => Domain::Control,
         | 
| 51 | 
            +
                                                                    :root_collection => :controls,
         | 
| 52 | 
            +
                                                                    :state           => :active },
         | 
| 53 | 
            +
                                  :archived_control            => { :klass           => Domain::ArchivedControl,
         | 
| 54 | 
            +
                                                                    :root_collection => :controls,
         | 
| 55 | 
            +
                                                                    :state           => :archived },
         | 
| 56 | 
            +
                                  :archived_controls           => { :klass           => Domain::ArchivedControl,
         | 
| 57 | 
            +
                                                                    :root_collection => :controls,
         | 
| 58 | 
            +
                                                                    :state           => :archived },
         | 
| 59 | 
            +
                                  :active_control              => { :klass           => Domain::ActiveControl,
         | 
| 60 | 
            +
                                                                    :root_collection => :controls,
         | 
| 61 | 
            +
                                                                    :state           => :active },
         | 
| 62 | 
            +
                                  :active_controls             => { :klass           => Domain::ActiveControl,
         | 
| 63 | 
            +
                                                                    :root_collection => :controls,
         | 
| 64 | 
            +
                                                                    :state           => :active },
         | 
| 65 | 
            +
                                  :org                         => { :klass           => Domain::Org,
         | 
| 66 | 
            +
                                                                    :root_collection => :orgs,
         | 
| 67 | 
            +
                                                                    :state           => :active },
         | 
| 68 | 
            +
                                  :orgs                        => { :klass           => Domain::Org,
         | 
| 69 | 
            +
                                                                    :root_collection => :orgs,
         | 
| 70 | 
            +
                                                                    :state           => :active },
         | 
| 71 | 
            +
                                  :archived_org                => { :klass           => Domain::ArchivedOrg,
         | 
| 72 | 
            +
                                                                    :root_collection => :orgs,
         | 
| 73 | 
            +
                                                                    :state           => :archived },
         | 
| 74 | 
            +
                                  :archived_orgs               => { :klass           => Domain::ArchivedOrg,
         | 
| 75 | 
            +
                                                                    :root_collection => :orgs,
         | 
| 76 | 
            +
                                                                    :state           => :archived },
         | 
| 77 | 
            +
                                  :active_org                  => { :klass           => Domain::ActiveOrg,
         | 
| 78 | 
            +
                                                                    :root_collection => :orgs,
         | 
| 79 | 
            +
                                                                    :state           => :active },
         | 
| 80 | 
            +
                                  :active_orgs                 => { :klass           => Domain::ActiveOrg,
         | 
| 81 | 
            +
                                                                    :root_collection => :orgs,
         | 
| 82 | 
            +
                                                                    :state           => :active },
         | 
| 83 | 
            +
                                  :book                        => { :klass           => Domain::Book,
         | 
| 84 | 
            +
                                                                    :root_collection => :books,
         | 
| 85 | 
            +
                                                                    :state           => :active },
         | 
| 86 | 
            +
                                  :books                       => { :klass           => Domain::Book,
         | 
| 87 | 
            +
                                                                    :root_collection => :books,
         | 
| 88 | 
            +
                                                                    :state           => :active },
         | 
| 89 | 
            +
                                  :archived_book               => { :klass           => Domain::ArchivedBook,
         | 
| 90 | 
            +
                                                                    :root_collection => :books,
         | 
| 91 | 
            +
                                                                    :state           => :archived },
         | 
| 92 | 
            +
                                  :archived_books              => { :klass           => Domain::ArchivedBook,
         | 
| 93 | 
            +
                                                                    :root_collection => :books,
         | 
| 94 | 
            +
                                                                    :state           => :archived },
         | 
| 95 | 
            +
                                  :active_book                 => { :klass           => Domain::ActiveBook,
         | 
| 96 | 
            +
                                                                    :root_collection => :books,
         | 
| 97 | 
            +
                                                                    :state           => :active },
         | 
| 98 | 
            +
                                  :active_books                => { :klass           => Domain::ActiveBook,
         | 
| 99 | 
            +
                                                                    :root_collection => :books,
         | 
| 100 | 
            +
                                                                    :state           => :active },
         | 
| 101 | 
            +
                                  :account                     => { :klass           => Domain::Account,
         | 
| 102 | 
            +
                                                                    :root_collection => :accounts,
         | 
| 103 | 
            +
                                                                    :state           => :active },
         | 
| 104 | 
            +
                                  :accounts                    => { :klass           => Domain::Account,
         | 
| 105 | 
            +
                                                                    :root_collection => :accounts,
         | 
| 106 | 
            +
                                                                    :state           => :active },
         | 
| 107 | 
            +
                                  :archived_account            => { :klass           => Domain::ArchivedAccount,
         | 
| 108 | 
            +
                                                                    :root_collection => :accounts,
         | 
| 109 | 
            +
                                                                    :state           => :archived },
         | 
| 110 | 
            +
                                  :archived_accounts           => { :klass           => Domain::ArchivedAccount,
         | 
| 111 | 
            +
                                                                    :root_collection => :accounts,
         | 
| 112 | 
            +
                                                                    :state           => :archived },
         | 
| 113 | 
            +
                                  :active_account              => { :klass           => Domain::ActiveAccount,
         | 
| 114 | 
            +
                                                                    :root_collection => :accounts,
         | 
| 115 | 
            +
                                                                    :state           => :active },
         | 
| 116 | 
            +
                                  :active_accounts             => { :klass           => Domain::ActiveAccount,
         | 
| 117 | 
            +
                                                                    :root_collection => :accounts,
         | 
| 118 | 
            +
                                                                    :state           => :active },
         | 
| 119 | 
            +
                                  :category_accounts           => { :klass           => Domain::Account,
         | 
| 120 | 
            +
                                                                    :root_collection => :category_accounts,
         | 
| 121 | 
            +
                                                                    :state           => :nil },
         | 
| 122 | 
            +
                                  :journal_entry               => { :klass           => Domain::JournalEntry,
         | 
| 123 | 
            +
                                                                    :root_collection => :journal_entries,
         | 
| 124 | 
            +
                                                                    :state           => :active },
         | 
| 125 | 
            +
                                  :journal_entries             => { :klass           => Domain::JournalEntry,
         | 
| 126 | 
            +
                                                                    :root_collection => :journal_entries,
         | 
| 127 | 
            +
                                                                    :state           => :active },
         | 
| 128 | 
            +
                                  :archived_journal_entry      => { :klass           => Domain::ArchivedJournalEntry,
         | 
| 129 | 
            +
                                                                    :root_collection => :journal_entries,
         | 
| 130 | 
            +
                                                                    :state           => :archived },
         | 
| 131 | 
            +
                                  :archived_journal_entries    => { :klass           => Domain::ArchivedJournalEntry,
         | 
| 132 | 
            +
                                                                    :root_collection => :journal_entries,
         | 
| 133 | 
            +
                                                                    :state           => :archived },
         | 
| 134 | 
            +
                                  :active_journal_entry        => { :klass           => Domain::ActiveJournalEntry,
         | 
| 135 | 
            +
                                                                    :root_collection => :journal_entries,
         | 
| 136 | 
            +
                                                                    :state           => :active },
         | 
| 137 | 
            +
                                  :active_journal_entries      => { :klass           => Domain::ActiveJournalEntry,
         | 
| 138 | 
            +
                                                                    :root_collection => :journal_entries,
         | 
| 139 | 
            +
                                                                    :state           => :active },
         | 
| 140 | 
            +
                                  :posting_journal_entry       => { :klass           => Domain::PostingJournalEntry,
         | 
| 141 | 
            +
                                                                    :root_collection => :journal_entries,
         | 
| 142 | 
            +
                                                                    :state           => :posting },
         | 
| 143 | 
            +
                                  :posting_journal_entries     => { :klass           => Domain::PostingJournalEntry,
         | 
| 144 | 
            +
                                                                    :root_collection => :journal_entries,
         | 
| 145 | 
            +
                                                                    :state           => :posting },
         | 
| 146 | 
            +
                                  :posted_journal_entry        => { :klass           => Domain::PostedJournalEntry,
         | 
| 147 | 
            +
                                                                    :root_collection => :journal_entries,
         | 
| 148 | 
            +
                                                                    :state           => :posted },
         | 
| 149 | 
            +
                                  :posted_journal_entries      => { :klass           => Domain::PostedJournalEntry,
         | 
| 150 | 
            +
                                                                    :root_collection => :journal_entries,
         | 
| 151 | 
            +
                                                                    :state           => :posted },
         | 
| 152 | 
            +
                                  :line                        => { :klass           => Domain::Line,
         | 
| 153 | 
            +
                                                                    :root_collection => :lines,
         | 
| 154 | 
            +
                                                                    :state           => :active },
         | 
| 155 | 
            +
                                  :lines                       => { :klass           => Domain::Line,
         | 
| 156 | 
            +
                                                                    :root_collection => :lines,
         | 
| 157 | 
            +
                                                                    :state           => :active },
         | 
| 158 | 
            +
                                  :archived_line               => { :klass           => Domain::ArchivedLine,
         | 
| 159 | 
            +
                                                                    :root_collection => :lines,
         | 
| 160 | 
            +
                                                                    :state           => :archived },
         | 
| 161 | 
            +
                                  :archived_lines              => { :klass           => Domain::ArchivedLine,
         | 
| 162 | 
            +
                                                                    :root_collection => :lines,
         | 
| 163 | 
            +
                                                                    :state           => :archived },
         | 
| 164 | 
            +
                                  :active_line                 => { :klass           => Domain::ActiveLine,
         | 
| 165 | 
            +
                                                                    :root_collection => :lines,
         | 
| 166 | 
            +
                                                                    :state           => :active },
         | 
| 167 | 
            +
                                  :active_lines                => { :klass           => Domain::ActiveLine,
         | 
| 168 | 
            +
                                                                    :root_collection => :lines,
         | 
| 169 | 
            +
                                                                    :state           => :active },
         | 
| 170 | 
            +
                                  :posted_line                 => { :klass           => Domain::PostedLine,
         | 
| 171 | 
            +
                                                                    :root_collection => :lines,
         | 
| 172 | 
            +
                                                                    :state           => :posted },
         | 
| 173 | 
            +
                                  :posted_lines                => { :klass           => Domain::PostedLine,
         | 
| 174 | 
            +
                                                                    :root_collection => :lines,
         | 
| 175 | 
            +
                                                                    :state           => :posted },
         | 
| 176 | 
            +
                                  :account_line                => { :klass           => Domain::PostedLine,
         | 
| 177 | 
            +
                                                                    :root_collection => :account_lines,
         | 
| 178 | 
            +
                                                                    :state           => :nil },
         | 
| 179 | 
            +
                                  :account_lines               => { :klass           => Domain::PostedLine,
         | 
| 180 | 
            +
                                                                    :root_collection => :account_lines,
         | 
| 181 | 
            +
                                                                    :state           => :nil },
         | 
| 182 | 
            +
                                  :category                    => { :klass           => Domain::Category,
         | 
| 183 | 
            +
                                                                    :root_collection => :categories,
         | 
| 184 | 
            +
                                                                    :state           => :active },
         | 
| 185 | 
            +
                                  :categories                  => { :klass           => Domain::Category,
         | 
| 186 | 
            +
                                                                    :root_collection => :categories,
         | 
| 187 | 
            +
                                                                    :state           => :active },
         | 
| 188 | 
            +
                                  :archived_category           => { :klass           => Domain::ArchivedCategory,
         | 
| 189 | 
            +
                                                                    :root_collection => :categories,
         | 
| 190 | 
            +
                                                                    :state           => :archived },
         | 
| 191 | 
            +
                                  :archived_categories         => { :klass           => Domain::ArchivedCategory,
         | 
| 192 | 
            +
                                                                    :root_collection => :categories,
         | 
| 193 | 
            +
                                                                    :state           => :archived },
         | 
| 194 | 
            +
                                  :active_category             => { :klass           => Domain::ActiveCategory,
         | 
| 195 | 
            +
                                                                    :root_collection => :categories,
         | 
| 196 | 
            +
                                                                    :state           => :active },
         | 
| 197 | 
            +
                                  :active_categories           => { :klass           => Domain::ActiveCategory,
         | 
| 198 | 
            +
                                                                    :root_collection => :categories,
         | 
| 199 | 
            +
                                                                    :state           => :active },
         | 
| 200 | 
            +
                                  :report_categories           => { :klass           => Domain::Category,
         | 
| 201 | 
            +
                                                                    :root_collection => :report_categories,
         | 
| 202 | 
            +
                                                                    :state           => :nil },
         | 
| 203 | 
            +
                                  :report                      => { :klass           => Domain::Report,
         | 
| 204 | 
            +
                                                                    :root_collection => :reports,
         | 
| 205 | 
            +
                                                                    :state           => :active },
         | 
| 206 | 
            +
                                  :reports                     => { :klass           => Domain::Report,
         | 
| 207 | 
            +
                                                                    :root_collection => :reports,
         | 
| 208 | 
            +
                                                                    :state           => :active },
         | 
| 209 | 
            +
                                  :archived_report             => { :klass           => Domain::ArchivedReport,
         | 
| 210 | 
            +
                                                                    :root_collection => :reports,
         | 
| 211 | 
            +
                                                                    :state           => :archived },
         | 
| 212 | 
            +
                                  :archived_reports            => { :klass           => Domain::ArchivedReport,
         | 
| 213 | 
            +
                                                                    :root_collection => :reports,
         | 
| 214 | 
            +
                                                                    :state           => :archived },
         | 
| 215 | 
            +
                                  :active_report               => { :klass           => Domain::ActiveReport,
         | 
| 216 | 
            +
                                                                    :root_collection => :reports,
         | 
| 217 | 
            +
                                                                    :state           => :active },
         | 
| 218 | 
            +
                                  :active_reports              => { :klass           => Domain::ActiveReport,
         | 
| 219 | 
            +
                                                                    :root_collection => :reports,
         | 
| 220 | 
            +
                                                                    :state           => :active },
         | 
| 221 | 
            +
                                  :report_rendering            => { :klass           => Domain::ReportRendering,
         | 
| 222 | 
            +
                                                                    :root_collection => :report_renderings,
         | 
| 223 | 
            +
                                                                    :state           => :building },
         | 
| 224 | 
            +
                                  :report_renderings           => { :klass           => Domain::ReportRendering,
         | 
| 225 | 
            +
                                                                    :root_collection => :report_renderings,
         | 
| 226 | 
            +
                                                                    :state           => :building },
         | 
| 227 | 
            +
                                  :building_report_rendering   => { :klass           => Domain::BuildingReportRendering,
         | 
| 228 | 
            +
                                                                    :root_collection => :report_renderings,
         | 
| 229 | 
            +
                                                                    :state           => :building },
         | 
| 230 | 
            +
                                  :building_report_renderings  => { :klass           => Domain::BuildingReportRendering,
         | 
| 231 | 
            +
                                                                    :root_collection => :report_renderings,
         | 
| 232 | 
            +
                                                                    :state           => :building },
         | 
| 233 | 
            +
                                  :completed_report_rendering  => { :klass           => Domain::CompletedReportRendering,
         | 
| 234 | 
            +
                                                                    :root_collection => :report_renderings,
         | 
| 235 | 
            +
                                                                    :state           => :completed },
         | 
| 236 | 
            +
                                  :completed_report_renderings => { :klass           => Domain::CompletedReportRendering,
         | 
| 237 | 
            +
                                                                    :root_collection => :report_renderings,
         | 
| 238 | 
            +
                                                                    :state           => :completed }
         | 
| 239 | 
            +
                  }
         | 
| 240 | 
            +
             | 
| 241 | 
            +
                  public
         | 
| 242 | 
            +
             | 
| 243 | 
            +
                  attr_reader :store
         | 
| 244 | 
            +
             | 
| 245 | 
            +
                  def initialize args
         | 
| 246 | 
            +
                    @client_args = args
         | 
| 247 | 
            +
             | 
| 248 | 
            +
                    # TODO client should not have @store and #store
         | 
| 249 | 
            +
             | 
| 250 | 
            +
                    @store = args[:store]
         | 
| 251 | 
            +
                  end
         | 
| 252 | 
            +
             | 
| 253 | 
            +
                  COLLECTIONS.each do |name, attributes|
         | 
| 254 | 
            +
                    klass           = attributes[:klass]
         | 
| 255 | 
            +
                    state           = attributes[:state] == :nil ? 'nil' : attributes[:state].inspect
         | 
| 256 | 
            +
                    root_collection = attributes[:root_collection]
         | 
| 257 | 
            +
             | 
| 258 | 
            +
                    method_text = <<-"EOM"
         | 
| 259 | 
            +
                      def #{name} *args
         | 
| 260 | 
            +
                        @#{name}_dispatcher ||= Dispatcher.new @client_args.
         | 
| 261 | 
            +
                                                                 merge(
         | 
| 262 | 
            +
                                                                   { :klass           => #{klass},
         | 
| 263 | 
            +
                                                                     :client          => self,
         | 
| 264 | 
            +
                                                                     :state           => #{state},
         | 
| 265 | 
            +
                                                                     :root_collection => :#{root_collection} } )
         | 
| 266 | 
            +
             | 
| 267 | 
            +
                        if args.empty?
         | 
| 268 | 
            +
                          @#{name}_dispatcher
         | 
| 269 | 
            +
                        else
         | 
| 270 | 
            +
                          @#{name}_dispatcher.new args.first.dup
         | 
| 271 | 
            +
                        end
         | 
| 272 | 
            +
                      end
         | 
| 273 | 
            +
                    EOM
         | 
| 274 | 
            +
             | 
| 275 | 
            +
                    class_eval method_text
         | 
| 276 | 
            +
                  end
         | 
| 277 | 
            +
             | 
| 278 | 
            +
                  def debit *args
         | 
| 279 | 
            +
                    args.empty? ? Domain::Debit  : Domain::Debit.new( *args )
         | 
| 280 | 
            +
                  end
         | 
| 281 | 
            +
             | 
| 282 | 
            +
                  def credit *args
         | 
| 283 | 
            +
                    args.empty? ? Domain::Credit : Domain::Credit.new( *args )
         | 
| 284 | 
            +
                  end
         | 
| 285 | 
            +
             | 
| 286 | 
            +
                  def zero *args
         | 
| 287 | 
            +
                    Domain::Zero.new
         | 
| 288 | 
            +
                  end
         | 
| 289 | 
            +
             | 
| 290 | 
            +
                  def balance *args
         | 
| 291 | 
            +
                    Domain::Balance.new *args
         | 
| 292 | 
            +
                  end
         | 
| 293 | 
            +
                end
         | 
| 294 | 
            +
              end
         | 
| 295 | 
            +
            end
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            module Subledger
         | 
| 2 | 
            +
              module Interface
         | 
| 3 | 
            +
                class Dispatcher
         | 
| 4 | 
            +
                  def initialize args
         | 
| 5 | 
            +
                    @klass  = args[:klass]
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                    @dispatch_args = args
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def method_missing method, args, &block
         | 
| 11 | 
            +
                    args.delete :store
         | 
| 12 | 
            +
                    args.delete :client
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                    merged_args = @dispatch_args.merge args
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                    @klass.send method, merged_args, &block
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         |