event_sourced_accounting 0.1.4 → 0.1.6

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: 90b7c29e9bf0e521aa32cdbeffad3aae4e3d9087
4
- data.tar.gz: 8c527303a6d14bfde792881745ca58db57d3c237
3
+ metadata.gz: d898cf40cfd5525402b244a8ebde093e0e9948fa
4
+ data.tar.gz: 4a925d9356d3aeee2a08790ad1b2ea28838dfc9c
5
5
  SHA512:
6
- metadata.gz: e5a2550c5b782488edd4332acae07da7d206bee352c5d25aefc9175deed45295fd03fb065bdebc77d4f3a0124a03dd81250d3b7b799b40ae34bf8acc7cc868b7
7
- data.tar.gz: a8f097694820cf6b0b9f9f228894df5fd393545fc18b8cabcc42a58b75fa7f968913f43f2642e200ca84ae31e1266685769e2a00bbf9c6f550640b151822710d
6
+ metadata.gz: 6e6c5f2d437c040f89af829811cc5b0f92b9da413c03a380479c03b6c9f2089d4ad7d7ea424833ea99a53be8f1eb112a8b6bbcd11bbd7ab3969a8f7951c4c740
7
+ data.tar.gz: 4d4c47371255499bcda065a9c78213a09a3ccb983388058057d4fa4db9fb60812a3e03a0686feac878b4024c527df1ea8308d95cb82a67b124b26e09a8be3d26
@@ -30,6 +30,9 @@ module ESA
30
30
  scope :roots, lambda { where(parent_id: nil) }
31
31
  scope :subs, lambda { where("esa_contexts.parent_id is not null") }
32
32
 
33
+ scope :fresh, lambda { where("`esa_contexts`.`freshness` > ?", ESA.configuration.context_freshness_threshold.ago) }
34
+ scope :stale, lambda { where("`esa_contexts`.`freshness` IS NULL OR `esa_contexts`.`freshness` <= ?", ESA.configuration.context_freshness_threshold.ago) }
35
+
33
36
  def is_root?
34
37
  self.parent_id.nil?
35
38
  end
@@ -68,6 +71,10 @@ module ESA
68
71
  end
69
72
  end
70
73
 
74
+ def is_fresh?(time=Time.zone.now)
75
+ self.freshness.present? and (self.freshness + ESA.configuration.context_freshness_threshold) > time
76
+ end
77
+
71
78
  def check_freshness(depth=0)
72
79
  if self.is_update_needed?
73
80
  self.update!
@@ -99,7 +106,7 @@ module ESA
99
106
  def update!
100
107
  self.freshness = Time.zone.now
101
108
 
102
- Config.context_checkers.each do |checker|
109
+ ESA.configuration.context_checkers.each do |checker|
103
110
  if checker.respond_to? :check
104
111
  checker.check(self)
105
112
  end
@@ -8,6 +8,8 @@ module ESA
8
8
  has_many :esa_flags, :as => :accountable, :class_name => ESA::Flag.extension_name(self), :extend => ESA::Associations::FlagsExtension
9
9
  has_many :esa_transactions, :as => :accountable, :class_name => ESA::Transaction.extension_name(self), :extend => ESA::Associations::TransactionsExtension
10
10
 
11
+ before_destroy :destroy_accountable
12
+
11
13
  def esa_ruleset
12
14
  ESA::Ruleset.extension_instance(self)
13
15
  end
@@ -15,6 +17,15 @@ module ESA
15
17
  def esa_chart
16
18
  self.esa_ruleset.chart
17
19
  end
20
+
21
+ def destroy_accountable
22
+ if self.esa_transactions.blank?
23
+ self.esa_flags.delete_all
24
+ self.esa_events.delete_all
25
+ else
26
+ false
27
+ end
28
+ end
18
29
  end
19
30
  end
20
31
  end
data/lib/esa.rb CHANGED
@@ -52,7 +52,7 @@ require 'esa/filters/context_filter'
52
52
  require 'esa/filters/date_time_filter'
53
53
  require 'esa/filters/timestamp_filter'
54
54
 
55
- require 'esa/config'
55
+ require 'esa/configuration'
56
56
 
57
57
  module ESA
58
58
  class Engine < Rails::Engine
@@ -0,0 +1,89 @@
1
+ module ESA
2
+ class << self
3
+ attr_accessor :configuration
4
+ end
5
+
6
+ def self.configure
7
+ self.configuration ||= Configuration.new
8
+ yield(configuration)
9
+ end
10
+
11
+ class Configuration
12
+ attr_accessor :base_classes
13
+ attr_accessor :extension_namespace
14
+ attr_accessor :processor
15
+ attr_accessor :context_checkers
16
+ attr_accessor :context_freshness_threshold
17
+ attr_accessor :context_providers
18
+ attr_accessor :context_tree
19
+
20
+ def initialize
21
+ @base_classes = [ESA::Ruleset, ESA::Event, ESA::Flag, ESA::Transaction].freeze
22
+
23
+ @extension_namespace = "Accounting"
24
+
25
+ @processor = ESA::BlockingProcessor
26
+
27
+ @context_checkers = Set.new
28
+ @context_checkers << ESA::BalanceChecker
29
+ @context_checkers << ESA::SubcontextChecker
30
+
31
+ @context_freshness_threshold = 15.minutes
32
+
33
+ @context_providers = {
34
+ 'account' => ESA::ContextProviders::AccountContextProvider,
35
+ 'accountable' => ESA::ContextProviders::AccountableContextProvider,
36
+ 'accountable_type' => ESA::ContextProviders::AccountableTypeContextProvider,
37
+ 'monthly' => [ESA::ContextProviders::DateContextProvider, {period: :month}],
38
+ 'daily' => [ESA::ContextProviders::DateContextProvider, {period: :day}],
39
+ }
40
+
41
+ @context_tree = {
42
+ 'account' => {
43
+ 'monthly' => {
44
+ 'daily' => {},
45
+ },
46
+ },
47
+ 'monthly' => {
48
+ 'account' => {
49
+ 'daily' => {},
50
+ },
51
+ },
52
+ 'daily' => {
53
+ 'account' => {},
54
+ },
55
+ }
56
+ end
57
+
58
+ def register(accountable, short_name=nil)
59
+ accountable_name = accountable.to_s
60
+ extension_name = short_name || accountable_name.demodulize
61
+
62
+ @base_classes.each do |klass|
63
+ klass.register_extension(accountable_name, self.extension_class(klass.name.demodulize, extension_name))
64
+ end
65
+ end
66
+
67
+ def extension_class(extension_type, extension_name)
68
+ [
69
+ @extension_namespace.presence,
70
+ "#{extension_type}s",
71
+ "#{extension_name}#{extension_type}"
72
+ ].compact.join('::')
73
+ end
74
+
75
+ def walk_context_tree(path=[], tree=@context_tree)
76
+ if path.respond_to? :count and path.count == 0
77
+ tree || {}
78
+ elsif path.respond_to? :first and tree.is_a? Hash and path.first.in? tree
79
+ self.walk_context_tree(path.drop(1), tree[path.first])
80
+ else
81
+ {}
82
+ end
83
+ end
84
+
85
+ def context_providers_for_path(path=[])
86
+ @context_providers.slice(*self.walk_context_tree(path).keys)
87
+ end
88
+ end
89
+ end
@@ -10,7 +10,7 @@ module ESA
10
10
  end
11
11
 
12
12
  def self.contained_ids(context, options = {})
13
- context.amounts.pluck(:account_id).uniq
13
+ context.amounts.uniq.pluck(:account_id)
14
14
  end
15
15
 
16
16
  def self.instantiate(parent, namespace, id, options = {})
@@ -10,7 +10,7 @@ module ESA
10
10
  end
11
11
 
12
12
  def self.contained_ids(context, options = {})
13
- context.transactions.pluck([:accountable_id, :accountable_type]).uniq
13
+ context.transactions.uniq.pluck([:accountable_id, :accountable_type])
14
14
  end
15
15
 
16
16
  def self.instantiate(parent, namespace, id, options = {})
@@ -10,7 +10,7 @@ module ESA
10
10
  end
11
11
 
12
12
  def self.contained_ids(context, options = {})
13
- context.transactions.pluck(:accountable_type).uniq
13
+ context.transactions.uniq.pluck(:accountable_type)
14
14
  end
15
15
 
16
16
  def self.instantiate(parent, namespace, id, options = {})
@@ -10,7 +10,7 @@ module ESA
10
10
  end
11
11
 
12
12
  def self.contained_ids(context, options = {})
13
- dates = context.transactions.pluck("date(esa_transactions.time)").uniq.sort
13
+ dates = context.transactions.uniq.pluck("date(esa_transactions.time)").sort
14
14
 
15
15
  if options[:period].present? and options[:period] == :month
16
16
  dates.group_by{|d| [d.year, d.month]}.keys.
@@ -1,7 +1,7 @@
1
1
  module ESA
2
2
  class SubcontextChecker
3
3
  def self.check(context)
4
- ESA::Config.context_providers_for_path(context.effective_path).each do |namespace,provider|
4
+ ESA.configuration.context_providers_for_path(context.effective_path).each do |namespace,provider|
5
5
  if provider.is_a? Class and provider.respond_to? :check_subcontexts
6
6
  provider.check_subcontexts(context, namespace)
7
7
  elsif provider.respond_to? :count and provider.count == 2 and
data/lib/esa/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ESA
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.6"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: event_sourced_accounting
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lenno Nagel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-16 00:00:00.000000000 Z
11
+ date: 2014-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -234,9 +234,9 @@ files:
234
234
  - lib/esa/context_providers/date_context_provider.rb
235
235
  - lib/esa/context_providers/accountable_context_provider.rb
236
236
  - lib/esa/context_providers/accountable_type_context_provider.rb
237
- - lib/esa/config.rb
238
237
  - lib/esa/context_provider.rb
239
238
  - lib/esa/balance_checker.rb
239
+ - lib/esa/configuration.rb
240
240
  - lib/esa/blocking_processor.rb
241
241
  - lib/esa/filters/chart_filter.rb
242
242
  - lib/esa/filters/accountable_type_filter.rb
data/lib/esa/config.rb DELETED
@@ -1,51 +0,0 @@
1
- module ESA
2
- module Config
3
- mattr_accessor :processor
4
- self.processor = ESA::BlockingProcessor
5
-
6
- mattr_accessor :context_checkers
7
- self.context_checkers = Set.new
8
- self.context_checkers << ESA::BalanceChecker
9
- self.context_checkers << ESA::SubcontextChecker
10
-
11
- mattr_accessor :context_providers
12
- self.context_providers = {
13
- 'account' => ESA::ContextProviders::AccountContextProvider,
14
- 'accountable' => ESA::ContextProviders::AccountableContextProvider,
15
- 'accountable_type' => ESA::ContextProviders::AccountableTypeContextProvider,
16
- 'monthly' => [ESA::ContextProviders::DateContextProvider, {period: :month}],
17
- 'daily' => [ESA::ContextProviders::DateContextProvider, {period: :day}],
18
- }
19
-
20
- mattr_accessor :context_tree
21
- self.context_tree = {
22
- 'account' => {
23
- 'monthly' => {
24
- 'daily' => {},
25
- },
26
- },
27
- 'monthly' => {
28
- 'account' => {
29
- 'daily' => {},
30
- },
31
- },
32
- 'daily' => {
33
- 'account' => {},
34
- },
35
- }
36
-
37
- def self.walk_context_tree(path=[], tree=self.context_tree)
38
- if path.respond_to? :count and path.count == 0
39
- tree || {}
40
- elsif path.respond_to? :first and tree.is_a? Hash and path.first.in? tree
41
- walk_context_tree(path.drop(1), tree[path.first])
42
- else
43
- {}
44
- end
45
- end
46
-
47
- def self.context_providers_for_path(path=[])
48
- context_providers.slice(*walk_context_tree(path).keys)
49
- end
50
- end
51
- end