eco-helpers 1.1.5 → 1.1.6

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