rom-factory 0.10.1 → 0.11.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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.action_hero.yml +21 -0
  3. data/.devtools/templates/changelog.erb +43 -0
  4. data/.devtools/templates/release.erb +36 -0
  5. data/.github/FUNDING.yml +1 -0
  6. data/.github/ISSUE_TEMPLATE/bug-report.md +26 -0
  7. data/.github/ISSUE_TEMPLATE/config.yml +5 -0
  8. data/.github/SUPPORT.md +3 -0
  9. data/.github/workflows/ci.yml +87 -0
  10. data/.github/workflows/docsite.yml +38 -9
  11. data/.github/workflows/rubocop.yml +46 -0
  12. data/.github/workflows/sync_configs.yml +41 -18
  13. data/.rspec +1 -1
  14. data/.rubocop.yml +198 -40
  15. data/CHANGELOG.md +88 -33
  16. data/CODEOWNERS +1 -0
  17. data/CODE_OF_CONDUCT.md +1 -1
  18. data/CONTRIBUTING.md +4 -4
  19. data/Gemfile +22 -22
  20. data/Gemfile.devtools +20 -0
  21. data/LICENSE +1 -1
  22. data/README.md +13 -48
  23. data/Rakefile +1 -1
  24. data/benchmarks/basic.rb +10 -10
  25. data/changelog.yml +99 -0
  26. data/docsite/source/index.html.md +162 -1
  27. data/lib/rom/factory/attribute_registry.rb +2 -2
  28. data/lib/rom/factory/attributes/association.rb +52 -12
  29. data/lib/rom/factory/attributes/callable.rb +1 -1
  30. data/lib/rom/factory/attributes/value.rb +1 -1
  31. data/lib/rom/factory/attributes.rb +4 -6
  32. data/lib/rom/factory/builder/persistable.rb +3 -5
  33. data/lib/rom/factory/builder.rb +8 -18
  34. data/lib/rom/factory/constants.rb +1 -1
  35. data/lib/rom/factory/dsl.rb +36 -23
  36. data/lib/rom/factory/factories.rb +13 -15
  37. data/lib/rom/factory/registry.rb +2 -2
  38. data/lib/rom/factory/sequences.rb +1 -1
  39. data/lib/rom/factory/tuple_evaluator.rb +18 -22
  40. data/lib/rom/factory/version.rb +1 -1
  41. data/lib/rom/factory.rb +8 -5
  42. data/lib/rom-factory.rb +1 -1
  43. data/project.yml +3 -0
  44. data/rom-factory.gemspec +8 -11
  45. metadata +43 -43
  46. data/.codeclimate.yml +0 -12
  47. data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +0 -10
  48. data/.github/ISSUE_TEMPLATE/----please-don-t-report-feature-requests-via-issues.md +0 -10
  49. data/.github/ISSUE_TEMPLATE/---a-detailed-bug-report.md +0 -30
  50. data/.github/ISSUE_TEMPLATE/---bug-report.md +0 -30
  51. data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
  52. data/.github/workflows/custom_ci.yml +0 -118
  53. data/Appraisals +0 -9
  54. data/LICENSE.txt +0 -21
  55. data/gemfiles/faker_1.gemfile +0 -34
  56. data/gemfiles/faker_1.gemfile.lock +0 -178
  57. data/gemfiles/faker_2.gemfile +0 -34
  58. data/gemfiles/faker_2.gemfile.lock +0 -178
data/README.md CHANGED
@@ -1,64 +1,29 @@
1
1
  [gem]: https://rubygems.org/gems/rom-factory
2
2
  [actions]: https://github.com/rom-rb/rom-factory/actions
3
- [codeclimate]: https://codeclimate.com/github/rom-rb/rom-factory
3
+ [codacy]: https://www.codacy.com/gh/rom-rb/rom-factory
4
+ [chat]: https://rom-rb.zulipchat.com
4
5
  [inchpages]: http://inch-ci.org/github/rom-rb/rom-factory
5
6
 
6
- # rom-factory
7
+ # rom-factory [![Join the chat at https://rom-rb.zulipchat.com](https://img.shields.io/badge/rom--rb-join%20chat-%23346b7a.svg)][chat]
7
8
 
8
9
  [![Gem Version](https://badge.fury.io/rb/rom-factory.svg)][gem]
9
10
  [![CI Status](https://github.com/rom-rb/rom-factory/workflows/ci/badge.svg)][actions]
10
- [![Code Climate](https://codeclimate.com/github/rom-rb/rom-factory/badges/gpa.svg)][codeclimate]
11
- [![Test Coverage](https://codeclimate.com/github/rom-rb/rom-factory/badges/coverage.svg)][codeclimate]
11
+ [![Codacy Badge](https://api.codacy.com/project/badge/Grade/5fd26fae687549218458879b1a607e18)][codacy]
12
+ [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/5fd26fae687549218458879b1a607e18)][codacy]
12
13
  [![Inline docs](http://inch-ci.org/github/rom-rb/rom-factory.svg?branch=master)][inchpages]
13
14
 
14
- Data generator with support for persistence backends, built on top of [rom-rb](http://rom-rb.org) and [dry-rb](http://dry-rb.org).
15
+ ## Links
15
16
 
16
- More information:
17
+ * [User documentation](https://rom-rb.org/learn/factory)
18
+ * [API documentation](https://rubydoc.info/gems/rom-factory)
17
19
 
18
- - [API docs](http://rubydoc.info/gems/rom-factory)
20
+ ## Supported Ruby versions
19
21
 
20
- ## Installation
22
+ This library officially supports the following Ruby versions:
21
23
 
22
- Add this line to your application's Gemfile:
23
-
24
- ```ruby
25
- gem 'rom-factory'
26
- ```
27
-
28
- And then execute:
29
-
30
- $ bundle
31
-
32
- Or install it yourself as:
33
-
34
- $ gem install rom-factory
35
-
36
- ### Performance
37
-
38
- Seems like this thing is a bit faster than other popular factory gems:
39
-
40
- ```
41
- Warming up --------------------------------------
42
- rom-factory 1.000 i/100ms
43
- factory_girl 1.000 i/100ms
44
- fabrication 1.000 i/100ms
45
- Calculating -------------------------------------
46
- rom-factory 1.550 (± 0.0%) i/s - 8.000 in 5.166227s
47
- factory_girl 0.982 (± 0.0%) i/s - 5.000 in 5.098193s
48
- fabrication 1.011 (± 0.0%) i/s - 6.000 in 5.942209s
49
-
50
- Comparison:
51
- rom-factory: 1.5 i/s
52
- fabrication: 1.0 i/s - 1.53x slower
53
- factory_girl: 1.0 i/s - 1.58x slower
54
- ```
55
-
56
- > See [benchmarks/basic.rb](https://github.com/rom-rb/rom-factory/blob/master/benchmarks/basic.rb)
57
-
58
- ## Credits
59
-
60
- This project was originally created by [Jānis Miezītis](https://github.com/janjiss) and eventually moved to `rom-rb` organization.
24
+ * MRI >= `2.5`
25
+ * jruby >= `9.2`
61
26
 
62
27
  ## License
63
28
 
64
- See `LICENSE.txt` file.
29
+ See `LICENSE` file.
data/Rakefile CHANGED
@@ -5,4 +5,4 @@ require "rspec/core/rake_task"
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
8
- task :default => :spec
8
+ task default: :spec
data/benchmarks/basic.rb CHANGED
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rom-factory'
4
- require 'rom-core'
5
- require 'active_record'
6
- require 'factory_bot'
7
- require 'fabrication'
8
- require 'benchmark/ips'
3
+ require "rom-factory"
4
+ require "rom-core"
5
+ require "active_record"
6
+ require "factory_bot"
7
+ require "fabrication"
8
+ require "benchmark/ips"
9
9
 
10
- DATABASE_URL = 'postgres://localhost/rom_factory_bench'.freeze
10
+ DATABASE_URL = "postgres://localhost/rom_factory_bench"
11
11
 
12
12
  rom = ROM.container(:sql, DATABASE_URL) do |conf|
13
13
  conf.default.connection.create_table?(:users) do
@@ -50,15 +50,15 @@ Fabricator(:user) do
50
50
  end
51
51
 
52
52
  Benchmark.ips do |x|
53
- x.report('rom-factory persisted struct') do
53
+ x.report("rom-factory persisted struct") do
54
54
  factory[:user]
55
55
  end
56
56
 
57
- x.report('factory_bot') do
57
+ x.report("factory_bot") do
58
58
  FactoryBot.create(:user)
59
59
  end
60
60
 
61
- x.report('fabrication') do
61
+ x.report("fabrication") do
62
62
  Fabricate(:user)
63
63
  end
64
64
 
data/changelog.yml ADDED
@@ -0,0 +1,99 @@
1
+ ---
2
+ - version: 0.11.0
3
+ date: 2022-11-11
4
+ added:
5
+ - Support for one-to-one associations (@ianks)
6
+ - "[internal] cache for Faker constants (@flash-gordon)"
7
+ changed:
8
+ - |
9
+ [BREAKING] attributes are always passed as keywords (@alassek)
10
+ This may affect your code in places where attributes are passed as hashes.
11
+ Places like
12
+ ```ruby
13
+ user_attributes = { name: 'Jane' }
14
+ Factory[:user, user_attributes]
15
+ ```
16
+ must be updated to
17
+ ```ruby
18
+ user_attributes = { name: 'Jane' }
19
+ Factory[:user, **user_attributes]
20
+ ```
21
+ - "Upgraded to the latest versions of dry-rb dependencies, compatible with rom 5.3 (@flash-gordon)"
22
+ - Support for Faker 1.x was dropped (@alassek)
23
+ fixed:
24
+ - Support for plural Faker generators (@wuarmin)
25
+ - version: 0.10.2
26
+ date: "2020-04-05"
27
+ fixed:
28
+ - Fix more keyword warnings (@flash-gordon)
29
+ - version: 0.10.1
30
+ date: '2019-12-28'
31
+ added:
32
+ - 'Support for faker 2 (@ianks)'
33
+ fixed:
34
+ - Keyword warnings reported by Ruby 2.7 (@flash-gordon)
35
+ - version: 0.10.0
36
+ date: '2019-12-11'
37
+ added:
38
+ - |-
39
+ `struct_namespace` option is supported by factory builders (@graceful-potato)
40
+
41
+ ``` ruby
42
+ factories.define(:user, struct_namespace: MyApp::Entities) do |f|
43
+ # ...
44
+ end
45
+ ```
46
+ fixed:
47
+ - Support building structs when child assoc does not define parent (@psparrow)
48
+ - 'Fixed `TupleEvaluator#struct_attrs` for non-standard output schema (@AMHOL)'
49
+ - version: 0.9.1
50
+ date: '2019-10-23'
51
+ fixed:
52
+ - Attributes of a struct are no longer accidentally passed to their associations (@psparrow)
53
+ - version: 0.9.0
54
+ date: '2019-08-12'
55
+ added:
56
+ - 'When attributes hash includes unknown attributes, a `ROM::Factory::UnknownAttributeError` will be raised (@rawburt)'
57
+ - version: 0.8.0
58
+ date: '2019-04-24'
59
+ fixed:
60
+ - 'Loaded association structs are no longer rejected by output schemas (issue #34) (flash-gordon + solnic)'
61
+ - version: 0.7.0
62
+ date: '2018-11-17'
63
+ added:
64
+ - Support for traits (v-kolesnikov)
65
+ - Support building structs with associations (@ianks)
66
+ fixed:
67
+ - Overwritten attributes with dependencies (JanaVPetrova)
68
+ - version: 0.6.0
69
+ date: '2018-01-31'
70
+ added:
71
+ - Support for factories with custom struct namespaces (solnic)
72
+ changed:
73
+ - 'Accessing a factory which is not defined will result in `FactoryNotDefinedError` exception (GustavoCaso + solnic)'
74
+ fixed:
75
+ - 'Using dependent attributes with sequences works correctly, ie `f.sequence(:login) { |i, name| "name-#{i}"}` (solnic)'
76
+ - version: 0.5.0
77
+ date: '2017-10-24'
78
+ added:
79
+ - Updated to rom 4.0 (solnic)
80
+ - 'Support for `has_many` and `has_one` associations (solnic)'
81
+ - Support for attributes depending on values from other attributes (solnic)
82
+ - 'Support for `rand` inside the generator block (flash-gordon)'
83
+ changed:
84
+ - 'Depends on `rom-core` now (solnic)'
85
+ - version: 0.4.0
86
+ date: '2017-03-03'
87
+ summary: improves internals.
88
+ added:
89
+ - 'Support for defining multiple factories via `MyFactory = ROM::Factory.configure { |c| ... }` (solnic)'
90
+ - 'Support for builder inheritence via `define(admin: :user) { |f| ... }` (solnic)'
91
+ - 'Support for generating in-memory structs via `MyFactory.structs[:user]` that are not persisted (solnic)'
92
+ - 'Support for `belongs_to` associations via `f.association(:user)` (solnic)'
93
+ - 'New DSL for defining builders `MyFactory.define(:user) { |f| ... }` which infers default relation name (solnic)'
94
+ - 'New factory method `MyFactory#[]` ie `MyFactory[:user, name: "Jane"]` (solnic)'
95
+ - 'New `fake` helper which uses faker gem under the hood ie `f.email { fake(:internet, :email) }` (solnic)'
96
+ changed:
97
+ - "`Rom::Factory::Config.configure` was replaced with `ROM::Factory.configure` (solnic)"
98
+ - Global factory config and builders are gone (solnic)
99
+ - Structs are now based on dry-struct (solnic)
@@ -5,4 +5,165 @@ chapter: Factory
5
5
 
6
6
  # rom-factory
7
7
 
8
- TODO: write docs :)
8
+ `rom-factory` provides a simple API for creating and persisting `ROM::Struct`'s. If you already know FactoryBot you'll definitely understand the concept.
9
+
10
+ ## Installation
11
+
12
+ First of all you need to define a ROM Container for Factory. For example if you are using `rspec`, you can add these lines to `spec_helper.rb`. Also you need to require here all files with Factories.
13
+
14
+ ```ruby
15
+ Factory = ROM::Factory.configure do |config|
16
+ config.rom = my_rom_container
17
+ end
18
+
19
+ Dir[File.dirname(__FILE__) + '/support/factories/*.rb'].each { |file| require file }
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ### Define factory
25
+
26
+ ```ruby
27
+ # 'spec/support/factories/users.rb'
28
+
29
+ Factory.define(:user) do |f|
30
+ f.name 'John'
31
+ f.age 42
32
+ end
33
+ ```
34
+ #### Specify relations
35
+
36
+ You can specify ROM relation if you want. It'll be pluralized factory name by default.
37
+
38
+ ```ruby
39
+ Factory.define(:user, relation: :people) do |f|
40
+ f.name 'John'
41
+ f.age 42
42
+ end
43
+ ```
44
+
45
+ #### Specify namespace for your structs
46
+
47
+ Struct `User` will be find in MyApp::Entities namespace
48
+
49
+ ```ruby
50
+ Factory.define(:user, struct_namespace: MyApp::Entities) do |f|
51
+ # ...
52
+ end
53
+ ```
54
+
55
+ #### Sequences
56
+
57
+ You can use sequences for uniq fields
58
+
59
+ ```ruby
60
+ Factory.define(:user) do |f|
61
+ f.name 'John'
62
+ f.sequence(:email) { |n| "john#{n}@example.com" }
63
+ end
64
+ ```
65
+
66
+ #### Timestamps
67
+
68
+ ```ruby
69
+ Factory.define(:user) do |f|
70
+ f.name 'John'
71
+ f.timestamps
72
+ # same as
73
+ # f.created_at { Time.now }
74
+ # f.updated_at { Time.now }
75
+ end
76
+ ```
77
+
78
+ #### Associations
79
+
80
+ * belongs_to
81
+
82
+ ```ruby
83
+ Factory.define(:group) do |f|
84
+ f.name 'Admins'
85
+ end
86
+
87
+ Factory.define(:user) do |f|
88
+ f.name 'John'
89
+ f.association(:user)
90
+ end
91
+ ```
92
+
93
+ * has_many
94
+
95
+ ```ruby
96
+ Factory.define(:group) do |f|
97
+ f.name 'Admins'
98
+ f.association(:user, count: 2)
99
+ end
100
+
101
+ Factory.define(:user) do |f|
102
+ f.name 'John'
103
+ end
104
+ ```
105
+
106
+ #### Extend already existing factory
107
+
108
+ ```ruby
109
+ Factory.define(:user) do |f|
110
+ f.name 'John'
111
+ f.admin false
112
+ end
113
+
114
+ Factory.define(admin: :user) do |f|
115
+ f.admin true
116
+ end
117
+
118
+ # Factory.structs(:admin)
119
+ ```
120
+
121
+ #### Traits
122
+
123
+ ```ruby
124
+ Factory.define(:user) do |f|
125
+ f.name 'John'
126
+ f.admin false
127
+
128
+ f.trait :with_age do |t|
129
+ t.age 42
130
+ end
131
+ end
132
+
133
+ # Factory.structs(:user, :with_age)
134
+ ```
135
+
136
+ #### Build-in [Faker](https://github.com/faker-ruby/faker) objects
137
+
138
+ ```ruby
139
+ Factory.define(:user) do |f|
140
+ f.email { fake(:internet, :email) }
141
+ end
142
+ ```
143
+
144
+ #### Dependent attributes
145
+
146
+ Attributes can be based on the values of other attributes:
147
+
148
+ ```ruby
149
+ Factory.define(:user) do |f|
150
+ f.full_name { fake(:name) }
151
+ # Dependent attributes are inferred from the block parameter names:
152
+ f.login { |full_name| full_name.downcase.gsub(/\s+/, '_') }
153
+ # Works with sequences too:
154
+ f.sequence(:email) { |n, login| "#{login}-#{n}@example.com" }
155
+ end
156
+ ```
157
+
158
+ ### Build and persist objects
159
+
160
+ ```ruby
161
+ # Create in-memory object
162
+ Factory.structs[:user]
163
+
164
+ # Persist struct in database
165
+ Factory[:user]
166
+
167
+ # Override attributes
168
+ Factory[:user, age: 24]
169
+ ```
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'tsort'
3
+ require "tsort"
4
4
 
5
5
  module ROM
6
6
  module Factory
@@ -47,7 +47,7 @@ module ROM
47
47
 
48
48
  # @api private
49
49
  def associations
50
- self.class.new(elements.select { |e| e.kind_of?(Attributes::Association::Core) })
50
+ self.class.new(elements.select { |e| e.is_a?(Attributes::Association::Core) })
51
51
  end
52
52
 
53
53
  private
@@ -5,10 +5,9 @@ module ROM::Factory
5
5
  # @api private
6
6
  module Association
7
7
  class << self
8
- def new(assoc, builder, *args)
9
- const_get(assoc.definition.type).new(assoc, builder, *args)
8
+ def new(assoc, builder, *traits, **options)
9
+ const_get(assoc.definition.type).new(assoc, builder, *traits, **options)
10
10
  end
11
- ruby2_keywords(:new) if respond_to?(:ruby2_keywords, true)
12
11
  end
13
12
 
14
13
  # @api private
@@ -23,6 +22,11 @@ module ROM::Factory
23
22
  @options = options
24
23
  end
25
24
 
25
+ # @api private
26
+ def through?
27
+ false
28
+ end
29
+
26
30
  # @api private
27
31
  def builder
28
32
  @__builder__ ||= @builder_proc.call
@@ -56,7 +60,7 @@ module ROM::Factory
56
60
  else
57
61
  builder.struct(*traits)
58
62
  end
59
- tuple = { name => struct }
63
+ tuple = {name => struct}
60
64
  assoc.associate(tuple, struct)
61
65
  end
62
66
  end
@@ -78,13 +82,13 @@ module ROM::Factory
78
82
  association_hash = assoc.associate(attrs, parent)
79
83
 
80
84
  if persist
81
- builder.persistable.create(*traits, association_hash)
85
+ builder.persistable.create(*traits, **association_hash)
82
86
  else
83
- builder.struct(*traits, attrs.merge(association_hash))
87
+ builder.struct(*traits, **attrs, **association_hash)
84
88
  end
85
89
  end
86
90
 
87
- { name => structs }
91
+ {name => structs}
88
92
  end
89
93
 
90
94
  # @api private
@@ -103,22 +107,22 @@ module ROM::Factory
103
107
  # @api private
104
108
  def call(attrs = EMPTY_HASH, parent, persist: true)
105
109
  # do not associate if count is 0
106
- return { name => nil } if count.zero?
110
+ return {name => nil} if count.zero?
107
111
 
108
112
  return if attrs.key?(name)
109
113
 
110
114
  association_hash = assoc.associate(attrs, parent)
111
115
 
112
116
  struct = if persist
113
- builder.persistable.create(*traits, association_hash)
117
+ builder.persistable.create(*traits, **association_hash)
114
118
  else
115
119
  belongs_to_name = Dry::Core::Inflector.singularize(assoc.source_alias)
116
- belongs_to_associations = { belongs_to_name.to_sym => parent }
120
+ belongs_to_associations = {belongs_to_name.to_sym => parent}
117
121
  final_attrs = attrs.merge(association_hash).merge(belongs_to_associations)
118
- builder.struct(*traits, final_attrs)
122
+ builder.struct(*traits, **final_attrs)
119
123
  end
120
124
 
121
- { name => struct }
125
+ {name => struct}
122
126
  end
123
127
 
124
128
  # @api private
@@ -126,6 +130,42 @@ module ROM::Factory
126
130
  options.fetch(:count, 1)
127
131
  end
128
132
  end
133
+
134
+ class OneToOneThrough < Core
135
+ def call(attrs = EMPTY_HASH, parent, persist: true)
136
+ return if attrs.key?(name)
137
+
138
+ struct = if persist && attrs[tpk]
139
+ attrs
140
+ elsif persist
141
+ builder.persistable.create(*traits, **attrs)
142
+ else
143
+ builder.struct(*traits, **attrs)
144
+ end
145
+
146
+ assoc.persist([parent], struct) if persist
147
+
148
+ {name => struct}
149
+ end
150
+
151
+ def dependency?(rel)
152
+ assoc.source == rel
153
+ end
154
+
155
+ def through?
156
+ true
157
+ end
158
+
159
+ private
160
+
161
+ def count
162
+ options.fetch(:count, 1)
163
+ end
164
+
165
+ def tpk
166
+ assoc.target.primary_key
167
+ end
168
+ end
129
169
  end
130
170
  end
131
171
  end
@@ -16,7 +16,7 @@ module ROM::Factory
16
16
  # @api private
17
17
  def call(attrs, *args)
18
18
  result = attrs[name] || dsl.instance_exec(*args, &block)
19
- { name => result }
19
+ {name => result}
20
20
  end
21
21
 
22
22
  # @api private
@@ -16,7 +16,7 @@ module ROM::Factory
16
16
  def call(attrs = EMPTY_HASH)
17
17
  return if attrs.key?(name)
18
18
 
19
- { name => value }
19
+ {name => value}
20
20
  end
21
21
 
22
22
  # @api private
@@ -1,14 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/core/constants'
4
-
5
3
  module ROM
6
4
  module Factory
7
5
  include Dry::Core::Constants
8
6
  end
9
7
  end
10
8
 
11
- require 'rom/factory/attributes/value'
12
- require 'rom/factory/attributes/callable'
13
- require 'rom/factory/attributes/sequence'
14
- require 'rom/factory/attributes/association'
9
+ require "rom/factory/attributes/value"
10
+ require "rom/factory/attributes/callable"
11
+ require "rom/factory/attributes/sequence"
12
+ require "rom/factory/attributes/association"
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'delegate'
3
+ require "delegate"
4
4
 
5
5
  module ROM
6
6
  module Factory
@@ -21,10 +21,8 @@ module ROM
21
21
  end
22
22
 
23
23
  # @api private
24
- def create(*args)
25
- traits, attrs = builder.extract_tuple(args)
26
-
27
- tuple = tuple(*traits, attrs)
24
+ def create(*traits, **attrs)
25
+ tuple = tuple(*traits, **attrs)
28
26
  validate_keys(traits, attrs)
29
27
  persisted = persist(tuple)
30
28
 
@@ -1,11 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/core/constants'
4
-
5
- require 'rom/struct'
6
- require 'rom/initializer'
7
- require 'rom/factory/tuple_evaluator'
8
- require 'rom/factory/builder/persistable'
3
+ require "rom/struct"
4
+ require "rom/initializer"
5
+ require "rom/factory/tuple_evaluator"
6
+ require "rom/factory/builder/persistable"
9
7
 
10
8
  module ROM::Factory
11
9
  # @api private
@@ -31,18 +29,15 @@ module ROM::Factory
31
29
  option :struct_namespace, reader: false
32
30
 
33
31
  # @api private
34
- def tuple(*args)
35
- traits, attrs = extract_tuple(args)
36
-
32
+ def tuple(*traits, **attrs)
37
33
  tuple_evaluator.defaults(traits, attrs)
38
34
  end
39
35
 
40
36
  # @api private
41
- def struct(*args)
42
- traits, attrs = extract_tuple(args)
37
+ def struct(*traits, **attrs)
43
38
  validate_keys(traits, attrs, allow_associations: true)
44
39
 
45
- tuple_evaluator.struct(*args)
40
+ tuple_evaluator.struct(*traits, **attrs)
46
41
  end
47
42
  alias_method :create, :struct
48
43
 
@@ -75,18 +70,13 @@ module ROM::Factory
75
70
  tuple_evaluator.relation
76
71
  end
77
72
 
78
- # @api private
79
- def extract_tuple(args)
80
- tuple_evaluator.extract_tuple(args)
81
- end
82
-
83
73
  # @api private
84
74
  def validate_keys(traits, tuple, allow_associations: false)
85
75
  schema_keys = relation.schema.attributes.map(&:name)
86
76
  assoc_keys = tuple_evaluator.assoc_names(traits)
87
77
  unknown_keys = tuple.keys - schema_keys - assoc_keys
88
78
 
89
- unknown_keys = unknown_keys - relation.schema.associations.to_h.keys if allow_associations
79
+ unknown_keys -= relation.schema.associations.to_h.keys if allow_associations
90
80
 
91
81
  raise UnknownFactoryAttributes, unknown_keys unless unknown_keys.empty?
92
82
  end
@@ -10,7 +10,7 @@ module ROM
10
10
 
11
11
  class UnknownFactoryAttributes < StandardError
12
12
  def initialize(attrs)
13
- super("Unknown attributes: #{attrs.join(', ')}")
13
+ super("Unknown attributes: #{attrs.join(", ")}")
14
14
  end
15
15
  end
16
16
  end