satisfactory 0.0.0 → 0.2.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/LICENCE +2 -0
- data/Rakefile +0 -2
- data/bin/console +13 -0
- data/bin/rubocop +27 -0
- data/bin/setup +8 -0
- data/bin/yard +27 -0
- data/bin/yardoc +27 -0
- data/bin/yri +27 -0
- data/lib/satisfactory/collection.rb +61 -0
- data/lib/satisfactory/loader.rb +43 -0
- data/lib/satisfactory/record.rb +208 -0
- data/lib/satisfactory/root.rb +47 -0
- data/lib/satisfactory/upstream_record_finder.rb +30 -0
- data/lib/satisfactory/version.rb +1 -3
- data/lib/satisfactory.rb +21 -5
- data/satisfactory.gemspec +39 -0
- metadata +72 -11
- data/.rubocop.yml +0 -13
- data/Gemfile +0 -10
- data/sig/satisfactory.rbs +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4bb15c794b5397907577dbe90ac97815f6636d7c0268db9c553a91a2b51b1a56
|
4
|
+
data.tar.gz: 84336045dedaea44be72e4bd3a108624af18986b8d7cc7b5a07381b3910620c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e018c58477288a2eac77a10889d31ba5a3c20b4c4c280d248789693d2c115849f88e42b7a759d471e8eadd4d46a079cb5496910248bb99a3f158bc420fb62d9b
|
7
|
+
data.tar.gz: bd5b099abce2a3d5b051a4c0e3343710d1305db4aa00a7b5c7e6a4c8614f84570afec990f86fe1d0c41228d803fd3db5bd61f1faaef9b2302e94e8fc4640573a
|
data/LICENCE
ADDED
data/Rakefile
CHANGED
data/bin/console
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "bundler/setup"
|
3
|
+
require "satisfactory"
|
4
|
+
|
5
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
6
|
+
# with your gem easier. You can also use a different console, if you like.
|
7
|
+
|
8
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
9
|
+
# require "pry"
|
10
|
+
# Pry.start
|
11
|
+
|
12
|
+
require "irb"
|
13
|
+
IRB.start(__FILE__)
|
data/bin/rubocop
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rubocop' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
12
|
+
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
14
|
+
|
15
|
+
if File.file?(bundle_binstub)
|
16
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
17
|
+
load(bundle_binstub)
|
18
|
+
else
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require "rubygems"
|
25
|
+
require "bundler/setup"
|
26
|
+
|
27
|
+
load Gem.bin_path("rubocop", "rubocop")
|
data/bin/setup
ADDED
data/bin/yard
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'yard' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
12
|
+
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
14
|
+
|
15
|
+
if File.file?(bundle_binstub)
|
16
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
17
|
+
load(bundle_binstub)
|
18
|
+
else
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require "rubygems"
|
25
|
+
require "bundler/setup"
|
26
|
+
|
27
|
+
load Gem.bin_path("yard", "yard")
|
data/bin/yardoc
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'yardoc' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
12
|
+
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
14
|
+
|
15
|
+
if File.file?(bundle_binstub)
|
16
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
17
|
+
load(bundle_binstub)
|
18
|
+
else
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require "rubygems"
|
25
|
+
require "bundler/setup"
|
26
|
+
|
27
|
+
load Gem.bin_path("yard", "yardoc")
|
data/bin/yri
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'yri' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
12
|
+
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
14
|
+
|
15
|
+
if File.file?(bundle_binstub)
|
16
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
17
|
+
load(bundle_binstub)
|
18
|
+
else
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require "rubygems"
|
25
|
+
require "bundler/setup"
|
26
|
+
|
27
|
+
load Gem.bin_path("yard", "yri")
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require_relative "upstream_record_finder"
|
2
|
+
|
3
|
+
module Satisfactory
|
4
|
+
# Represents a collection of homogenous records.
|
5
|
+
class Collection < Array
|
6
|
+
# @api private
|
7
|
+
def initialize(*args, upstream:, **kwargs, &block)
|
8
|
+
super(*args, **kwargs, &block)
|
9
|
+
@upstream = upstream
|
10
|
+
end
|
11
|
+
|
12
|
+
# @api private
|
13
|
+
attr_reader :upstream
|
14
|
+
|
15
|
+
# @!method and
|
16
|
+
# Delegates to the upstream record.
|
17
|
+
# @return (see Satisfactory::Record#and)
|
18
|
+
# @see Satisfactory::Record#and
|
19
|
+
# @!method create
|
20
|
+
# Delegates to the upstream record.
|
21
|
+
# @return (see Satisfactory::Record#create)
|
22
|
+
# @see Satisfactory::Record#create
|
23
|
+
# @!method to_plan
|
24
|
+
# Delegates to the upstream record.
|
25
|
+
# @return (see Satisfactory::Record#to_plan)
|
26
|
+
# @see Satisfactory::Record#to_plan
|
27
|
+
delegate :and, :create, :to_plan, to: :upstream
|
28
|
+
|
29
|
+
# Calls {#with} on each entry in the collection.
|
30
|
+
#
|
31
|
+
# @return [Satisfactory::Collection]
|
32
|
+
def with(...)
|
33
|
+
self.class.new(map { |entry| entry.with(...) }, upstream:)
|
34
|
+
end
|
35
|
+
alias each_with with
|
36
|
+
|
37
|
+
# Calls {#which_is} on each entry in the collection.
|
38
|
+
#
|
39
|
+
# @param (see Satisfactory::Record#which_is)
|
40
|
+
# @return [Satisfactory::Collection]
|
41
|
+
def which_are(...)
|
42
|
+
self.class.new(map { |entry| entry.which_is(...) }, upstream:)
|
43
|
+
end
|
44
|
+
alias which_is which_are
|
45
|
+
|
46
|
+
# (see Satisfactory::Record#and_same)
|
47
|
+
def and_same(upstream_type)
|
48
|
+
Satisfactory::UpstreamRecordFinder.new(upstream:).find(upstream_type)
|
49
|
+
end
|
50
|
+
|
51
|
+
# @api private
|
52
|
+
def build
|
53
|
+
flat_map(&:build)
|
54
|
+
end
|
55
|
+
|
56
|
+
# @api private
|
57
|
+
def build_plan
|
58
|
+
flat_map(&:build_plan)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "factory_bot_rails"
|
2
|
+
|
3
|
+
module Satisfactory
|
4
|
+
# Loads factory configurations from FactoryBot.
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
class Loader
|
8
|
+
class << self
|
9
|
+
# Skips factories that don't have a model that inherits from ApplicationRecord.
|
10
|
+
#
|
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|
|
14
|
+
next unless (model = factory.build_class)
|
15
|
+
next unless model < ApplicationRecord
|
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
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def associations_for(model)
|
33
|
+
all = model.reflect_on_all_associations.reject(&:polymorphic?)
|
34
|
+
plural = model.reflect_on_all_associations(:has_many).reject(&:polymorphic?)
|
35
|
+
|
36
|
+
{
|
37
|
+
plural:,
|
38
|
+
singular: all - plural,
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
require_relative "collection"
|
2
|
+
require_relative "upstream_record_finder"
|
3
|
+
|
4
|
+
module Satisfactory
|
5
|
+
# Represents a usage of a type.
|
6
|
+
#
|
7
|
+
# @todo This whole class needs a tidy up
|
8
|
+
class Record # rubocop:disable Metrics/ClassLength
|
9
|
+
# @api private
|
10
|
+
# @param type [Symbol] The type of record to create. Must be a known factory.
|
11
|
+
# @param factory_name [Symbol] The name of the factory to use (if different).
|
12
|
+
# @param upstream [Satisfactory::Record, Satisfactory::Collection, Satisfactory::Root] The upstream record-ish.
|
13
|
+
# @param attributes [Hash] The attributes to use when creating the record.
|
14
|
+
def initialize(type:, factory_name: nil, upstream: nil, attributes: {})
|
15
|
+
@factory_name = factory_name || type
|
16
|
+
|
17
|
+
config = Satisfactory.factory_configurations[type]
|
18
|
+
raise ArgumentError, "Unknown factory #{type}" unless config
|
19
|
+
|
20
|
+
@type = config[:parent] || type
|
21
|
+
@type_config = Satisfactory.factory_configurations[@type]
|
22
|
+
@traits = []
|
23
|
+
@upstream = upstream
|
24
|
+
|
25
|
+
@attributes = attributes
|
26
|
+
|
27
|
+
@associations = type_config.dig(:associations, :plural).each.with_object({}) do |name, hash|
|
28
|
+
hash[name] = Satisfactory::Collection.new(upstream: self)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# @api private
|
33
|
+
attr_accessor :type, :type_config, :traits, :upstream, :factory_name, :attributes
|
34
|
+
|
35
|
+
# Add an associated record to this record's build plan.
|
36
|
+
#
|
37
|
+
# @param count [Integer] The number of records to create.
|
38
|
+
# @param downstream_type [Symbol] The type of record to create.
|
39
|
+
# @param force [Boolean] Whether to force the creation of the record.
|
40
|
+
# For internal use only. Use {#and} instead.
|
41
|
+
# @param attributes [Hash] The attributes to use when creating the record.
|
42
|
+
# @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:)
|
63
|
+
else
|
64
|
+
raise ArgumentError, "Unknown association #{type}->#{downstream_type}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Add a sibling record to the parent record's build plan.
|
69
|
+
# e.g. adding a second user to a project.
|
70
|
+
#
|
71
|
+
# @param count [Integer] The number of records to create.
|
72
|
+
# @param downstream_type [Symbol] The type of record to create.
|
73
|
+
# @param attributes [Hash] The attributes to use when creating the record.
|
74
|
+
# @return (see #with)
|
75
|
+
def and(count = nil, downstream_type, **attributes) # rubocop:disable Style/OptionalArguments
|
76
|
+
upstream.with(count, downstream_type, force: true, **attributes)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Apply one or more traits to this record's build plan.
|
80
|
+
#
|
81
|
+
# @param *traits [Symbol, ...] The traits to apply.
|
82
|
+
def which_is(*traits)
|
83
|
+
traits.each { |trait| self.traits << trait }
|
84
|
+
self
|
85
|
+
end
|
86
|
+
|
87
|
+
# Locate the nearest ancestor of the given type.
|
88
|
+
#
|
89
|
+
# @param upstream_type [Symbol] The type of ancestor to find.
|
90
|
+
# @return [Satisfactory::Record, Satisfactory::Collection, Satisfactory::Root]
|
91
|
+
def and_same(upstream_type)
|
92
|
+
Satisfactory::UpstreamRecordFinder.new(upstream:).find(upstream_type)
|
93
|
+
end
|
94
|
+
|
95
|
+
# @api private
|
96
|
+
def modify
|
97
|
+
yield(self).upstream
|
98
|
+
end
|
99
|
+
|
100
|
+
# Trigger the creation of this tree's build plan.
|
101
|
+
#
|
102
|
+
# @return (see Satisfactory::Root#create)
|
103
|
+
# @todo Check if we still need the upstream check.
|
104
|
+
def create
|
105
|
+
if upstream
|
106
|
+
upstream.create
|
107
|
+
else
|
108
|
+
create_self
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Construct this tree's build plan.
|
113
|
+
#
|
114
|
+
# @return [Hash]
|
115
|
+
def to_plan
|
116
|
+
if upstream
|
117
|
+
upstream.to_plan
|
118
|
+
else
|
119
|
+
build_plan
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# @api private
|
124
|
+
def build_plan
|
125
|
+
{
|
126
|
+
traits:,
|
127
|
+
}.merge(associations_plan).compact_blank
|
128
|
+
end
|
129
|
+
|
130
|
+
# @api private
|
131
|
+
# @return (see #reify)
|
132
|
+
def build
|
133
|
+
reify(:build)
|
134
|
+
end
|
135
|
+
|
136
|
+
# @api private
|
137
|
+
# @return (see #reify)
|
138
|
+
def create_self
|
139
|
+
reify(:create)
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
attr_reader :associations
|
145
|
+
|
146
|
+
# @return [ApplicationRecord]
|
147
|
+
def reify(method)
|
148
|
+
FactoryBot.public_send(method, factory_name, *traits, attributes.merge(associations.transform_values(&:build)))
|
149
|
+
end
|
150
|
+
|
151
|
+
def associations_plan
|
152
|
+
associations.transform_values(&:build_plan).compact_blank
|
153
|
+
end
|
154
|
+
|
155
|
+
def plural?(association_name)
|
156
|
+
type_config.dig(:associations, :plural).include?(association_name)
|
157
|
+
end
|
158
|
+
|
159
|
+
def singular?(association_name)
|
160
|
+
type_config.dig(:associations, :singular).include?(association_name)
|
161
|
+
end
|
162
|
+
|
163
|
+
def plural_from_singular(singular_association_name)
|
164
|
+
type_config.dig(:associations, :plural).find do |name|
|
165
|
+
singular_association_name.to_s == name.to_s.singularize
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def singular_from_plural(plural_association_name)
|
170
|
+
Satisfactory.factory_configurations.keys.find do |name|
|
171
|
+
plural_association_name.to_s == name.to_s.pluralize
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def add_singular_association(name, factory_name:, force: false, attributes: {})
|
176
|
+
if force || associations[name].blank?
|
177
|
+
associations[name] = self.class.new(type: name, factory_name:, upstream: self, attributes:)
|
178
|
+
else
|
179
|
+
associations[name]
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def add_plural_association(name, factory_name:, count: nil, force: false, attributes: {})
|
184
|
+
count ||= 1
|
185
|
+
singular_name = name.to_s.singularize.to_sym
|
186
|
+
|
187
|
+
Satisfactory::Collection.new(upstream: self).tap do |new_associations|
|
188
|
+
count.times do
|
189
|
+
new_associations << self.class.new(type: singular_name, factory_name:, upstream: self, attributes:)
|
190
|
+
end
|
191
|
+
|
192
|
+
if force
|
193
|
+
associations[name] << new_associations
|
194
|
+
else
|
195
|
+
associations[name] = new_associations
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def add_singular_for_plural_association(name, singular:, factory_name:, force: false, attributes: {})
|
201
|
+
if force || associations[name].empty?
|
202
|
+
associations[name] << self.class.new(type: singular, factory_name:, upstream: self, attributes:)
|
203
|
+
end
|
204
|
+
|
205
|
+
associations[name].last
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative "record"
|
2
|
+
|
3
|
+
module Satisfactory
|
4
|
+
# The root of the factory graph.
|
5
|
+
# This is where you begin creating records.
|
6
|
+
class Root
|
7
|
+
# @api private
|
8
|
+
def initialize
|
9
|
+
@root_records = Hash.new { |h, k| h[k] = [] }
|
10
|
+
end
|
11
|
+
|
12
|
+
# Add a top-level record to the root.
|
13
|
+
# This is your entry point into the factory graph, and
|
14
|
+
# the way to begin creating records.
|
15
|
+
def add(factory_name, **attributes)
|
16
|
+
raise FactoryNotDefinedError, factory_name unless Satisfactory.factory_configurations.key?(factory_name)
|
17
|
+
|
18
|
+
Satisfactory::Record.new(
|
19
|
+
type: factory_name,
|
20
|
+
upstream: self,
|
21
|
+
attributes:,
|
22
|
+
).tap { |r| @root_records[factory_name] << r }
|
23
|
+
end
|
24
|
+
|
25
|
+
# @api private
|
26
|
+
# @return [Hash<Symbol, Array<ApplicationRecord>>]
|
27
|
+
def create
|
28
|
+
@root_records.transform_values do |records|
|
29
|
+
records.map(&:create_self)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# @api private
|
34
|
+
# @return [Hash<Symbol, Array<Hash>>]
|
35
|
+
def to_plan
|
36
|
+
@root_records.transform_values do |records|
|
37
|
+
records.map(&:build_plan)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# @api private
|
42
|
+
# @return [nil]
|
43
|
+
def upstream
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Satisfactory
|
2
|
+
# Finds the upstream record of a given type.
|
3
|
+
#
|
4
|
+
# @api private
|
5
|
+
class UpstreamRecordFinder
|
6
|
+
def initialize(upstream:)
|
7
|
+
@upstream = upstream
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_accessor :upstream
|
11
|
+
|
12
|
+
def find(type)
|
13
|
+
raise MissingUpstreamRecordError, type if upstream.nil?
|
14
|
+
|
15
|
+
if type == upstream.type
|
16
|
+
self
|
17
|
+
else
|
18
|
+
self.upstream = upstream.upstream
|
19
|
+
find(type)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def with(*args, **kwargs)
|
24
|
+
upstream.with(*args, force: true, **kwargs)
|
25
|
+
end
|
26
|
+
|
27
|
+
# @api private
|
28
|
+
class MissingUpstreamRecordError < StandardError; end
|
29
|
+
end
|
30
|
+
end
|
data/lib/satisfactory/version.rb
CHANGED
data/lib/satisfactory.rb
CHANGED
@@ -1,8 +1,24 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require_relative "satisfactory/version"
|
1
|
+
require_relative "satisfactory/loader"
|
2
|
+
require_relative "satisfactory/root"
|
4
3
|
|
4
|
+
# Satisfactory is a factory library for Ruby,
|
5
|
+
# helping you to navigate your factory associations.
|
6
|
+
#
|
7
|
+
# Currently implemented atop FactoryBot, but
|
8
|
+
# could be extended to support other factory libraries.
|
9
|
+
#
|
10
|
+
# @since 0.2.0
|
5
11
|
module Satisfactory
|
6
|
-
|
7
|
-
|
12
|
+
# @!attribute [r] factory_configurations
|
13
|
+
class << self
|
14
|
+
def root
|
15
|
+
Root.new
|
16
|
+
end
|
17
|
+
|
18
|
+
# @api private
|
19
|
+
# @return (see Loader.factory_configurations)
|
20
|
+
def factory_configurations
|
21
|
+
@factory_configurations ||= Loader.factory_configurations
|
22
|
+
end
|
23
|
+
end
|
8
24
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative "lib/satisfactory/version"
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "satisfactory"
|
5
|
+
spec.version = Satisfactory::VERSION
|
6
|
+
spec.authors = ["Elliot Crosby-McCullough"]
|
7
|
+
spec.email = ["elliot.cm@gmail.com"]
|
8
|
+
|
9
|
+
spec.summary = "A DSL for navigating your factories and building test data"
|
10
|
+
spec.homepage = "https://github.com/SmartCasual/satisfactory"
|
11
|
+
spec.license = "CC-BY-NC-SA-4.0"
|
12
|
+
|
13
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/v#{spec.version}/CHANGELOG.md"
|
14
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
15
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
16
|
+
|
17
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
18
|
+
spec.required_ruby_version = ">= 3.1.0"
|
19
|
+
|
20
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) {
|
21
|
+
Dir[
|
22
|
+
"{bin,lib}/**/*",
|
23
|
+
"CHANGELOG.md",
|
24
|
+
"LICENCE",
|
25
|
+
"Rakefile",
|
26
|
+
"README.md",
|
27
|
+
"satisfactory.gemspec",
|
28
|
+
]
|
29
|
+
}
|
30
|
+
|
31
|
+
spec.bindir = "bin"
|
32
|
+
spec.executables = spec.files.grep(%r{\Abin/}) { |f| File.basename(f) }
|
33
|
+
spec.require_paths = ["lib"]
|
34
|
+
|
35
|
+
spec.add_dependency "factory_bot_rails", "~> 6.2"
|
36
|
+
|
37
|
+
spec.add_development_dependency "rubocop", "~> 1.40"
|
38
|
+
spec.add_development_dependency "yard", "~> 0.9"
|
39
|
+
end
|
metadata
CHANGED
@@ -1,35 +1,96 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: satisfactory
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elliot Crosby-McCullough
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-12-
|
12
|
-
dependencies:
|
11
|
+
date: 2022-12-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: factory_bot_rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '6.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rubocop
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.40'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.40'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.9'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.9'
|
13
55
|
description:
|
14
56
|
email:
|
15
57
|
- elliot.cm@gmail.com
|
16
|
-
executables:
|
58
|
+
executables:
|
59
|
+
- console
|
60
|
+
- rubocop
|
61
|
+
- setup
|
62
|
+
- yard
|
63
|
+
- yardoc
|
64
|
+
- yri
|
17
65
|
extensions: []
|
18
66
|
extra_rdoc_files: []
|
19
67
|
files:
|
20
|
-
- ".rubocop.yml"
|
21
68
|
- CHANGELOG.md
|
22
|
-
-
|
69
|
+
- LICENCE
|
23
70
|
- README.md
|
24
71
|
- Rakefile
|
72
|
+
- bin/console
|
73
|
+
- bin/rubocop
|
74
|
+
- bin/setup
|
75
|
+
- bin/yard
|
76
|
+
- bin/yardoc
|
77
|
+
- bin/yri
|
25
78
|
- lib/satisfactory.rb
|
79
|
+
- lib/satisfactory/collection.rb
|
80
|
+
- lib/satisfactory/loader.rb
|
81
|
+
- lib/satisfactory/record.rb
|
82
|
+
- lib/satisfactory/root.rb
|
83
|
+
- lib/satisfactory/upstream_record_finder.rb
|
26
84
|
- lib/satisfactory/version.rb
|
27
|
-
-
|
85
|
+
- satisfactory.gemspec
|
28
86
|
homepage: https://github.com/SmartCasual/satisfactory
|
29
|
-
licenses:
|
87
|
+
licenses:
|
88
|
+
- CC-BY-NC-SA-4.0
|
30
89
|
metadata:
|
90
|
+
changelog_uri: https://github.com/SmartCasual/satisfactory/blob/v0.2.0/CHANGELOG.md
|
31
91
|
homepage_uri: https://github.com/SmartCasual/satisfactory
|
32
92
|
source_code_uri: https://github.com/SmartCasual/satisfactory
|
93
|
+
rubygems_mfa_required: 'true'
|
33
94
|
post_install_message:
|
34
95
|
rdoc_options: []
|
35
96
|
require_paths:
|
@@ -38,7 +99,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
38
99
|
requirements:
|
39
100
|
- - ">="
|
40
101
|
- !ruby/object:Gem::Version
|
41
|
-
version:
|
102
|
+
version: 3.1.0
|
42
103
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
104
|
requirements:
|
44
105
|
- - ">="
|
@@ -48,5 +109,5 @@ requirements: []
|
|
48
109
|
rubygems_version: 3.3.7
|
49
110
|
signing_key:
|
50
111
|
specification_version: 4
|
51
|
-
summary:
|
112
|
+
summary: A DSL for navigating your factories and building test data
|
52
113
|
test_files: []
|
data/.rubocop.yml
DELETED
data/Gemfile
DELETED
data/sig/satisfactory.rbs
DELETED