eco-helpers 1.3.1 → 1.3.2

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
  SHA256:
3
- metadata.gz: adb97e964a09a628b29aa507f3f6d764df82b7c8dbdd568f86245ab05fdfb4bb
4
- data.tar.gz: 1f09ede76add050f3800d6683717a1ccd8f45e6af46f030e53d24edee74f7273
3
+ metadata.gz: aa39fb0038e03d65a129a3d7df06f5c3fba60518ef847cd89cfe0d973f27065e
4
+ data.tar.gz: f22d6d27a952af99e4f84eb1ed29a8b930d7226f0a67d60c86f6eabb4a15715f
5
5
  SHA512:
6
- metadata.gz: c0d9585e4c20c5e9f0f8ca0101789dc9e50e6e08a71297c0376f1c2334abe602fbe24ca5fee178c840c2c52e0ee6a1446c26eee0103a377f29e99fbe9afece46
7
- data.tar.gz: e3894a74b853858da71ee783f460eed18cbd68dae92a941ea755a687b84c7b27f4899a675c7cb16ecbb83d0eb4105aa8380d8dea3ac64493a7e82f6802a14e37
6
+ metadata.gz: 070ee0c500e334ef8bf149bdf3ec24fd20480a16a3b4742f25247fccd09a8ef476a3bdfcfb45119a4fa37dc1c0dbe415cf53de2fa6ecd4722fa81f65c3762450
7
+ data.tar.gz: c4456bbbfd19b4e03734f6dd9b388087c7a7aee44dba138ec2aa1dfc78ceff0024c222589d5e9857561b25ef730faf3f9e8008dfb5d4dd006cfaa47c15c197a7
@@ -6,6 +6,7 @@ require 'pp'
6
6
  module Eco
7
7
  end
8
8
 
9
+ require_relative 'eco/csv'
9
10
  require_relative 'eco/language'
10
11
  require_relative 'eco/common'
11
12
  require_relative 'eco/data'
@@ -15,5 +15,6 @@ require_relative 'people/person_parser'
15
15
  require_relative 'people/default_parsers'
16
16
  require_relative 'people/person_entry_attribute_mapper'
17
17
  require_relative 'people/person_entry'
18
+ require_relative 'people/supervisor_helpers'
18
19
  require_relative 'people/entries'
19
20
  require_relative 'people/entry_factory'
@@ -18,7 +18,7 @@ module Eco
18
18
  private
19
19
 
20
20
  def truthy (value)
21
- %w[true y yes x].include?(value.to_s&.downcase)
21
+ %w[true y yes x].include?(value.to_s.strip.downcase)
22
22
  end
23
23
  end
24
24
  end
@@ -9,7 +9,10 @@ module Eco
9
9
  @parsers.define_attribute(:csv, dependencies: @options) do |parser|
10
10
  parser.def_parser do |data, deps|
11
11
  arr_hash = []
12
- CSV.parse(data, headers: true).each do |row|
12
+ CSV.parse(data, headers: true, skip_blanks: true).reject do |row|
13
+ values = row.to_hash.values
14
+ values.all?(&:nil?) || values.map(&:to_s).all?(&:empty?)
15
+ end.each do |row|
13
16
  row_hash = row.headers.uniq.each_with_object({}) do |attr, hash|
14
17
  value = row[attr]
15
18
  hash[attr] = value.to_s.empty?? nil : value
@@ -8,7 +8,7 @@ module Eco
8
8
  def process
9
9
  @parsers.define_attribute(:number, dependencies: @options) do |parser|
10
10
  parser.def_parser do |value, deps|
11
- value = value.to_s.strip == "" ? nil : (value.to_f rescue nil)
11
+ value = value.to_s.strip.empty? ? nil : (value.to_f rescue nil)
12
12
  end.def_serializer do |value|
13
13
  value.is_a?(Array) ? value.map { |v| v.to_s } : value.to_s
14
14
  end
@@ -10,11 +10,20 @@ module Eco
10
10
 
11
11
  alias_method :entries, :to_a
12
12
 
13
+ include Eco::API::Common::People::SupervisorHelpers
14
+
13
15
  def initialize(data = [], klass:, factory:)
14
16
  super(data, klass: klass, factory: factory)
15
17
  @caches_init = false
16
18
  end
17
19
 
20
+ # Override `each` to make it work with supervisor hiearchy
21
+ def each(params: {}, &block)
22
+ return to_enum(:each) unless block
23
+ @array_supers = sort_by_supervisors(@items) unless @caches_init
24
+ @array_supers.each(&block)
25
+ end
26
+
18
27
  def [](id_or_ext)
19
28
  id(id_or_ext) || external_id(id_or_ext)
20
29
  end
@@ -96,6 +105,7 @@ module Eco
96
105
  @by_id = to_h
97
106
  @by_external_id = to_h('external_id')
98
107
  @by_email = to_h('email')
108
+ @array_supers = sort_by_supervisors(@items)
99
109
  @caches_init = true
100
110
  end
101
111
 
@@ -0,0 +1,142 @@
1
+ module Eco
2
+ module API
3
+ module Common
4
+ module People
5
+ # Used with `Enumerable` of objects that have the following methods:
6
+ # * `supervisor_id`
7
+ # * `external_id`
8
+ # * `id`
9
+ module SupervisorHelpers
10
+
11
+ # Reorders as follows:
12
+ # 1. supervisors, people with no supervisor or where their supervisor not present
13
+ # 2. subordinates
14
+ def sort_by_supervisors(values, supervisors_first: true)
15
+ raise "Expected non hash Enumerable. Given: #{values.class}" if values.is_a?(Hash)
16
+ return [] unless values && values.is_a?(Enumerable)
17
+ roam = Proc.new do |tree|
18
+ [].tap do |out|
19
+ sub_outs = tree.empty?? [] : tree.map {|sup, subtree| roam.call(subtree)}
20
+ tree.each do |sup, subtree|
21
+ sout = subtree.empty?? [] :roam.call(subtree)
22
+ supervisors_first ? sout.unshift(sup) : sout.push(sup)
23
+ out.concat(sout)
24
+ end
25
+ end
26
+ end
27
+
28
+ roam.call(supervisors_tree(values))
29
+ end
30
+
31
+ def tree_to_str(tree, lev: 0)
32
+ raise "Required Hash tree structure. Given: #{tree.class}" unless tree.is_a?(Hash)
33
+ "".tap do |str|
34
+ tree.each do |entry, subtree|
35
+ str << "#{" " * lev}+-- #{entry.id || entry.external_id}\n"
36
+ str << tree_to_str(subtree, lev: lev + 1) unless !subtree || subtree.empty?
37
+ end
38
+ end
39
+ end
40
+
41
+ def print_tree(tree, lev: 0)
42
+ puts tree_to_str(tree)
43
+ end
44
+
45
+ # Generates a `Hash` tree structure, where:
46
+ # * **keys** are nodes
47
+ # * **values** are `Hash` subtree structures of `key` subordinates
48
+ # @note it is resilient to cyclic supervisors (it will just add the last at the top)
49
+ # @param values [Enumerable<Object>] of objects with methods:
50
+ # `id`, `external_id` and `supervisor_id`
51
+ # @return [Hash] the tree structure
52
+ def supervisors_tree(values)
53
+ raise "Expected non hash Enumerable. Given: #{values.class}" if values.is_a?(Hash)
54
+ return {} unless values && values.is_a?(Enumerable)
55
+ idx = get_super_indexes(values)
56
+
57
+ processed = []
58
+ subtree = Proc.new do |entry, level, toptree|
59
+ if processed.include?(entry)
60
+ next {} unless toptree.key?(entry) && level > 0
61
+ # needs to be moved as a child
62
+ subnodes = toptree.delete(entry)
63
+ processed.delete(entry)
64
+ end
65
+
66
+ subnodes ||= {}.tap do |tree|
67
+ subs = idx[:subordinates].call(entry)
68
+ processed.push(entry)
69
+ next nil unless subs && !subs.empty?
70
+ subs.each do |sub|
71
+ sub_tree = subtree.call(sub, level + 1, toptree)
72
+ tree.merge!(sub_tree)
73
+ end
74
+ end
75
+
76
+ {entry => subnodes}
77
+ end
78
+
79
+ {}.tap do |tree|
80
+ idx[:by_sup].keys.each do |sup_id|
81
+ if sup = idx[:supers][sup_id]
82
+ tree.merge!(subtree.call(sup, 0, tree))
83
+ else
84
+ idx[:by_sup][sup_id].each do |sub|
85
+ tree.merge!(subtree.call(sub, 0, tree))
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ private
93
+
94
+ def get_super_indexes(values)
95
+ raise "Expected non hash Enumerable. Given: #{values.class}" if values.is_a?(Hash)
96
+ {}.tap do |indexes|
97
+ indexes[:by_id] = values.map do |e|
98
+ e.id && [e.id, e]
99
+ end.compact.to_h
100
+ indexes[:by_ext] = values.map do |e|
101
+ e.external_id && [e.external_id, e]
102
+ end.compact.to_h
103
+
104
+ indexes[:by_sup] = {}.tap do |by_s|
105
+ values.group_by do |e|
106
+ e.supervisor_id
107
+ end.tap do |by_sup|
108
+ by_s[nil] = by_sup.delete(nil) if by_sup.key?(nil)
109
+ by_s.merge!(by_sup)
110
+ end
111
+ end
112
+
113
+ indexes[:supers] = {}.tap do |sups|
114
+ indexes[:by_ext].select do |ext, e|
115
+ ext && indexes[:by_sup].key?(ext)
116
+ end.tap {|found| sups.merge!(found)}
117
+ indexes[:by_id].select do |id, e|
118
+ id && indexes[:by_sup].key?(id)
119
+ end.tap {|found| sups.merge!(found)}
120
+ end
121
+
122
+ indexes[:is_super] = Proc.new do |entry|
123
+ !!(indexes[:supers][entry.id] || indexes[:supers][entry.external_id])
124
+ end
125
+
126
+ indexes[:subordinates] = Proc.new do |entry|
127
+ subs = nil
128
+ if sup = indexes[:supers][entry.id] || indexes[:supers][entry.external_id]
129
+ subs ||= indexes[:by_sup][sup.id] unless !sup.id
130
+ subs ||= indexes[:by_sup][sup.external_id] unless !sup.external_id
131
+ end
132
+ subs
133
+ end
134
+ end
135
+
136
+ end
137
+
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -56,13 +56,13 @@ ASSETS.cli.config do |cnf|
56
56
  end
57
57
 
58
58
  options.deep_merge!(people: {filter: {details: {schema_id: sch_id}}})
59
- session.logger.info("Filtering for schema #{sch_name}")
60
-
61
- session.schema = sch_id
62
-
59
+ session.logger.info("Filtering people entries with schema #{session.schemas.to_name(sch_id)}")
60
+
63
61
  filtered = people.select do |person|
64
62
  person.details && (person.details.schema_id == sch_id)
65
63
  end
64
+ session.logger.info("Filtered #{filtered.count} people out of #{people.count} total")
65
+
66
66
  people.newFrom filtered
67
67
  end
68
68
 
@@ -1,6 +1,22 @@
1
1
  ASSETS.cli.config do |cnf|
2
2
  cnf.options_set do |options_set, options|
3
3
 
4
+ options_set.add("-schema-id") do |options, session|
5
+ sch_name = SCR.get_arg("-schema-id", with_param: true)
6
+ sch_id = session.schemas.to_id(sch_name)
7
+
8
+ unless sch_id
9
+ msg = "You need to specify a schema id or name. '#{sch_id}' does not exist"
10
+ session.logger.error(msg)
11
+ exit(1)
12
+ end
13
+
14
+ options.deep_merge!(people: {filter: {details: {schema_id: sch_id}}})
15
+ session.logger.info("Setting schema #{session.schemas.to_name(sch_id)}")
16
+
17
+ session.schema = sch_id
18
+ end
19
+
4
20
  options_set.add("-entries-from") do |options, session|
5
21
  options.deep_merge!(input: {entries_from: true})
6
22
  end
@@ -0,0 +1,33 @@
1
+ require 'csv'
2
+
3
+ module Eco
4
+ class CSV < ::CSV
5
+
6
+ class << self
7
+
8
+ def parse(data, **kargs, &block)
9
+ kargs = {headers: true, skip_blanks: true}.merge(kargs)
10
+ out = super(data, **kargs, &block).reject do |row|
11
+ values = row.to_hash.values
12
+ values.all?(&:nil?) || values.map(&:to_s).all?(&:empty?)
13
+ end
14
+ Eco::CSV::Table.new(out)
15
+ end
16
+
17
+ def read(file, **kargs)
18
+ coding = Eco::API::Common::Session::FileManager.encoding(file)
19
+ kargs = {headers: true, skip_blanks: true, encoding: coding}.merge(kargs)
20
+ out = super(file, **kargs).reject do |row|
21
+ values = row.to_hash.values
22
+ values.all?(&:nil?) || values.map(&:to_s).all?(&:empty?)
23
+ end
24
+ Eco::CSV::Table.new(out)
25
+ end
26
+
27
+ end
28
+
29
+
30
+ end
31
+ end
32
+
33
+ require_relative 'csv/table'
@@ -0,0 +1,79 @@
1
+
2
+ module Eco
3
+ class CSV
4
+ class Table < ::CSV::Table
5
+
6
+ # @param ary_arrays [Array<Row>, Array<Array>, Eco::CSV::Table, ::CSV::Table]
7
+ # - when `Array<Array>` => all `rows` as arrays where first array is the **header**
8
+ def initialize(input)
9
+ super(to_rows_array(input))
10
+ end
11
+
12
+ # @return [Array<::CSV::Row>]
13
+ def rows
14
+ [].tap do |out|
15
+ self.each {|row| out << row}
16
+ end
17
+ end
18
+
19
+ # @return [Integer] total number of rows not including the header
20
+ def length
21
+ to_a.length - 1
22
+ end
23
+
24
+ # @return [Array<Array>] each array is the column header followed by its values
25
+ def columns
26
+ to_a.transpose
27
+ end
28
+
29
+ # Adds a new column at the end
30
+ # @param header_name [String] header of the new column
31
+ # @return [Eco::CSV::Table] with a new empty column
32
+ def add_column(header_name)
33
+ new_col = Array.new(length).unshift(header_name)
34
+ columns_to_table(columns.push(new_col))
35
+ end
36
+
37
+ # @note it will override columns with same header name
38
+ # @return [Hash] keys are headers, values are arrays
39
+ def columns_hash
40
+ columns.map do |col|
41
+ [col.first, col[1..-1]]
42
+ end.to_h
43
+ end
44
+
45
+ private
46
+
47
+ def columns_to_table(columns_array)
48
+ data = to_rows_array(columns_array.transpose)
49
+ self.class.new(data)
50
+ end
51
+
52
+ def to_rows_array(data)
53
+ case data
54
+ when Array
55
+ return data unless data.length > 0
56
+ if data.first.is_a?(::CSV::Row)
57
+ data
58
+ elsif data.first.is_a?(Array)
59
+ headers = data.shift
60
+ data.map do |arr_row|
61
+ CSV::Row.new(headers, arr_row)
62
+ end.compact
63
+ else
64
+ raise "Expected data that can be transformed into Array<Array>"
65
+ end
66
+ when ::CSV::Table
67
+ to_rows_array(data.to_a)
68
+ when Hash
69
+ # hash of columns header as key and column array as value
70
+ rows_arrays = [a.keys].concat(a.values.first.zip(*a.values[1..-1]))
71
+ to_rows_array(data.keys)
72
+ else
73
+ raise "Input type not supported. Given: #{data.class}"
74
+ end
75
+ end
76
+
77
+ end
78
+ end
79
+ end
@@ -154,10 +154,9 @@ module Eco
154
154
  self.attr(attr, value, modifier)
155
155
  end
156
156
 
157
- def group_by(attr)
158
- to_h(attr)
159
- #return {} if !attr
160
- #self.to_a.group_by { |object| object.method(attr).call }
157
+ def group_by(attr = nil, &block)
158
+ return to_h(attr) if attr
159
+ to_a.group_by(&block) if block
161
160
  end
162
161
 
163
162
  def to_h(attr)
@@ -1,3 +1,3 @@
1
1
  module Eco
2
- VERSION = "1.3.1"
2
+ VERSION = "1.3.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eco-helpers
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oscar Segura
@@ -82,22 +82,22 @@ dependencies:
82
82
  name: redcarpet
83
83
  requirement: !ruby/object:Gem::Requirement
84
84
  requirements:
85
- - - ">="
86
- - !ruby/object:Gem::Version
87
- version: 3.5.0
88
85
  - - "~>"
89
86
  - !ruby/object:Gem::Version
90
87
  version: '3.5'
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: 3.5.0
91
91
  type: :development
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
- - - ">="
96
- - !ruby/object:Gem::Version
97
- version: 3.5.0
98
95
  - - "~>"
99
96
  - !ruby/object:Gem::Version
100
97
  version: '3.5'
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: 3.5.0
101
101
  - !ruby/object:Gem::Dependency
102
102
  name: ecoportal-api
103
103
  requirement: !ruby/object:Gem::Requirement
@@ -142,42 +142,42 @@ dependencies:
142
142
  name: aws-sdk-ses
143
143
  requirement: !ruby/object:Gem::Requirement
144
144
  requirements:
145
- - - ">="
146
- - !ruby/object:Gem::Version
147
- version: 1.14.0
148
145
  - - "~>"
149
146
  - !ruby/object:Gem::Version
150
147
  version: '1.14'
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: 1.14.0
151
151
  type: :runtime
152
152
  prerelease: false
153
153
  version_requirements: !ruby/object:Gem::Requirement
154
154
  requirements:
155
- - - ">="
156
- - !ruby/object:Gem::Version
157
- version: 1.14.0
158
155
  - - "~>"
159
156
  - !ruby/object:Gem::Version
160
157
  version: '1.14'
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: 1.14.0
161
161
  - !ruby/object:Gem::Dependency
162
162
  name: dotenv
163
163
  requirement: !ruby/object:Gem::Requirement
164
164
  requirements:
165
- - - ">="
166
- - !ruby/object:Gem::Version
167
- version: 2.6.0
168
165
  - - "~>"
169
166
  - !ruby/object:Gem::Version
170
167
  version: '2.6'
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: 2.6.0
171
171
  type: :runtime
172
172
  prerelease: false
173
173
  version_requirements: !ruby/object:Gem::Requirement
174
174
  requirements:
175
- - - ">="
176
- - !ruby/object:Gem::Version
177
- version: 2.6.0
178
175
  - - "~>"
179
176
  - !ruby/object:Gem::Version
180
177
  version: '2.6'
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: 2.6.0
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: net-sftp
183
183
  requirement: !ruby/object:Gem::Requirement
@@ -235,6 +235,7 @@ files:
235
235
  - lib/eco/api/common/people/person_factory.rb
236
236
  - lib/eco/api/common/people/person_modifier.rb
237
237
  - lib/eco/api/common/people/person_parser.rb
238
+ - lib/eco/api/common/people/supervisor_helpers.rb
238
239
  - lib/eco/api/common/session.rb
239
240
  - lib/eco/api/common/session/base_session.rb
240
241
  - lib/eco/api/common/session/environment.rb
@@ -344,6 +345,8 @@ files:
344
345
  - lib/eco/cli/scripting/argument.rb
345
346
  - lib/eco/cli/scripting/arguments.rb
346
347
  - lib/eco/common.rb
348
+ - lib/eco/csv.rb
349
+ - lib/eco/csv/table.rb
347
350
  - lib/eco/data.rb
348
351
  - lib/eco/data/crypto.rb
349
352
  - lib/eco/data/crypto/encryption.rb
@@ -384,7 +387,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
384
387
  - !ruby/object:Gem::Version
385
388
  version: '0'
386
389
  requirements: []
387
- rubygems_version: 3.0.3
390
+ rubyforge_project:
391
+ rubygems_version: 2.7.6.2
388
392
  signing_key:
389
393
  specification_version: 4
390
394
  summary: eco-helpers to manage people api cases