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 +4 -4
- data/app/models/esa/context.rb +8 -1
- data/app/models/esa/traits/accountable.rb +11 -0
- data/lib/esa.rb +1 -1
- data/lib/esa/configuration.rb +89 -0
- data/lib/esa/context_providers/account_context_provider.rb +1 -1
- data/lib/esa/context_providers/accountable_context_provider.rb +1 -1
- data/lib/esa/context_providers/accountable_type_context_provider.rb +1 -1
- data/lib/esa/context_providers/date_context_provider.rb +1 -1
- data/lib/esa/subcontext_checker.rb +1 -1
- data/lib/esa/version.rb +1 -1
- metadata +3 -3
- data/lib/esa/config.rb +0 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d898cf40cfd5525402b244a8ebde093e0e9948fa
|
4
|
+
data.tar.gz: 4a925d9356d3aeee2a08790ad1b2ea28838dfc9c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e6c5f2d437c040f89af829811cc5b0f92b9da413c03a380479c03b6c9f2089d4ad7d7ea424833ea99a53be8f1eb112a8b6bbcd11bbd7ab3969a8f7951c4c740
|
7
|
+
data.tar.gz: 4d4c47371255499bcda065a9c78213a09a3ccb983388058057d4fa4db9fb60812a3e03a0686feac878b4024c527df1ea8308d95cb82a67b124b26e09a8be3d26
|
data/app/models/esa/context.rb
CHANGED
@@ -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
|
-
|
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
@@ -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.transactions.pluck([:accountable_id, :accountable_type])
|
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
|
-
dates = context.transactions.pluck("date(esa_transactions.time)").
|
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
|
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
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
|
+
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-
|
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
|