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,157 @@
|
|
1
|
+
module Subledger
|
2
|
+
module Domain
|
3
|
+
class CategoryError < Error; end
|
4
|
+
|
5
|
+
class Category
|
6
|
+
|
7
|
+
include Domain
|
8
|
+
|
9
|
+
include Roles::Attributable
|
10
|
+
include Roles::Describable
|
11
|
+
include Roles::Identifiable
|
12
|
+
include Roles::Storable
|
13
|
+
include Roles::Versionable
|
14
|
+
|
15
|
+
include Roles::Creatable
|
16
|
+
include Roles::Readable
|
17
|
+
include Roles::Updatable
|
18
|
+
|
19
|
+
include Roles::Collectable
|
20
|
+
|
21
|
+
include Roles::Activatable
|
22
|
+
include Roles::Archivable
|
23
|
+
|
24
|
+
include Roles::Restable
|
25
|
+
|
26
|
+
attr_reader :book
|
27
|
+
attr_accessor :normal_balance
|
28
|
+
|
29
|
+
def self.post_keys
|
30
|
+
[ :description, :reference, :normal_balance ]
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.patch_keys
|
34
|
+
[ :id, :description, :reference, :normal_balance, :version ]
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.root_klass
|
38
|
+
Category
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.sub_klasses
|
42
|
+
[ active_klass, archived_klass ]
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.active_klass
|
46
|
+
ActiveCategory
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.archived_klass
|
50
|
+
ArchivedCategory
|
51
|
+
end
|
52
|
+
|
53
|
+
def initialize args
|
54
|
+
describable args
|
55
|
+
identifiable args
|
56
|
+
storable args
|
57
|
+
versionable args
|
58
|
+
|
59
|
+
@book = args[:book]
|
60
|
+
@normal_balance = args[:normal_balance]
|
61
|
+
end
|
62
|
+
|
63
|
+
def accounts &block
|
64
|
+
begin
|
65
|
+
store.collect_accounts_for_category self, &block
|
66
|
+
rescue Store::CollectError => e
|
67
|
+
raise CategoryError, e
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class Entity < Grape::Entity
|
72
|
+
root 'categories', 'category'
|
73
|
+
|
74
|
+
expose :id, :documentation => { :type => 'string', :desc => 'category ID' }
|
75
|
+
|
76
|
+
expose :book, :format_with => :id,
|
77
|
+
:documentation => { :type => 'string', :desc => 'book ID' }
|
78
|
+
|
79
|
+
expose :description, :documentation => { :type => 'string', :desc => 'description' }
|
80
|
+
|
81
|
+
expose :reference, :documentation => { :type => 'string', :desc => 'reference URI' }
|
82
|
+
|
83
|
+
expose :normal_balance, :format_with => :normal_balance,
|
84
|
+
:documentation => { :type => 'string', :desc => 'normal balance type' }
|
85
|
+
|
86
|
+
expose :version, :documentation => { :type => 'integer', :desc => 'version' }
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
ACCEPTABLE_NORMAL_BALANCES = [ Debit, Credit ]
|
92
|
+
|
93
|
+
def self.raise_unless_creatable args
|
94
|
+
|
95
|
+
book = args[:book]
|
96
|
+
|
97
|
+
if book.nil? or not book.kind_of? Book
|
98
|
+
raise CategoryError, ':book is required and must be a Book'
|
99
|
+
elsif UUID.invalid? book.id
|
100
|
+
raise CategoryError, ':book must have a valid :id'
|
101
|
+
end
|
102
|
+
|
103
|
+
normal_balance = args[:normal_balance]
|
104
|
+
|
105
|
+
if normal_balance.nil? or not ACCEPTABLE_NORMAL_BALANCES.include? normal_balance
|
106
|
+
raise CategoryError, ":normal_balance is required and must be one of #{ACCEPTABLE_NORMAL_BALANCES.join(', ')}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class ArchivedCategory < Category
|
112
|
+
class Entity < Category::Entity
|
113
|
+
root 'archived_categories', 'archived_category'
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.sub_klasses
|
117
|
+
[ archived_klass ]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class ActiveCategory < Category
|
122
|
+
class Entity < Category::Entity
|
123
|
+
root 'active_categories', 'active_category'
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.sub_klasses
|
127
|
+
[ active_klass ]
|
128
|
+
end
|
129
|
+
|
130
|
+
def attach args
|
131
|
+
account = args[:account]
|
132
|
+
|
133
|
+
begin
|
134
|
+
store.attach_account_to_category :category => self,
|
135
|
+
:account => account
|
136
|
+
rescue Store::AttachError => e
|
137
|
+
raise CategoryError, e
|
138
|
+
end
|
139
|
+
|
140
|
+
account
|
141
|
+
end
|
142
|
+
|
143
|
+
def detach args
|
144
|
+
account = args[:account]
|
145
|
+
|
146
|
+
begin
|
147
|
+
store.detach_account_from_category :category => self,
|
148
|
+
:account => account
|
149
|
+
rescue Store::DetachError => e
|
150
|
+
raise CategoryError, e
|
151
|
+
end
|
152
|
+
|
153
|
+
account
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
module Subledger
|
2
|
+
module Domain
|
3
|
+
class ControlError < Error; end
|
4
|
+
|
5
|
+
class Control
|
6
|
+
|
7
|
+
include Domain
|
8
|
+
|
9
|
+
include Roles::Attributable
|
10
|
+
include Roles::Identifiable
|
11
|
+
include Roles::Storable
|
12
|
+
include Roles::Creatable
|
13
|
+
include Roles::Readable
|
14
|
+
include Roles::Collectable
|
15
|
+
include Roles::Activatable
|
16
|
+
include Roles::Archivable
|
17
|
+
include Roles::Restable
|
18
|
+
|
19
|
+
attr_reader :identity, :verbs, :path, :mode
|
20
|
+
|
21
|
+
def self.root_klass
|
22
|
+
Control
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.post_keys
|
26
|
+
[ :id, :identity, :verbs, :path, :mode ]
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.patch_keys
|
30
|
+
[ ]
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.sub_klasses
|
34
|
+
[ active_klass, archived_klass ]
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.active_klass
|
38
|
+
ActiveControl
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.archived_klass
|
42
|
+
ArchivedControl
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize args
|
46
|
+
identifiable args
|
47
|
+
storable args
|
48
|
+
|
49
|
+
@identity = args[:identity]
|
50
|
+
@verbs = args[:verbs]
|
51
|
+
@path = args[:path]
|
52
|
+
@mode = args[:mode]
|
53
|
+
end
|
54
|
+
|
55
|
+
# def revoke
|
56
|
+
# @revoked = true
|
57
|
+
#
|
58
|
+
# self.update
|
59
|
+
#
|
60
|
+
# self
|
61
|
+
# end
|
62
|
+
|
63
|
+
# def revoked?
|
64
|
+
# @revoked == true
|
65
|
+
# end
|
66
|
+
|
67
|
+
# def is verb, url
|
68
|
+
# verb == @verbs and url == @path
|
69
|
+
# end
|
70
|
+
|
71
|
+
def match? verb, url
|
72
|
+
@verbs.split('|').include?(verb) and match_wildcard(url, @path)
|
73
|
+
end
|
74
|
+
|
75
|
+
class Entity < Grape::Entity
|
76
|
+
root 'controls', 'control'
|
77
|
+
|
78
|
+
expose :id, :documentation => { :type => 'string', :desc => 'control ID' }
|
79
|
+
|
80
|
+
expose :identity, :format_with => :id,
|
81
|
+
:documentation => { :type => 'string', :desc => 'identity ID' }
|
82
|
+
|
83
|
+
expose :verbs, :documentation => { :type => 'string', :desc => 'HTTP verbs' }
|
84
|
+
|
85
|
+
expose :path, :documentation => { :type => 'string', :desc => 'HTTP path' }
|
86
|
+
|
87
|
+
expose :mode, :documentation => { :type => 'string', :desc => 'allow or deny' }
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def match_wildcard actual, authorized
|
93
|
+
actual = strip_version actual
|
94
|
+
authorized = strip_version authorized
|
95
|
+
|
96
|
+
regx = authorized.gsub(/\*(.)/, '[^\1]*\1').gsub(/\*$/, '.*')
|
97
|
+
|
98
|
+
actual == authorized or ( actual =~ /^#{regx}$/ ) == 0
|
99
|
+
end
|
100
|
+
|
101
|
+
def strip_version path
|
102
|
+
path[3..-1]
|
103
|
+
end
|
104
|
+
|
105
|
+
ACCEPTABLE_VERBS = [ 'POST', 'GET', 'PATCH' ]
|
106
|
+
ACCEPTABLE_MODES = [ :allow, :deny ]
|
107
|
+
|
108
|
+
def self.raise_unless_creatable args
|
109
|
+
|
110
|
+
identity = args[:identity]
|
111
|
+
|
112
|
+
if identity.nil? or not identity.kind_of? Identity
|
113
|
+
raise ControlError, ':identity is required and must be an Identity'
|
114
|
+
elsif UUID.invalid? identity.id
|
115
|
+
raise ControlError, ':identity must have a valid :id'
|
116
|
+
end
|
117
|
+
|
118
|
+
# TODO :verb(s) should be a domain object
|
119
|
+
|
120
|
+
verbs = args[:verbs]
|
121
|
+
|
122
|
+
if verbs.nil?
|
123
|
+
raise ControlError, ':verbs is required'
|
124
|
+
end
|
125
|
+
|
126
|
+
verbs.split('|').each do |verb|
|
127
|
+
unless ACCEPTABLE_VERBS.include? verb
|
128
|
+
raise ControlError, ":verbs must contain one or more of #{ACCEPTABLE_VERBS.join(', ')} separated by |"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# TODO :path should be a domain object
|
133
|
+
|
134
|
+
path = args[:path]
|
135
|
+
|
136
|
+
if path.nil?
|
137
|
+
raise ControlError, ':path is required'
|
138
|
+
end
|
139
|
+
|
140
|
+
api_version = path[1,2]
|
141
|
+
|
142
|
+
unless api_version == API_VERSION
|
143
|
+
raise ControlError, ":path must begin with /#{API_VERSION}/"
|
144
|
+
end
|
145
|
+
|
146
|
+
path[4,].split( '/' ).each do |part|
|
147
|
+
unless part =~ /[*_0-9A-Za-z]+/
|
148
|
+
raise ControlError, 'invalid :path'
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
mode = args[:mode]
|
153
|
+
|
154
|
+
if mode.nil? or not ACCEPTABLE_MODES.include? mode
|
155
|
+
raise ControlError, ":mode must contain one or more of :allow, :deny}"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
class ArchivedControl < Control
|
161
|
+
class Entity < Control::Entity
|
162
|
+
root 'archived_controls', 'archived_control'
|
163
|
+
end
|
164
|
+
|
165
|
+
def self.sub_klasses
|
166
|
+
[ archived_klass ]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class ActiveControl < Control
|
171
|
+
class Entity < Control::Entity
|
172
|
+
root 'active_controls', 'active_control'
|
173
|
+
end
|
174
|
+
|
175
|
+
def self.sub_klasses
|
176
|
+
[ active_klass ]
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Grape::Entity.format_with :id do |entity|
|
2
|
+
entity.id unless entity.nil?
|
3
|
+
end
|
4
|
+
|
5
|
+
Grape::Entity.format_with :normal_balance do |value_klass|
|
6
|
+
value_klass.type unless value_klass.nil?
|
7
|
+
end
|
8
|
+
|
9
|
+
Grape::Entity.format_with :time do |time|
|
10
|
+
time.iso8601(3) unless time.nil?
|
11
|
+
end
|
12
|
+
|
13
|
+
Grape::Entity.format_with :time_full_second do |time|
|
14
|
+
time.iso8601 unless time.nil?
|
15
|
+
end
|
16
|
+
|
17
|
+
Grape::Entity.format_with :value do |value|
|
18
|
+
value.rest_hash unless value.nil?
|
19
|
+
end
|
20
|
+
|
21
|
+
Grape::Entity.format_with :progress do |value|
|
22
|
+
{ :percentage => value }
|
23
|
+
end
|
24
|
+
|
25
|
+
Grape::Entity.format_with :integer do |value|
|
26
|
+
value.to_i unless value.nil?
|
27
|
+
end
|
28
|
+
|
29
|
+
Grape::Entity.format_with :balance do |value|
|
30
|
+
value.serializable_hash unless value.nil?
|
31
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
module Subledger
|
2
|
+
module Domain
|
3
|
+
class IdentityError < Error; end
|
4
|
+
|
5
|
+
class Identity
|
6
|
+
|
7
|
+
include Domain
|
8
|
+
|
9
|
+
include Roles::Attributable
|
10
|
+
include Roles::Describable
|
11
|
+
include Roles::Identifiable
|
12
|
+
include Roles::Storable
|
13
|
+
include Roles::Versionable
|
14
|
+
|
15
|
+
include Roles::Creatable
|
16
|
+
include Roles::Readable
|
17
|
+
include Roles::Updatable
|
18
|
+
|
19
|
+
include Roles::Activatable
|
20
|
+
include Roles::Archivable
|
21
|
+
|
22
|
+
include Roles::Restable
|
23
|
+
|
24
|
+
attr_accessor :email
|
25
|
+
|
26
|
+
def self.post_keys
|
27
|
+
[ :id, :email, :description, :reference ]
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.patch_keys
|
31
|
+
[ :id, :email, :description, :reference, :version ]
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.root_klass
|
35
|
+
Identity
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.sub_klasses
|
39
|
+
[ archived_klass, active_klass ]
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.archived_klass
|
43
|
+
ArchivedIdentity
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.active_klass
|
47
|
+
ActiveIdentity
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.create args
|
51
|
+
validate_creatability args
|
52
|
+
|
53
|
+
identity = args[:client].send active_klass.collection_name, args
|
54
|
+
|
55
|
+
args[:store].create_identity identity
|
56
|
+
end
|
57
|
+
|
58
|
+
def create
|
59
|
+
identity, key = self.class.create self.attributes
|
60
|
+
|
61
|
+
initialize identity.attributes
|
62
|
+
|
63
|
+
return self, key
|
64
|
+
end
|
65
|
+
|
66
|
+
def initialize args
|
67
|
+
describable args
|
68
|
+
identifiable args
|
69
|
+
storable args
|
70
|
+
versionable args
|
71
|
+
|
72
|
+
@email = args[:email]
|
73
|
+
end
|
74
|
+
|
75
|
+
# def by_email email
|
76
|
+
# # TODO
|
77
|
+
# end
|
78
|
+
|
79
|
+
# def by_org org
|
80
|
+
# # TODO look in OrgIdentities table
|
81
|
+
# end
|
82
|
+
|
83
|
+
def authorize verb, url
|
84
|
+
raise KeyError if @retired
|
85
|
+
|
86
|
+
controls.each do |control|
|
87
|
+
return true if control.match(verb, url) unless control.revoked?
|
88
|
+
end
|
89
|
+
|
90
|
+
false
|
91
|
+
end
|
92
|
+
|
93
|
+
# def grant args
|
94
|
+
# args[:client].controls.create args
|
95
|
+
# end
|
96
|
+
|
97
|
+
# def revoke args
|
98
|
+
# org_id = args[:org_id]
|
99
|
+
# verb = args[:verb]
|
100
|
+
# url = args[:url]
|
101
|
+
#
|
102
|
+
# revoked = false
|
103
|
+
#
|
104
|
+
# controls.each do |control|
|
105
|
+
# if control.is org_id, verb, url
|
106
|
+
# control.revoke
|
107
|
+
# revoked = true
|
108
|
+
# end
|
109
|
+
# end
|
110
|
+
#
|
111
|
+
# raise IdentityError unless revoked
|
112
|
+
#
|
113
|
+
# self
|
114
|
+
# end
|
115
|
+
|
116
|
+
class Entity < Grape::Entity
|
117
|
+
root 'identities', 'identity'
|
118
|
+
|
119
|
+
expose :id, :documentation => { :type => 'string', :desc => 'identity ID' }
|
120
|
+
|
121
|
+
expose :email, :documentation => { :type => 'string', :desc => 'identity email' }
|
122
|
+
|
123
|
+
expose :description, :documentation => { :type => 'string', :desc => 'description' }
|
124
|
+
|
125
|
+
expose :reference, :documentation => { :type => 'string', :desc => 'reference URI' }
|
126
|
+
|
127
|
+
expose :version, :documentation => { :type => 'integer', :desc => 'version' }
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def self.raise_unless_creatable args
|
133
|
+
unless ValidateEmail.mx_valid? args[:email]
|
134
|
+
raise IdentityError, ':email is required and must have an MX record for the domain'
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
class ArchivedIdentity < Identity
|
140
|
+
class Entity < Identity::Entity
|
141
|
+
root 'archived_identities', 'archived_identity'
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.sub_klasses
|
145
|
+
[ archived_klass ]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class ActiveIdentity < Identity
|
150
|
+
class Entity < Identity::Entity
|
151
|
+
root 'active_identities', 'active_identity'
|
152
|
+
end
|
153
|
+
|
154
|
+
def self.sub_klasses
|
155
|
+
[ active_klass ]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|