faker_maker 1.3.0 → 2.0.0
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/.github/workflows/ruby.yml +37 -0
- data/.gitignore +2 -1
- data/.rubocop.yml +6 -0
- data/bin/console +1 -0
- data/docs/usage/chaos.md +45 -0
- data/faker_maker.gemspec +1 -1
- data/lib/faker_maker/attribute.rb +22 -2
- data/lib/faker_maker/factory.rb +98 -9
- data/lib/faker_maker/version.rb +1 -1
- data/lib/faker_maker.rb +1 -0
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc9201db222f65f8df79f92edc882d9d76e5ca21c6220b377f5e86ce9414d287
|
4
|
+
data.tar.gz: d4601f347ce1231fd287d33addde2bb83c00a1a770783eec8007dd7417c6c2f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce1be4538d82898bb1accd89585485e6072974350088261dece5f0481a3d1950cbf1462dba6363231e2b25019632d8f1aa649e04cab5c4a0a752c6ca9e428c7f
|
7
|
+
data.tar.gz: 2d442d69c483b0aa5ba5f7bc9fd26396376edbc2ff700c9d47305d27f2fc809d42d4971bf8ef8b09c67f7f4912395e6eb0127c0d105e6763708f342916e2ae85
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: Ruby
|
9
|
+
|
10
|
+
on:
|
11
|
+
push:
|
12
|
+
pull_request:
|
13
|
+
branches: [ "master" ]
|
14
|
+
|
15
|
+
permissions:
|
16
|
+
contents: read
|
17
|
+
|
18
|
+
jobs:
|
19
|
+
test:
|
20
|
+
|
21
|
+
runs-on: ubuntu-latest
|
22
|
+
strategy:
|
23
|
+
matrix:
|
24
|
+
ruby-version: ["3.0", "3.1", "3.2"]
|
25
|
+
|
26
|
+
steps:
|
27
|
+
- uses: actions/checkout@v3
|
28
|
+
- name: Set up Ruby
|
29
|
+
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
30
|
+
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
31
|
+
# uses: ruby/setup-ruby@v1
|
32
|
+
uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0
|
33
|
+
with:
|
34
|
+
ruby-version: ${{ matrix.ruby-version }}
|
35
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
36
|
+
- name: Run tests
|
37
|
+
run: bundle exec rake
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/bin/console
CHANGED
data/docs/usage/chaos.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
---
|
2
|
+
layout: default
|
3
|
+
title: Chaos
|
4
|
+
parent: Usage
|
5
|
+
nav_order: 11
|
6
|
+
---
|
7
|
+
|
8
|
+
# Chaos
|
9
|
+
|
10
|
+
Chaos mode introduces extra spice to your generated factories.
|
11
|
+
|
12
|
+
Attributes can be marked as either `required` or `optional`, which Chaos will use to determine what attributes are included when instantiating your factory.
|
13
|
+
|
14
|
+
Required attributes will always be present, however, optional attributes are not guaranteed to be present when Chaos is enabled.
|
15
|
+
|
16
|
+
*All attributes are optional by default.*
|
17
|
+
|
18
|
+
To explicitly mark attributes as either required or optional:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
FM.factory :item, naming: :json do
|
22
|
+
name { 'Blanket' }
|
23
|
+
price(required: true) { 100 }
|
24
|
+
description(optional: true) { 'Keeps you warm and cozy' }
|
25
|
+
manufacturer(optional: 0.7) { 'A large fruit company' }
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
You can state an attribute is optional using the `optional` option set to either be a `Boolean`, `Integer` or a `Float`.
|
30
|
+
|
31
|
+
When optional is set to either an `Integer` or a `Float`, this overrides the weighting which Chaos uses to determine the likelihood that attribute will be removed.
|
32
|
+
|
33
|
+
Higher the value, the more likely that attribute will be present. By default there's a 50/50 chance an optional attribute will be present.
|
34
|
+
|
35
|
+
To unleash Chaos over a factory, you need to enable it when instantiating your object:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
result = FakerMaker[:item].build( chaos: true )
|
39
|
+
```
|
40
|
+
|
41
|
+
You can also specify which attributes Chaos can use when instantiating your object:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
result = FakerMaker[:item].build( chaos: %i[name manufacturer] )
|
45
|
+
```
|
data/faker_maker.gemspec
CHANGED
@@ -44,7 +44,7 @@ Gem::Specification.new do |spec|
|
|
44
44
|
spec.add_dependency 'activesupport', '>= 5.2', '< 8'
|
45
45
|
|
46
46
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
47
|
-
spec.add_development_dependency 'faker', '~> 2
|
47
|
+
spec.add_development_dependency 'faker', '~> 3.2'
|
48
48
|
spec.add_development_dependency 'guard', '~> 2.16'
|
49
49
|
spec.add_development_dependency 'guard-bundler', '~> 3.0'
|
50
50
|
spec.add_development_dependency 'guard-rubocop', '~> 1.3'
|
@@ -3,7 +3,9 @@
|
|
3
3
|
module FakerMaker
|
4
4
|
# Attributes describe the fields of classes
|
5
5
|
class Attribute
|
6
|
-
attr_reader :name, :block, :translation
|
6
|
+
attr_reader :name, :block, :translation, :required, :optional, :optional_weighting
|
7
|
+
|
8
|
+
DEFAULT_OPTIONAL_WEIGHTING = 0.5
|
7
9
|
|
8
10
|
def initialize( name, block = nil, options = {} )
|
9
11
|
assert_valid_options options
|
@@ -13,6 +15,13 @@ module FakerMaker
|
|
13
15
|
@translation = options[:json]
|
14
16
|
@omit = *options[:omit]
|
15
17
|
@array = options[:array] == true
|
18
|
+
|
19
|
+
if options[:required].to_s.downcase.eql?('true') || options[:optional].to_s.downcase.eql?('false')
|
20
|
+
@required = true
|
21
|
+
else
|
22
|
+
@optional = true
|
23
|
+
@optional_weighting = determine_optional_weighting(options[:optional])
|
24
|
+
end
|
16
25
|
end
|
17
26
|
|
18
27
|
def array?
|
@@ -49,7 +58,18 @@ module FakerMaker
|
|
49
58
|
end
|
50
59
|
|
51
60
|
def assert_valid_options( options )
|
52
|
-
options.assert_valid_keys :has, :array, :json, :omit
|
61
|
+
options.assert_valid_keys :has, :array, :json, :omit, :required, :optional
|
62
|
+
end
|
63
|
+
|
64
|
+
def determine_optional_weighting( value )
|
65
|
+
case value
|
66
|
+
when Float
|
67
|
+
value.between?(0, 1) ? value : (value / 100)
|
68
|
+
when Integer
|
69
|
+
value.ceil.between?(0, 100) ? (value.to_f / 100) : DEFAULT_OPTIONAL_WEIGHTING
|
70
|
+
else
|
71
|
+
DEFAULT_OPTIONAL_WEIGHTING
|
72
|
+
end
|
53
73
|
end
|
54
74
|
end
|
55
75
|
end
|
data/lib/faker_maker/factory.rb
CHANGED
@@ -5,7 +5,7 @@ module FakerMaker
|
|
5
5
|
# Factories construct instances of a fake
|
6
6
|
class Factory
|
7
7
|
include Auditable
|
8
|
-
attr_reader :name, :class_name, :parent
|
8
|
+
attr_reader :name, :class_name, :parent, :chaos_selected_attributes
|
9
9
|
|
10
10
|
def initialize( name, options = {} )
|
11
11
|
assert_valid_options options
|
@@ -19,7 +19,7 @@ module FakerMaker
|
|
19
19
|
when nil
|
20
20
|
nil
|
21
21
|
else
|
22
|
-
raise FakerMaker::NoSuchAttributeNamingStrategy,
|
22
|
+
raise FakerMaker::NoSuchAttributeNamingStrategy, options[:naming]
|
23
23
|
end
|
24
24
|
@attributes = []
|
25
25
|
@klass = nil
|
@@ -42,11 +42,22 @@ module FakerMaker
|
|
42
42
|
@instance ||= instantiate
|
43
43
|
end
|
44
44
|
|
45
|
-
def build( attributes
|
45
|
+
def build( attributes: {}, chaos: false, **kwargs )
|
46
|
+
if kwargs.present?
|
47
|
+
validate_deprecated_build(kwargs)
|
48
|
+
attributes = kwargs
|
49
|
+
end
|
50
|
+
|
46
51
|
@instance = nil
|
47
52
|
before_build if respond_to? :before_build
|
48
53
|
assert_only_known_attributes_for_override( attributes )
|
49
|
-
|
54
|
+
|
55
|
+
assert_chaos_options chaos if chaos
|
56
|
+
|
57
|
+
optional_attributes
|
58
|
+
required_attributes
|
59
|
+
|
60
|
+
populate_instance instance, attributes, chaos
|
50
61
|
yield instance if block_given?
|
51
62
|
after_build if respond_to? :after_build
|
52
63
|
audit(@instance) if FakerMaker.configuration.audit?
|
@@ -110,11 +121,14 @@ module FakerMaker
|
|
110
121
|
|
111
122
|
protected
|
112
123
|
|
113
|
-
def populate_instance( instance, attr_override_values )
|
114
|
-
FakerMaker[parent].populate_instance instance, attr_override_values if parent?
|
115
|
-
|
116
|
-
|
117
|
-
|
124
|
+
def populate_instance( instance, attr_override_values, chaos )
|
125
|
+
FakerMaker[parent].populate_instance instance, attr_override_values, chaos if parent?
|
126
|
+
|
127
|
+
attributes = chaos ? chaos_select(chaos) : @attributes
|
128
|
+
|
129
|
+
attributes.each do |attribute|
|
130
|
+
value = value_for_attribute( instance, attribute, attr_override_values )
|
131
|
+
instance.send "#{attribute.name}=", value
|
118
132
|
end
|
119
133
|
instance.instance_variable_set( :@fm_factory, self )
|
120
134
|
end
|
@@ -128,6 +142,19 @@ module FakerMaker
|
|
128
142
|
raise FakerMaker::NoSuchAttributeError, issue unless unknown_attrs.empty?
|
129
143
|
end
|
130
144
|
|
145
|
+
def assert_only_known_and_optional_attributes_for_chaos( chaos_attr_values )
|
146
|
+
chaos_attr_values = chaos_attr_values.map(&:to_sym)
|
147
|
+
unknown_attrs = chaos_attr_values - attribute_names
|
148
|
+
issue = "Can't build an instance of '#{class_name}' " \
|
149
|
+
"setting '#{unknown_attrs.join( ', ' )}', no such attribute(s)"
|
150
|
+
raise FakerMaker::NoSuchAttributeError, issue unless unknown_attrs.empty?
|
151
|
+
|
152
|
+
# Are any chaos attributes marked as required?
|
153
|
+
conflicting_attributes = chaos_attr_values.select { |attr| required_attributes.map(&:name).include? attr }
|
154
|
+
issue = "Can't use chaos on a required attribute: '#{conflicting_attributes}'"
|
155
|
+
raise FakerMaker::ChaosConflictingAttributeError, issue unless conflicting_attributes.empty?
|
156
|
+
end
|
157
|
+
|
131
158
|
def attribute_hash_overridden_value?( attr, attr_override_values )
|
132
159
|
attr_override_values.keys.include?( attr.name )
|
133
160
|
end
|
@@ -164,6 +191,68 @@ module FakerMaker
|
|
164
191
|
def assert_valid_options( options )
|
165
192
|
options.assert_valid_keys :class, :parent, :naming
|
166
193
|
end
|
194
|
+
|
195
|
+
# Asserts attributes passed in for chaos mode are valid
|
196
|
+
def assert_chaos_options( chaos )
|
197
|
+
eval = -> { [Array, String, TrueClass, FalseClass, Symbol].include? chaos.class }
|
198
|
+
msg = "chaos: arg does not support object of type: '#{chaos.class}'"
|
199
|
+
raise NoSuchAttributeError, msg unless eval.call
|
200
|
+
|
201
|
+
case chaos
|
202
|
+
when Array
|
203
|
+
assert_only_known_and_optional_attributes_for_chaos(chaos)
|
204
|
+
when String, Symbol
|
205
|
+
assert_only_known_and_optional_attributes_for_chaos([chaos])
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# Selects required @attributes
|
210
|
+
def required_attributes
|
211
|
+
@required_attributes ||= @attributes.select { |attr| attr.required.eql? true }
|
212
|
+
end
|
213
|
+
|
214
|
+
# Selects optional @attributes
|
215
|
+
def optional_attributes
|
216
|
+
@optional_attributes ||= @attributes.select(&:optional)
|
217
|
+
end
|
218
|
+
|
219
|
+
# Randomly selects optional attributes
|
220
|
+
# Attributes selected from parent will also be selected for the child
|
221
|
+
# @param [Array || TrueClass] chaos_attrs
|
222
|
+
# @return [Array]
|
223
|
+
def chaos_select( chaos_attrs = [] )
|
224
|
+
selected_attrs = []
|
225
|
+
optional_attrs = optional_attributes.dup
|
226
|
+
|
227
|
+
# Filter specific optional attributes if present
|
228
|
+
if chaos_attrs.is_a?(Array) && chaos_attrs.size.positive?
|
229
|
+
optional_attrs, selected_attrs = optional_attrs.partition { |attr| chaos_attrs.include?(attr.name) }
|
230
|
+
end
|
231
|
+
|
232
|
+
# Grab parent selected attributes
|
233
|
+
@chaos_selected_attributes = parent? ? FakerMaker[parent].chaos_selected_attributes : []
|
234
|
+
selected_inherited_attr = optional_attrs.select do |attr|
|
235
|
+
@chaos_selected_attributes.map(&:name).include? attr.name
|
236
|
+
end
|
237
|
+
|
238
|
+
# Select optional attributes based on weighting
|
239
|
+
optional_attrs.each do |optional_attr|
|
240
|
+
selected_attrs.push(optional_attr) if Random.rand < optional_attr.optional_weighting
|
241
|
+
end
|
242
|
+
|
243
|
+
# Concat required, selected and parent attributes
|
244
|
+
@chaos_selected_attributes.concat(required_attributes)
|
245
|
+
.concat(selected_inherited_attr)
|
246
|
+
.concat(selected_attrs).uniq!
|
247
|
+
@chaos_selected_attributes
|
248
|
+
end
|
249
|
+
|
250
|
+
def validate_deprecated_build(kwargs)
|
251
|
+
usage = kwargs.each_with_object([]) { |kwarg, result| result << "#{kwarg.first}: #{kwarg.last}" }.join(', ')
|
252
|
+
|
253
|
+
warn "[DEPRECATION] `FM[:#{name}].build(#{usage})` is deprecated. " \
|
254
|
+
"Please use `FM[:#{name}].build(attributes: { #{usage} })` instead."
|
255
|
+
end
|
167
256
|
end
|
168
257
|
end
|
169
258
|
# rubocop:enable Metrics/ClassLength
|
data/lib/faker_maker/version.rb
CHANGED
data/lib/faker_maker.rb
CHANGED
@@ -27,6 +27,7 @@ module FakerMaker
|
|
27
27
|
class Error < StandardError; end
|
28
28
|
class NoSuchFactoryError < StandardError; end
|
29
29
|
class NoSuchAttributeError < StandardError; end
|
30
|
+
class ChaosConflictingAttributeError < StandardError; end
|
30
31
|
class NoSuchAttributeNamingStrategy < StandardError; end
|
31
32
|
# Your code goes here...
|
32
33
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: faker_maker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nigel Brookes-Thomas
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-06-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -50,14 +50,14 @@ dependencies:
|
|
50
50
|
requirements:
|
51
51
|
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: '2
|
53
|
+
version: '3.2'
|
54
54
|
type: :development
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
58
|
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: '2
|
60
|
+
version: '3.2'
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: guard
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -179,6 +179,7 @@ extensions: []
|
|
179
179
|
extra_rdoc_files: []
|
180
180
|
files:
|
181
181
|
- ".github/dependabot.yml"
|
182
|
+
- ".github/workflows/ruby.yml"
|
182
183
|
- ".gitignore"
|
183
184
|
- ".rspec"
|
184
185
|
- ".rubocop.yml"
|
@@ -202,6 +203,7 @@ files:
|
|
202
203
|
- docs/usage/arrays.md
|
203
204
|
- docs/usage/audit_logs.md
|
204
205
|
- docs/usage/building_instances.md
|
206
|
+
- docs/usage/chaos.md
|
205
207
|
- docs/usage/dependencies.md
|
206
208
|
- docs/usage/destroying_factories.md
|
207
209
|
- docs/usage/embedding_factories.md
|