event_sourced_accounting 0.1.4 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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