eco-helpers 1.3.1 → 1.3.2

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
  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