eco-helpers 0.6.17 → 0.7.1
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 +4 -4
- data/.gitignore +19 -0
- data/.yardopts +2 -2
- data/Gemfile +6 -0
- data/Rakefile +27 -0
- data/eco-helpers.gemspec +9 -6
- data/lib/eco/api.rb +2 -1
- data/lib/eco/api/common/people.rb +1 -1
- data/lib/eco/api/common/people/base_parser.rb +31 -1
- data/lib/eco/api/common/people/default_parsers.rb +5 -1
- data/lib/eco/api/common/people/default_parsers/csv_parser.rb +37 -0
- data/lib/eco/api/common/people/default_parsers/numeric_parser.rb +0 -1
- data/lib/eco/api/common/people/entries.rb +14 -18
- data/lib/eco/api/common/people/entry_factory.rb +97 -9
- data/lib/eco/api/common/people/person_entry.rb +147 -206
- data/lib/eco/api/common/people/person_entry_attribute_mapper.rb +212 -0
- data/lib/eco/api/common/people/person_factory.rb +10 -12
- data/lib/eco/api/common/people/person_parser.rb +97 -37
- data/lib/eco/api/common/session/base_session.rb +1 -2
- data/lib/eco/api/common/session/file_manager.rb +1 -1
- data/lib/eco/api/organization.rb +2 -1
- data/lib/eco/api/organization/people.rb +54 -22
- data/lib/eco/api/organization/person_schemas.rb +54 -0
- data/lib/eco/api/organization/policy_groups.rb +5 -9
- data/lib/eco/api/organization/{presets.rb → presets_factory.rb} +1 -1
- data/lib/eco/api/policies.rb +10 -0
- data/lib/eco/api/policies/base_policy.rb +14 -0
- data/lib/eco/api/policies/policy.rb +20 -0
- data/lib/eco/api/policies/used_policies.rb +37 -0
- data/lib/eco/api/session.rb +36 -34
- data/lib/eco/api/session/batch.rb +94 -44
- data/lib/eco/api/session/batch_job.rb +108 -48
- data/lib/eco/api/session/batch_jobs.rb +4 -5
- data/lib/eco/api/session/batch_status.rb +70 -11
- data/lib/eco/api/session/config.rb +22 -5
- data/lib/eco/api/session/config/files.rb +10 -1
- data/lib/eco/api/session/config/people.rb +18 -5
- data/lib/eco/api/session/config/policies.rb +29 -0
- data/lib/eco/api/session/config/use_cases.rb +3 -7
- data/lib/eco/api/session/job_groups.rb +9 -10
- data/lib/eco/api/usecases.rb +2 -1
- data/lib/eco/api/usecases/base_case.rb +7 -2
- data/lib/eco/api/usecases/default_cases/change_email_case.rb +4 -2
- data/lib/eco/api/usecases/default_cases/create_case.rb +2 -1
- data/lib/eco/api/usecases/default_cases/create_details_case.rb +3 -1
- data/lib/eco/api/usecases/default_cases/create_details_with_supervisor_case.rb +4 -2
- data/lib/eco/api/usecases/default_cases/hris_case.rb +20 -13
- data/lib/eco/api/usecases/default_cases/new_email_case.rb +3 -1
- data/lib/eco/api/usecases/default_cases/new_id_case.rb +4 -2
- data/lib/eco/api/usecases/default_cases/recover_db_case.rb +9 -5
- data/lib/eco/api/usecases/default_cases/remove_account_case.rb +4 -2
- data/lib/eco/api/usecases/default_cases/set_supervisor_case.rb +4 -2
- data/lib/eco/api/usecases/default_cases/to_csv_case.rb +2 -2
- data/lib/eco/api/usecases/default_cases/to_csv_detailed_case.rb +2 -2
- data/lib/eco/api/usecases/default_cases/update_case.rb +16 -2
- data/lib/eco/api/usecases/default_cases/update_details_case.rb +3 -1
- data/lib/eco/api/usecases/default_cases/upsert_case.rb +25 -3
- data/lib/eco/api/usecases/use_case.rb +23 -140
- data/lib/eco/api/usecases/use_case_chain.rb +95 -0
- data/lib/eco/api/usecases/use_case_io.rb +117 -0
- data/lib/eco/api/usecases/use_group.rb +25 -5
- data/lib/eco/common/base_cli_backup.rb +1 -0
- data/lib/eco/language/models.rb +1 -1
- data/lib/eco/language/models/collection.rb +42 -31
- data/lib/eco/language/models/parser_serializer.rb +68 -0
- data/lib/eco/version.rb +1 -1
- metadata +93 -38
- data/lib/eco/api/common/people/types.rb +0 -47
- data/lib/eco/api/usecases/case_data.rb +0 -13
- data/lib/eco/language/models/attribute_parser.rb +0 -38
- data/lib/eco/lexic/dictionary.rb +0 -33
- data/lib/eco/lexic/dictionary/dictionary.txt +0 -355484
- data/lib/eco/lexic/dictionary/tags.json +0 -38
@@ -0,0 +1,212 @@
|
|
1
|
+
module Eco
|
2
|
+
module API
|
3
|
+
module Common
|
4
|
+
module People
|
5
|
+
|
6
|
+
# @attr_reader core_attrs [Array<String>] core attributes that are present in the person entry.
|
7
|
+
# @attr_reader details_attrs [Array<String>] schema details attributes that are present in the person entry.
|
8
|
+
# @attr_reader account_attrs [Array<String>] account attributes that are present in the person entry.
|
9
|
+
# @attr_reader all_attrs [Array<String>] all the attrs that are present in the person entry.
|
10
|
+
# @attr_reader internal_attrs [Array<String>] all the internally named attributes that the person entry has.
|
11
|
+
# @attr_reader aliased_attrs [Array<String>] only those internal attributes present in the person entry that have an internal/external name mapping.
|
12
|
+
# @attr_reader direct_attrs [Array<String>] only those internal attributes present in the person entry that do **not** have an internal/external name mapping.
|
13
|
+
class PersonEntryAttributeMapper
|
14
|
+
@@cached_warnings = {}
|
15
|
+
|
16
|
+
attr_reader :core_attrs, :details_attrs, :account_attrs, :all_attrs
|
17
|
+
attr_reader :internal_attrs, :aliased_attrs, :direct_attrs
|
18
|
+
|
19
|
+
# Helper class tied to `PersonEntry` that allows to track which attributes of a person entry are present
|
20
|
+
# and how they should be mapped between internal and external names if applicable.
|
21
|
+
# This class is meant to help in providing a common interface to access entries of source data that come in different formats.
|
22
|
+
# @note
|
23
|
+
# - if `data` is a `Person` object, its behaviour is `serialise`.
|
24
|
+
# - if `data` is **not** a `Person` object, it does a `parse`.
|
25
|
+
# - currently **in rework**, so there may be subtle differences that make it temporarily unstable (yet it is reliable).
|
26
|
+
# @param data [Hash, Person] `Person` object to be serialized or hashed entry (`CSV::Row` is accepted).
|
27
|
+
# @param person_parser [Common::People::PersonParser] parser/serializer of person attributes (it contains a set of attribute parsers).
|
28
|
+
# @param attr_map [Eco::Data::Mapper] mapper to translate attribute names from _external_ to _internal_ names and _vice versa_.
|
29
|
+
# @param logger [Common::Session::Logger, ::Logger] object to manage logs.
|
30
|
+
def initialize(data, person_parser:, attr_map:, logger: ::Logger.new(IO::NULL))
|
31
|
+
raise "Constructor needs a PersonParser. Given: #{parser}" if !person_parser.is_a?(Eco::API::Common::People::PersonParser)
|
32
|
+
raise "Expecting Mapper object. Given: #{attr_map}" if attr_map && !attr_map.is_a?(Eco::Data::Mapper)
|
33
|
+
|
34
|
+
@source = data
|
35
|
+
@person_parser = person_parser
|
36
|
+
@attr_map = attr_map
|
37
|
+
@logger = logger
|
38
|
+
|
39
|
+
if parsing?
|
40
|
+
@external_entry = data
|
41
|
+
init_attr_trackers
|
42
|
+
else # SERIALIZING
|
43
|
+
@person = data
|
44
|
+
@internal_attrs = @person_parser.all_attrs
|
45
|
+
end
|
46
|
+
|
47
|
+
@core_attrs = @person_parser.target_attrs_core(@internal_attrs)
|
48
|
+
@details_attrs = @person_parser.target_attrs_details(@internal_attrs)
|
49
|
+
@account_attrs = @person_parser.target_attrs_account(@internal_attrs)
|
50
|
+
@all_attrs = @core_attrs | @account_attrs | @details_attrs
|
51
|
+
end
|
52
|
+
|
53
|
+
# To know if currently the object is in parse or serialize mode.
|
54
|
+
# @return [Boolean] returns `true` if we are **parsing**, `false` otherwise.
|
55
|
+
def parsing?
|
56
|
+
!@source.is_a?(Ecoportal::API::Internal::Person)
|
57
|
+
end
|
58
|
+
|
59
|
+
# To know if currently the object is in parse or serialize mode.
|
60
|
+
# @return [Boolean] returns `true` if we are **serializing**, `false` otherwise.
|
61
|
+
def serializing?
|
62
|
+
!parsing?
|
63
|
+
end
|
64
|
+
|
65
|
+
# If there **no** `mapper` defined for the object, it mirrors `value`.
|
66
|
+
# If there is a `mapper` defined for the object:
|
67
|
+
# 1. if the `value` exists as external, translates it into an internal one.
|
68
|
+
# 2. if it doesn't exist, returns `nil`.
|
69
|
+
# @note
|
70
|
+
# 1. the **scope of attributes** is based on all the attributes recognized by the person parser.
|
71
|
+
# 2. the attributes recognized by the person parser are those of of the `Person` model (where details attributes depend on the `schema`).
|
72
|
+
# @param value [String, Array<String>] value(s) to be translated into internal names.
|
73
|
+
# @return [String, nil, Array<String] the internal name(s) of `value`.
|
74
|
+
def to_internal(value)
|
75
|
+
return value if !@attr_map
|
76
|
+
attr = value
|
77
|
+
case value
|
78
|
+
when Array
|
79
|
+
return value.map do |v|
|
80
|
+
to_internal(v)
|
81
|
+
end.compact
|
82
|
+
when String
|
83
|
+
case
|
84
|
+
when @attr_map.external?(value)
|
85
|
+
attr = @attr_map.to_internal(value)
|
86
|
+
when @attr_map.external?(value.strip)
|
87
|
+
unless cached_warning("external", "spaces", value)
|
88
|
+
logger.warn("The external person field name '#{value}' contains additional spaces in the reference file")
|
89
|
+
end
|
90
|
+
attr = @attr_map.to_internal(value.strip)
|
91
|
+
when @attr_map.internal?(value) || @attr_map.internal?(value.strip) || @attr_map.internal?(value.strip.downcase)
|
92
|
+
unless cached_warning("external", "reversed", value)
|
93
|
+
logger.warn("The mapper [external, internal] attribute names may be declared reversedly for EXTERNAL attribute: '#{value}'")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
return nil unless @person_parser.all_attrs.include?(attr)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Serializing helper also used to do a reverse mapping when parsing:
|
102
|
+
# - as there could be _internal attributes_ that shared _external attributes_,
|
103
|
+
# - when parsing, you use this helper to recognize the source _external attribute_ of each _internal_ one.
|
104
|
+
# If there **no** `mapper` defined for the object, it mirrors `value`.
|
105
|
+
# If there is a `mapper` defined for the object:
|
106
|
+
# 1. if the `value` exists as _internal-, translates it into an _external_ one.
|
107
|
+
# 2. if it doesn't exist, returns `nil`.
|
108
|
+
# @note
|
109
|
+
# 1. the **scope of attributes** is based on all the attributes defined in the current entry.
|
110
|
+
# 2. the attributes recognized by the person parser are those of of the `Person` model (where details attributes depend on the `schema`).
|
111
|
+
# @param value [String, Array<String>] value(s) to be translated or aliased into external ones.
|
112
|
+
# @return [String, nil, Array<String] the external name(s) of `value`.
|
113
|
+
def to_external(value)
|
114
|
+
return value if !@attr_map
|
115
|
+
attr = value
|
116
|
+
case value
|
117
|
+
when Array
|
118
|
+
return value.map do |v|
|
119
|
+
to_external(v)
|
120
|
+
end.compact
|
121
|
+
when String
|
122
|
+
case
|
123
|
+
when @attr_map.internal?(value)
|
124
|
+
attr = @attr_map.to_external(value)
|
125
|
+
when @attr_map.internal?(value.strip)
|
126
|
+
unless cached_warning("internal", "spaces", value)
|
127
|
+
logger.warn("The internal person field name '#{value}' contains additional spaces in the reference file")
|
128
|
+
end
|
129
|
+
attr = @attr_map.to_external(value.strip)
|
130
|
+
when @attr_map.external?(value) || @attr_map.external?(value.strip) || @attr_map.external?(value.strip.downcase)
|
131
|
+
unless cached_warning("internal", "reversed", value)
|
132
|
+
logger.warn("The mapper [external, internal] attribute names may be declared reversedly for INTERNAL attribute: '#{value}'")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
return nil unless !@external_entry || attributes(@external_entry).include?(attr)
|
138
|
+
attr
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
# when parsing:
|
144
|
+
def init_attr_trackers
|
145
|
+
# internal <-> external attributes
|
146
|
+
int_aliased = @person_parser.all_attrs.select { |attr| to_external(attr) }
|
147
|
+
ext_alias = int_aliased.map { |attr| to_external(attr) }
|
148
|
+
|
149
|
+
# virtual attrs (non native internal attr that require aliasing):
|
150
|
+
ext_vi_aliased = attributes(@external_entry).select do |attr|
|
151
|
+
!ext_alias.include?(attr) && @attr_map&.external?(attr)
|
152
|
+
end
|
153
|
+
|
154
|
+
# internal name of external attrs that are not native internal attrs
|
155
|
+
int_vi_aliased = ext_vi_aliased.map do |attr|
|
156
|
+
# to_internal(attr) can't be used here, becauase virtual fields would get filtered out,
|
157
|
+
# as they are not recognized by @parser.all_attrs.include?(attr)
|
158
|
+
@attr_map.to_internal(attr)
|
159
|
+
end.compact
|
160
|
+
|
161
|
+
@aliased_attrs = int_aliased + int_vi_aliased
|
162
|
+
|
163
|
+
int_unlinked = @person_parser.undefined_attrs.select { |attr| !to_external(attr) }
|
164
|
+
# those with parser or alias:
|
165
|
+
int_linked = @person_parser.all_attrs - int_unlinked
|
166
|
+
|
167
|
+
ext_aliased = ext_alias + ext_vi_aliased
|
168
|
+
# those that are direct external to internal:
|
169
|
+
ext_direct = attributes(@external_entry) - ext_aliased
|
170
|
+
# to avoid collisions between internal names:
|
171
|
+
@direct_attrs = ext_direct - int_linked
|
172
|
+
@internal_attrs = @aliased_attrs | @direct_attrs
|
173
|
+
end
|
174
|
+
|
175
|
+
def attributes(value)
|
176
|
+
case value
|
177
|
+
when CSV::Row
|
178
|
+
value&.headers
|
179
|
+
when Hash
|
180
|
+
value&.keys
|
181
|
+
when PersonEntry
|
182
|
+
@person_parser.target_attrs_core
|
183
|
+
else
|
184
|
+
[]
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# LOGGER
|
189
|
+
def logger
|
190
|
+
@logger || ::Logger.new(IO::NULL)
|
191
|
+
end
|
192
|
+
|
193
|
+
def cached_warning(*args)
|
194
|
+
unless exists = !!@@cached_warnings.dig(*args)
|
195
|
+
args.reduce(@@cached_warnings) do |cache, level|
|
196
|
+
cache[level] = {} if !cache.key?(level)
|
197
|
+
cache[level]
|
198
|
+
end
|
199
|
+
end
|
200
|
+
exists
|
201
|
+
end
|
202
|
+
|
203
|
+
def fatal(msg)
|
204
|
+
logger.fatal(msg)
|
205
|
+
exit
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
@@ -4,8 +4,6 @@ module Eco
|
|
4
4
|
module People
|
5
5
|
class PersonFactory
|
6
6
|
|
7
|
-
include Common::People
|
8
|
-
|
9
7
|
attr_reader :schema_attrs
|
10
8
|
|
11
9
|
def initialize(person: {}, schema: {}, account: {}, modifier: Common::People::PersonModifier.new)
|
@@ -43,9 +41,9 @@ module Eco
|
|
43
41
|
|
44
42
|
def klass
|
45
43
|
if @modifier.external?
|
46
|
-
|
44
|
+
Ecoportal::API::V1::Person
|
47
45
|
else
|
48
|
-
|
46
|
+
Ecoportal::API::Internal::Person
|
49
47
|
end
|
50
48
|
end
|
51
49
|
|
@@ -69,10 +67,10 @@ module Eco
|
|
69
67
|
end
|
70
68
|
|
71
69
|
def person_hash(person)
|
72
|
-
case
|
73
|
-
when
|
70
|
+
case person
|
71
|
+
when Ecoportal::API::V1::Person
|
74
72
|
JSON.parse(person.doc.to_json)
|
75
|
-
when
|
73
|
+
when Hash
|
76
74
|
JSON.parse(person.to_json)
|
77
75
|
else
|
78
76
|
{}
|
@@ -80,12 +78,12 @@ module Eco
|
|
80
78
|
end
|
81
79
|
|
82
80
|
def details_hash(details)
|
83
|
-
case
|
84
|
-
when
|
81
|
+
case details
|
82
|
+
when Ecoportal::API::V1::PersonDetails
|
85
83
|
doc = JSON.parse(details.doc.to_json)
|
86
|
-
when
|
84
|
+
when Ecoportal::API::V1::PersonSchema
|
87
85
|
doc =JSON.parse(details.doc.to_json)
|
88
|
-
when
|
86
|
+
when Hash
|
89
87
|
doc = JSON.parse(details.to_json)
|
90
88
|
doc = doc["details"] if doc.key?("details")
|
91
89
|
else
|
@@ -97,7 +95,7 @@ module Eco
|
|
97
95
|
|
98
96
|
def account_hash(account)
|
99
97
|
case
|
100
|
-
when account.is_a?(
|
98
|
+
when account.is_a?(Ecoportal::API::Internal::Account)
|
101
99
|
JSON.parse(account.doc.to_json)
|
102
100
|
when account.is_a?(Hash)
|
103
101
|
doc = JSON.parse(account.to_json)
|
@@ -2,17 +2,35 @@ module Eco
|
|
2
2
|
module API
|
3
3
|
module Common
|
4
4
|
module People
|
5
|
+
|
6
|
+
# Class to define/group a set of parsers/serializers.
|
7
|
+
#
|
8
|
+
# @attr_reader schema [Ecoportal::API::V1::PersonSchema, nil] schema of person details that this parser will be based upon.
|
9
|
+
# @attr_reader details_attrs [Array<String>] internal names of schema details attributes.
|
10
|
+
# @attr_reader all_attrs [Array<String>] all the internal name attributes, including _core_, _account_ and _details_.
|
5
11
|
class PersonParser
|
6
12
|
CORE_ATTRS = ["id", "external_id", "email", "name", "supervisor_id"]
|
7
13
|
ACCOUNT_ATTRS = ["policy_group_ids", "filter_tags", "default_tag"]
|
8
14
|
TYPE = [:select, :text, :date, :number, :phone_number, :boolean, :multiple]
|
15
|
+
FORMAT = [:csv, :xml, :json]
|
9
16
|
|
10
17
|
attr_reader :schema
|
11
18
|
attr_reader :details_attrs, :all_attrs
|
12
19
|
attr_reader :defined_attrs
|
13
20
|
|
14
|
-
|
15
|
-
|
21
|
+
# @example Example of usage:
|
22
|
+
# person_parser = PersonParser.new(schema: schema)
|
23
|
+
# person_parser.define_attribute("example") do |parser|
|
24
|
+
# parser.def_parser do |str, deps|
|
25
|
+
# i = value.to_i rescue 0
|
26
|
+
# i +=5 if deps.dig(:sum_5)
|
27
|
+
# i
|
28
|
+
# end.def_serializer do |value|
|
29
|
+
# value.to_s
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
# @param schema [Ecoportal::API::V1::PersonSchema, nil] schema of person details that this parser will be based upon.
|
33
|
+
def initialize(schema: nil)
|
16
34
|
raise "Constructor needs a PersonSchema. Given: #{schema}" if schema && !schema.is_a?(Ecoportal::API::V1::PersonSchema)
|
17
35
|
@details_attrs = []
|
18
36
|
@parsers = {}
|
@@ -23,49 +41,66 @@ module Eco
|
|
23
41
|
end
|
24
42
|
|
25
43
|
@all_attrs = CORE_ATTRS + ACCOUNT_ATTRS + @details_attrs
|
26
|
-
#init_default_parsers if @schema
|
27
44
|
end
|
28
45
|
|
46
|
+
# Lists all defined attributes, types and formats.
|
47
|
+
# @return [Array<String>] the list of defined parsers/serializers.
|
48
|
+
def list_defined
|
49
|
+
@parsers.keys
|
50
|
+
end
|
51
|
+
|
52
|
+
# Scopes `source_attrs` using the _**core** attributes_.
|
53
|
+
# @note use this helper to know which among your attributes are **core** ones.
|
54
|
+
# @param source_attrs [Array<String>]
|
55
|
+
# @return [Array<String>] the scoped **core** attributes, if `source_attrs` is not `nil`. All the _core attributes_, otherwise.
|
29
56
|
def target_attrs_core(source_attrs = nil)
|
30
57
|
return CORE_ATTRS if !source_attrs
|
31
58
|
scoped_attrs(source_attrs, CORE_ATTRS)
|
32
59
|
end
|
33
60
|
|
61
|
+
# Scopes `source_attrs` using the schema _**details** attributes_.
|
62
|
+
# @note use this helper to know which among your attributes are schema **details** ones.
|
63
|
+
# @param source_attrs [Array<String>]
|
64
|
+
# @return [Array<String>] the scoped **details** attributes, if `source_attrs` is not `nil`. All the _details attributes_, otherwise.
|
34
65
|
def target_attrs_details(source_attrs = nil)
|
35
66
|
return @details_attrs if ! source_attrs
|
36
67
|
scoped_attrs(source_attrs, @details_attrs)
|
37
68
|
end
|
38
69
|
|
70
|
+
# Scopes `source_attrs` using the schema _**account** attributes_.
|
71
|
+
# @note use this helper to know which among your attributes are **account** ones.
|
72
|
+
# @param source_attrs [Array<String>]
|
73
|
+
# @return [Array<String>] the scoped **account** attributes, if `source_attrs` is not `nil`. All the _account attributes_, otherwise.
|
39
74
|
def target_attrs_account(source_attrs = nil)
|
40
75
|
return ACCOUNT_ATTRS if !source_attrs
|
41
76
|
scoped_attrs(source_attrs, ACCOUNT_ATTRS)
|
42
77
|
end
|
43
78
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
def list
|
49
|
-
@parsers.keys
|
50
|
-
end
|
51
|
-
|
79
|
+
# Returns a list of all the internal attributes of the model that have a parser defined.
|
80
|
+
# @note it excludes any parser that is not in the model, such as type parsers (i.e. ``:boolean`, ``:multiple`)
|
81
|
+
# @return [Array<String>] list of all attribute defined parsers.
|
52
82
|
def defined_attrs
|
83
|
+
defined = @parsers.keys
|
53
84
|
defined - (defined - all_attrs)
|
54
85
|
end
|
55
86
|
|
87
|
+
# Returns a list of all the internal attributes of the model that do **not** have a parser defined.
|
88
|
+
# @note it excludes any parser that is **not** in the model, such as type parsers (i.e. :boolean, :multiple)
|
89
|
+
# @return [Array<String>] list of all attributes without a defined parser.
|
56
90
|
def undefined_attrs
|
57
91
|
all_attrs - defined_attrs
|
58
92
|
end
|
59
93
|
|
94
|
+
# @param attr [String] internal name of an attribute.
|
95
|
+
# @return [Boolean] `true` if the attribute `attr` has parser defined, and `false` otherwise.
|
60
96
|
def defined?(attr)
|
61
|
-
|
97
|
+
@parsers.key?(attr)
|
62
98
|
end
|
63
99
|
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
|
68
|
-
# merges parser overriding self for exisint parsers
|
100
|
+
# Helper to **merge** a set of parsers of another `PersonParser` into the current object.
|
101
|
+
# @note if there are parsers with same name, it **overrides** the ones of the current object with them.
|
102
|
+
# @param parser [Eco::API::Common::People::PersonParser] a `PersonParser` containing defined parsers.
|
103
|
+
# @return [Eco::API::Common::People::PersonParser] the current object (to ease chainig).
|
69
104
|
def merge(parser)
|
70
105
|
return self if !parser
|
71
106
|
raise "Expected a PersonParser object. Given #{parser}" if !parser.is_a?(PersonParser)
|
@@ -73,16 +108,51 @@ module Eco
|
|
73
108
|
self
|
74
109
|
end
|
75
110
|
|
76
|
-
|
77
|
-
|
111
|
+
|
112
|
+
# Helper to define and associate a parser/serializer to a type or attribute.
|
113
|
+
# @raise [Exception] if trying to define a parser/serializer for:
|
114
|
+
# - an unkown attribute (`String`)
|
115
|
+
# - an unrecognized type or format (`Symbol`)
|
116
|
+
# @param attr [String] type (`Symbol`) or attribute (`String`) to define the parser/serializer to.
|
117
|
+
# @param dependencies [Hash] dependencies to be used when calling the parser/serializer.
|
118
|
+
# @yield [parser] the definition of the parser.
|
119
|
+
# @yieldparam parser [Eco::Language::Models::ParserSerializer] parser to define.
|
120
|
+
# @return [Eco::API::Common::People::PersonParser] the current object (to ease chainig).
|
121
|
+
def define_attribute(attr, dependencies: {}, &definition)
|
122
|
+
if !valid?(attr)
|
123
|
+
msg = "The attribute '#{attr_to_str(attr)}' is not part of core, account or target schema, or does not match any type: #{@details_attrs}"
|
124
|
+
raise msg
|
125
|
+
end
|
126
|
+
|
127
|
+
Eco::Language::Models::ParserSerializer.new(attr, dependencies: dependencies).tap do |parser|
|
128
|
+
@parsers[attr] = parser
|
129
|
+
definition.call(parser)
|
130
|
+
end
|
131
|
+
|
78
132
|
self
|
79
133
|
end
|
80
134
|
|
135
|
+
# Call to parser `source` value of attribute or type `attr` into an internal valid value.
|
136
|
+
# @note dependencies introduced on `parse` call will be merged with those defined during the
|
137
|
+
# initialization of the parser `attr`.
|
138
|
+
# @raise [Exception] if there is **no** parser for attribute or type `attr`.
|
139
|
+
# @param attr [String] target attribute or type to **parse**.
|
140
|
+
# @param source [Any] source value to be parsed.
|
141
|
+
# @param deps [Hash] key-value pairs of call dependencies.
|
142
|
+
# @return [Any] a valid internal value.
|
81
143
|
def parse(attr, source, deps: {})
|
82
144
|
raise "There is no parser for attribute '#{attr}'" if !self.defined?(attr)
|
83
145
|
@parsers[attr].parse(source, dependencies: deps)
|
84
146
|
end
|
85
147
|
|
148
|
+
# Call to serialise `object` value of attribute or type `attr` into an external valid value.
|
149
|
+
# @note dependencies introduced on `serialise` call will be merged with those defined during the
|
150
|
+
# initialization of the parser/serialiser `attr`.
|
151
|
+
# @raise [Exception] if there is **no** serialiser for attribute or type `attr`.
|
152
|
+
# @param attr [String] target attribute or type to **serialize**.
|
153
|
+
# @param object [Any] object value to be serialized.
|
154
|
+
# @param deps [Hash] key-value pairs of call dependencies.
|
155
|
+
# @return a valid external value.
|
86
156
|
def serialize(attr, object, deps: {})
|
87
157
|
raise "There is no parser for attribute '#{attr}'" if !self.defined?(attr)
|
88
158
|
@parsers[attr].serialize(object, dependencies: deps)
|
@@ -90,6 +160,7 @@ module Eco
|
|
90
160
|
|
91
161
|
protected
|
92
162
|
|
163
|
+
# @return [Hash] attr-parser pairs with all the defined type and attribute parsers/serializers.
|
93
164
|
def hash
|
94
165
|
@parsers
|
95
166
|
end
|
@@ -102,35 +173,24 @@ module Eco
|
|
102
173
|
(source_attrs + parsed_attrs) & (direct_attrs + parsed_attrs)
|
103
174
|
end
|
104
175
|
|
105
|
-
def
|
106
|
-
|
107
|
-
str_attr = (attr.is_a?(Symbol) ? ":" : "") + attr.to_s
|
108
|
-
msg = "The attribute '#{str_attr}' is not part of core, account or target schema, or does not match any type: #{@details_attrs}"
|
109
|
-
raise msg
|
110
|
-
end
|
111
|
-
parser = Eco::Language::Models::AttributeParser.new(attr, dependencies: dependencies)
|
112
|
-
#yield(parser)
|
113
|
-
definition.call(parser)
|
114
|
-
parser
|
176
|
+
def attr_to_str(attr)
|
177
|
+
attr.is_a?(Symbol)? ":#{attr.to_s}" : "#{attr.to_s}"
|
115
178
|
end
|
116
179
|
|
117
180
|
def valid?(attr)
|
118
|
-
(attr
|
119
|
-
(attr.is_a?(String) && (!@schema || valid_attr?(attr)))
|
181
|
+
valid_attr?(attr) || valid_type?(attr) || valid_format?(attr)
|
120
182
|
end
|
121
183
|
|
122
184
|
def valid_attr?(attr)
|
123
|
-
@all_attrs.include?(attr)
|
185
|
+
attr.is_a?(String) && (!@schema || @all_attrs.include?(attr))
|
124
186
|
end
|
125
187
|
|
126
188
|
def valid_type?(attr)
|
127
|
-
TYPE.include?(attr)
|
189
|
+
attr.is_a?(Symbol) && TYPE.include?(attr)
|
128
190
|
end
|
129
191
|
|
130
|
-
def
|
131
|
-
|
132
|
-
value = [].push(value) unless value.is_a?(Array)
|
133
|
-
value
|
192
|
+
def valid_format?(attr)
|
193
|
+
attr.is_a?(Symbol) && FORMAT.include?(attr)
|
134
194
|
end
|
135
195
|
|
136
196
|
end
|