satisfactory 0.3.1 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb0881c675798a625a5af2ba2837a9689191df29051a54c12f3e0f6e38a948d7
4
- data.tar.gz: cfe749028066a66f517679c6132e6d5a884b673e4bf5f3c329aadc4cb43acaf4
3
+ metadata.gz: 65c8d9c40c194cb99ea20abed50386c82150e1474a3b82089a2c9d14948ccc3c
4
+ data.tar.gz: 568fdc7b04e1d89f26e5832f61b406dd54e3c501c1cfcf35586cddcfb25e829a
5
5
  SHA512:
6
- metadata.gz: 87e998bfc2817381695b8b16a212fe5d328db770549613dbe962406574446f8017f77d068f5ea447df97b2abe75710662544500fae9728855e167c3915b6b737
7
- data.tar.gz: 442023301434a224e7b3b71f36762a21432ef681cdf9951672286c6377454649aa4fea7abd8f3e93e5de79f17587f0cc0c8f7e1398c61239dc6f6dc0dedc85ab
6
+ metadata.gz: 25f309d08266688c528b1ce09a9830b17219d74402ef168a4ba77f88ee8234822be463426db03fcd1e1e7ddb24940ea0d55b1a4a35604ced4eeac24c7984155f
7
+ data.tar.gz: ee0a8f3615eaaa8f9578e770703c8819297c7eb0a75f9f4332168c4522e1510b8bd66e7bf66a7071b95895a5b012f7dfd1b54ec11aa729af2a1e47ae42f1df7a
data/CHANGELOG.md CHANGED
@@ -1,4 +1,24 @@
1
- ## [Unreleased]
1
+ ## [1.0.0] - 2026-06-11
2
+
3
+ - Require Ruby >= 3.2, dropping end-of-life Ruby 3.1
4
+ - Update the development toolchain to Ruby 3.4, Rails 8.0, RSpec 3.13, rspec-rails 7.0, and the latest RuboCop
5
+ - Replace the `byebug` development dependency with `debug`
6
+ - Run the RSpec suite as part of the default Rake task (and in CI), not just RuboCop
7
+ - Load the dummy app's schema automatically when running the suite
8
+ - Share a single Gemfile between the gem and its dummy test app
9
+ - Refresh the bundle for current platforms (Apple Silicon and Linux)
10
+ - Replace the boilerplate README with real installation and usage instructions
11
+ - Add a Rails-free unit suite characterising `Record`, `Collection`, `Root`, and `UpstreamRecordFinder`, plus a `Loader` spec
12
+ - Depend on `factory_bot` and `activesupport` directly instead of `factory_bot_rails`, so the gem no longer pulls in a Railtie
13
+ - Refactor `Record#with` into a small classifier plus focused helpers, removing all of its RuboCop disables
14
+ - `Record#with(2, :racing_wheels)` (the plural of an STI child type) now works instead of raising "Unknown association"; the plural of a parentless singular now raises the clearer "Cannot create multiple of singular associations" error
15
+ - Include provided attributes in the output of `#to_plan` / `#build_plan`
16
+ - Show every association that was explicitly added in the build plan (including empty singular associations), rather than silently dropping empties
17
+ - Drop the unused `model`, `name`, and `traits` fields from loaded factory configurations
18
+
19
+ ## [0.3.2] - 2023-01-24
20
+
21
+ - Add some missing proxy methods
2
22
 
3
23
  ## [0.3.1] - 2023-01-18
4
24
 
data/README.md CHANGED
@@ -1,29 +1,96 @@
1
1
  # Satisfactory
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/satisfactory`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ Satisfactory is a factory library for Ruby that helps you navigate your factory
4
+ associations and build trees of test data with a fluent, readable DSL.
4
5
 
5
- TODO: Delete this and the text above, and describe your gem
6
+ It is currently implemented on top of
7
+ [FactoryBot](https://github.com/thoughtbot/factory_bot), but could be extended to
8
+ support other factory libraries.
6
9
 
7
10
  ## Installation
8
11
 
9
- Install the gem and add to the application's Gemfile by executing:
12
+ Install the gem and add it to the application's Gemfile by executing:
10
13
 
11
- $ bundle add satisfactory
14
+ ```sh
15
+ bundle add satisfactory
16
+ ```
12
17
 
13
18
  If bundler is not being used to manage dependencies, install the gem by executing:
14
19
 
15
- $ gem install satisfactory
20
+ ```sh
21
+ gem install satisfactory
22
+ ```
23
+
24
+ Satisfactory reads your existing FactoryBot factories. Only factories whose model
25
+ inherits from `ApplicationRecord` are picked up.
16
26
 
17
27
  ## Usage
18
28
 
19
- TODO: Write usage instructions here
29
+ Start from the root and describe the tree of records you want, then call `create`
30
+ to build it (or `to_plan` to inspect what would be built):
31
+
32
+ ```ruby
33
+ Satisfactory.root
34
+ .add(:candidate, email_address: "sample@example.com")
35
+ .with(:application_form).which_is(:submitted)
36
+ .with(:application_choice)
37
+ .and(2, :application_choices)
38
+ .each_with(:course_option).which_is(:part_time)
39
+ .and_same(:candidate)
40
+ .with(:application_form, first_name: "Jane")
41
+ .with(:application_choice).which_is(:rejected)
42
+ .create
43
+ ```
44
+
45
+ ### The DSL
46
+
47
+ - `Satisfactory.root` — the entry point into the factory graph.
48
+ - `add(:factory, **attributes)` — add a top-level record to the root.
49
+ - `with(count = nil, :association, **attributes)` — add an associated record (or
50
+ `count` of them for plural associations) to the current record.
51
+ - `with_new(count = nil, :association, **attributes)` — like `with`, but always
52
+ creates a new record rather than reusing an existing one.
53
+ - `and(count = nil, :association, **attributes)` — add a sibling record to the
54
+ current record's parent (e.g. a second `application_form` on the same candidate).
55
+ - `which_is(*traits)` / `which_are(*traits)` — apply one or more FactoryBot traits
56
+ to the current record(s).
57
+ - `each_with(...)` / `which_are(...)` — operate on every record in a collection.
58
+ - `and_same(:type)` (aliased as `return_to`) — walk back up the tree to the nearest
59
+ ancestor of the given type to continue building from there.
60
+ - `create` — build the whole tree and persist it. Returns the created records.
61
+ - `to_plan` — return a hash describing what would be built, without persisting.
20
62
 
21
63
  ## Development
22
64
 
23
- After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
65
+ After checking out the repo, run `bin/setup` to install dependencies.
66
+
67
+ The test suite exercises a dummy Rails application backed by PostgreSQL, so you'll
68
+ need a running PostgreSQL server. Create the test database once with:
69
+
70
+ ```sh
71
+ createdb satisfactory_dummy_test
72
+ ```
24
73
 
25
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
74
+ Then run the default task, which runs both the specs and RuboCop:
75
+
76
+ ```sh
77
+ bin/rake
78
+ ```
79
+
80
+ You can also run them individually with `bin/rspec` and `bin/rubocop`, or open an
81
+ interactive prompt with `bin/console`.
82
+
83
+ To install this gem onto your local machine, run `bundle exec rake install`. To
84
+ release a new version, update the version number in `version.rb`, and then run
85
+ `bundle exec rake release`, which will create a git tag for the version, push git
86
+ commits and the created tag, and push the `.gem` file to
87
+ [rubygems.org](https://rubygems.org).
26
88
 
27
89
  ## Contributing
28
90
 
29
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/satisfactory.
91
+ Bug reports and pull requests are welcome on GitHub at
92
+ https://github.com/SmartCasual/satisfactory.
93
+
94
+ ## Licence
95
+
96
+ Released under the [CC-BY-NC-SA-4.0](LICENCE) licence.
@@ -1,11 +1,13 @@
1
+ require "active_support/core_ext/module/delegation"
2
+
1
3
  require_relative "upstream_record_finder"
2
4
 
3
5
  module Satisfactory
4
6
  # Represents a collection of homogenous records.
5
7
  class Collection < Array
6
8
  # @api private
7
- def initialize(*args, upstream:, **kwargs, &block)
8
- super(*args, **kwargs, &block)
9
+ def initialize(*, upstream:, **, &)
10
+ super(*, **, &)
9
11
  @upstream = upstream
10
12
  end
11
13
 
@@ -47,6 +49,7 @@ module Satisfactory
47
49
  def and_same(upstream_type)
48
50
  Satisfactory::UpstreamRecordFinder.new(upstream:).find(upstream_type)
49
51
  end
52
+ alias return_to and_same
50
53
 
51
54
  # @api private
52
55
  def build
@@ -1,4 +1,4 @@
1
- require "factory_bot_rails"
1
+ require "factory_bot"
2
2
 
3
3
  module Satisfactory
4
4
  # Loads factory configurations from FactoryBot.
@@ -9,26 +9,26 @@ module Satisfactory
9
9
  # Skips factories that don't have a model that inherits from ApplicationRecord.
10
10
  #
11
11
  # @return [{Symbol => Hash}] a hash of factory configurations by factory name
12
- def factory_configurations # rubocop:disable Metrics/AbcSize
13
- FactoryBot.factories.each.with_object({}) do |(factory, model), configurations|
12
+ def factory_configurations
13
+ FactoryBot.factories.each.with_object({}) do |factory, configurations|
14
14
  next unless (model = factory.build_class)
15
15
  next unless model < ApplicationRecord
16
16
 
17
- associations = associations_for(model)
18
- parent_factory = factory.send(:parent)
19
-
20
- configurations[factory.name] = {
21
- associations: associations.transform_values { |a| a.map(&:name) },
22
- model:,
23
- name: factory.name,
24
- parent: (parent_factory.name unless parent_factory.is_a?(FactoryBot::NullFactory)),
25
- traits: factory.defined_traits.map(&:name),
26
- }
17
+ configurations[factory.name] = configuration_for(factory, model)
27
18
  end
28
19
  end
29
20
 
30
21
  private
31
22
 
23
+ def configuration_for(factory, model)
24
+ parent_factory = factory.send(:parent)
25
+
26
+ {
27
+ associations: associations_for(model).transform_values { |a| a.map(&:name) },
28
+ parent: (parent_factory.name unless parent_factory.is_a?(FactoryBot::NullFactory)),
29
+ }
30
+ end
31
+
32
32
  def associations_for(model)
33
33
  all = model.reflect_on_all_associations.reject(&:polymorphic?)
34
34
  plural = model.reflect_on_all_associations(:has_many).reject(&:polymorphic?)
@@ -1,10 +1,12 @@
1
+ require "active_support/core_ext/enumerable"
2
+ require "active_support/core_ext/object/blank"
3
+ require "active_support/core_ext/string/inflections"
4
+
1
5
  require_relative "collection"
2
6
  require_relative "upstream_record_finder"
3
7
 
4
8
  module Satisfactory
5
9
  # Represents a usage of a type.
6
- #
7
- # @todo This whole class needs a tidy up
8
10
  class Record # rubocop:disable Metrics/ClassLength
9
11
  # @api private
10
12
  # @param type [Symbol] The type of record to create. Must be a known factory.
@@ -30,7 +32,7 @@ module Satisfactory
30
32
  end
31
33
 
32
34
  # @api private
33
- attr_accessor :type, :type_config, :traits, :upstream, :factory_name, :attributes
35
+ attr_reader :type, :type_config, :traits, :upstream, :factory_name, :attributes
34
36
 
35
37
  # Add an associated record to this record's build plan.
36
38
  #
@@ -40,26 +42,16 @@ module Satisfactory
40
42
  # For internal use only. Use {#and} instead.
41
43
  # @param attributes [Hash] The attributes to use when creating the record.
42
44
  # @return [Satisfactory::Record, Satisfactory::Collection]
43
- def with(count = nil, downstream_type, force: false, **attributes) # rubocop:disable Style/OptionalArguments, Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
44
- if singular?(downstream_type)
45
- if count && count > 1 # rubocop:disable Style/IfUnlessModifier
46
- raise ArgumentError, "Cannot create multiple of singular associations (e.g. belongs_to)"
47
- end
48
-
49
- add_singular_association(downstream_type, factory_name: downstream_type, force:, attributes:)
50
- elsif plural?(downstream_type) && (singular = singular_from_plural(downstream_type))
51
- add_plural_association(downstream_type, factory_name: singular, count:, force:, attributes:)
52
- elsif (config = Satisfactory.factory_configurations[downstream_type])
53
- singular = config[:parent] || downstream_type
54
- plural = plural_from_singular(singular)
55
- add_singular_for_plural_association(plural, singular:, factory_name: downstream_type, force:, attributes:)
56
- elsif (config = Satisfactory.factory_configurations[downstream_type.to_s.singularize])
57
- unless (parent = config[:parent])
58
- raise ArgumentError, "Cannot create multiple of singular associations (e.g. belongs_to)"
59
- end
60
-
61
- plural = plural_from_singular(parent)
62
- add_plural_association(plural, factory_name: downstream_type.to_s.singularize, count:, force:, attributes:)
45
+ def with(*arguments, force: false, **attributes)
46
+ count, downstream_type = parse_with_arguments(arguments)
47
+
48
+ case association_kind(downstream_type)
49
+ when :singular then add_singular(downstream_type, count:, force:, attributes:)
50
+ when :plural then add_plural(downstream_type, count:, force:, attributes:)
51
+ when :child then add_child(downstream_type, force:, attributes:)
52
+ when :child_collection then add_child_collection(downstream_type, count:, force:, attributes:)
53
+ when :singular_collection
54
+ raise ArgumentError, "Cannot create multiple of singular associations (e.g. belongs_to)"
63
55
  else
64
56
  raise ArgumentError, "Unknown association #{type}->#{downstream_type}"
65
57
  end
@@ -69,8 +61,8 @@ module Satisfactory
69
61
  #
70
62
  # @param (see #and)
71
63
  # @return (see #with)
72
- def with_new(count = nil, downstream_type, **attributes) # rubocop:disable Style/OptionalArguments
73
- with(count, downstream_type, force: true, **attributes)
64
+ def with_new(*, **attributes)
65
+ with(*, force: true, **attributes)
74
66
  end
75
67
 
76
68
  # Add a sibling record to the parent record's build plan.
@@ -80,8 +72,8 @@ module Satisfactory
80
72
  # @param downstream_type [Symbol] The type of record to create.
81
73
  # @param attributes [Hash] The attributes to use when creating the record.
82
74
  # @return (see #with)
83
- def and(count = nil, downstream_type, **attributes) # rubocop:disable Style/OptionalArguments
84
- upstream.with(count, downstream_type, force: true, **attributes)
75
+ def and(*, **attributes)
76
+ upstream.with(*, force: true, **attributes)
85
77
  end
86
78
 
87
79
  # Apply one or more traits to this record's build plan.
@@ -104,7 +96,6 @@ module Satisfactory
104
96
  # Trigger the creation of this tree's build plan.
105
97
  #
106
98
  # @return (see Satisfactory::Root#create)
107
- # @todo Check if we still need the upstream check.
108
99
  def create
109
100
  if upstream
110
101
  upstream.create
@@ -126,9 +117,9 @@ module Satisfactory
126
117
 
127
118
  # @api private
128
119
  def build_plan
129
- {
130
- traits:,
131
- }.merge(associations_plan).compact_blank
120
+ plan = associations_plan
121
+ plan[:traits] = traits if traits.any?
122
+ plan.merge(attributes)
132
123
  end
133
124
 
134
125
  # @api private
@@ -152,8 +143,60 @@ module Satisfactory
152
143
  FactoryBot.public_send(method, factory_name, *traits, provided_associations.merge(attributes))
153
144
  end
154
145
 
146
+ # Split the variadic positional arguments to {#with} into an optional count
147
+ # and the downstream type. Supports `with(:type)` and `with(2, :types)`.
148
+ def parse_with_arguments(arguments)
149
+ *count, downstream_type = arguments
150
+ [count.first, downstream_type]
151
+ end
152
+
153
+ # Classify how +downstream_type+ relates to this record.
154
+ #
155
+ # @return [Symbol] one of +:singular+, +:plural+, +:child+,
156
+ # +:child_collection+, +:singular_collection+ or +:unknown+.
157
+ def association_kind(downstream_type)
158
+ return :singular if singular?(downstream_type)
159
+ return :plural if plural?(downstream_type) && singular_from_plural(downstream_type)
160
+ return :child if Satisfactory.factory_configurations.key?(downstream_type)
161
+
162
+ config = Satisfactory.factory_configurations[downstream_type.to_s.singularize.to_sym]
163
+ return :unknown unless config
164
+
165
+ config[:parent] ? :child_collection : :singular_collection
166
+ end
167
+
168
+ def add_singular(downstream_type, count:, force:, attributes:)
169
+ raise ArgumentError, "Cannot create multiple of singular associations (e.g. belongs_to)" if count && count > 1
170
+
171
+ add_singular_association(downstream_type, factory_name: downstream_type, force:, attributes:)
172
+ end
173
+
174
+ def add_plural(downstream_type, count:, force:, attributes:)
175
+ singular = singular_from_plural(downstream_type)
176
+ add_plural_association(downstream_type, factory_name: singular, count:, force:, attributes:)
177
+ end
178
+
179
+ def add_child(downstream_type, force:, attributes:)
180
+ config = Satisfactory.factory_configurations[downstream_type]
181
+ singular = config[:parent] || downstream_type
182
+ plural = plural_from_singular(singular)
183
+ add_singular_for_plural_association(plural, singular:, factory_name: downstream_type, force:, attributes:)
184
+ end
185
+
186
+ def add_child_collection(downstream_type, count:, force:, attributes:)
187
+ singular = downstream_type.to_s.singularize.to_sym
188
+ parent = Satisfactory.factory_configurations[singular][:parent]
189
+ plural = plural_from_singular(parent)
190
+ add_plural_association(plural, factory_name: singular, count:, force:, attributes:)
191
+ end
192
+
155
193
  def associations_plan
156
- associations.transform_values(&:build_plan).compact_blank
194
+ associations.each_with_object({}) do |(name, association), plan|
195
+ sub_plan = association.build_plan
196
+ next if plural?(name) && sub_plan.empty?
197
+
198
+ plan[name] = sub_plan
199
+ end
157
200
  end
158
201
 
159
202
  def plural?(association_name)
@@ -1,3 +1,5 @@
1
+ require "active_support/core_ext/module/delegation"
2
+
1
3
  module Satisfactory
2
4
  # Finds the upstream record of a given type.
3
5
  #
@@ -18,7 +20,11 @@ module Satisfactory
18
20
  # Delegates to the upstream record.
19
21
  # @return (see Satisfactory::Record#with_new)
20
22
  # @see Satisfactory::Record#with_new
21
- delegate :create, :with_new, to: :upstream
23
+ # @!method to_plan
24
+ # Delegates to the upstream record.
25
+ # @return (see Satisfactory::Record#with_new)
26
+ # @see Satisfactory::Record#with_new
27
+ delegate :create, :with_new, :to_plan, to: :upstream
22
28
 
23
29
  # Find the upstream record of the given type.
24
30
  #
@@ -37,8 +43,8 @@ module Satisfactory
37
43
  end
38
44
 
39
45
  # (see Satisfactory::Record#with)
40
- def with(*args, **kwargs)
41
- upstream.with(*args, force: true, **kwargs)
46
+ def with(*, **)
47
+ upstream.with(*, force: true, **)
42
48
  end
43
49
 
44
50
  # @api private
@@ -1,3 +1,3 @@
1
1
  module Satisfactory
2
- VERSION = "0.3.1".freeze
2
+ VERSION = "1.0.0".freeze
3
3
  end
data/satisfactory.gemspec CHANGED
@@ -15,9 +15,9 @@ Gem::Specification.new do |spec|
15
15
  spec.metadata["source_code_uri"] = spec.homepage
16
16
 
17
17
  spec.metadata["rubygems_mfa_required"] = "true"
18
- spec.required_ruby_version = ">= 3.1.0"
18
+ spec.required_ruby_version = ">= 3.2.0"
19
19
 
20
- spec.files = Dir.chdir(File.expand_path(__dir__)) {
20
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
21
21
  Dir[
22
22
  "lib/**/*",
23
23
  "CHANGELOG.md",
@@ -25,9 +25,10 @@ Gem::Specification.new do |spec|
25
25
  "README.md",
26
26
  "satisfactory.gemspec",
27
27
  ]
28
- }
28
+ end
29
29
 
30
30
  spec.require_paths = ["lib"]
31
31
 
32
- spec.add_dependency "factory_bot_rails", "~> 6.2"
32
+ spec.add_dependency "activesupport", ">= 7.1"
33
+ spec.add_dependency "factory_bot", "~> 6.4"
33
34
  end
metadata CHANGED
@@ -1,30 +1,42 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: satisfactory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elliot Crosby-McCullough
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-01-18 00:00:00.000000000 Z
10
+ date: 2026-06-11 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
- name: factory_bot_rails
13
+ name: activesupport
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '7.1'
26
+ - !ruby/object:Gem::Dependency
27
+ name: factory_bot
15
28
  requirement: !ruby/object:Gem::Requirement
16
29
  requirements:
17
30
  - - "~>"
18
31
  - !ruby/object:Gem::Version
19
- version: '6.2'
32
+ version: '6.4'
20
33
  type: :runtime
21
34
  prerelease: false
22
35
  version_requirements: !ruby/object:Gem::Requirement
23
36
  requirements:
24
37
  - - "~>"
25
38
  - !ruby/object:Gem::Version
26
- version: '6.2'
27
- description:
39
+ version: '6.4'
28
40
  email:
29
41
  - elliot.cm@gmail.com
30
42
  executables: []
@@ -46,11 +58,10 @@ homepage: https://github.com/SmartCasual/satisfactory
46
58
  licenses:
47
59
  - CC-BY-NC-SA-4.0
48
60
  metadata:
49
- changelog_uri: https://github.com/SmartCasual/satisfactory/blob/v0.3.1/CHANGELOG.md
61
+ changelog_uri: https://github.com/SmartCasual/satisfactory/blob/v1.0.0/CHANGELOG.md
50
62
  homepage_uri: https://github.com/SmartCasual/satisfactory
51
63
  source_code_uri: https://github.com/SmartCasual/satisfactory
52
64
  rubygems_mfa_required: 'true'
53
- post_install_message:
54
65
  rdoc_options: []
55
66
  require_paths:
56
67
  - lib
@@ -58,15 +69,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
58
69
  requirements:
59
70
  - - ">="
60
71
  - !ruby/object:Gem::Version
61
- version: 3.1.0
72
+ version: 3.2.0
62
73
  required_rubygems_version: !ruby/object:Gem::Requirement
63
74
  requirements:
64
75
  - - ">="
65
76
  - !ruby/object:Gem::Version
66
77
  version: '0'
67
78
  requirements: []
68
- rubygems_version: 3.3.7
69
- signing_key:
79
+ rubygems_version: 3.6.2
70
80
  specification_version: 4
71
81
  summary: A DSL for navigating your factories and building test data
72
82
  test_files: []