eco-helpers 1.1.5 → 1.1.6

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: 90298e8d317e2d72234cdb650b018b40d71dae3c0b95143ac4510f9f3242a42c
4
- data.tar.gz: 8833b41ee773996db86e26392ae8be989db9ecdb2f6a5b9602ec9143277840a0
3
+ metadata.gz: e0c1cca427dcc2ced629146debcbe71a05f062002919b68b32e88ebddd86c25c
4
+ data.tar.gz: e74e5b3c8007af145e1255903a4a1a26dc785b84004434291524275a5ac38734
5
5
  SHA512:
6
- metadata.gz: 36b915adf179fb4adaec1a27335770378449a0fcdecc3e39d8e5af6c0208fdd8688ac43ec670207b41faaa7bd518822c10b73c44ef11802d28548c80ded34678
7
- data.tar.gz: 34ed17712f7071649ea20391dcd820f2cb0e67fcba0b2742685f25fe9270d59be1eb43cd533c260877565621b3c9202babfcdfa34176a30ea6a84f1b527d6ce0
6
+ metadata.gz: 55e089b0827e28aafb5ac51e5b7ff37a09a81ab71160087080ecff70a10a44397dec6d0e2d847f8a5767b52c44a6ae548affd06c28a6e4ccb3d2edf37472f81a
7
+ data.tar.gz: 4801acfeedc39e1287808f812845c915316e0bac92d16594fe412899483104cba6604f30e1cf717dae6438c2f4e69a4e1adb1ea7af863d3a2a27273a36b1ec3a
@@ -33,7 +33,5 @@ Gem::Specification.new do |s|
33
33
  s.add_dependency 'aws-sdk-ses', '~> 1.14', '>= 1.14.0'
34
34
  s.add_dependency 'dotenv', '~> 2.6', '>= 2.6.0'
35
35
  s.add_dependency 'net-sftp', '~> 2.1', '>= 2.1.2'
36
- s.add_dependency 'faker', '~> 2', '>= 2.1'
37
- s.add_dependency 'distribution', '~> 0.7', '>= 0.7.3'
38
36
 
39
37
  end
@@ -10,6 +10,5 @@ require_relative 'eco/language'
10
10
  require_relative 'eco/common'
11
11
  require_relative 'eco/data'
12
12
  require_relative 'eco/api'
13
- require_relative 'eco/tester'
14
13
  require_relative 'eco/cli'
15
14
  require_relative 'eco/assets'
@@ -11,4 +11,3 @@ require_relative 'api/policies'
11
11
  require_relative 'api/error'
12
12
  require_relative 'api/organization'
13
13
  require_relative 'api/session'
14
- require_relative 'api/eco_faker'
@@ -31,10 +31,10 @@ module Eco
31
31
  raise "Constructor needs a PersonParser. Given: #{parser}" if !person_parser.is_a?(Eco::API::Common::People::PersonParser)
32
32
  raise "Expecting Mapper object. Given: #{attr_map}" if attr_map && !attr_map.is_a?(Eco::Data::Mapper)
33
33
 
34
- @source = data
34
+ @source = data
35
35
  @person_parser = person_parser
36
- @attr_map = attr_map
37
- @logger = logger
36
+ @attr_map = attr_map
37
+ @logger = logger
38
38
 
39
39
  if parsing?
40
40
  @external_entry = data
@@ -142,34 +142,54 @@ module Eco
142
142
 
143
143
  # when parsing:
144
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)
145
+ # (def) all internal attributes we can expect
146
+ def_all_attrs = @person_parser.all_attrs
147
+ # (def) internal attrs with no aliasing nor parser definition (expected to be direct)
148
+ def_unlinked = @person_parser.undefined_attrs.select { |attr| !to_external(attr) }
149
+ # (def) those with parser or alias:
150
+ def_linked = def_all_attrs - def_unlinked
151
+
152
+ # (data) data attributes (actual attributes of the entry)
153
+ data_attrs = attributes(@external_entry)
154
+ # (data) attributes of the data that come directly as internal attribute names
155
+ data_direct_attrs = data_attrs & def_all_attrs
156
+
157
+ # (def) configured as alised (internal <-> external attributes)
158
+ def_int_aliased = def_all_attrs.select { |attr| to_external(attr) }
159
+ def_ext_alias = def_int_aliased.map { |attr| to_external(attr) }
160
+
161
+ # (data) virtual attrs (external alias of non native internal attr in data):
162
+ data_vi_ext_alias = data_attrs.select do |attr|
163
+ !def_ext_alias.include?(attr) && @attr_map&.external?(attr)
152
164
  end
153
-
154
- # internal name of external attrs that are not native internal attrs
155
- int_vi_aliased = ext_vi_aliased.map do |attr|
165
+ # (data) virtual internal attrs (the internal names of those virtual attrs)
166
+ data_vi_int_aliased = data_vi_ext_alias.map do |attr|
156
167
  # to_internal(attr) can't be used here, becauase virtual fields would get filtered out,
157
168
  # as they are not recognized by @parser.all_attrs.include?(attr)
158
169
  @attr_map.to_internal(attr)
159
170
  end.compact
160
171
 
161
- @aliased_attrs = int_aliased + int_vi_aliased
172
+ # (data) attrs that could come aliased in the current data
173
+ # => modify aliased based on those that came directly as internal attrs in the entry
174
+ data_def_int_aliased = def_int_aliased - data_direct_attrs
175
+ data_def_ext_alias = data_def_int_aliased.map { |attr| to_external(attr) }
176
+ # (data) actual attrs of the data that come aliased
177
+ data_ext_alias = data_def_ext_alias & data_attrs
162
178
 
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
179
+ # (data) all internal attributes that could come aliased, with given the entry
180
+ @aliased_attrs = data_def_int_aliased + data_vi_int_aliased
181
+ # (data) all those ext attrs present that will require aliasing
182
+ #data_ext_alias_all = data_def_ext_alias + data_vi_ext_alias
183
+ data_ext_alias_all = data_ext_alias + data_vi_ext_alias
166
184
 
167
- ext_aliased = ext_alias + ext_vi_aliased
168
185
  # those that are direct external to internal:
169
- ext_direct = attributes(@external_entry) - ext_aliased
186
+ data_ext_direct = data_attrs - data_ext_alias_all
187
+
188
+ # (data) attributes that do not require aliasing
170
189
  # to avoid collisions between internal names:
171
- @direct_attrs = ext_direct - int_linked
172
- @internal_attrs = @aliased_attrs | @direct_attrs
190
+ #@direct_attrs = data_ext_direct - def_linked
191
+ @direct_attrs = data_ext_direct
192
+ @internal_attrs = @aliased_attrs | @direct_attrs
173
193
  end
174
194
 
175
195
  def attributes(value)
@@ -100,8 +100,11 @@ module Eco
100
100
  end
101
101
  msg << "#{sample.slice(0, sample_length).pretty_inspect}"
102
102
  end
103
- msg << "#{"+"*3} #{type.to_s.upcase} length: #{requests.length} #{"+"*3} STATS (job '#{name}') #{"+"*3}"
103
+ stats_str = "#{"+"*3} #{type.to_s.upcase} length: #{requests.length} #{"+"*3} STATS (job '#{name}') #{"+"*3}"
104
+ msg << "#{"-"*stats_str.length}" if only_stats
105
+ msg << stats_str
104
106
  msg << "#{request_stats(requests).message}"
107
+ msg << "#{"-"*stats_str.length}" if only_stats
105
108
  msg << "*" * header.length unless only_stats
106
109
  end
107
110
  end.join("\n")
@@ -29,7 +29,7 @@ module Eco
29
29
  attr_reader :usecase
30
30
  attr_reader :status, :feedback
31
31
 
32
- # @param e [Eco::API::Common::Session::Environment] requires a session environmen, as any child of `Eco::API::Common::Session::BaseSession`
32
+ # @param e [Eco::API::Common::Session::Environment] requires a session environment, as any child of `Eco::API::Common::Session::BaseSession`
33
33
  # @param name [String] the name of this `batch job`
34
34
  # @param type [Symbol] a valid batch operation
35
35
  # @param usecase [Eco::API::UseCases::UseCase, nil] when provided: `usecase` that generated this `batch job`
@@ -27,7 +27,7 @@ module Eco
27
27
  end
28
28
  end
29
29
 
30
- # @param e [Eco::API::Common::Session::Environment] requires a session environmen, as any child of `Eco::API::Common::Session::BaseSession`
30
+ # @param e [Eco::API::Common::Session::Environment] requires a session environment, as any child of `Eco::API::Common::Session::BaseSession`
31
31
  # @param queue [Array<Hash>, Array<Ecoportal::API::V1::Person>, Array<Ecoportal::API::Internal::Person>] the `source_queue`
32
32
  # @param method [Symbol] the type of `batch operation`
33
33
  # @param mode [Symbol] the mode of `batch operation` (search)
@@ -83,7 +83,7 @@ module Eco
83
83
  # 1. `Integer`: index/position of the entry in the final `queue`
84
84
  # 2. `Hash`: entry queries can be raw `Hash` objects
85
85
  # 3. `Person` object: the most common case is to use the person wrapper classes of the `Ecoportal::API` namespace.
86
- # @return response key [Ecoportal::API::Common::BatchResponse]
86
+ # @return [Ecoportal::API::Common::BatchResponse]
87
87
  def [](key)
88
88
  @responses[to_index(key)]
89
89
  end
@@ -97,10 +97,10 @@ module Eco
97
97
  end
98
98
 
99
99
  # The _person_ we got from the Server wrapped to the `Person` object for the input entry object `key`
100
- # @note it only makes sense when the batch method used was `get`
100
+ # @note it only makes sense when the used batch method was `get`
101
101
  # @param key [Integer, Hash, Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person]
102
102
  # @see Eco::API::Session::Batch::Status#[] for `key` options
103
- # return [Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person]
103
+ # @return [Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person]
104
104
  def person(key)
105
105
  return self[key].result if success?(key)
106
106
  nil
@@ -112,7 +112,7 @@ module Eco
112
112
  # - **found using a search criteria** (`mode` == `:search`), as opposite to find the person directly by `external_id`
113
113
  # @param key [Integer, Hash, Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person]
114
114
  # @see Eco::API::Session::Batch::Status#[] for `key` options
115
- # return [Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person]
115
+ # @return [Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person]
116
116
  def person_match(key)
117
117
  @person_match[to_index(key)]
118
118
  end
@@ -130,14 +130,14 @@ module Eco
130
130
  end
131
131
 
132
132
  # Has the _entry_ `key` been queried to the server?
133
- # @param key [Hash, Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person]
133
+ # @param key [Integer, Hash, Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person]
134
134
  # @return [Boolean] `true` if input entry `key` has an associated `Ecoportal::API::Common::BatchResponse`
135
135
  def received?(key)
136
136
  !!self[key]
137
137
  end
138
138
 
139
139
  # Has the _entry_ `key` 's query to the server been successful
140
- # @param key [Hash, Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person]
140
+ # @param key [Integer, Hash, Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person]
141
141
  # @return [Boolean] `true` if input entry `key` has not had a server Error during the query
142
142
  def success?(key)
143
143
  self[key]&.success?
@@ -169,6 +169,7 @@ module Eco
169
169
  end
170
170
 
171
171
  # Helper to transform any `key` to an `Integer` index
172
+ # @param key [Integer, Hash, Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person]
172
173
  # @return [Integer] the index that `key` has in the final `queue`
173
174
  def to_index(key)
174
175
  key.is_a?(Integer) ? valid_index(index: key) : valid_index(entry: key)
@@ -234,7 +234,7 @@ module Eco
234
234
  rescue SystemExit
235
235
  exit
236
236
  rescue Interrupt => i
237
- raise i
237
+ raise
238
238
  rescue Exception => e
239
239
  self.rescue.call(e, io) if self.rescue
240
240
  raise
@@ -5,5 +5,4 @@ end
5
5
 
6
6
  require_relative 'data/crypto'
7
7
  require_relative 'data/files'
8
- require_relative 'data/random'
9
8
  require_relative 'data/mapper'
@@ -1,3 +1,3 @@
1
1
  module Eco
2
- VERSION = "1.1.5"
2
+ VERSION = "1.1.6"
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.1.5
4
+ version: 1.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oscar Segura
@@ -198,46 +198,6 @@ dependencies:
198
198
  - - ">="
199
199
  - !ruby/object:Gem::Version
200
200
  version: 2.1.2
201
- - !ruby/object:Gem::Dependency
202
- name: faker
203
- requirement: !ruby/object:Gem::Requirement
204
- requirements:
205
- - - "~>"
206
- - !ruby/object:Gem::Version
207
- version: '2'
208
- - - ">="
209
- - !ruby/object:Gem::Version
210
- version: '2.1'
211
- type: :runtime
212
- prerelease: false
213
- version_requirements: !ruby/object:Gem::Requirement
214
- requirements:
215
- - - "~>"
216
- - !ruby/object:Gem::Version
217
- version: '2'
218
- - - ">="
219
- - !ruby/object:Gem::Version
220
- version: '2.1'
221
- - !ruby/object:Gem::Dependency
222
- name: distribution
223
- requirement: !ruby/object:Gem::Requirement
224
- requirements:
225
- - - "~>"
226
- - !ruby/object:Gem::Version
227
- version: '0.7'
228
- - - ">="
229
- - !ruby/object:Gem::Version
230
- version: 0.7.3
231
- type: :runtime
232
- prerelease: false
233
- version_requirements: !ruby/object:Gem::Requirement
234
- requirements:
235
- - - "~>"
236
- - !ruby/object:Gem::Version
237
- version: '0.7'
238
- - - ">="
239
- - !ruby/object:Gem::Version
240
- version: 0.7.3
241
201
  description:
242
202
  email:
243
203
  - oscar@ecoportal.co.nz
@@ -291,7 +251,6 @@ files:
291
251
  - lib/eco/api/common/version_patches/exception.rb
292
252
  - lib/eco/api/common/version_patches/hash.rb
293
253
  - lib/eco/api/common/version_patches/hash/deep_merge.rb
294
- - lib/eco/api/eco_faker.rb
295
254
  - lib/eco/api/error.rb
296
255
  - lib/eco/api/error/handler.rb
297
256
  - lib/eco/api/error/handlers.rb
@@ -390,10 +349,6 @@ files:
390
349
  - lib/eco/data/files/file_pattern.rb
391
350
  - lib/eco/data/files/helpers.rb
392
351
  - lib/eco/data/mapper.rb
393
- - lib/eco/data/random.rb
394
- - lib/eco/data/random/distribution.rb
395
- - lib/eco/data/random/fake.rb
396
- - lib/eco/data/random/values.rb
397
352
  - lib/eco/language.rb
398
353
  - lib/eco/language/curry.rb
399
354
  - lib/eco/language/hash_transform.rb
@@ -406,7 +361,6 @@ files:
406
361
  - lib/eco/language/models/parser_serializer.rb
407
362
  - lib/eco/language/models/wrap.rb
408
363
  - lib/eco/language/values_at.rb
409
- - lib/eco/tester.rb
410
364
  - lib/eco/version.rb
411
365
  homepage: https://www.ecoportal.com
412
366
  licenses:
@@ -1,59 +0,0 @@
1
- module Eco
2
- module API
3
- # faker object
4
- @@faker = nil
5
- class EcoFaker
6
- @@api = nil
7
- @org = nil
8
- # attr_accessor
9
- attr_reader :org
10
- def initialize(init = {})
11
- set_settings(init)
12
- end
13
- # allows to change certain configuration settings on an existing Faker instance object
14
- def set_settings (init = {})
15
- @today = (aux = init['today'])? aux : Time.now
16
- api = init.fetch('api', nil)
17
- @@api = api.instance_of?(Ecoportal::API::Internal) && api
18
- # this will initialize org basics (i.e. people_schemas, policy_groups, login_providers)
19
- @org = Organization.new(init)
20
- end
21
- def newPerson ()
22
-
23
- end
24
- def modifyPerson(person)
25
-
26
- end
27
- private
28
- end
29
-
30
- def self.new(init = {})
31
- @@faker = EcoFaker.new(init)
32
- end
33
-
34
- class FakePerson < Ecoportal::API::Internal::Person
35
- @@faker
36
- def initialize(faker, *args)
37
- raise "You must initialize the faker first" unless faker && faker.instance_of(Faker)
38
- @@faker = faker
39
- super(*args)
40
- @@faker.set_details
41
- end
42
- end
43
-
44
- class FakeField
45
- @@types = ["boolean", "number", "text", "select", "date", "phone_number"]
46
- @@multiple = false
47
- attr_accessor :type, :multiple
48
- #attr_reader
49
- def initialize (init = {})
50
- init_values_generator(init)
51
- end
52
- private
53
- def init_values_faker (init = {})
54
- include
55
- @fake_values = API::Data::Random::ValuesGenerator.new(init)
56
- end
57
- end
58
- end
59
- end
@@ -1,10 +0,0 @@
1
- module Eco
2
- module Data
3
- module Random
4
- end
5
- end
6
- end
7
-
8
- require_relative 'random/distribution'
9
- require_relative 'random/values'
10
- require_relative 'random/fake'
@@ -1,133 +0,0 @@
1
- require 'distribution' # source: https://github.com/sciruby/distribution
2
-
3
- # todo: remove distribution dependency by developing a normal distribution generator
4
- # - Reference: https://stackoverflow.com/a/6178290/4352306
5
-
6
- module Eco
7
- module Data
8
- module Random
9
- class Distribution
10
-
11
- MAX_DECIMALS = 10
12
- BALANCE = ["uniform", "normal", "half-normal", "forged"]
13
-
14
- attr_accessor :decimals
15
- attr_reader :calls
16
- attr_reader :range, :min, :max, :balance, :mean, :sigma
17
- attr_reader :weights, :weights_distribution
18
- def initialize(init = {})
19
- @calls = 0
20
- @weight_positions = 0
21
-
22
- @decimals = init.fetch('decimals', MAX_DECIMALS)
23
- self.range = init.fetch('range', 0..1)
24
- self.weights = init.fetch('weights', nil)
25
- self.balance = init.fetch('balance', nil)
26
-
27
- @normal = ::Distribution::Normal.rng(@mean, @sigma)
28
- @random = ::Random.new
29
- end
30
-
31
- def balance=(value)
32
- @balance = value
33
- @balance = BALANCE[0] if !BALANCE.include?(@balance)
34
- case @balance
35
- when 'forged'
36
- if @weights&.instance_of?(Array)
37
- top = @weights.length - 1
38
- self.range = (0..top)
39
- end
40
- end
41
- end
42
-
43
- def range=(value)
44
- @range = value
45
- @min = @range.first; @max = @range.last
46
- @mean = @max / 2
47
- @sigma = (@max - @mean) / 3.5
48
- end
49
-
50
- def weights=(value)
51
- @weights = nil; @weights_distribution = nil; @weight_positions = 0
52
- @weights = value if value && value.instance_of?(Array)
53
- if @weights
54
- total = @weights.inject(0, :+)
55
- @weight_positions = total * 20
56
- @weights_distribution = Array.new(@weight_positions)
57
-
58
- i = 0; j = 0
59
- while i < @weights.length
60
- positions = (@weights[i] * @weight_positions / total).round
61
- positions.times do
62
- @weights_distribution[j] = i
63
- j += 1
64
- end
65
- i += 1
66
- end
67
- if (missing = @weight_positions - j) >= 0
68
- (missing + 1).times {
69
- @weights_distribution[j] = 0
70
- j += 1
71
- }
72
- end
73
- end
74
- end
75
-
76
- def generate
77
- @calls += 1
78
- case @balance
79
- when 'uniform'
80
- num = generate_uniform
81
- when 'normal'
82
- num = generate_normal
83
- when 'half-normal'
84
- num = generate_half_normal
85
- when 'forged'
86
- num = generate_forged
87
- else
88
- num = generate_uniform
89
- end
90
-
91
- num = generate if num && !@range.member?(num.round)
92
- return num && num.round(@decimals)
93
- end
94
-
95
- private
96
-
97
- def generate_uniform
98
- @random.rand(@range)
99
- end
100
-
101
- def generate_normal
102
- @normal.call
103
- end
104
-
105
- def generate_half_normal
106
- num = generate_normal
107
- num = normal_mirror(num, @mean) if num.round < @mean
108
- num = generate_half_normal if num.round == @mean
109
- num -= @mean
110
- num = num - 1 if num.round > 0 # move distribution to left (mirroring doubles density except at mean)
111
- return num
112
- end
113
-
114
- def generate_forged
115
- #raise "You need to assign weights to be able to use the forge balance!" if !@weights_distribution&.instance_of?(Array)
116
- if @weights_distribution&.instance_of?(Array)
117
- top = @weight_positions - 1
118
- pos = @random.rand(0..top)
119
- return weights_distribution[pos]
120
- end
121
- return generate_normal # should raise error at the beginning of the function
122
- end
123
-
124
- def normal_mirror (num, mean)
125
- return mean + (mean - num) if num.round < mean
126
- return mean - (num - mean) if num.round > mean
127
- return num
128
- end
129
-
130
- end
131
- end
132
- end
133
- end
@@ -1,320 +0,0 @@
1
- require 'faker'
2
-
3
- module Eco
4
- module Data
5
- module Random
6
- class Fake
7
-
8
- MAX_UNIQUE_ERRORS = 13
9
- DEFAULT_LOCALE = 'en'
10
- DEFAULT_EMAIL_PATTERN = 'oscar+name@ecoportal.co.nz'
11
- LOCALES_MAPS = {'en' => 'en', 'nz' => 'en-NZ', 'ca' => 'en-CA', 'uk' => 'en-GB', 'usa' => 'en-USA'}
12
- TOPICS_MAPS = {
13
- 'general' => ['General', 'Vehicle', 'University', 'Address'],
14
- 'fantasy' => ['LordOfTheRings', 'Hobbit', 'HarryPotter', 'BackToTheFuture', 'FunnyName', 'GameOfThrones', 'PricesBride', 'StarWars', 'StarkTrek'],
15
- 'medieval-fantasy' => ['LordOfTheRings', 'Hobbit', 'GameOfThrones', 'PricesBride'],
16
- 'futuristic-fantasy' => ['BackToTheFuture', 'StarWars', 'StarTrek'],
17
- 'tolkien' => ['LordOfTheRings', 'Hobbit'],
18
- 'funny' => ['FunnyName', 'Simpsons', 'Superhero'],
19
- 'famous' => ['Book', 'GreekPhilosophers' ,'Scientists', 'SiliconValley', 'Space', 'WorldCup'],
20
- 'philosophers' => 'GreekPhilosophers'
21
- }
22
- @name = nil; @name_topics = nil
23
- @location = nil; @location_topics = nil
24
-
25
- attr_reader :local, :topic, :general_topic_on_fail
26
- attr_reader :today, :email_pattern, :unique_errors, :unique_resets, :force_unique
27
-
28
- def initialize(init = {})
29
- @unique_resets = 0; @unique_errors = 0
30
- init_topics
31
- self.topic = init.fetch('topic', TOPICS_MAPS.keys.sample)
32
- self.general_topic_on_fail = init.fetch('general_topic_on_fail', false)
33
- self.force_unique = init.fetch('force_unique', false)
34
-
35
- self.local = init.fetch('local', nil)
36
- self.today = init.fetch('today', Date.today)
37
- self.email_pattern = init.fetch('email_pattern', DEFAULT_EMAIL_PATTERN)
38
-
39
- @boolean = Faker::Boolean.method('boolean')
40
- @date_between = Faker::Date.method('between')
41
-
42
- @gender = Faker::Gender.method('binary_type')
43
-
44
- @name = get_topic_wrapper(@name_topics)
45
- @company = get_topic_wrapper(@company_topics)
46
- @location = get_topic_wrapper(@location_topics)
47
-
48
- @community = wrap_method { Faker::Address.community }
49
- @address = wrap_method { Faker::Address.unique.full_address }
50
- @country = wrap_method { Faker::Address.country }
51
- @city = wrap_method { Faker::Address.city }
52
- @postcode = wrap_method { Faker::Address.postcode }
53
- @timezone = Faker::Address.method('time_zone')
54
-
55
- @phone = wrap_method { Faker::PhoneNumber.unique.phone_number }
56
- @mobile = wrap_method { Faker::PhoneNumber.unique.cell_phone }
57
- @mobile_code = wrap_method { Faker::Code.unique.imei }
58
- end
59
-
60
- def topic=(value)
61
- @topic = TOPICS_MAPS.values.first # 'General'
62
- @topic = TOPICS_MAPS[value.downcase] if value && TOPICS_MAPS.keys.include?(value.downcase)
63
- init_topic_wrappers
64
- end
65
-
66
- def general_topic_on_fail=(value)
67
- @general_topic_on_fail = value
68
- end
69
-
70
- def today=(value)
71
- @today = nil
72
- @today = value if value.instance_of?(Date)
73
- @today = Date.today if !@today
74
- end
75
-
76
- def email_pattern=(value)
77
- @email_pattern = value
78
- @email_pattern = DEFAULT_EMAIL_PATTERN if !@mail_pattern&.include?('@ecoportal.co.nz')
79
- end
80
-
81
- def local=(value)
82
- @local = DEFAULT_LOCALE
83
- alias_locales = LOCALES_MAPS.keys; locales = LOCALES_MAPS.values
84
- permitted = value && (alias_locales.include?(value.downcase) || locales.include?(value))
85
- @local = LOCALES_MAPS[value.downcase] if permitted
86
- ::Faker::Config.locale = @local
87
- end
88
-
89
- def force_unique=(value)
90
- @force_unique = !!value
91
- end
92
-
93
- def reset_unique
94
- @unique_errors = 0
95
- @unique_resets += 1
96
- ::Faker::UniqueGenerator.clear
97
- end
98
-
99
- def boolean
100
- @boolean.call
101
- end
102
-
103
- def past_date(years = 3)
104
- @date_between.call(previous_date(years), @today)
105
- end
106
-
107
- def future_date(years = 3)
108
- @date_between.call(@today, later_date(years))
109
- end
110
-
111
- def birthday(min_age = 18, max_age = 65)
112
- @date_between.call(previous_date(min_age), previous_date(max_age))
113
- end
114
-
115
- def name
116
- new_value = get_unique(@name, @name_topics)
117
- @name = get_topic_wrapper(@name_topics)
118
- return new_value
119
- end
120
-
121
- def company
122
- new_value = get_unique(@company, @company_topics)
123
- @company = get_topic_wrapper(@company_topics)
124
- return new_value
125
- end
126
-
127
- def community
128
- @community.call
129
- end
130
-
131
- def location
132
- new_value = get_unique(@location, @location_topics)
133
- @location = get_topic_wrapper(@location_topics)
134
- return new_value
135
- end
136
-
137
- def address
138
- @address.call
139
- end
140
-
141
- def contry
142
- @country.call
143
- end
144
-
145
- def city
146
- @city.call
147
- end
148
-
149
- def postcode
150
- @postcode.call
151
- end
152
-
153
- def timezone
154
- @timezone.call
155
- end
156
-
157
- def gender
158
- @geneder.call
159
- end
160
-
161
- def email(str_name = nil)
162
- str_name = self.name if !str_name&.strip
163
- @email_pattern.gsub('name', email_encode(str_name))
164
- end
165
-
166
- def phone
167
- @phone.call
168
- end
169
-
170
- def mobile
171
- @mobile.call
172
- end
173
-
174
- def mobile_code
175
- @mobile_code.call
176
- end
177
-
178
- private
179
-
180
- def unique_error_count
181
- @unique_errors += 1
182
- unique_overflow = @unique_errors > MAX_UNIQUE_ERRORS
183
- err_msg = "Error uniqueness broken"
184
- raise Faker::UniqueGenerator::RetryLimitExceeded.new(err_msg), err_msg if self.force_unique && unique_overflow
185
- self.reset_unique if unique_overflow
186
- end
187
-
188
- def previous_date(years = 3)
189
- @today - (years * 365)
190
- end
191
-
192
- def later_date(years = 3)
193
- @today + (years * 365)
194
- end
195
-
196
- def init_topics
197
- @name_topics = {
198
- 'General' => wrap_method { Faker::Name.unique.name },
199
- 'LordOfTheRings' => wrap_method { Faker::LordOfTheRings.unique.character },
200
- 'Hobbit' => wrap_method { Faker::Hobbit.unique.character },
201
- 'BackToTheFuture' => wrap_method { Faker::BackToTheFuture.unique.character },
202
- 'HarryPotter' => wrap_method { Faker::HarryPotter.unique.character },
203
- 'GameOfThrones' => wrap_method { Faker::GameOfThrones.unique.character },
204
- 'PrincesBride' => wrap_method { Faker::PrincesBride.unique.character },
205
- 'StarWars' => wrap_method { Faker::StarWars.unique.character },
206
- 'StarTrek' => wrap_method { Faker::StarTrek.unique.character },
207
- 'Simpsons' => wrap_method { Faker::Simpsons.unique.character },
208
- 'Superhero' => wrap_method { Faker::Superhero.unique.name },
209
- 'FunnyName' => wrap_method { Faker::FunnyName.unique.name },
210
- 'Book' => wrap_method { Faker::Book.unique.author },
211
- 'GreekPhilosophers' => wrap_method { Faker::GreekPhilosophers.unique.name },
212
- 'Scientists' => wrap_method { Faker::Science.unique.scientist },
213
- 'SiliconValley' => wrap_method { Faker::SiliconValley.unique.character },
214
- 'WorldCup' => wrap_method { Faker::WorldCup.unique.roster }
215
- }
216
-
217
- @location_topics = {
218
- 'General' => wrap_method { Faker::Nation.capital_city },
219
- 'LordOfTheRings' => wrap_method { Faker::LordOfTheRings.location },
220
- 'Hobbit' => wrap_method { Faker::Hobbit.location },
221
- 'HarryPotter' => wrap_method { Faker::HarryPotter.location },
222
- 'GameOfThrones' => wrap_method { Faker::GameOfThrones.city },
223
- 'Simpsons' => wrap_method { Faker::Simpsons.location },
224
- 'StarTrek' => wrap_method { Faker::StarTrek.location },
225
- 'WorldCup' => wrap_method { Faker::WorldCup.city },
226
- 'University' => wrap_method { Faker::University.name },
227
- 'Address' => wrap_method { Faker::Address.city }
228
- }
229
-
230
- @company_topics = {
231
- 'General' => wrap_method { Faker::Company.name },
232
- 'Vehicle' => wrap_method { Faker::Vehicle.manufacture },
233
- 'SiliconValley' => wrap_method { Faker::SiliconValley.company },
234
- 'Space' => wrap_method { Faker::Space.company }
235
- }
236
-
237
- @deparment_topics = {
238
- 'General' => wrap_method { Faker::Commerce.department }
239
- }
240
- end
241
-
242
- def init_topic_wrappers
243
- @name = get_topic_wrapper(@name_topics)
244
- @location = get_topic_wrapper(@location_topics)
245
- end
246
-
247
- def get_topic_wrapper(type_topics)
248
- all_topics = @topic.instance_of?(Array)? @topic : [@topic]
249
- topics = filter_by_key(type_topics, all_topics)
250
- failed_topic = !@topic || !topics || topics.values.length < 1
251
-
252
- if !failed_topic
253
- topic = topics.values.sample
254
- #puts "\"Custom!!!!\""
255
- else
256
- if @general_topic_on_fail
257
- topic = type_topics.fetch('General', nil)
258
- #puts "\"Genearal!!!!\""
259
- else
260
- topic = type_topics.values.sample
261
- #puts "\"Force Random!!!!\""
262
- end
263
- end
264
- return topic
265
- end
266
-
267
- def get_unique(wrapper, related_topics)
268
- begin
269
- new_value = wrapper.call
270
- rescue Faker::UniqueGenerator::RetryLimitExceeded
271
- unique_error_count
272
- wrapper = get_topic_wrapper(related_topics)
273
- new_value = get_unique(wrapper, related_topics)
274
- end
275
- return new_value
276
- end
277
-
278
- def filter_by_key (hash, keys)
279
- hash.select { |k,v| keys.include?(k) }
280
- end
281
-
282
- # should allow different topics
283
- def email_encode(str)
284
- return nil if !str.is_a?(String)
285
- return str.gsub(/\s+/,"_")&.gsub(/\W/,"")&.slice(0,25).downcase
286
- end
287
-
288
- def wrap_method(&block)
289
- block
290
- end
291
-
292
- def self.test(test_times = 500, fantasy: true, force_unique: false)
293
- pp "########## Testing Faker wrapper ###########"
294
- topic = if fantasy then 'fantasy' else nil end
295
- faker = self.new({
296
- 'today' => Date.new(2018,1,1),
297
- 'locale' => 'nz',
298
- 'topic' => topic,
299
- 'general_topic_on_fail' => true,
300
- 'force_unique' => force_unique
301
- })
302
- begin
303
- items = 0
304
- test_times.times {
305
- pp "#{name=faker.name} - #{faker.birthday(20, 40).to_s} : #{faker.mobile} : #{faker.email(name)}" + \
306
- " : #{faker.location} : #{faker.company} : #{faker.community}"
307
- items += 1
308
- }
309
- rescue ::Faker::UniqueGenerator::RetryLimitExceeded => e
310
- puts "### Error: #{e.message} ###"
311
- end
312
- puts "total generated: #{items}"
313
- puts "locale: #{faker.local}; topic: #{topic}"
314
- puts "unique errors: #{faker.unique_errors} & #{faker.unique_resets} resets"
315
- end
316
-
317
- end
318
- end
319
- end
320
- end
@@ -1,80 +0,0 @@
1
- require 'json'
2
-
3
- module Eco
4
- module Data
5
- module Random
6
- class Values
7
-
8
- attr_accessor :multiple, :unique
9
- attr_reader :options, :weights, :options_weight, :quantity
10
- attr_reader :generator, :generator_config
11
-
12
- def initialize(init = {})
13
- @multiple = init.fetch('multiple', false)
14
- @unique = init.fetch('unique', true)
15
- self.quantity = init.fetch('quantity', nil)
16
- @options_weight = init.fetch('options_weight', nil)
17
- @options = init.fetch('options', @options_weight&.keys)
18
- @weights = @options_weight&.values
19
-
20
- @generator_config = init.fetch('generator_config', { "decimals" => 0 })
21
- if @weights
22
- @generator_config['weights'] = @weights unless @generator_config.key?('weights')
23
- @generator_config['balance'] = 'forged' unless @generator_config.key?('balance')
24
- else
25
- case
26
- when @options&.instance_of?(Array)
27
- @generator_config['weights'] = @weights unless @generator_config.key?('weights')
28
- end
29
- end
30
- @generator = Distribution.new(@generator_config)
31
- @random = ::Random.new
32
- end
33
-
34
- def quantity=(num_or_range) # attr_writer
35
- val = num_or_range
36
- case
37
- when val.is_a?(Numeric)
38
- num = val.round
39
- rng = (num..num)
40
- when val.instance_of?(Range)
41
- rng = val
42
- else
43
- rng = (0..1)
44
- end
45
- @quantity = rng
46
- end
47
-
48
- def generate
49
- if @multiple
50
- quantity = @random.rand(@quantity)
51
- value = []
52
- quantity.times {
53
- val = @unique? generate_option(exclude: value): generate_option
54
- value.push(val)
55
- }
56
- value = value.uniq if @unique
57
- else
58
- value = generate_option
59
- end
60
- return value
61
- end
62
-
63
- def generate_option(exclude: [])
64
- case
65
- when @options&.instance_of?(Array)
66
- val = @options[@generator.generate]
67
- else
68
- puts "something bad with @options"
69
- end
70
- #exclude_aux = Marshal.load(Marshal::dump(exclude))
71
- exclude_aux = JSON.parse(exclude.to_json)
72
- exclude_aux.pop
73
- val = generate_option(exclude: exclude_aux) if exclude.include?(val)
74
- return val
75
- end
76
-
77
- end
78
- end
79
- end
80
- end
@@ -1,97 +0,0 @@
1
- require 'pp'
2
-
3
- module Eco
4
- TEST_TIMES = 5000
5
- RANDOM = Eco::Data::Random
6
- class Tester
7
- include Data
8
-
9
- def test_normal(test_times = TEST_TIMES)
10
- pp "########## Testing Normal Distribution ###########"
11
- generator_config = {
12
- "range" => (1..100),
13
- "decimals" => 0,
14
- "balance" => 'normal'
15
- }
16
- generator = RANDOM::Distribution.new(generator_config)
17
- frequency = frequency_sample(generator, test_times)
18
- draw_frequency(frequency)
19
- end
20
-
21
- def test_half_normal(test_times = TEST_TIMES)
22
- pp "########## Testing Half-Normal Distribution ###########"
23
- generator_config = {
24
- "range" => (1..100),
25
- "decimals" => 0,
26
- "balance" => 'half-normal'
27
- }
28
- generator = RANDOM::Distribution.new(generator_config)
29
- frequency = frequency_sample(generator, test_times)
30
- draw_frequency(frequency)
31
- end
32
-
33
- def test_forged(test_times = TEST_TIMES)
34
- pp "########## Testing Forged Distribution ###########"
35
- generator_config = {
36
- "range" => (1..100),
37
- "decimals" => 0,
38
- "balance" => 'forged'
39
- }
40
- options_weight = {"One" => 10, "Two" => 5, "Three" => 2, "Four" => 1, "Five" => 1}
41
- options_config = {
42
- #'generator_config' => generator_config,
43
- 'options_weight' => options_weight,
44
- 'multiple' => false,
45
- 'quantity' => 2
46
- }
47
-
48
- generator = RANDOM::Values.new(options_config)
49
- frequency = frequency_sample(generator, test_times)
50
- draw_frequency(frequency)
51
- end
52
-
53
- private
54
-
55
- def frequency_sample (generator, test_times = TEST_TIMES)
56
- frequency = Hash.new {|hash, key| hash[key]=0}
57
- test_times.times.map {
58
- val = generator.generate
59
- "here a nil!!" if !val
60
- val = val.round if val.is_a? Numeric
61
- frequency[val] += 1 if val
62
- }
63
- return frequency
64
- end
65
-
66
- def draw_frequency(frequency, generator = nil, histogram: true)
67
- #pp frequency
68
- vals = frequency.values
69
- test_times = vals.inject(0, :+)
70
- opts = vals.length
71
-
72
- raise "no tests to show" if !test_times || test_times < 1
73
- dimension = Math::log10(test_times)
74
- draw_unit = (10**(dimension - 1) / (opts * 3)).round
75
-
76
- total = 0; sum = 0
77
- frequency.keys.sort.each do |k|
78
- f = frequency[k]
79
- percent = (f * 100 / test_times ).round
80
- puts "#{k} (#{percent}/100): #{'*' * (f / draw_unit).round}" if :historgram
81
- #puts "#{k} (#{percent}/100): #{'*' * f}" if :historgram
82
- puts "#{k} (#{percent}/100): #{f}" if !:historgram
83
- total += frequency[k]
84
- v = k
85
- v = 1 if !k.is_a? Numeric
86
- sum += (frequency[k] * v)
87
- end
88
-
89
- summary = "total: #{total}; mean: #{sum / total}"
90
- summary += "; draw unit #{draw_unit}" if :historgram
91
- puts summary
92
- pp "generator weights (config): #{generator.weights}" if generator
93
- pp "generator unique (config): #{generator.unique}" if generator
94
- end
95
-
96
- end
97
- end