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 +4 -4
- data/eco-helpers.gemspec +0 -2
- data/lib/eco-helpers.rb +0 -1
- data/lib/eco/api.rb +0 -1
- data/lib/eco/api/common/people/person_entry_attribute_mapper.rb +41 -21
- data/lib/eco/api/session/batch/feedback.rb +4 -1
- data/lib/eco/api/session/batch/job.rb +1 -1
- data/lib/eco/api/session/batch/status.rb +8 -7
- data/lib/eco/api/session/config/workflow.rb +1 -1
- data/lib/eco/data.rb +0 -1
- data/lib/eco/version.rb +1 -1
- metadata +1 -47
- data/lib/eco/api/eco_faker.rb +0 -59
- data/lib/eco/data/random.rb +0 -10
- data/lib/eco/data/random/distribution.rb +0 -133
- data/lib/eco/data/random/fake.rb +0 -320
- data/lib/eco/data/random/values.rb +0 -80
- data/lib/eco/tester.rb +0 -97
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0c1cca427dcc2ced629146debcbe71a05f062002919b68b32e88ebddd86c25c
|
4
|
+
data.tar.gz: e74e5b3c8007af145e1255903a4a1a26dc785b84004434291524275a5ac38734
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55e089b0827e28aafb5ac51e5b7ff37a09a81ab71160087080ecff70a10a44397dec6d0e2d847f8a5767b52c44a6ae548affd06c28a6e4ccb3d2edf37472f81a
|
7
|
+
data.tar.gz: 4801acfeedc39e1287808f812845c915316e0bac92d16594fe412899483104cba6604f30e1cf717dae6438c2f4e69a4e1adb1ea7af863d3a2a27273a36b1ec3a
|
data/eco-helpers.gemspec
CHANGED
@@ -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
|
data/lib/eco-helpers.rb
CHANGED
data/lib/eco/api.rb
CHANGED
@@ -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
|
34
|
+
@source = data
|
35
35
|
@person_parser = person_parser
|
36
|
-
@attr_map
|
37
|
-
@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
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
#
|
150
|
-
|
151
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
164
|
-
|
165
|
-
|
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
|
-
|
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
|
-
|
172
|
-
@
|
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
|
-
|
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
|
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
|
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
|
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
|
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)
|
data/lib/eco/data.rb
CHANGED
data/lib/eco/version.rb
CHANGED
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.
|
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:
|
data/lib/eco/api/eco_faker.rb
DELETED
@@ -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
|
data/lib/eco/data/random.rb
DELETED
@@ -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
|
data/lib/eco/data/random/fake.rb
DELETED
@@ -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
|
data/lib/eco/tester.rb
DELETED
@@ -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
|