mongoid-fixture_kit 0.3.1 → 0.4.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: 6174b5eb254b73dda38a9e2edb58610a7c826e0572178e94059050d850668313
4
- data.tar.gz: e227334e2cb880f870f97679e567ebe0bf5a2cd2b37ec4430057e5c8831a1555
3
+ metadata.gz: fd5ebdcfcdbb7c1e5688c3192bde7bba3d343aaf500a78dd46bf8edaae69ce4e
4
+ data.tar.gz: 9030d69cf2f9f4b37cdaa53b657e726dd6dd98c8b05c04725077484a3772b7ef
5
5
  SHA512:
6
- metadata.gz: 6a6e57a38aed49d3a15f51775c59ceb8d68d8d67fcc6ba0dadb2c52a8c43e3acb4ae8cc22358722400d07cc9779a23e8f626c07665428da13c955c9d13b03e8a
7
- data.tar.gz: ff02e462158039045a563eb2e4a578176c900d45d56aca15d324ab4453b67af2bcdedc0d9dc2f7c0785c48c024a81309278f1d3b1abd4be644f3747ffea81248
6
+ metadata.gz: 1ccf73e370a9db3da023420e1b19434f9674ab70d00051c3a5ffb43d6d0567cfa55c3ae116a61bc2e5cef8175b93fdc99a16b749358b032d1c50af36a7626bee
7
+ data.tar.gz: 13210177d5be94c71337ef9af9d6200c874db77fb42219bd91a23e8c1e4cad6b37e5838c76980ecf669c6813420a60809df849f9471d60574574076d19da4ff4
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023 Dániel Sipos
3
+ Copyright (c) 2023-2026 Dániel Sipos
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md ADDED
@@ -0,0 +1,175 @@
1
+ # mongoid-fixture_kit
2
+
3
+ [![Version](https://img.shields.io/gem/v/mongoid-fixture_kit.svg?style=square)](https://rubygems.org/gems/mongoid-fixture_kit)
4
+ [![Download](https://img.shields.io/gem/dt/mongoid-fixture_kit.svg?style=square)](https://rubygems.org/gems/mongoid-fixture_kit)
5
+ [![License](https://img.shields.io/github/license/siposdani87/mongoid-fixture-kit.svg?style=square)](./LICENSE)
6
+
7
+ <a href="https://www.buymeacoffee.com/siposdani87" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-green.png" alt="Buy Me A Coffee" width="150" height="39" /></a>
8
+
9
+ This package is a Ruby gem that provides a way to load sample data into a MongoDB database for testing purposes. It provides a simple and convenient way to manage test data by defining fixtures in YAML files, which can be loaded into the database before running tests.
10
+
11
+ This library aims to provide fixtures for Mongoid the same way you have them with ActiveRecord.
12
+
13
+ ## Getting Started
14
+
15
+ ### Installing
16
+
17
+ ```ruby
18
+ gem 'mongoid-fixture_kit'
19
+ ```
20
+
21
+ ### Usage
22
+
23
+ In your tests, add:
24
+
25
+ ```ruby
26
+ class ActiveSupport::TestCase
27
+ include Mongoid::FixtureKit::TestHelper
28
+ self.fixture_path = "#{Rails.root}/test/fixtures"
29
+ end
30
+ ```
31
+
32
+ This is also done by `ActiveRecord`, but magically in the railties.
33
+
34
+ Then when you want to access a fixture:
35
+
36
+ ```ruby
37
+ class UsersControllerTest < ActionController::TestCase
38
+ setup do
39
+ @user = users(:user_1)
40
+ end
41
+
42
+ test 'should show user' do
43
+ get :show, params: { id: @user }
44
+ assert_response :success
45
+ end
46
+ end
47
+ ```
48
+
49
+ ### Features
50
+
51
+ - Creation of a document from a YAML file
52
+ - ERB inside YAML files
53
+ - `$LABEL` interpolation in fixture values
54
+ - `belongs_to` relations
55
+ - Polymorphic `belongs_to`
56
+ - `has_many` relations
57
+ - `has_and_belongs_to_many` relations
58
+ - Embedded documents (`embeds_one`, `embeds_many`)
59
+ - `DEFAULTS` key for shared fixture attributes
60
+ - `TestHelper` module to include in your tests
61
+
62
+ ### ERB in Fixtures
63
+
64
+ You can use ERB in your YAML fixture files to generate dynamic data:
65
+
66
+ ```yaml
67
+ <% 5.times do |i| %>
68
+ school<%= i %>:
69
+ name: School <%= i %>
70
+ <% end %>
71
+ ```
72
+
73
+ ### Label Interpolation
74
+
75
+ Use `$LABEL` in fixture values to reference the fixture's own name:
76
+
77
+ ```yaml
78
+ user_john:
79
+ username: $LABEL
80
+ email: $LABEL@example.com
81
+ ```
82
+
83
+ This will set `username` to `"user_john"` and `email` to `"user_john@example.com"`.
84
+
85
+ ### Defaults
86
+
87
+ Use the `DEFAULTS` key to define shared attributes for all fixtures in a file:
88
+
89
+ ```yaml
90
+ DEFAULTS:
91
+ role: member
92
+
93
+ admin:
94
+ name: Admin
95
+ role: admin
96
+
97
+ regular_user:
98
+ name: Regular User
99
+ ```
100
+
101
+ The `DEFAULTS` entry is removed during loading and is not inserted as a document.
102
+
103
+ ### Compatibility
104
+
105
+ | Dependency | Supported versions |
106
+ |---|---|
107
+ | Ruby | 3.1, 3.2, 3.3, 3.4 |
108
+ | Mongoid | 7.x, 8.x, 9.x |
109
+ | Rails (ActiveSupport) | 7.0+ |
110
+
111
+ ### Notes
112
+
113
+ Documents are stored with a special attribute `__fixture_name` which is used to retrieve it and establish relations.
114
+
115
+ `Mongoid::Document` has a `attr_accessor` defined for `__fixture_name`, so it doesn't pose any problem if you try to `dup` a document for example.
116
+
117
+ ### Changes compared to ActiveRecord
118
+
119
+ - There is an option to load fixtures only once.
120
+ - Fixture accessor methods are defined publicly.
121
+
122
+ These changes are here to let you create another class holding persistent data inside your tests.
123
+
124
+ ```ruby
125
+ class TestData
126
+ include Mongoid::FixtureKit::TestHelper
127
+
128
+ self.fixture_path = "#{Rails.root}/test/fixtures_universes"
129
+ self.load_fixtures_once = true
130
+
131
+ def TestData.instance
132
+ @instance ||= ->(){
133
+ instance = new
134
+ instance.setup_fixtures
135
+ instance
136
+ }.call
137
+ end
138
+
139
+ private_class_method :new
140
+ end
141
+
142
+ class ActiveSupport::TestCase
143
+ include Mongoid::FixtureKit::TestHelper
144
+ self.fixture_path = "#{Rails.root}/test/fixtures"
145
+
146
+ def data
147
+ TestData.instance
148
+ end
149
+ end
150
+
151
+ # somewhere else
152
+ test 'should validate complex data structure' do
153
+ assert_nothing_raised do
154
+ DataStructure.process(data.structures(:complex))
155
+ end
156
+ end
157
+ ```
158
+
159
+ ## License
160
+
161
+ The original version of this library is [mongoid-fixture_set](https://github.com/Aethelflaed/mongoid-fixture_set) by Geoffroy Planquart in 2014
162
+
163
+ ## Bugs or Requests
164
+
165
+ If you encounter any problems feel free to open an [issue](https://github.com/siposdani87/mongoid-fixture-kit/issues/new?template=bug_report.md). If you feel the library is missing a feature, please raise a [ticket](https://github.com/siposdani87/mongoid-fixture-kit/issues/new?template=feature_request.md). Pull request are also welcome.
166
+
167
+ [![DigitalOcean Referral Badge](https://web-platforms.sfo2.cdn.digitaloceanspaces.com/WWW/Badge%201.svg)](https://www.digitalocean.com/?refcode=b992bb656478&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge)
168
+
169
+ ## Developer
170
+
171
+ [Dániel Sipos](https://siposdani87.com)
172
+
173
+ ## Sponsors
174
+
175
+ This project is generously supported by [TrophyMap](https://trophymap.org), [I18Nature](https://i18nature.com), and several other amazing organizations.
@@ -5,7 +5,7 @@ module Mongoid
5
5
  class File
6
6
  include Enumerable
7
7
 
8
- def self.open(file)
8
+ def self.parse(file)
9
9
  x = new(file)
10
10
  block_given? ? yield(x) : x
11
11
  end
@@ -1,8 +1,6 @@
1
1
  module Mongoid
2
2
  class FixtureKit
3
3
  class Fixture
4
- include Enumerable
5
-
6
4
  attr_reader :name, :fixture, :model_class
7
5
 
8
6
  def initialize(name, fixture, model_class)
@@ -53,7 +53,7 @@ module Mongoid
53
53
 
54
54
  define_method(accessor_name) do |*fixture_names|
55
55
  force_reload = false
56
- force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
56
+ force_reload = fixture_names.pop if [true, :reload].include?(fixture_names.last)
57
57
  @fixture_cache[fs_name] ||= {}
58
58
  instances =
59
59
  fixture_names.map do |f_name|
@@ -44,8 +44,7 @@ module Mongoid
44
44
  fixtures_map = {}
45
45
  fixture_kits =
46
46
  files_to_read.map do |fs_name|
47
- fixtures_map[fs_name] =
48
- Mongoid::FixtureKit.new(fs_name, class_names[fs_name], ::File.join(fixtures_directory, fs_name))
47
+ fixtures_map[fs_name] = Mongoid::FixtureKit.new(fs_name, class_names[fs_name], ::File.join(fixtures_directory, fs_name))
49
48
  end
50
49
 
51
50
  update_all_loaded_fixtures(fixtures_map)
@@ -75,6 +74,14 @@ module Mongoid
75
74
  def update_document(document, attributes)
76
75
  attributes.delete('_id') if document.attributes.key?('_id')
77
76
 
77
+ # Extract embedded document attributes before processing.
78
+ # In Mongoid 8+, document["field"] = hash (bracket notation) stores the raw hash
79
+ # but does NOT build the embedded model object, so document.field returns nil.
80
+ # We handle embedded docs separately: bracket notation + save + reload.
81
+ embedded_attrs = extract_embedded_attributes(document, attributes)
82
+ # Temporarily skip extraction for debugging
83
+ # embedded_attrs = {}
84
+
78
85
  keys = (attributes.keys + document.attributes.keys).uniq
79
86
  keys.each do |key|
80
87
  value = attributes[key] || document[key]
@@ -88,7 +95,14 @@ module Mongoid
88
95
  end
89
96
 
90
97
  sanitize_new_embedded_documents(document)
98
+
99
+ # Save non-embedded attributes first, so embedded attr fallbacks
100
+ # (which may need to reload) don't lose the non-embedded data.
101
+ save_document(document) if embedded_attrs.any?
102
+
103
+ apply_embedded_attributes(document, embedded_attrs)
91
104
  save_document(document)
105
+
92
106
  document
93
107
  end
94
108
 
@@ -107,25 +121,18 @@ module Mongoid
107
121
  (is_new && document[name])
108
122
 
109
123
  embedded_documents = document.public_send(relation.name)
110
- embedded_documents.each_with_index do |embedded_document, i|
111
- embedded_document_set_default_values(embedded_document, document[name][i])
124
+ embedded_documents.each_with_index do |embed_doc, i|
125
+ embedded_document_set_default_values(embed_doc, document[name][i])
112
126
  end
113
127
  end
114
128
  when :belongs_to
115
129
  if is_new && document.attributes[name]
116
130
  value = document.attributes.delete(name)
117
- if value.is_a?(Hash)
118
- raise(
119
- Mongoid::FixtureKit::FixtureError,
120
- 'Unable to create nested document inside an embedded document'
121
- )
122
- end
131
+ raise(Mongoid::FixtureKit::FixtureError, 'Unable to create nested document inside an embedded document') if value.is_a?(Hash)
123
132
 
124
133
  doc = find_or_create_document(relation.class_name, value)
125
134
  document.attributes[relation.foreign_key] = doc.id
126
135
  end
127
- else
128
- # type code here
129
136
  end
130
137
  end
131
138
  end
@@ -137,7 +144,7 @@ module Mongoid
137
144
  document.fields.select do |k, v|
138
145
  k != '_id' && v.default_val.present? && attributes[k] == document[k]
139
146
  end
140
- removable_fields.each do |k, _v|
147
+ removable_fields.each_key do |k|
141
148
  attributes.delete(k)
142
149
  end
143
150
  end
@@ -149,13 +156,7 @@ module Mongoid
149
156
  if document.nil?
150
157
  document = model.new
151
158
  document['__fixture_name'] = fixture_name
152
- begin
153
- save_document(document)
154
- rescue StandardError => e
155
- Rails.logger.debug(document.attributes)
156
- Rails.logger.debug(e)
157
- Rails.logger.debug { "Backtrace:\n\t#{e.backtrace.join("\n\t")}" }
158
- end
159
+ save_document(document)
159
160
  end
160
161
  document
161
162
  end
@@ -167,22 +168,87 @@ module Mongoid
167
168
  end
168
169
 
169
170
  def collection_documents(fixture_kit)
170
- # allow a standard key to be used for doing defaults in YAML
171
- fixture_kit.fixtures.delete('DEFAULTS')
172
-
173
171
  # track any join collection we need to insert later
174
172
  documents = {}
173
+ # allow a standard key to be used for doing defaults in YAML
174
+ fixtures = fixture_kit.fixtures.except('DEFAULTS')
175
175
  documents[fixture_kit.class_name] =
176
- fixture_kit.fixtures.map do |label, fixture|
176
+ fixtures.map do |label, fixture|
177
177
  unmarshall_fixture(label, fixture, fixture_kit.model_class)
178
178
  end
179
179
  documents
180
180
  end
181
181
 
182
+ def extract_embedded_attributes(document, attributes)
183
+ embedded_attrs = {}
184
+ document.relations.each do |name, relation|
185
+ macro = macro_from_relation(relation)
186
+ next unless %i[embeds_one embeds_many].include?(macro)
187
+ next unless attributes.key?(name)
188
+ next unless attributes[name].is_a?(Hash) || attributes[name].is_a?(Array)
189
+
190
+ embedded_attrs[name] = attributes.delete(name).dup
191
+ end
192
+ embedded_attrs
193
+ end
194
+
195
+ def apply_embedded_attributes(document, embedded_attrs)
196
+ embedded_attrs.each do |name, attrs|
197
+ relation = document.relations[name]
198
+ next unless relation
199
+
200
+ # Resolve belongs_to fixture references within embedded attrs
201
+ # before storing, because Mongoid won't resolve them.
202
+ embedded_class = relation.class_name.constantize
203
+ macro = macro_from_relation(relation)
204
+
205
+ case macro
206
+ when :embeds_one
207
+ resolve_embedded_belongs_to(embedded_class, attrs) if attrs.is_a?(Hash)
208
+ when :embeds_many
209
+ Array(attrs).each { |item| resolve_embedded_belongs_to(embedded_class, item) if item.is_a?(Hash) }
210
+ end
211
+
212
+ # Use bracket notation to store raw hash data. In Mongoid 8+,
213
+ # bracket notation doesn't build embedded model objects, but the
214
+ # data persists correctly. After save + reload, Mongoid hydrates
215
+ # the embedded documents from the stored hash.
216
+ document[name] = attrs
217
+ end
218
+
219
+ # Save and reload to hydrate embedded documents from stored hash data.
220
+ return if embedded_attrs.none?
221
+
222
+ save_document(document)
223
+ document.reload
224
+ end
225
+
226
+ def resolve_embedded_belongs_to(embedded_class, attrs)
227
+ embedded_class.relations.each do |rel_name, rel|
228
+ macro = macro_from_relation(rel)
229
+
230
+ case macro
231
+ when :belongs_to
232
+ next unless attrs.key?(rel_name) && attrs[rel_name].is_a?(String)
233
+
234
+ doc = find_or_create_document(rel.class_name, attrs.delete(rel_name))
235
+ attrs[rel.foreign_key] = doc.id
236
+ when :embeds_one
237
+ next unless attrs.key?(rel_name) && attrs[rel_name].is_a?(Hash)
238
+
239
+ resolve_embedded_belongs_to(rel.class_name.constantize, attrs[rel_name])
240
+ when :embeds_many
241
+ next unless attrs.key?(rel_name) && attrs[rel_name].is_a?(Array)
242
+
243
+ attrs[rel_name].each { |item| resolve_embedded_belongs_to(rel.class_name.constantize, item) if item.is_a?(Hash) }
244
+ end
245
+ end
246
+ end
247
+
182
248
  private
183
249
 
184
250
  def save_document(doc)
185
- doc.save({ validate: false })
251
+ doc.save(validate: false)
186
252
  end
187
253
 
188
254
  def unmarshall_fixture(label, attributes, model_class)
@@ -220,8 +286,6 @@ module Mongoid
220
286
  unmarshall_has_many(model_class, attributes, relation)
221
287
  when :has_and_belongs_to_many
222
288
  unmarshall_has_and_belongs_to_many(model_class, attributes, relation)
223
- else
224
- # type code here
225
289
  end
226
290
  end
227
291
 
@@ -233,12 +297,7 @@ module Mongoid
233
297
  return if value.nil?
234
298
 
235
299
  if value.is_a?(Hash)
236
- if relation.polymorphic?
237
- raise(
238
- Mongoid::FixtureKit::FixtureError,
239
- 'Unable to create document from nested attributes in a polymorphic relation'
240
- )
241
- end
300
+ raise(Mongoid::FixtureKit::FixtureError, 'Unable to create document from nested attributes in a polymorphic relation') if relation.polymorphic?
242
301
 
243
302
  document = relation.class_name.constantize.new
244
303
  value = unmarshall_fixture(nil, value, relation.class_name)
@@ -247,7 +306,8 @@ module Mongoid
247
306
  return
248
307
  end
249
308
 
250
- if relation.polymorphic? && value.sub!(/\s*\(([^)]*)\)\s*/, '')
309
+ if relation.polymorphic? && value.match?(/\s*\([^)]*\)\s*/)
310
+ value = value.sub(/\s*\(([^)]*)\)\s*/, '')
251
311
  type = Regexp.last_match(1)
252
312
  attributes[relation.inverse_type] = type
253
313
  attributes[relation.foreign_key] = find_or_create_document(type, value).id
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
2
  class FixtureKit
3
- VERSION = '0.3.1'.freeze
3
+ VERSION = '0.4.0'.freeze
4
4
  end
5
5
  end
@@ -14,6 +14,10 @@ module Mongoid
14
14
  @context_class ||= Class.new
15
15
  end
16
16
 
17
+ def self.reset_context_class!
18
+ @context_class = nil
19
+ end
20
+
17
21
  def initialize(name, class_name, path)
18
22
  @name = name
19
23
  @path = path
@@ -46,7 +50,9 @@ module Mongoid
46
50
  yaml_files = files.push("#{path}.yml")
47
51
 
48
52
  yaml_files.each_with_object({}) do |file, fixtures|
49
- Mongoid::FixtureKit::File.open(file) do |f|
53
+ next unless ::File.exist?(file)
54
+
55
+ Mongoid::FixtureKit::File.parse(file) do |f|
50
56
  f.each do |fixture_name, row|
51
57
  fixtures[fixture_name] = Mongoid::FixtureKit::Fixture.new(fixture_name, row, model_class)
52
58
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-fixture_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dániel Sipos
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2026-01-06 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activesupport
@@ -46,6 +45,7 @@ extensions: []
46
45
  extra_rdoc_files: []
47
46
  files:
48
47
  - LICENSE
48
+ - README.md
49
49
  - Rakefile
50
50
  - lib/mongoid/fixture_kit.rb
51
51
  - lib/mongoid/fixture_kit/class_cache.rb
@@ -65,7 +65,10 @@ licenses:
65
65
  - MIT
66
66
  metadata:
67
67
  rubygems_mfa_required: 'true'
68
- post_install_message:
68
+ homepage_uri: https://github.com/siposdani87/mongoid-fixture-kit
69
+ source_code_uri: https://github.com/siposdani87/mongoid-fixture-kit
70
+ bug_tracker_uri: https://github.com/siposdani87/mongoid-fixture-kit/issues
71
+ changelog_uri: https://github.com/siposdani87/mongoid-fixture-kit/releases
69
72
  rdoc_options: []
70
73
  require_paths:
71
74
  - lib
@@ -73,15 +76,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
73
76
  requirements:
74
77
  - - ">="
75
78
  - !ruby/object:Gem::Version
76
- version: 3.1.0
79
+ version: 3.2.0
77
80
  required_rubygems_version: !ruby/object:Gem::Requirement
78
81
  requirements:
79
82
  - - ">="
80
83
  - !ruby/object:Gem::Version
81
84
  version: '0'
82
85
  requirements: []
83
- rubygems_version: 3.5.22
84
- signing_key:
86
+ rubygems_version: 3.6.9
85
87
  specification_version: 4
86
88
  summary: Fixtures for Rails Mongoid
87
89
  test_files: []