rom-factory 0.12.0 → 0.13.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: 0cae4bd0ca2ec550f5fdfb9e17151f6e4be3b575f382935281721f75f905f46b
4
- data.tar.gz: 1c6291ac1413d16b15fe946378d1eb59e08d8bafa61f2c8eb7743412bd53d31a
3
+ metadata.gz: 946c06da46cc1d12ac8e90fc8b79661ce43e9ed2ab2ba0e3ffd93f5c1ac7e419
4
+ data.tar.gz: fa2c475a578ba75f7574ed5d883a4432fc4f2328849fc4be74813b854a0c6dba
5
5
  SHA512:
6
- metadata.gz: 14b6dcc4ea8a9077684b372baba986a0bd51b081ab75faadb954156c9b09dbcdf5f05bfe1a0cfc886e915b461c13afa8c0d42213337264188d438a0064ab8c34
7
- data.tar.gz: 5705eb8df8fd99a9ff93c53b769a3c3c7f09749740642abf9a2d8f6907b67104147286d667d18de8ae372c8bafd7edad86d1baba8273cd2e67613ecc68a474c9
6
+ metadata.gz: b1dea330b287e3b56c2acaea898c9139317b0de709098c0c7525d05215db34571dfa41447337ca39b39f7d1d5ace98fde9f442854a725870fa6496c24d00eee3
7
+ data.tar.gz: 6279eb190440aeb10dc03c26fe18cfcc67f846e8d0981b7822746172f564936f5d2fd7cbf41a68336be1865516afda03947302804db8d6a1e05040198137beb9
@@ -2,20 +2,10 @@
2
2
  name: ci
3
3
  on:
4
4
  push:
5
- paths:
6
- - ".github/workflows/ci.yml"
7
- - lib/**
8
- - "*.gemspec"
9
- - spec/**
10
- - Rakefile
11
- - Gemfile
12
- - Gemfile.devtools
13
- - ".rubocop.yml"
14
- - project.yml
15
5
  pull_request:
16
- branches:
17
- - master
18
6
  create:
7
+ schedule:
8
+ - cron: "30 4 * * *"
19
9
  jobs:
20
10
  tests:
21
11
  runs-on: ubuntu-latest
@@ -23,14 +13,15 @@ jobs:
23
13
  fail-fast: false
24
14
  matrix:
25
15
  ruby:
16
+ - '3.4'
26
17
  - '3.3'
27
18
  - '3.2'
28
19
  - '3.1'
29
- - '3.0'
30
20
  env:
31
21
  COVERAGE: "${{matrix.coverage}}"
32
22
  COVERAGE_TOKEN: "${{secrets.CODACY_PROJECT_TOKEN}}"
33
23
  APT_DEPS: libpq-dev libmysqlclient-dev libsqlite3-dev
24
+ DATABASE_URL: "postgres://rom-factory:rom-factory@localhost:5432/rom_factory"
34
25
  steps:
35
26
  - name: Checkout
36
27
  uses: actions/checkout@v1
@@ -56,10 +47,10 @@ jobs:
56
47
  coverage-reports: coverage/coverage.xml
57
48
  services:
58
49
  db:
59
- image: postgres:10.8
50
+ image: postgres:16.1
60
51
  env:
61
- POSTGRES_USER: runner
62
- POSTGRES_PASSWORD: ''
52
+ POSTGRES_USER: rom-factory
53
+ POSTGRES_PASSWORD: rom-factory
63
54
  POSTGRES_DB: rom_factory
64
55
  ports:
65
56
  - 5432:5432
@@ -86,3 +77,11 @@ jobs:
86
77
  run: |
87
78
  tag=$(echo $GITHUB_REF | cut -d / -f 3)
88
79
  ossy gh w rom-rb/devtools release --payload "{\"tag\":\"$tag\",\"sha\":\"${{github.sha}}\",\"tag_creator\":\"$GITHUB_ACTOR\",\"repo\":\"$GITHUB_REPOSITORY\",\"repo_name\":\"${{github.event.repository.name}}\"}"
80
+
81
+ workflow-keepalive:
82
+ if: github.event_name == 'schedule'
83
+ runs-on: ubuntu-latest
84
+ permissions:
85
+ actions: write
86
+ steps:
87
+ - uses: liskin/gh-workflow-keepalive@v1
data/.postgres.env ADDED
@@ -0,0 +1,4 @@
1
+ POSTGRES_USER="rom"
2
+ POSTGRES_PASSWORD="password"
3
+ POSTGRES_DATABASE="rom_factory"
4
+ POSTGRES_HOST_AUTH_METHOD="trust"
data/.rubocop.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  # This is a config synced from rom-rb/template-gem repo
2
2
  AllCops:
3
- TargetRubyVersion: 2.7
4
- NewCops: disable
3
+ TargetRubyVersion: 3.1
4
+ NewCops: enable
5
5
  SuggestExtensions: false
6
6
  Exclude:
7
7
  - spec/support/coverage.rb
data/CHANGELOG.md CHANGED
@@ -1,17 +1,47 @@
1
1
  <!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
2
2
 
3
+ ## 0.13.0 2025-01-21
4
+
5
+
6
+ ### Added
7
+
8
+ - Support for unique options in `fake` DSL (via #94) (@sean-dickinson)
9
+
10
+ ```ruby
11
+ Factory.define(:user) do |f|
12
+ f.name { fake(:name, unique: true) }
13
+ end
14
+ ```
15
+
16
+ Be advised there's `Faker::UniqueGenerator.clear` to clear the cache of unique values.
17
+
18
+ - Support for setting traits with a keyword argument for associations (via #84) (@parndt)
19
+
20
+ ```ruby
21
+ Factory.define :category do |f|
22
+ f.association :image, traits: [:fancy]
23
+ end
24
+ ```
25
+
26
+
27
+ ### Changed
28
+
29
+ - Minimum Ruby version is now 3.1 (@flash-gordon)
30
+
31
+ [Compare v0.12.0...v0.13.0](https://github.com/rom-rb/rom-factory/compare/v0.12.0...v0.13.0)
32
+
3
33
  ## 0.12.0 2024-01-19
4
34
 
5
35
 
6
36
  ### Added
7
37
 
8
- - Support for many-to-many and one-to-one-through associations (via
9
- - Support for UUID as PKs in associations (via
38
+ - Support for many-to-many and one-to-one-through associations (via #86) (@solnic)
39
+ - Support for UUID as PKs in associations (via #87) (@solnic)
10
40
 
11
41
  ### Fixed
12
42
 
13
- - Relations without PKs should work too (via
14
- - Relations with PK values generated on the Ruby side should work in SQlite too (via
43
+ - Relations without PKs should work too (via #87) (@solnic)
44
+ - Relations with PK values generated on the Ruby side should work in SQlite too (via #87) (@solnic)
15
45
 
16
46
 
17
47
  [Compare v0.11.0...v0.12.0](https://github.com/rom-rb/rom-factory/compare/v0.11.0...v0.12.0)
data/Gemfile CHANGED
@@ -10,24 +10,34 @@ gem "faker", "~> 3.0"
10
10
 
11
11
  gem "rspec", "~> 3.0"
12
12
 
13
- git "https://github.com/rom-rb/rom.git", branch: "release-5.3" do
14
- gem "rom-core"
13
+ gem "dotenv"
14
+
15
+ git "https://github.com/rom-rb/rom.git", branch: "release-5.4" do
16
+ gem "rom"
15
17
  gem "rom-changeset"
18
+ gem "rom-core"
16
19
  gem "rom-repository"
17
- gem "rom"
18
20
  end
19
21
 
20
22
  group :test do
21
- gem "pry"
22
- gem "pry-byebug", "~> 3.8", platforms: :ruby
23
- gem "rom-sql", github: "rom-rb/rom-sql", branch: "release-3.6"
23
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4")
24
+ gem "debug"
25
+ else
26
+ gem "pry"
27
+ gem "pry-byebug", "~> 3.8", platforms: :ruby
28
+ end
29
+ gem "rom-sql", github: "rom-rb/rom-sql", branch: "release-3.7"
24
30
 
25
31
  gem "jdbc-postgres", platforms: :jruby
26
32
  gem "pg", "~> 1.5", platforms: :ruby
27
33
  end
28
34
 
29
35
  group :tools do
30
- gem "byebug", platform: :mri
36
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4")
37
+ gem "byebug", platform: :mri
38
+ else
39
+ gem "pry-byebug", "~> 3.8", platforms: :ruby
40
+ end
31
41
  gem "redcarpet" # for yard
32
42
  end
33
43
 
data/Gemfile.devtools CHANGED
@@ -16,5 +16,5 @@ end
16
16
 
17
17
  group :tools do
18
18
  # this is the same version that we use on codacy
19
- gem "rubocop", "1.26.1"
19
+ gem "rubocop", "1.69.2"
20
20
  end
data/README.md CHANGED
@@ -21,8 +21,8 @@
21
21
 
22
22
  This library officially supports the following Ruby versions:
23
23
 
24
- * MRI >= `2.5`
25
- * jruby >= `9.2`
24
+ * MRI >= `3.1`
25
+ * jruby >= `9.4` (not tested in CI)
26
26
 
27
27
  ## License
28
28
 
data/changelog.yml CHANGED
@@ -1,16 +1,39 @@
1
1
  ---
2
+ - version: 0.13.0
3
+ date: 2025-01-21
4
+ added:
5
+ - |
6
+ Support for unique options in `fake` DSL (via #94) (@sean-dickinson)
7
+
8
+ ```ruby
9
+ Factory.define(:user) do |f|
10
+ f.name { fake(:name, unique: true) }
11
+ end
12
+ ```
13
+
14
+ Be advised there's `Faker::UniqueGenerator.clear` to clear the cache of unique values.
15
+ - |
16
+ Support for setting traits with a keyword argument for associations (via #84) (@parndt)
17
+
18
+ ```ruby
19
+ Factory.define :category do |f|
20
+ f.association :image, traits: [:fancy]
21
+ end
22
+ ```
23
+ changed:
24
+ - Minimum Ruby version is now 3.1 (@flash-gordon)
2
25
  - version: 0.12.0
3
26
  date: 2024-01-19
4
27
  added:
5
- - Support for many-to-many and one-to-one-through associations (via #86) (@solnic)
6
- - Support for UUID as PKs in associations (via #87) (@solnic)
28
+ - "Support for many-to-many and one-to-one-through associations (via #86) (@solnic)"
29
+ - "Support for UUID as PKs in associations (via #87) (@solnic)"
7
30
  fixed:
8
- - Relations without PKs should work too (via #87) (@solnic)
9
- - Relations with PK values generated on the Ruby side should work in SQlite too (via #87) (@solnic)
31
+ - "Relations without PKs should work too (via #87) (@solnic)"
32
+ - "Relations with PK values generated on the Ruby side should work in SQlite too (via #87) (@solnic)"
10
33
  - version: 0.11.0
11
34
  date: 2022-11-11
12
35
  added:
13
- - Support for one-to-one associations (@ianks)
36
+ - "Support for one-to-one associations (@ianks)"
14
37
  - "[internal] cache for Faker constants (@flash-gordon)"
15
38
  changed:
16
39
  - |
data/compose.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ services:
3
+ db:
4
+ image: postgres
5
+ ports:
6
+ - 5432
7
+ env_file: .postgres.env
@@ -141,6 +141,14 @@ Factory.define(:user) do |f|
141
141
  end
142
142
  ```
143
143
 
144
+ ##### Unique values with fake
145
+ Passing the unique: true option will use Faker's [unique](https://github.com/faker-ruby/faker#ensuring-unique-values) feature
146
+ ```ruby
147
+ Factory.define(:user) do |f|
148
+ f.email { fake(:internet, :email, unique: true) }
149
+ end
150
+ ```
151
+
144
152
  #### Dependent attributes
145
153
 
146
154
  Attributes can be based on the values of other attributes:
@@ -159,11 +167,15 @@ end
159
167
 
160
168
  ```ruby
161
169
  # Create in-memory object
162
- Factory.structs[:user]
170
+ Factory.build(:user)
163
171
 
164
172
  # Persist struct in database
165
- Factory[:user]
173
+ Factory.create(:user)
166
174
 
167
175
  # Override attributes
168
- Factory[:user, age: 24]
176
+ Factory.create(:user, age: 24)
177
+
178
+ # Build and Create via #[] accessors
179
+ Factory.structs[:user]
180
+ Factory[:user]
169
181
  ```
@@ -18,14 +18,10 @@ module ROM
18
18
  end
19
19
 
20
20
  # @api private
21
- def each(&block)
22
- elements.each(&block)
23
- end
21
+ def each(&) = elements.each(&)
24
22
 
25
23
  # @api private
26
- def [](name)
27
- detect { |e| e.name.equal?(name) }
28
- end
24
+ def [](name) = detect { |e| e.name.equal?(name) }
29
25
 
30
26
  # @api private
31
27
  def <<(element)
@@ -36,34 +32,32 @@ module ROM
36
32
  end
37
33
 
38
34
  # @api private
39
- def dup
40
- self.class.new(elements.dup)
41
- end
35
+ def dup = self.class.new(elements.dup)
42
36
 
43
37
  # @api private
44
- def values
45
- self.class.new(elements.select(&:value?))
46
- end
38
+ def values = self.class.new(elements.select(&:value?))
47
39
 
48
40
  # @api private
49
41
  def associations
50
42
  self.class.new(elements.select { |e| e.is_a?(Attributes::Association::Core) })
51
43
  end
52
44
 
53
- def reject(&block)
54
- self.class.new(elements.reject(&block))
45
+ def reject(&) = self.class.new(elements.reject(&))
46
+
47
+ # @api private
48
+ def inspect
49
+ "#<#{self.class} #{elements.inspect}>"
55
50
  end
51
+ alias_method :to_s, :inspect
56
52
 
57
53
  private
58
54
 
59
55
  # @api private
60
- def tsort_each_node(&block)
61
- each(&block)
62
- end
56
+ def tsort_each_node(&) = each(&)
63
57
 
64
58
  # @api private
65
- def tsort_each_child(attr, &block)
66
- attr.dependency_names.map { |name| self[name] }.compact.each(&block)
59
+ def tsort_each_child(attr, &)
60
+ attr.dependency_names.map { |name| self[name] }.compact.each(&)
67
61
  end
68
62
  end
69
63
  end
@@ -6,8 +6,8 @@ module ROM::Factory
6
6
  # rubocop:disable Style/OptionalArguments
7
7
  module Association
8
8
  class << self
9
- def new(assoc, builder, *traits, **options)
10
- const_get(assoc.definition.type).new(assoc, builder, *traits, **options)
9
+ def new(assoc, ...)
10
+ const_get(assoc.definition.type).new(assoc, ...)
11
11
  end
12
12
  end
13
13
 
@@ -24,9 +24,7 @@ module ROM::Factory
24
24
  end
25
25
 
26
26
  # @api private
27
- def through?
28
- false
29
- end
27
+ def through? = false
30
28
 
31
29
  # @api private
32
30
  def builder
@@ -34,34 +32,22 @@ module ROM::Factory
34
32
  end
35
33
 
36
34
  # @api private
37
- def name
38
- assoc.key
39
- end
35
+ def name = assoc.key
40
36
 
41
37
  # @api private
42
- def dependency?(*)
43
- false
44
- end
38
+ def dependency?(*) = false
45
39
 
46
40
  # @api private
47
- def value?
48
- false
49
- end
41
+ def value? = false
50
42
 
51
43
  # @api private
52
- def factories
53
- builder.factories
54
- end
44
+ def factories = builder.factories
55
45
 
56
46
  # @api private
57
- def foreign_key
58
- assoc.foreign_key
59
- end
47
+ def foreign_key = assoc.foreign_key
60
48
 
61
49
  # @api private
62
- def count
63
- options.fetch(:count, 1)
64
- end
50
+ def count = options.fetch(:count, 1)
65
51
  end
66
52
 
67
53
  # @api private
@@ -73,19 +59,20 @@ module ROM::Factory
73
59
 
74
60
  assoc_data = attrs.fetch(name, EMPTY_HASH)
75
61
 
76
- if assoc_data.is_a?(Hash) && assoc_data[assoc.target.primary_key] && !attrs[foreign_key]
62
+ if assoc_data.is_a?(::Hash) && assoc_data[assoc.target.primary_key] && !attrs[foreign_key]
77
63
  assoc.associate(attrs, attrs[name])
78
- elsif assoc_data.is_a?(ROM::Struct)
64
+ elsif assoc_data.is_a?(::ROM::Struct)
79
65
  assoc.associate(attrs, assoc_data)
80
66
  else
81
- parent = if persist && !attrs[foreign_key]
82
- builder.persistable.create(*parent_traits, **assoc_data)
83
- else
84
- builder.struct(
85
- *parent_traits,
86
- **assoc_data.merge(assoc.target.primary_key => attrs[foreign_key])
87
- )
88
- end
67
+ parent =
68
+ if persist && !attrs[foreign_key]
69
+ builder.persistable.create(*parent_traits, **assoc_data)
70
+ else
71
+ builder.struct(
72
+ *parent_traits,
73
+ **assoc_data, assoc.target.primary_key => attrs[foreign_key]
74
+ )
75
+ end
89
76
 
90
77
  tuple = {name => parent}
91
78
 
@@ -112,7 +99,7 @@ module ROM::Factory
112
99
  def call(attrs = EMPTY_HASH, parent, persist: true)
113
100
  return if attrs.key?(name)
114
101
 
115
- structs = Array.new(count).map do
102
+ structs = ::Array.new(count).map do
116
103
  # hash which contains the foreign key info, i.e: { user_id: 1 }
117
104
  association_hash = assoc.associate(attrs, parent)
118
105
 
@@ -127,9 +114,7 @@ module ROM::Factory
127
114
  end
128
115
 
129
116
  # @api private
130
- def dependency?(rel)
131
- assoc.source == rel
132
- end
117
+ def dependency?(rel) = assoc.source == rel
133
118
  end
134
119
 
135
120
  # @api private
@@ -143,14 +128,15 @@ module ROM::Factory
143
128
 
144
129
  association_hash = assoc.associate(attrs, parent)
145
130
 
146
- struct = if persist
147
- builder.persistable.create(*traits, **association_hash)
148
- else
149
- belongs_to_name = Dry::Core::Inflector.singularize(assoc.source_alias)
150
- belongs_to_associations = {belongs_to_name.to_sym => parent}
151
- final_attrs = attrs.merge(association_hash).merge(belongs_to_associations)
152
- builder.struct(*traits, **final_attrs)
153
- end
131
+ struct =
132
+ if persist
133
+ builder.persistable.create(*traits, **association_hash)
134
+ else
135
+ belongs_to_name = ::ROM::Inflector.singularize(assoc.source_alias)
136
+ belongs_to_associations = {belongs_to_name.to_sym => parent}
137
+ final_attrs = attrs.merge(association_hash).merge(belongs_to_associations)
138
+ builder.struct(*traits, **final_attrs)
139
+ end
154
140
 
155
141
  {name => struct}
156
142
  end
@@ -175,7 +161,7 @@ module ROM::Factory
175
161
  if through_factory?
176
162
  structs.each do |child|
177
163
  through_attrs = {
178
- Dry::Core::Inflector.singularize(assoc.source.name.key).to_sym => parent,
164
+ ::ROM::Inflector.singularize(assoc.source.name.key).to_sym => parent,
179
165
  assoc.through.assoc_name => child
180
166
  }
181
167
 
@@ -191,37 +177,27 @@ module ROM::Factory
191
177
  end
192
178
  end
193
179
 
194
- def result(structs)
195
- {name => structs}
196
- end
180
+ def result(structs) = {name => structs}
197
181
 
198
- def dependency?(rel)
199
- assoc.source == rel
200
- end
182
+ def dependency?(rel) = assoc.source == rel
201
183
 
202
- def through?
203
- true
204
- end
184
+ def through? = true
205
185
 
206
186
  def through_factory?
207
187
  factories.registry.key?(through_factory_name)
208
188
  end
209
189
 
210
190
  def through_factory_name
211
- ROM::Inflector.singularize(assoc.definition.through.source).to_sym
191
+ ::ROM::Inflector.singularize(assoc.definition.through.source).to_sym
212
192
  end
213
193
 
214
194
  private
215
195
 
216
- def tpk
217
- assoc.target.primary_key
218
- end
196
+ def tpk = assoc.target.primary_key
219
197
  end
220
198
 
221
199
  class OneToOneThrough < ManyToMany
222
- def result(structs)
223
- {name => structs[0]}
224
- end
200
+ def result(structs) = {name => structs[0]}
225
201
  end
226
202
  end
227
203
  end
@@ -28,6 +28,12 @@ module ROM::Factory
28
28
  def dependency_names
29
29
  block.parameters.map(&:last)
30
30
  end
31
+
32
+ # @api private
33
+ def inspect
34
+ "#<#{self.class.name} #{name} at #{block.source_location.join(":")}>"
35
+ end
36
+ alias_method :to_s, :inspect
31
37
  end
32
38
  end
33
39
  end
@@ -12,26 +12,39 @@ module ROM
12
12
 
13
13
  class << self
14
14
  # @api private
15
- def fake(*args, **options)
16
- api = fetch_or_store(:faker, *args) do
15
+ def fake(*args, unique: false, **options)
16
+ factory, produce = fetch_or_store(:faker, unique, *args) do
17
17
  *ns, method_name = args
18
18
 
19
19
  const = ns.reduce(::Faker) do |obj, name|
20
- obj.const_get(::Dry::Core::Inflector.camelize(name))
20
+ obj.const_get(::ROM::Inflector.camelize(name))
21
21
  end
22
22
 
23
- const.method(method_name)
23
+ if unique
24
+ [const.unique, method_name]
25
+ else
26
+ [const, method_name]
27
+ end
24
28
  end
25
29
 
26
- api.(**options)
30
+ factory.public_send(produce, **options)
27
31
  end
28
32
  end
29
33
 
30
34
  # Factory builder DSL
31
35
  #
32
36
  # @api public
33
- class DSL < BasicObject
34
- define_method(:rand, ::Kernel.instance_method(:rand))
37
+ class DSL < ::BasicObject
38
+ # @api private
39
+ module Kernel
40
+ %i[binding class instance_of? is_a? rand respond_to_missing? singleton_class].each do |meth|
41
+ define_method(meth, ::Kernel.instance_method(meth))
42
+ end
43
+
44
+ private :respond_to_missing?, :rand, :binding
45
+ end
46
+
47
+ include Kernel
35
48
 
36
49
  attr_reader :_name, :_relation, :_attributes, :_factories, :_struct_namespace, :_valid_names
37
50
  attr_reader :_traits
@@ -64,17 +77,15 @@ module ROM
64
77
  # @param [Symbol] The name of the registered builder
65
78
  #
66
79
  # @api public
67
- def create(name, *args)
68
- _factories[name, *args]
69
- end
80
+ def create(name, *args) = _factories[name, *args]
70
81
 
71
82
  # Create a sequence attribute
72
83
  #
73
84
  # @param [Symbol] name The attribute name
74
85
  #
75
86
  # @api private
76
- def sequence(meth, &block)
77
- define_sequence(meth, block) if _valid_names.include?(meth)
87
+ def sequence(meth, &)
88
+ define_sequence(meth, &) if _valid_names.include?(meth)
78
89
  end
79
90
 
80
91
  # Set timestamp attributes
@@ -104,9 +115,13 @@ module ROM
104
115
  # @example
105
116
  # f.email { fake(:number, :between, from: 10, to: 100) }
106
117
  #
118
+ # @example
119
+ # f.email { fake(:internet, :email, unique: true) }
120
+ #
107
121
  # @param [Symbol] genre The faker API identifier ie. :internet, :product etc.
108
122
  # @param [Symbol] type The value type to generate
109
- # @param [Hash] options Additional arguments
123
+ # @param [Hash] options Additional arguments, including unique: true will generate unique values
124
+ #
110
125
  #
111
126
  # @overload fake(genre, subgenre, type, **options)
112
127
  # @example
@@ -120,11 +135,9 @@ module ROM
120
135
  # @see https://github.com/faker-ruby/faker/tree/master/doc
121
136
  #
122
137
  # @api public
123
- def fake(type, *args, **options)
124
- ::ROM::Factory.fake(type, *args, **options)
125
- end
138
+ def fake(...) = ::ROM::Factory.fake(...)
126
139
 
127
- def trait(name, parents = [], &block)
140
+ def trait(name, parents = [], &)
128
141
  _traits[name] = DSL.new(
129
142
  "#{_name}_#{name}",
130
143
  attributes: _traits.values_at(*parents).flat_map(&:elements).inject(
@@ -133,7 +146,7 @@ module ROM
133
146
  relation: _relation,
134
147
  factories: _factories,
135
148
  struct_namespace: _struct_namespace,
136
- &block
149
+ &
137
150
  )._attributes
138
151
  end
139
152
 
@@ -145,12 +158,16 @@ module ROM
145
158
  # @example has-many
146
159
  # f.association(:posts, count: 2)
147
160
  #
161
+ # @example adding traits
162
+ # f.association(:posts, traits: [:published])
163
+ #
148
164
  # @param [Symbol] name The name of the configured association
149
165
  # @param [Hash] options Additional options
150
166
  # @option options [Integer] count Number of objects to generate
167
+ # @option options [Array<Symbol>] traits Traits to apply to the association
151
168
  #
152
169
  # @api public
153
- def association(name, *traits, **options)
170
+ def association(name, *seq_traits, traits: EMPTY_ARRAY, **options)
154
171
  assoc = _relation.associations[name]
155
172
 
156
173
  if assoc.is_a?(::ROM::SQL::Associations::OneToOne) && options.fetch(:count, 1) > 1
@@ -159,15 +176,25 @@ module ROM
159
176
 
160
177
  builder = -> { _factories.for_relation(assoc.target) }
161
178
 
162
- _attributes << attributes::Association.new(assoc, builder, *traits, **options)
179
+ _attributes << attributes::Association.new(
180
+ assoc,
181
+ builder,
182
+ *seq_traits,
183
+ *traits,
184
+ **options
185
+ )
163
186
  end
164
187
 
188
+ # @api private
189
+ def inspect = "#<#{self.class} name=#{_name}>"
190
+ alias_method :to_s, :inspect
191
+
165
192
  private
166
193
 
167
194
  # @api private
168
- def method_missing(meth, *args, &block)
195
+ def method_missing(meth, ...)
169
196
  if _valid_names.include?(meth)
170
- define_attr(meth, *args, &block)
197
+ define_attr(meth, ...)
171
198
  else
172
199
  super
173
200
  end
@@ -175,27 +202,26 @@ module ROM
175
202
 
176
203
  # @api private
177
204
  def respond_to_missing?(method_name, include_private = false)
178
- _valid_names.include?(meth) || super
205
+ _valid_names.include?(method_name) || super
179
206
  end
180
207
 
181
208
  # @api private
182
- def define_sequence(name, block)
183
- _attributes << attributes::Callable.new(name, self, attributes::Sequence.new(name, &block))
209
+ def define_sequence(name, &)
210
+ _attributes << attributes::Callable.new(name, self, attributes::Sequence.new(name, &))
184
211
  end
185
212
 
186
213
  # @api private
187
214
  def define_attr(name, *args, &block)
188
- _attributes << if block
189
- attributes::Callable.new(name, self, block)
190
- else
191
- attributes::Value.new(name, *args)
192
- end
215
+ _attributes <<
216
+ if block
217
+ attributes::Callable.new(name, self, block)
218
+ else
219
+ attributes::Value.new(name, *args)
220
+ end
193
221
  end
194
222
 
195
223
  # @api private
196
- def attributes
197
- ::ROM::Factory::Attributes
198
- end
224
+ def attributes = ::ROM::Factory::Attributes
199
225
  end
200
226
  end
201
227
  end
@@ -126,7 +126,7 @@ module ROM::Factory
126
126
  # @return [ROM::Factory::Builder]
127
127
  #
128
128
  # @api public
129
- def define(spec, opts = EMPTY_HASH, &block)
129
+ def define(spec, opts = EMPTY_HASH, &)
130
130
  name, parent = spec.is_a?(Hash) ? spec.flatten(1) : spec
131
131
  namespace = opts[:struct_namespace]
132
132
  relation_name = opts.fetch(:relation) { infer_relation(name) }
@@ -137,7 +137,7 @@ module ROM::Factory
137
137
 
138
138
  builder =
139
139
  if parent
140
- extend_builder(name, registry[parent], relation_name, namespace, &block)
140
+ extend_builder(name, registry[parent], relation_name, namespace, &)
141
141
  else
142
142
  relation = rom.relations[relation_name]
143
143
  DSL.new(
@@ -145,7 +145,7 @@ module ROM::Factory
145
145
  relation: relation,
146
146
  factories: self,
147
147
  struct_namespace: builder_struct_namespace(namespace),
148
- &block
148
+ &
149
149
  ).call
150
150
  end
151
151
 
@@ -170,6 +170,7 @@ module ROM::Factory
170
170
  def [](name, *traits, **attrs)
171
171
  registry[name].struct_namespace(struct_namespace).persistable.create(*traits, **attrs)
172
172
  end
173
+ alias_method :create, :[]
173
174
 
174
175
  # Return in-memory struct builder
175
176
  #
@@ -180,6 +181,25 @@ module ROM::Factory
180
181
  @__structs__ ||= Structs.new(registry, struct_namespace)
181
182
  end
182
183
 
184
+ # Return a new, non-persisted struct
185
+ #
186
+ # @example create a struct with default attributes
187
+ # MyFactory.build(:user)
188
+ #
189
+ # @example create a struct with some attributes overridden
190
+ # MyFactory.build(:uesr, name: "Jane")
191
+ #
192
+ # @param [Symbol] name The name of the registered factory
193
+ # @param [Array<Symbol>] traits List of traits to apply
194
+ # @param [Hash] attrs optional attributes to override the defaults
195
+ #
196
+ # @return [ROM::Struct]
197
+ #
198
+ # @api public
199
+ def build(name, *traits, **attrs)
200
+ structs[name, *traits, **attrs]
201
+ end
202
+
183
203
  # Get factories with a custom struct namespace
184
204
  #
185
205
  # @example
@@ -213,16 +233,16 @@ module ROM::Factory
213
233
 
214
234
  # @api private
215
235
  def infer_factory_name(name)
216
- ::Dry::Core::Inflector.singularize(name).to_sym
236
+ ::ROM::Inflector.singularize(name).to_sym
217
237
  end
218
238
 
219
239
  # @api private
220
240
  def infer_relation(name)
221
- ::Dry::Core::Inflector.pluralize(name).to_sym
241
+ ::ROM::Inflector.pluralize(name).to_sym
222
242
  end
223
243
 
224
244
  # @api private
225
- def extend_builder(name, parent, relation_name, ns, &block)
245
+ def extend_builder(name, parent, relation_name, ns, &)
226
246
  namespace = parent.options[:struct_namespace]
227
247
  namespace = builder_struct_namespace(ns) if ns
228
248
  relation = rom.relations.fetch(relation_name) { parent.relation }
@@ -232,7 +252,7 @@ module ROM::Factory
232
252
  relation: relation,
233
253
  factories: self,
234
254
  struct_namespace: namespace,
235
- &block
255
+ &
236
256
  ).call
237
257
  end
238
258
  end
@@ -151,9 +151,9 @@ module ROM
151
151
 
152
152
  # @api private
153
153
  def evaluate_values(attrs)
154
- attributes.values.tsort.each_with_object({}) do |attr, h|
155
- deps = attr.dependency_names.map { |k| h[k] }.compact
156
- result = attr.(attrs, *deps)
154
+ attributes.values.tsort.each_with_object(attrs.dup) do |attr, h|
155
+ deps = attr.dependency_names.filter_map { |k| h[k] }
156
+ result = attr.(h, *deps)
157
157
 
158
158
  if result
159
159
  h.update(result)
@@ -162,7 +162,7 @@ module ROM
162
162
  end
163
163
 
164
164
  def evaluate_traits(trait_list, attrs, opts)
165
- return {} if trait_list.empty?
165
+ return EMPTY_HASH if trait_list.empty?
166
166
 
167
167
  traits = trait_list.map { |v| v.is_a?(Hash) ? v : {v => true} }.reduce(:merge)
168
168
 
@@ -208,7 +208,7 @@ module ROM
208
208
 
209
209
  def select_mergeable_attrs(traits, attrs)
210
210
  unmergeable = assocs(traits).select(&:through?).map do |a|
211
- Dry::Core::Inflector.singularize(a.assoc.target.name.to_sym).to_sym
211
+ ::ROM::Inflector.singularize(a.assoc.target.name.to_sym).to_sym
212
212
  end
213
213
  attrs.dup.delete_if { |key, _| unmergeable.include?(key) }
214
214
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ROM
4
4
  module Factory
5
- VERSION = "0.12.0"
5
+ VERSION = "0.13.0"
6
6
  end
7
7
  end
data/rom-factory.gemspec CHANGED
@@ -1,9 +1,8 @@
1
- # coding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
- lib = File.expand_path('../lib', __FILE__)
3
+ lib = File.expand_path("lib", __dir__)
5
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
- require 'rom/factory/version'
5
+ require "rom/factory/version"
7
6
 
8
7
  Gem::Specification.new do |spec|
9
8
  spec.name = "rom-factory"
@@ -11,25 +10,26 @@ Gem::Specification.new do |spec|
11
10
  spec.authors = ["Janis Miezitis", "Piotr Solnica"]
12
11
  spec.email = ["janjiss@gmail.com", "piotr.solnica@gmail.com"]
13
12
 
14
- spec.summary = %q{ROM based builder library to make your specs awesome. DSL partially inspired by FactoryBot.}
15
- spec.description = %q{}
13
+ spec.summary = "ROM based builder library to make your specs awesome. DSL partially inspired by FactoryBot."
14
+ spec.description = ""
16
15
  spec.homepage = "https://github.com/rom-rb/rom-factory"
17
16
  spec.license = "MIT"
18
17
 
19
18
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
20
19
  # to allow pushing to a single host or delete this section to allow pushing to any host.
21
- spec.metadata['allowed_push_host'] = "https://rubygems.org"
20
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
21
+ spec.metadata["rubygems_mfa_required"] = "true"
22
22
 
23
23
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
24
  spec.bindir = "exe"
25
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
26
  spec.require_paths = ["lib"]
27
27
 
28
- spec.required_ruby_version = ">= 2.7.0"
28
+ spec.required_ruby_version = ">= 3.1.0"
29
29
 
30
- spec.add_runtime_dependency "dry-configurable", "~> 1.0"
31
- spec.add_runtime_dependency "dry-core", "~> 1.0"
32
- spec.add_runtime_dependency "dry-struct", "~> 1.6"
33
- spec.add_runtime_dependency "faker", ">= 2.0", "< 4"
34
- spec.add_runtime_dependency "rom-core", "~> 5.3"
30
+ spec.add_dependency "dry-configurable", "~> 1.3"
31
+ spec.add_dependency "dry-core", "~> 1.1"
32
+ spec.add_dependency "dry-struct", "~> 1.7"
33
+ spec.add_dependency "faker", ">= 2.0", "< 4"
34
+ spec.add_dependency "rom-core", "~> 5.4"
35
35
  end
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rom-factory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janis Miezitis
8
8
  - Piotr Solnica
9
- autorequire:
10
9
  bindir: exe
11
10
  cert_chain: []
12
- date: 2024-01-19 00:00:00.000000000 Z
11
+ date: 2025-01-21 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: dry-configurable
@@ -17,42 +16,42 @@ dependencies:
17
16
  requirements:
18
17
  - - "~>"
19
18
  - !ruby/object:Gem::Version
20
- version: '1.0'
19
+ version: '1.3'
21
20
  type: :runtime
22
21
  prerelease: false
23
22
  version_requirements: !ruby/object:Gem::Requirement
24
23
  requirements:
25
24
  - - "~>"
26
25
  - !ruby/object:Gem::Version
27
- version: '1.0'
26
+ version: '1.3'
28
27
  - !ruby/object:Gem::Dependency
29
28
  name: dry-core
30
29
  requirement: !ruby/object:Gem::Requirement
31
30
  requirements:
32
31
  - - "~>"
33
32
  - !ruby/object:Gem::Version
34
- version: '1.0'
33
+ version: '1.1'
35
34
  type: :runtime
36
35
  prerelease: false
37
36
  version_requirements: !ruby/object:Gem::Requirement
38
37
  requirements:
39
38
  - - "~>"
40
39
  - !ruby/object:Gem::Version
41
- version: '1.0'
40
+ version: '1.1'
42
41
  - !ruby/object:Gem::Dependency
43
42
  name: dry-struct
44
43
  requirement: !ruby/object:Gem::Requirement
45
44
  requirements:
46
45
  - - "~>"
47
46
  - !ruby/object:Gem::Version
48
- version: '1.6'
47
+ version: '1.7'
49
48
  type: :runtime
50
49
  prerelease: false
51
50
  version_requirements: !ruby/object:Gem::Requirement
52
51
  requirements:
53
52
  - - "~>"
54
53
  - !ruby/object:Gem::Version
55
- version: '1.6'
54
+ version: '1.7'
56
55
  - !ruby/object:Gem::Dependency
57
56
  name: faker
58
57
  requirement: !ruby/object:Gem::Requirement
@@ -79,14 +78,14 @@ dependencies:
79
78
  requirements:
80
79
  - - "~>"
81
80
  - !ruby/object:Gem::Version
82
- version: '5.3'
81
+ version: '5.4'
83
82
  type: :runtime
84
83
  prerelease: false
85
84
  version_requirements: !ruby/object:Gem::Requirement
86
85
  requirements:
87
86
  - - "~>"
88
87
  - !ruby/object:Gem::Version
89
- version: '5.3'
88
+ version: '5.4'
90
89
  description: ''
91
90
  email:
92
91
  - janjiss@gmail.com
@@ -106,12 +105,12 @@ files:
106
105
  - ".github/workflows/rubocop.yml"
107
106
  - ".github/workflows/sync_configs.yml"
108
107
  - ".gitignore"
108
+ - ".postgres.env"
109
109
  - ".repobot.yml"
110
110
  - ".rspec"
111
111
  - ".rubocop.yml"
112
112
  - ".yardopts"
113
113
  - CHANGELOG.md
114
- - CODEOWNERS
115
114
  - CODE_OF_CONDUCT.md
116
115
  - CONTRIBUTING.md
117
116
  - Gemfile
@@ -121,6 +120,7 @@ files:
121
120
  - Rakefile
122
121
  - benchmarks/basic.rb
123
122
  - changelog.yml
123
+ - compose.yml
124
124
  - docsite/source/index.html.md
125
125
  - lib/rom-factory.rb
126
126
  - lib/rom/factory.rb
@@ -146,7 +146,7 @@ licenses:
146
146
  - MIT
147
147
  metadata:
148
148
  allowed_push_host: https://rubygems.org
149
- post_install_message:
149
+ rubygems_mfa_required: 'true'
150
150
  rdoc_options: []
151
151
  require_paths:
152
152
  - lib
@@ -154,15 +154,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
154
154
  requirements:
155
155
  - - ">="
156
156
  - !ruby/object:Gem::Version
157
- version: 2.7.0
157
+ version: 3.1.0
158
158
  required_rubygems_version: !ruby/object:Gem::Requirement
159
159
  requirements:
160
160
  - - ">="
161
161
  - !ruby/object:Gem::Version
162
162
  version: '0'
163
163
  requirements: []
164
- rubygems_version: 3.5.5
165
- signing_key:
164
+ rubygems_version: 3.6.2
166
165
  specification_version: 4
167
166
  summary: ROM based builder library to make your specs awesome. DSL partially inspired
168
167
  by FactoryBot.
data/CODEOWNERS DELETED
@@ -1 +0,0 @@
1
- * @solnic