activerecord-bitemporal 5.2.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 690af251479740f03e0dafd504a9b906672e8860c6f8734b37b24f0d2c0c2b5d
4
- data.tar.gz: 2b41e3d362d267e4b573911ec75a1b03de9c4259bf8312c6fae9759aae29bf34
3
+ metadata.gz: b36848b2facc997f9179abd32f96d7fde53cd9464f9009fa25a1ca5f13f57890
4
+ data.tar.gz: 8498da159a6e051841ce253b7051f0722b0cb33d2358fc13a1b3f5c0664cf1f7
5
5
  SHA512:
6
- metadata.gz: d86c42c61e77843ef9a76e45868d71722f08e8af28f6c1747f2d4ea55ecd1bf5d5731d3e4b41ad82827c59e0f8e21f3b9ab714a7dc2a442c387c17c97858c8bc
7
- data.tar.gz: e53538e79ab1b48563e804080a23f8e8aa6f67f6fa71a54880fa7c93696a9e8778fc5248937ea653cefe72f8cb215e84aec223559f1436506354f65ade735f8d
6
+ metadata.gz: bd8c531ad27a3ba0693d3923a00f62abb4b730251e235d0f3a78b449f2fdc7336052a4e5c0115748330e95a6f75eff2f20dcfc71d3fa1360d3d7e4c98c2b38af
7
+ data.tar.gz: fe72790fbcb1372f8127afe702cf2696f930c901aaa2b6243c913243b299a74917bca867d068e09039a6df001c942f7db81b0a3c64daa54a919bbdb4714de4ac
@@ -10,8 +10,8 @@ reviewers:
10
10
  - lighty
11
11
  - mkmn
12
12
  - osyo-manga
13
- - wata727
14
13
  - yono
14
+ - kumaie-shr
15
15
 
16
16
  # A list of keywords to be skipped the process that add reviewers if pull requests include it
17
17
  skipKeywords:
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
@@ -19,11 +19,11 @@ jobs:
19
19
  GEM_HOST_API_KEY: ${{ secrets.GEM_HOST_API_KEY }}
20
20
  GEM_HOST_OTP_CODE: ${{ github.event.inputs.rubygems-otp-code }}
21
21
  steps:
22
- - uses: actions/checkout@v3
22
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
23
23
  with:
24
24
  fetch-depth: 0
25
25
 
26
- - uses: ruby/setup-ruby@v1
26
+ - uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
27
27
  with:
28
28
  ruby-version: '3.1'
29
29
  bundler-cache: true
@@ -0,0 +1,49 @@
1
+ # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
2
+
3
+ name: Test
4
+
5
+ on:
6
+ push:
7
+ branches:
8
+ - master
9
+ pull_request:
10
+
11
+ jobs:
12
+ test:
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ ruby-version:
18
+ - '3.1'
19
+ - '3.2'
20
+ - '3.3'
21
+ - '3.4'
22
+ gemfile:
23
+ - rails_7.0
24
+ - rails_7.1
25
+ - rails_7.2
26
+ services:
27
+ postgres:
28
+ image: postgres:14
29
+ env:
30
+ POSTGRES_PASSWORD: postgres
31
+ # Set health checks to wait until postgres has started
32
+ options: >-
33
+ --health-cmd pg_isready
34
+ --health-interval 10s
35
+ --health-timeout 5s
36
+ --health-retries 5
37
+ ports:
38
+ - 5432:5432
39
+ env:
40
+ BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
41
+ steps:
42
+ - name: Checkout
43
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
44
+ - name: Setup Ruby
45
+ uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
46
+ with:
47
+ ruby-version: ${{ matrix.ruby-version }}
48
+ bundler-cache: true
49
+ - run: bundle exec rspec
data/Appraisals CHANGED
@@ -1,13 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- appraise "rails-6.1" do
4
- gem "rails", "~> 6.1.0"
5
- end
6
-
7
3
  appraise "rails-7.0" do
8
4
  gem "rails", "~> 7.0.1"
5
+
6
+ # for Ruby 3.4
7
+ gem "base64"
8
+ gem "bigdecimal"
9
+ gem "mutex_m"
10
+
11
+ # NOTE: concurrent-ruby gem no longer loads the logger gem since v1.3.5.
12
+ # https://github.com/ruby-concurrency/concurrent-ruby/pull/1062
13
+ # https://github.com/rails/rails/pull/54264
14
+ gem "concurrent-ruby", "< 1.3.5"
9
15
  end
10
16
 
11
17
  appraise "rails-7.1" do
12
18
  gem "rails", "~> 7.1.0"
13
19
  end
20
+
21
+ appraise "rails-7.2" do
22
+ gem "rails", "~> 7.2.0"
23
+ end
data/CHANGELOG.md CHANGED
@@ -1,5 +1,69 @@
1
1
  # Changelog
2
2
 
3
+ ## 6.0.0
4
+
5
+ ### Breaking Changed
6
+
7
+ - [Add Ruby 3.4 and remove Ruby 3.0 in CI #185](https://github.com/kufu/activerecord-bitemporal/pull/185)
8
+ - [Drop support Rails 6.1 #192](https://github.com/kufu/activerecord-bitemporal/pull/192)
9
+
10
+ ### Added
11
+
12
+ - [CI against Rails 7.2 #164](https://github.com/kufu/activerecord-bitemporal/pull/164)
13
+ - [Support custom column names for valid time in .bitemporalize #200](https://github.com/kufu/activerecord-bitemporal/pull/200)
14
+
15
+ ### Changed
16
+
17
+ ### Deprecated
18
+
19
+ ### Removed
20
+
21
+ ### Fixed
22
+
23
+ - [Prevent where clauses from ignored by `ignore_valid_datetime` #190](https://github.com/kufu/activerecord-bitemporal/pull/190)
24
+
25
+ ### Chores
26
+
27
+ - [Add a note to the README that PostgreSQL is required to run the tests. #188](https://github.com/kufu/activerecord-bitemporal/pull/188)
28
+ - [Remove specs for Rails 5.x #191](https://github.com/kufu/activerecord-bitemporal/pull/191)
29
+ - [Update auto assgin member #193](https://github.com/kufu/activerecord-bitemporal/pull/193)
30
+ - [Pin GitHub Actions dependencies to specific commit hashes #194](https://github.com/kufu/activerecord-bitemporal/pull/194)
31
+ - [Bump ruby/setup-ruby from 1.227.0 to 1.229.0 #195](https://github.com/kufu/activerecord-bitemporal/pull/195)
32
+ - [Bump ruby/setup-ruby from 1.229.0 to 1.233.0 #197](https://github.com/kufu/activerecord-bitemporal/pull/197)
33
+ - [Bump ruby/setup-ruby from 1.233.0 to 1.235.0 #198](https://github.com/kufu/activerecord-bitemporal/pull/198)
34
+ - [Bump ruby/setup-ruby from 1.235.0 to 1.237.0 #199](https://github.com/kufu/activerecord-bitemporal/pull/199)
35
+ - [Bump ruby/setup-ruby from 1.237.0 to 1.238.0 #201](https://github.com/kufu/activerecord-bitemporal/pull/201)
36
+ - [Bump ruby/setup-ruby from 1.238.0 to 1.242.0 #202](https://github.com/kufu/activerecord-bitemporal/pull/202)
37
+ - [Bump ruby/setup-ruby from 1.242.0 to 1.244.0 #203](https://github.com/kufu/activerecord-bitemporal/pull/203)
38
+ - [Update auto assgin member #204](https://github.com/kufu/activerecord-bitemporal/pull/204)
39
+
40
+ ## 5.3.0
41
+
42
+ ### Added
43
+
44
+ ### Changed
45
+
46
+ - [Replace `default` overrides from `load_schema!` to `attribute` #172](https://github.com/kufu/activerecord-bitemporal/pull/172)
47
+ - [`Or` node changed to `Nary` in Rails 7.2 #173](https://github.com/kufu/activerecord-bitemporal/pull/173)
48
+ - [Exclude record valid range end in uniqueness validation #184](https://github.com/kufu/activerecord-bitemporal/pull/184)
49
+
50
+ ### Deprecated
51
+
52
+ ### Removed
53
+
54
+ ### Fixed
55
+
56
+ ### Chores
57
+
58
+ - [Add specs under specific conditions #171](https://github.com/kufu/activerecord-bitemporal/pull/171)
59
+ - [Add Dependabot for GitHub Actions #174](https://github.com/kufu/activerecord-bitemporal/pull/174)
60
+ - [Bump actions/checkout from 3 to 4 #175](https://github.com/kufu/activerecord-bitemporal/pull/175)
61
+ - [Replace CircleCI with GitHub Actions #177](https://github.com/kufu/activerecord-bitemporal/pull/177)
62
+ - [Update README as `within_deleted` and `without_deleted` are deprecated #178](https://github.com/kufu/activerecord-bitemporal/pull/178)
63
+ - [Fix typo #181](https://github.com/kufu/activerecord-bitemporal/pull/181)
64
+ - [Fix #force_update block comment #183](https://github.com/kufu/activerecord-bitemporal/pull/183)
65
+ - [Support Docker Compose V2 #186](https://github.com/kufu/activerecord-bitemporal/pull/186)
66
+
3
67
  ## 5.2.0
4
68
 
5
69
  ### Added
data/README.md CHANGED
@@ -317,7 +317,7 @@ Timecop.freeze("2019/1/10") {
317
317
  }
318
318
 
319
319
  Timecop.freeze("2019/1/20") {
320
- # #force_update のでは自身を受け取る
320
+ # #force_update のブロック内で自身を受け取る
321
321
  # このブロック内であれば履歴を生成せずにレコードの変更が行われる
322
322
  employee.force_update { |employee|
323
323
  employee.update(name: "Tom")
@@ -415,7 +415,7 @@ BTDM では DB からレコードを参照する場合、暗黙的に
415
415
  Timecop.freeze("2019/1/20") {
416
416
  # 現在の時間の履歴を返すために暗黙的に時間指定や論理削除されたレコードが除かれる
417
417
  puts Employee.all.to_sql
418
- # => SELECT "employees".* FROM "employees" WHERE "employees"."valid_from" <= '2019-01-20 00:00:00' AND "employees"."valid_to" > '2019-01-20 00:00:00' AND "employees"."transaction_to" = '9999-12-31 00:00:00'
418
+ # => SELECT "employees".* FROM "employees" WHERE "employees"."valid_from" <= '2019-01-20 00:00:00' AND "employees"."valid_to" > '2019-01-20 00:00:00' AND "employees"."transaction_from" <= '2019-01-20 00:00:00' AND "employees"."transaction_to" > '2019-01-20 00:00:00'
419
419
  }
420
420
  ```
421
421
 
@@ -454,7 +454,7 @@ Timecop.freeze("2019/1/20") {
454
454
 
455
455
  # なぜなら暗黙的に時間指定のクエリが追加されている為
456
456
  puts Employee.where(name: "Jane").to_sql
457
- # => SELECT "employees".* FROM "employees" WHERE "employees"."valid_from" <= '2019-01-20 00:00:00' AND "employees"."valid_to" > '2019-01-20 00:00:00' AND "employees"."transaction_to" = '9999-12-31 00:00:00' AND "employees"."name" = 'Jane'
457
+ # => SELECT "employees".* FROM "employees" WHERE "employees"."valid_from" <= '2019-01-20 00:00:00' AND "employees"."valid_to" > '2019-01-20 00:00:00' AND "employees"."transaction_from" <= '2019-01-20 00:00:00' AND "employees"."transaction_to" > '2019-01-20 00:00:00' AND "employees"."name" = 'Jane'
458
458
  }
459
459
  ```
460
460
 
@@ -464,7 +464,7 @@ Timecop.freeze("2019/1/20") {
464
464
  ```ruby
465
465
  # default_scope であれば unscoped で無効化することが出来るが、BTDM のデフォルトクエリはそのまま
466
466
  puts Employee.unscoped { Employee.all.to_sql }
467
- # => SELECT "employees".* FROM "employees" WHERE "employees"."valid_from" <= '2019-10-25 07:56:06.731259' AND "employees"."valid_to" > '2019-10-25 07:56:06.731259' AND "employees"."transaction_to" = '9999-12-31 00:00:00'
467
+ # => SELECT "employees".* FROM "employees" WHERE "employees"."valid_from" <= '2019-10-25 07:56:06.731259' AND "employees"."valid_to" > '2019-10-25 07:56:06.731259' AND "employees"."transaction_from" <= '2019-10-25 07:56:06.731259' AND "employees"."transaction_to" > '2019-10-25 07:56:06.731259'
468
468
  ```
469
469
 
470
470
 
@@ -475,21 +475,21 @@ puts Employee.unscoped { Employee.all.to_sql }
475
475
  | スコープ | 動作 |
476
476
  | --- | --- |
477
477
  | `.ignore_valid_datetime` | 時間指定を無視する |
478
- | `.within_deleted` | 論理削除されているレコードを含める |
479
- | `.without_deleted` | 論理削除されているレコードを含めない |
478
+ | `.ignore_transaction_datetime` | 論理削除されているレコードを含める |
479
+ | `.ignore_bitemporal_datetime` | 全てのレコードを対象とする |
480
480
 
481
481
  ```ruby
482
482
  Timecop.freeze("2019/1/20") {
483
483
  # 時間指定をしているクエリを取り除く
484
484
  puts Employee.ignore_valid_datetime.to_sql
485
- # => SELECT "employees".* FROM "employees" WHERE "employees"."transaction_to" = '9999-12-31 00:00:00'
485
+ # => SELECT "employees".* FROM "employees" WHERE "employees"."transaction_from" <= '2019-01-20 00:00:00' AND "employees"."transaction_to" > '2019-01-20 00:00:00'
486
486
 
487
487
  # 論理削除しているレコードも含める
488
- puts Employee.within_deleted.to_sql
488
+ puts Employee.ignore_transaction_datetime.to_sql
489
489
  # => SELECT "employees".* FROM "employees" WHERE "employees"."valid_from" <= '2019-01-20 00:00:00' AND "employees"."valid_to" > '2019-01-20 00:00:00'
490
490
 
491
491
  # 全てのレコードを対象とする
492
- puts Employee.ignore_valid_datetime.within_deleted.to_sql
492
+ puts Employee.ignore_bitemporal_datetime.to_sql
493
493
  # => SELECT "employees".* FROM "employees"
494
494
  }
495
495
  ```
@@ -534,7 +534,7 @@ Timecop.freeze("2019/1/15") {
534
534
  Timecop.freeze("2019/1/20") {
535
535
  # valid_at で任意の時間を参照して検索する事が出来る
536
536
  puts Employee.valid_at("2019/1/10").to_sql
537
- # => SELECT "employees".* FROM "employees" WHERE "employees"."valid_from" <= '2019-01-10 00:00:00' AND "employees"."valid_to" > '2019-01-10 00:00:00' AND "employees"."transaction_to" = '9999-12-31 00:00:00'
537
+ # => SELECT "employees".* FROM "employees" WHERE "employees"."valid_from" <= '2019-01-10 00:00:00' AND "employees"."valid_to" > '2019-01-10 00:00:00' AND "employees"."transaction_from" <= '2019-01-20 00:00:00' AND "employees"."transaction_to" > '2019-01-20 00:00:00'
538
538
 
539
539
  pp Employee.valid_at("2019/1/10").map(&:name)
540
540
  # => ["Jane"]
@@ -696,7 +696,7 @@ BTDM では `find_by(id: xxx)` や `where(id: xxx)` を行う場合 `id` では
696
696
  Employee.find_by(id: employee.id)
697
697
 
698
698
  # OK : bitemporal_id で検索を行う
699
- # MEMO: id = bitemporal_id なの
699
+ # MEMO: id = bitemporal_id なので
700
700
  # find_by(bitemporal_id: employee.id)
701
701
  # でも動作するが employee.bitemporal_id と書いたほうが意図が伝わりやすい
702
702
  Employee.find_by(bitemporal_id: employee.bitemporal_id)
@@ -711,7 +711,7 @@ Employee.where(bitemporal_id: employee.bitemporal_id)
711
711
 
712
712
  ## Development
713
713
 
714
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
714
+ After checking out the repo, run `bin/setup` to install dependencies. And start PostgreSQL on port 5432. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
715
715
 
716
716
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
717
717
 
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
14
14
  spec.description = %q{Enable ActiveRecord models to be handled as BiTemporal Data Model.}
15
15
  spec.homepage = "https://github.com/kufu/activerecord-bitemporal"
16
16
  spec.license = "Apache 2.0"
17
- spec.required_ruby_version = ">= 3.0"
17
+ spec.required_ruby_version = ">= 3.1"
18
18
 
19
19
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
20
20
  f.match(%r{^(test|spec|features)/})
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
24
  spec.require_paths = ["lib"]
25
25
 
26
- spec.add_dependency "activerecord", ">= 6.1"
26
+ spec.add_dependency "activerecord", ">= 7.0"
27
27
 
28
28
  spec.add_development_dependency "bundler"
29
29
  spec.add_development_dependency "rake", "~> 13.0"
@@ -1,4 +1,3 @@
1
- version: '2.1'
2
1
  services:
3
2
  db:
4
3
  image: postgres:latest
@@ -4,5 +4,9 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "appraisal"
6
6
  gem "rails", "~> 7.0.1"
7
+ gem "base64"
8
+ gem "bigdecimal"
9
+ gem "mutex_m"
10
+ gem "concurrent-ruby", "< 1.3.5"
7
11
 
8
12
  gemspec path: "../"
@@ -3,6 +3,6 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "appraisal"
6
- gem "rails", "~> 6.1.0"
6
+ gem "rails", "~> 7.2.0"
7
7
 
8
8
  gemspec path: "../"
@@ -313,7 +313,7 @@ module ActiveRecord
313
313
  def _create_record(attribute_names = self.attribute_names)
314
314
  bitemporal_assign_initialize_value(valid_datetime: self.valid_datetime)
315
315
 
316
- ActiveRecord::Bitemporal.valid_at!(self.valid_from) {
316
+ ActiveRecord::Bitemporal.valid_at!(self[valid_from_key]) {
317
317
  super()
318
318
  }
319
319
  end
@@ -346,8 +346,8 @@ module ActiveRecord
346
346
  # update 後に新しく生成したインスタンスのデータを移行する
347
347
  @_swapped_id_previously_was = swapped_id
348
348
  @_swapped_id = after_instance.swapped_id
349
- self.valid_from = after_instance.valid_from
350
- self.valid_to = after_instance.valid_to
349
+ self[valid_from_key] = after_instance[valid_from_key]
350
+ self[valid_to_key] = after_instance[valid_to_key]
351
351
  self.transaction_from = after_instance.transaction_from
352
352
  self.transaction_to = after_instance.transaction_to
353
353
 
@@ -373,14 +373,14 @@ module ActiveRecord
373
373
  # force_update の場合は削除時の状態の履歴を残さない
374
374
  unless force_update?
375
375
  # 削除時の状態を履歴レコードとして保存する
376
- duplicated_instance.valid_to = target_datetime
376
+ duplicated_instance[valid_to_key] = target_datetime
377
377
  duplicated_instance.transaction_from = operated_at
378
378
  duplicated_instance.save_without_bitemporal_callbacks!(validate: false)
379
379
  if @destroyed
380
380
  @_swapped_id_previously_was = swapped_id
381
381
  @_swapped_id = duplicated_instance.swapped_id
382
- self.valid_from = duplicated_instance.valid_from
383
- self.valid_to = duplicated_instance.valid_to
382
+ self[valid_from_key] = duplicated_instance[valid_from_key]
383
+ self[valid_to_key] = duplicated_instance[valid_to_key]
384
384
  self.transaction_from = duplicated_instance.transaction_from
385
385
  self.transaction_to = duplicated_instance.transaction_to
386
386
  end
@@ -393,6 +393,7 @@ module ActiveRecord
393
393
  rescue => e
394
394
  @destroyed = false
395
395
  @_association_destroy_exception = ActiveRecord::RecordNotDestroyed.new("Failed to destroy the record: class=#{e.class}, message=#{e.message}", self)
396
+ @_association_destroy_exception.set_backtrace(e.backtrace)
396
397
  false
397
398
  end
398
399
 
@@ -411,55 +412,29 @@ module ActiveRecord
411
412
  module ::ActiveRecord::Persistence
412
413
  # MEMO: Must be override ActiveRecord::Persistence#reload
413
414
  alias_method :active_record_bitemporal_original_reload, :reload unless method_defined? :active_record_bitemporal_original_reload
414
- if Gem::Version.new("7.0.0.alpha") <= ActiveRecord.version
415
- def reload(options = nil)
416
- return active_record_bitemporal_original_reload(options) unless self.class.bi_temporal_model?
417
-
418
- self.class.connection.clear_query_cache
419
-
420
- fresh_object =
421
- ActiveRecord::Bitemporal.with_bitemporal_option(**bitemporal_option) {
422
- if apply_scoping?(options)
423
- _find_record(options)
424
- else
425
- self.class.unscoped { self.class.bitemporal_default_scope.scoping { _find_record(options) } }
426
- end
427
- }
415
+ def reload(options = nil)
416
+ return active_record_bitemporal_original_reload(options) unless self.class.bi_temporal_model?
428
417
 
429
- @association_cache = fresh_object.instance_variable_get(:@association_cache)
430
- @attributes = fresh_object.instance_variable_get(:@attributes)
431
- @new_record = false
432
- @previously_new_record = false
433
- # NOTE: Hook to copying swapped_id
434
- @_swapped_id_previously_was = nil
435
- @_swapped_id = fresh_object.swapped_id
436
- @previously_force_updated = false
437
- self
438
- end
439
- else
440
- def reload(options = nil)
441
- return active_record_bitemporal_original_reload(options) unless self.class.bi_temporal_model?
442
-
443
- self.class.connection.clear_query_cache
444
-
445
- fresh_object =
446
- ActiveRecord::Bitemporal.with_bitemporal_option(**bitemporal_option) {
447
- if options && options[:lock]
448
- self.class.unscoped { self.class.lock(options[:lock]).bitemporal_default_scope.find(id) }
449
- else
450
- self.class.unscoped { self.class.bitemporal_default_scope.find(id) }
451
- end
452
- }
418
+ self.class.connection.clear_query_cache
453
419
 
454
- @attributes = fresh_object.instance_variable_get(:@attributes)
455
- @new_record = false
456
- @previously_new_record = false
457
- # NOTE: Hook to copying swapped_id
458
- @_swapped_id_previously_was = nil
459
- @_swapped_id = fresh_object.swapped_id
460
- @previously_force_updated = false
461
- self
462
- end
420
+ fresh_object =
421
+ ActiveRecord::Bitemporal.with_bitemporal_option(**bitemporal_option) {
422
+ if apply_scoping?(options)
423
+ _find_record(options)
424
+ else
425
+ self.class.unscoped { self.class.bitemporal_default_scope.scoping { _find_record(options) } }
426
+ end
427
+ }
428
+
429
+ @association_cache = fresh_object.instance_variable_get(:@association_cache)
430
+ @attributes = fresh_object.instance_variable_get(:@attributes)
431
+ @new_record = false
432
+ @previously_new_record = false
433
+ # NOTE: Hook to copying swapped_id
434
+ @_swapped_id_previously_was = nil
435
+ @_swapped_id = fresh_object.swapped_id
436
+ @previously_force_updated = false
437
+ self
463
438
  end
464
439
  end
465
440
 
@@ -467,7 +442,7 @@ module ActiveRecord
467
442
 
468
443
  def bitemporal_assign_initialize_value(valid_datetime:, current_time: Time.current)
469
444
  # 自身の `valid_from` を設定
470
- self.valid_from = valid_datetime || current_time if self.valid_from == ActiveRecord::Bitemporal::DEFAULT_VALID_FROM
445
+ self[valid_from_key] = valid_datetime || current_time if self[valid_from_key] == ActiveRecord::Bitemporal::DEFAULT_VALID_FROM
471
446
 
472
447
  self.transaction_from = current_time if self.transaction_from == ActiveRecord::Bitemporal::DEFAULT_TRANSACTION_FROM
473
448
 
@@ -485,7 +460,7 @@ module ActiveRecord
485
460
  def bitemporal_build_update_records(valid_datetime:, current_time: Time.current, force_update: false)
486
461
  target_datetime = valid_datetime || current_time
487
462
  # NOTE: force_update の場合は自身のレコードを取得するような時間を指定しておく
488
- target_datetime = valid_from_changed? ? valid_from_was : valid_from if force_update
463
+ target_datetime = attribute_changed?(valid_from_key) ? attribute_was(valid_from_key) : self[valid_from_key] if force_update
489
464
 
490
465
  # 対象基準日において有効なレコード
491
466
  # NOTE: 論理削除対象
@@ -516,26 +491,26 @@ module ActiveRecord
516
491
  current_valid_record.assign_transaction_to(current_time)
517
492
 
518
493
  # 以前の履歴データは valid_to を詰めて保存
519
- before_instance.valid_to = target_datetime
494
+ before_instance[valid_to_key] = target_datetime
520
495
  if before_instance.valid_from_cannot_be_greater_equal_than_valid_to
521
- raise ValidDatetimeRangeError.new("valid_from #{before_instance.valid_from} can't be greater equal than valid_to #{before_instance.valid_to}")
496
+ raise ValidDatetimeRangeError.new("#{valid_from_key} #{before_instance[valid_from_key]} can't be greater equal than #{valid_to_key} #{before_instance[valid_to_key]}")
522
497
  end
523
498
  before_instance.transaction_from = current_time
524
499
 
525
500
  # 以降の履歴データは valid_from と valid_to を調整して保存する
526
- after_instance.valid_from = target_datetime
527
- after_instance.valid_to = current_valid_record.valid_to
501
+ after_instance[valid_from_key] = target_datetime
502
+ after_instance[valid_to_key] = current_valid_record[valid_to_key]
528
503
  if after_instance.valid_from_cannot_be_greater_equal_than_valid_to
529
- raise ValidDatetimeRangeError.new("valid_from #{after_instance.valid_from} can't be greater equal than valid_to #{after_instance.valid_to}")
504
+ raise ValidDatetimeRangeError.new("#{valid_from_key} #{after_instance[valid_from_key]} can't be greater equal than #{valid_to_key} #{after_instance[valid_to_key]}")
530
505
  end
531
506
  after_instance.transaction_from = current_time
532
507
 
533
508
  # 有効なレコードがない場合
534
509
  else
535
510
  # 一番近い未来にある Instance を取ってきて、その valid_from を valid_to に入れる
536
- nearest_instance = self.class.where(bitemporal_id: bitemporal_id).valid_from_gt(target_datetime).ignore_valid_datetime.order(valid_from: :asc).first
511
+ nearest_instance = self.class.where(bitemporal_id: bitemporal_id).ignore_valid_datetime.valid_from_gt(target_datetime).order(valid_from_key => :asc).first
537
512
  if nearest_instance.nil?
538
- message = "Update failed: Couldn't find #{self.class} with 'bitemporal_id'=#{self.bitemporal_id} and 'valid_from' < #{target_datetime}"
513
+ message = "Update failed: Couldn't find #{self.class} with 'bitemporal_id'=#{self.bitemporal_id} and '#{valid_from_key}' > #{target_datetime}"
539
514
  raise ActiveRecord::RecordNotFound.new(message, self.class, "bitemporal_id", self.bitemporal_id)
540
515
  end
541
516
 
@@ -546,8 +521,8 @@ module ActiveRecord
546
521
  before_instance = nil
547
522
 
548
523
  # 以降の履歴データは valid_from と valid_to を調整して保存する
549
- after_instance.valid_from = target_datetime
550
- after_instance.valid_to = nearest_instance.valid_from
524
+ after_instance[valid_from_key] = target_datetime
525
+ after_instance[valid_to_key] = nearest_instance[valid_from_key]
551
526
  after_instance.transaction_from = current_time
552
527
  end
553
528
 
@@ -569,7 +544,7 @@ module ActiveRecord
569
544
 
570
545
  target_datetime = record.valid_datetime || Time.current
571
546
 
572
- valid_from = record.valid_from.yield_self { |valid_from|
547
+ valid_from = record[record.valid_from_key].yield_self { |valid_from|
573
548
  # NOTE: valid_from が初期値の場合は現在の時間を基準としてバリデーションする
574
549
  # valid_from が初期値の場合は Persistence#_create_record に Time.current が割り当てられる為
575
550
  # バリデーション時と生成時で若干時間がずれてしまうことには考慮する
@@ -586,17 +561,17 @@ module ActiveRecord
586
561
  }
587
562
 
588
563
  # MEMO: `force_update` does not refer to `valid_datetime`
589
- valid_from = record.valid_from if record.force_update?
564
+ valid_from = record[record.valid_from_key] if record.force_update?
590
565
 
591
- valid_to = record.valid_to.yield_self { |valid_to|
566
+ valid_to = record[record.valid_to_key].yield_self { |valid_to|
592
567
  # NOTE: `cover?` may give incorrect results, when the time zone is not UTC and `valid_from` is date type
593
568
  # Therefore, cast to type of `valid_from`
594
- record_valid_time = finder_class.type_for_attribute(:valid_from).cast(record.valid_datetime)
569
+ record_valid_time = finder_class.type_for_attribute(record.valid_from_key).cast(record.valid_datetime)
595
570
  # レコードを更新する時に valid_datetime が valid_from ~ valid_to の範囲外だった場合、
596
571
  # 一番近い未来の履歴レコードを参照して更新する
597
572
  # という仕様があるため、それを考慮して valid_to を設定する
598
- if (record_valid_time && (record.valid_from..record.valid_to).cover?(record_valid_time)) == false && (record.persisted?)
599
- finder_class.ignore_valid_datetime.where(bitemporal_id: record.bitemporal_id).valid_from_gt(target_datetime).order(valid_from: :asc).first.valid_from
573
+ if (record_valid_time && (record[record.valid_from_key]...record[record.valid_to_key]).cover?(record_valid_time)) == false && (record.persisted?)
574
+ finder_class.ignore_valid_datetime.where(bitemporal_id: record.bitemporal_id).valid_from_gteq(target_datetime).order(record.valid_from_key => :asc).first[record.valid_from_key]
600
575
  else
601
576
  valid_to
602
577
  end
@@ -27,6 +27,10 @@ module ActiveRecord::Bitemporal
27
27
  end
28
28
 
29
29
  module Relation
30
+ # see: https://github.com/rails/rails/pull/51492
31
+ NARY_NODE = ActiveRecord.gem_version >= Gem::Version.new("7.2.0") ? Arel::Nodes::Nary : Arel::Nodes::And
32
+ private_constant :NARY_NODE
33
+
30
34
  using Module.new {
31
35
  refine ActiveRecord::Relation::WhereClause do
32
36
  using Module.new {
@@ -56,7 +60,7 @@ module ActiveRecord::Bitemporal
56
60
  case node
57
61
  when Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
58
62
  y << node if node && node.left.respond_to?(:relation)
59
- when Arel::Nodes::And
63
+ when NARY_NODE
60
64
  each_operatable_node(node.children) { |node| y << node }
61
65
  when Arel::Nodes::Binary
62
66
  each_operatable_node(node.left) { |node| y << node }
@@ -82,9 +86,9 @@ module ActiveRecord::Bitemporal
82
86
 
83
87
  refine Relation do
84
88
  def bitemporal_clause(table_name = klass.table_name)
85
- node_hash = where_clause.bitemporal_query_hash("valid_from", "valid_to", "transaction_from", "transaction_to")
86
- valid_from = node_hash.dig(table_name, "valid_from", 1)
87
- valid_to = node_hash.dig(table_name, "valid_to", 1)
89
+ node_hash = where_clause.bitemporal_query_hash(valid_from_key, valid_to_key, "transaction_from", "transaction_to")
90
+ valid_from = node_hash.dig(table_name, valid_from_key, 1)
91
+ valid_to = node_hash.dig(table_name, valid_to_key, 1)
88
92
  transaction_from = node_hash.dig(table_name, "transaction_from", 1)
89
93
  transaction_to = node_hash.dig(table_name, "transaction_to", 1)
90
94
  {
@@ -251,19 +255,24 @@ module ActiveRecord::Bitemporal
251
255
  rewhere(table[attr_name].public_send(operator, predicate_builder.build_bind_attribute(attr_name, value)))
252
256
  end
253
257
 
254
- %i(valid_from valid_to transaction_from transaction_to).each { |column|
258
+ [
259
+ [:valid_from, "\#{valid_from_key}"], # Evaluate `valid_from/to_key` at runtime using `\#`
260
+ [:valid_to, "\#{valid_to_key}"],
261
+ [:transaction_from, "transaction_from"],
262
+ [:transaction_to, "transaction_to"]
263
+ ].each { |column, column_name|
255
264
  module_eval <<-STR, __FILE__, __LINE__ + 1
256
265
  def _ignore_#{column}
257
- unscope(where: :"\#{table.name}.#{column}")
258
- .tap { |relation| relation.unscope!(where: bitemporal_value[:through].arel_table["#{column}"]) if bitemporal_value[:through] }
266
+ unscope(where: :"\#{table.name}.#{column_name}")
267
+ .tap { |relation| relation.unscope!(where: bitemporal_value[:through].arel_table["#{column_name}"]) if bitemporal_value[:through] }
259
268
  end
260
269
 
261
270
  def _except_#{column}
262
271
  return self unless where_clause.send(:predicates).find { |node|
263
- node.bitemporal_include?("\#{table.name}.#{column}")
272
+ node.bitemporal_include?("\#{table.name}.#{column_name}")
264
273
  }
265
274
  _ignore_#{column}.tap { |relation|
266
- relation.unscope_values.reject! { |query| query.equal_attribute_name("\#{table.name}.#{column}") }
275
+ relation.unscope_values.reject! { |query| query.equal_attribute_name("\#{table.name}.#{column_name}") }
267
276
  }
268
277
  end
269
278
  STR
@@ -277,8 +286,8 @@ module ActiveRecord::Bitemporal
277
286
  module_eval <<-STR, __FILE__, __LINE__ + 1
278
287
  def _#{column}_#{op}(datetime)
279
288
  target_datetime = datetime&.in_time_zone || Time.current
280
- bitemporal_rewhere_bind("#{column}", :#{op}, target_datetime)
281
- .tap { |relation| break relation.bitemporal_rewhere_bind("#{column}", :#{op}, target_datetime, bitemporal_value[:through].arel_table) if bitemporal_value[:through] }
289
+ bitemporal_rewhere_bind("#{column_name}", :#{op}, target_datetime)
290
+ .tap { |relation| break relation.bitemporal_rewhere_bind("#{column_name}", :#{op}, target_datetime, bitemporal_value[:through].arel_table) if bitemporal_value[:through] }
282
291
  end
283
292
  STR
284
293
  }
@@ -424,17 +433,17 @@ module ActiveRecord::Bitemporal
424
433
  # beginless range
425
434
  if begin_
426
435
  # from < valid_to
427
- relation = relation.bitemporal_where_bind("valid_to", :gt, begin_.in_time_zone.to_datetime)
436
+ relation = relation.bitemporal_where_bind(valid_to_key, :gt, begin_.in_time_zone.to_datetime)
428
437
  end
429
438
 
430
439
  # endless range
431
440
  if end_
432
441
  if range.exclude_end?
433
442
  # valid_from < to
434
- relation = relation.bitemporal_where_bind("valid_from", :lt, end_.in_time_zone.to_datetime)
443
+ relation = relation.bitemporal_where_bind(valid_from_key, :lt, end_.in_time_zone.to_datetime)
435
444
  else
436
445
  # valid_from <= to
437
- relation = relation.bitemporal_where_bind("valid_from", :lteq, end_.in_time_zone.to_datetime)
446
+ relation = relation.bitemporal_where_bind(valid_from_key, :lteq, end_.in_time_zone.to_datetime)
438
447
  end
439
448
  end
440
449
 
@@ -449,14 +458,14 @@ module ActiveRecord::Bitemporal
449
458
  begin_, end_ = range.begin, range.end
450
459
 
451
460
  if begin_
452
- relation = relation.bitemporal_where_bind("valid_from", :gteq, begin_.in_time_zone.to_datetime)
461
+ relation = relation.bitemporal_where_bind(valid_from_key, :gteq, begin_.in_time_zone.to_datetime)
453
462
  end
454
463
 
455
464
  if end_
456
465
  if range.exclude_end?
457
466
  raise 'Range with excluding end is not supported'
458
467
  else
459
- relation = relation.bitemporal_where_bind("valid_to", :lteq, end_.in_time_zone.to_datetime)
468
+ relation = relation.bitemporal_where_bind(valid_to_key, :lteq, end_.in_time_zone.to_datetime)
460
469
  end
461
470
  end
462
471
 
@@ -472,10 +481,10 @@ module ActiveRecord::Bitemporal
472
481
  ignore_valid_datetime.bitemporal_for(*ids)
473
482
  }
474
483
  def self.bitemporal_most_future(id)
475
- bitemporal_histories(id).order(valid_from: :asc).last
484
+ bitemporal_histories(id).order(valid_from_key => :asc).last
476
485
  end
477
486
  def self.bitemporal_most_past(id)
478
- bitemporal_histories(id).order(valid_from: :asc).first
487
+ bitemporal_histories(id).order(valid_from_key => :asc).first
479
488
  end
480
489
  end
481
490
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Bitemporal
5
- VERSION = "5.2.0"
5
+ VERSION = "6.0.0"
6
6
  end
7
7
  end
@@ -22,7 +22,7 @@ module ActiveRecord::Bitemporal
22
22
  module_function
23
23
 
24
24
  def visualize(record, height: 10, width: 40, highlight: true)
25
- histories = record.class.ignore_bitemporal_datetime.bitemporal_for(record).order(:transaction_from, :valid_from)
25
+ histories = record.class.ignore_bitemporal_datetime.bitemporal_for(record).order(:transaction_from, record.valid_from_key)
26
26
 
27
27
  if highlight
28
28
  visualize_records(histories, [record], height: height, width: width)
@@ -36,7 +36,7 @@ module ActiveRecord::Bitemporal
36
36
  raise 'More than 3 relations are not supported' if relations.size >= 3
37
37
  records = relations.flatten
38
38
 
39
- valid_times = (records.map(&:valid_from) + records.map(&:valid_to)).sort.uniq
39
+ valid_times = (records.map { _1[_1.valid_from_key] } + records.map { _1[_1.valid_to_key] }).sort.uniq
40
40
  transaction_times = (records.map(&:transaction_from) + records.map(&:transaction_to)).sort.uniq
41
41
 
42
42
  time_length = Time.zone.now.strftime('%F %T.%3N').length
@@ -60,9 +60,11 @@ module ActiveRecord::Bitemporal
60
60
 
61
61
  relation.each do |record|
62
62
  line = lines[record.transaction_from]
63
- column = columns[record.valid_from]
63
+ valid_from = record[record.valid_from_key]
64
+ valid_to = record[record.valid_to_key]
65
+ column = columns[valid_from]
64
66
 
65
- width = columns[record.valid_to] - columns[record.valid_from] - 1
67
+ width = columns[valid_to] - columns[valid_from] - 1
66
68
  height = lines[record.transaction_to] - lines[record.transaction_from] - 1
67
69
 
68
70
  body.print("#{record.transaction_from.strftime('%F %T.%3N')} ", line: line)
@@ -37,13 +37,6 @@ module ActiveRecord::Bitemporal::Bitemporalize
37
37
  module ClassMethods
38
38
  include ActiveRecord::Bitemporal::Relation::Finder
39
39
 
40
- DEFAULT_ATTRIBUTES = {
41
- valid_from: ActiveRecord::Bitemporal::DEFAULT_VALID_FROM,
42
- valid_to: ActiveRecord::Bitemporal::DEFAULT_VALID_TO,
43
- transaction_from: ActiveRecord::Bitemporal::DEFAULT_TRANSACTION_FROM,
44
- transaction_to: ActiveRecord::Bitemporal::DEFAULT_TRANSACTION_TO
45
- }.freeze
46
-
47
40
  def bitemporal_id_key
48
41
  'bitemporal_id'
49
42
  end
@@ -62,16 +55,6 @@ module ActiveRecord::Bitemporal::Bitemporalize
62
55
  klass.relation_delegate_class(ActiveRecord::Relation).prepend ActiveRecord::Bitemporal::Relation::MergeWithExceptBitemporalDefaultScope
63
56
  end
64
57
  end
65
-
66
- private
67
- def load_schema!
68
- super
69
-
70
- DEFAULT_ATTRIBUTES.each do |name, default_value|
71
- type = type_for_attribute(name)
72
- define_attribute(name.to_s, type, default: default_value)
73
- end
74
- end
75
58
  end
76
59
 
77
60
  module InstanceMethods
@@ -109,8 +92,8 @@ module ActiveRecord::Bitemporal::Bitemporalize
109
92
  end
110
93
 
111
94
  def valid_from_cannot_be_greater_equal_than_valid_to
112
- if valid_from && valid_to && valid_from >= valid_to
113
- errors.add(:valid_from, "can't be greater equal than valid_to")
95
+ if self[valid_from_key] && self[valid_to_key] && self[valid_from_key] >= self[valid_to_key]
96
+ errors.add(valid_from_key, "can't be greater equal than #{valid_to_key}")
114
97
  end
115
98
  end
116
99
 
@@ -124,10 +107,15 @@ module ActiveRecord::Bitemporal::Bitemporalize
124
107
  def bitemporalize(
125
108
  enable_strict_by_validates_bitemporal_id: false,
126
109
  enable_default_scope: true,
127
- enable_merge_with_except_bitemporal_default_scope: false
110
+ enable_merge_with_except_bitemporal_default_scope: false,
111
+ valid_from_key: :valid_from,
112
+ valid_to_key: :valid_to
128
113
  )
114
+ return if ancestors.include? InstanceMethods
115
+
129
116
  extend ClassMethods
130
117
  include InstanceMethods
118
+ include ActiveRecord::Bitemporal
131
119
  include ActiveRecord::Bitemporal::Scope
132
120
  include ActiveRecord::Bitemporal::Callbacks
133
121
 
@@ -153,14 +141,22 @@ module ActiveRecord::Bitemporal::Bitemporalize
153
141
  @previously_force_updated = false
154
142
  end
155
143
 
144
+ self.class_attribute :valid_from_key, :valid_to_key, instance_writer: false
145
+ self.valid_from_key = valid_from_key.to_s
146
+ self.valid_to_key = valid_to_key.to_s
147
+ attribute valid_from_key, default: ActiveRecord::Bitemporal::DEFAULT_VALID_FROM
148
+ attribute valid_to_key, default: ActiveRecord::Bitemporal::DEFAULT_VALID_TO
149
+ attribute :transaction_from, default: ActiveRecord::Bitemporal::DEFAULT_TRANSACTION_FROM
150
+ attribute :transaction_to, default: ActiveRecord::Bitemporal::DEFAULT_TRANSACTION_TO
151
+
156
152
  # Callback hook to `validates :xxx, uniqueness: true`
157
153
  const_set(:UniquenessValidator, Class.new(ActiveRecord::Validations::UniquenessValidator) {
158
154
  prepend ActiveRecord::Bitemporal::Uniqueness
159
155
  })
160
156
 
161
157
  # validations
162
- validates :valid_from, presence: true
163
- validates :valid_to, presence: true
158
+ validates valid_from_key, presence: true
159
+ validates valid_to_key, presence: true
164
160
  validates :transaction_from, presence: true
165
161
  validates :transaction_to, presence: true
166
162
  validate :valid_from_cannot_be_greater_equal_than_valid_to
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-bitemporal
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.0
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - SmartHR
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-24 00:00:00.000000000 Z
11
+ date: 2025-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '6.1'
19
+ version: '7.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '6.1'
26
+ version: '7.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -129,9 +129,10 @@ executables: []
129
129
  extensions: []
130
130
  extra_rdoc_files: []
131
131
  files:
132
- - ".circleci/config.yml"
133
132
  - ".github/auto_assign.yml"
133
+ - ".github/dependabot.yml"
134
134
  - ".github/workflows/release.yml"
135
+ - ".github/workflows/test.yml"
135
136
  - ".gitignore"
136
137
  - Appraisals
137
138
  - CHANGELOG.md
@@ -144,10 +145,10 @@ files:
144
145
  - activerecord-bitemporal.gemspec
145
146
  - bin/console
146
147
  - bin/setup
147
- - docker-compose.yml
148
- - gemfiles/rails_6.1.gemfile
148
+ - compose.yml
149
149
  - gemfiles/rails_7.0.gemfile
150
150
  - gemfiles/rails_7.1.gemfile
151
+ - gemfiles/rails_7.2.gemfile
151
152
  - lib/activerecord-bitemporal.rb
152
153
  - lib/activerecord-bitemporal/bitemporal.rb
153
154
  - lib/activerecord-bitemporal/callbacks.rb
@@ -160,7 +161,7 @@ homepage: https://github.com/kufu/activerecord-bitemporal
160
161
  licenses:
161
162
  - Apache 2.0
162
163
  metadata: {}
163
- post_install_message:
164
+ post_install_message:
164
165
  rdoc_options: []
165
166
  require_paths:
166
167
  - lib
@@ -168,7 +169,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
168
169
  requirements:
169
170
  - - ">="
170
171
  - !ruby/object:Gem::Version
171
- version: '3.0'
172
+ version: '3.1'
172
173
  required_rubygems_version: !ruby/object:Gem::Requirement
173
174
  requirements:
174
175
  - - ">="
@@ -176,7 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
176
177
  version: '0'
177
178
  requirements: []
178
179
  rubygems_version: 3.3.27
179
- signing_key:
180
+ signing_key:
180
181
  specification_version: 4
181
182
  summary: BiTemporal Data Model for ActiveRecord
182
183
  test_files: []
data/.circleci/config.yml DELETED
@@ -1,40 +0,0 @@
1
- version: 2.1
2
-
3
- jobs:
4
- rspec:
5
- parameters:
6
- ruby-version:
7
- type: string
8
- gemfile:
9
- type: string
10
- docker:
11
- - image: ruby:<< parameters.ruby-version >>
12
- environment:
13
- BUNDLE_GEMFILE: gemfiles/<< parameters.gemfile >>.gemfile
14
- - image: cimg/postgres:11.16
15
- steps:
16
- - checkout
17
- - run: gem install bundler
18
- - run: bundle install
19
- - run: bundle exec rspec
20
-
21
- workflows:
22
- test:
23
- jobs:
24
- - rspec:
25
- matrix:
26
- parameters:
27
- ruby-version:
28
- - '3.0'
29
- - '3.1'
30
- - '3.2'
31
- - '3.3'
32
- gemfile:
33
- - rails_6.1
34
- - rails_7.0
35
- - rails_7.1
36
- exclude:
37
- - ruby-version: '3.2'
38
- gemfile: rails_6.1
39
- - ruby-version: '3.3'
40
- gemfile: rails_6.1