temporal_tables 0.7.1 → 1.0.2

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +53 -0
  3. data/.rubocop.yml +158 -0
  4. data/.ruby-version +1 -1
  5. data/.travis.yml +5 -7
  6. data/Gemfile +2 -0
  7. data/README.md +15 -5
  8. data/Rakefile +7 -2
  9. data/config.ru +2 -0
  10. data/gemfiles/Gemfile.6.0.mysql.lock +84 -84
  11. data/gemfiles/Gemfile.6.0.pg.lock +103 -98
  12. data/gemfiles/Gemfile.6.1.mysql.lock +180 -0
  13. data/gemfiles/Gemfile.6.1.pg.lock +180 -0
  14. data/gemfiles/{Gemfile.5.1.mysql → Gemfile.7.0.mysql} +2 -2
  15. data/gemfiles/Gemfile.7.0.mysql.lock +173 -0
  16. data/gemfiles/{Gemfile.5.2.pg → Gemfile.7.0.pg} +1 -1
  17. data/gemfiles/Gemfile.7.0.pg.lock +173 -0
  18. data/lib/temporal_tables/arel_table.rb +10 -9
  19. data/lib/temporal_tables/association_extensions.rb +2 -0
  20. data/lib/temporal_tables/connection_adapters/mysql_adapter.rb +8 -3
  21. data/lib/temporal_tables/connection_adapters/postgresql_adapter.rb +5 -3
  22. data/lib/temporal_tables/history_hook.rb +8 -5
  23. data/lib/temporal_tables/preloader_extensions.rb +2 -0
  24. data/lib/temporal_tables/reflection_extensions.rb +11 -14
  25. data/lib/temporal_tables/relation_extensions.rb +11 -24
  26. data/lib/temporal_tables/temporal_adapter.rb +93 -97
  27. data/lib/temporal_tables/temporal_adapter_six_oh.rb +187 -0
  28. data/lib/temporal_tables/temporal_class.rb +29 -28
  29. data/lib/temporal_tables/version.rb +3 -1
  30. data/lib/temporal_tables/whodunnit.rb +5 -3
  31. data/lib/temporal_tables.rb +48 -33
  32. data/spec/basic_history_spec.rb +65 -35
  33. data/spec/internal/app/models/broom.rb +2 -0
  34. data/spec/internal/app/models/cat.rb +5 -0
  35. data/spec/internal/app/models/cat_life.rb +5 -0
  36. data/spec/internal/app/models/coven.rb +2 -0
  37. data/spec/internal/app/models/flying_machine.rb +2 -0
  38. data/spec/internal/app/models/person.rb +2 -0
  39. data/spec/internal/app/models/rocket_broom.rb +2 -0
  40. data/spec/internal/app/models/wart.rb +3 -1
  41. data/spec/internal/config/database.ci.yml +12 -0
  42. data/spec/internal/db/schema.rb +28 -5
  43. data/spec/spec_helper.rb +39 -5
  44. data/spec/support/database.rb +10 -6
  45. data/temporal_tables.gemspec +31 -18
  46. metadata +108 -39
  47. data/CHANGELOG.md +0 -73
  48. data/gemfiles/Gemfile.5.0.mysql +0 -16
  49. data/gemfiles/Gemfile.5.0.mysql.lock +0 -147
  50. data/gemfiles/Gemfile.5.0.pg +0 -16
  51. data/gemfiles/Gemfile.5.0.pg.lock +0 -147
  52. data/gemfiles/Gemfile.5.1.mysql.lock +0 -147
  53. data/gemfiles/Gemfile.5.1.pg +0 -16
  54. data/gemfiles/Gemfile.5.1.pg.lock +0 -147
  55. data/gemfiles/Gemfile.5.2.mysql +0 -16
  56. data/gemfiles/Gemfile.5.2.mysql.lock +0 -155
  57. data/gemfiles/Gemfile.5.2.pg.lock +0 -155
  58. data/lib/temporal_tables/join_extensions.rb +0 -20
  59. data/spec/extensions/combustion.rb +0 -9
  60. data/spec/internal/config/routes.rb +0 -3
@@ -1,67 +1,82 @@
1
- require "temporal_tables/temporal_adapter"
2
- require "temporal_tables/connection_adapters/mysql_adapter"
3
- require "temporal_tables/connection_adapters/postgresql_adapter"
4
- require "temporal_tables/whodunnit"
5
- require "temporal_tables/temporal_class"
6
- require "temporal_tables/history_hook"
7
- require "temporal_tables/relation_extensions"
8
- require "temporal_tables/association_extensions"
9
- require "temporal_tables/join_extensions"
10
- require "temporal_tables/preloader_extensions"
11
- require "temporal_tables/reflection_extensions"
12
- require "temporal_tables/arel_table"
13
- require "temporal_tables/version"
1
+ # frozen_string_literal: true
2
+
3
+ require 'temporal_tables/temporal_adapter'
4
+ require 'temporal_tables/temporal_adapter_six_oh'
5
+ require 'temporal_tables/connection_adapters/mysql_adapter'
6
+ require 'temporal_tables/connection_adapters/postgresql_adapter'
7
+ require 'temporal_tables/whodunnit'
8
+ require 'temporal_tables/temporal_class'
9
+ require 'temporal_tables/history_hook'
10
+ require 'temporal_tables/relation_extensions'
11
+ require 'temporal_tables/association_extensions'
12
+ require 'temporal_tables/preloader_extensions'
13
+ require 'temporal_tables/reflection_extensions'
14
+ require 'temporal_tables/arel_table'
15
+ require 'temporal_tables/version'
14
16
 
15
17
  module TemporalTables
16
18
  class Railtie < ::Rails::Railtie
17
- initializer "temporal_tables.load" do
19
+ initializer 'temporal_tables.load' do
18
20
  # Iterating the subclasses will find any adapter implementations
19
21
  # which are in use by the rails app, and mixin the temporal functionality.
20
22
  # It's necessary to do this on the implementations in order for the
21
23
  # alias method chain hooks to work.
22
24
  ActiveRecord::ConnectionAdapters::AbstractAdapter.subclasses.each do |subclass|
23
- subclass.send :prepend, TemporalTables::TemporalAdapter
25
+ if ActiveRecord.version < ::Gem::Version.new('6.1')
26
+ subclass.send :prepend, TemporalTables::TemporalAdapterSixOh
27
+ else
28
+ subclass.send :prepend, TemporalTables::TemporalAdapter
29
+ end
30
+
31
+ module_name = subclass.name.split('::').last
32
+ next unless TemporalTables::ConnectionAdapters.const_defined?(module_name)
24
33
 
25
- module_name = subclass.name.split("::").last
26
- subclass.send :prepend, TemporalTables::ConnectionAdapters.const_get(module_name) if TemporalTables::ConnectionAdapters.const_defined?(module_name)
34
+ subclass.send(
35
+ :prepend,
36
+ TemporalTables::ConnectionAdapters.const_get(module_name)
37
+ )
27
38
  end
28
39
 
29
- ActiveRecord::Base.send :include, TemporalTables::Whodunnit
40
+ ActiveRecord::Base.include TemporalTables::Whodunnit
30
41
  end
31
42
  end
32
43
 
33
- @@create_by_default = false
44
+ @create_by_default = false
34
45
  def self.create_by_default
35
- @@create_by_default
46
+ @create_by_default
36
47
  end
48
+
37
49
  def self.create_by_default=(default)
38
- @@create_by_default = default
50
+ @create_by_default = default
39
51
  end
40
52
 
41
- @@skipped_temporal_tables = [:schema_migrations, :sessions, :ar_internal_metadata]
53
+ @skipped_temporal_tables = [:schema_migrations, :sessions, :ar_internal_metadata]
42
54
  def self.skip_temporal_table_for(*tables)
43
- @@skipped_temporal_tables += tables
55
+ @skipped_temporal_tables += tables
44
56
  end
57
+
45
58
  def self.skipped_temporal_tables
46
- @@skipped_temporal_tables.dup
59
+ @skipped_temporal_tables.dup
47
60
  end
48
61
 
49
- @@add_updated_by_field = false
50
- @@updated_by_type = :string
51
- @@updated_by_proc = nil
62
+ @add_updated_by_field = false
63
+ @updated_by_type = :string
64
+ @updated_by_proc = nil
52
65
  def self.updated_by_type
53
- @@updated_by_type
66
+ @updated_by_type
54
67
  end
68
+
55
69
  def self.updated_by_proc
56
- @@updated_by_proc
70
+ @updated_by_proc
57
71
  end
72
+
58
73
  def self.add_updated_by_field(type = :string, &block)
59
74
  if block_given?
60
- @@add_updated_by_field = true
61
- @@updated_by_type = type
62
- @@updated_by_proc = block
75
+ @add_updated_by_field = true
76
+ @updated_by_type = type
77
+ @updated_by_proc = block
63
78
  end
64
79
 
65
- @@add_updated_by_field
80
+ @add_updated_by_field
66
81
  end
67
82
  end
@@ -1,66 +1,68 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Person do
4
- let(:emily) { Person.create name: "Emily" }
6
+ let(:emily) { Person.create name: 'Emily' }
5
7
  let(:historical_emily) { emily.history.last }
6
8
 
7
9
  before do
8
10
  emily
9
- @init_time = Time.now
11
+ @init_time = Time.zone.now
10
12
  sleep 0.1
11
13
  end
12
14
 
13
- describe "upon making significant life changes" do
14
- let!(:coven) { Coven.create name: "Double Double Toil & Trouble" }
15
+ describe 'upon making significant life changes' do
16
+ let!(:coven) { Coven.create name: 'Double Double Toil & Trouble' }
15
17
  let!(:wart) { Wart.create person: emily, hairiness: 3 }
16
18
 
17
19
  before do
18
- emily.update name: "Grunthilda", coven: coven
20
+ emily.update name: 'Grunthilda', coven: coven
19
21
  sleep 0.1
20
22
  end
21
23
 
22
- describe "when affirming changes" do
23
- it "should have new name" do
24
- expect(emily.name).to eq("Grunthilda")
25
- expect(historical_emily.name).to eq("Grunthilda")
24
+ describe 'when affirming changes' do
25
+ it 'should have new name' do
26
+ expect(emily.name).to eq('Grunthilda')
27
+ expect(historical_emily.name).to eq('Grunthilda')
26
28
  end
27
29
 
28
- it "should belong to coven" do
30
+ it 'should belong to coven' do
29
31
  expect(emily.coven.name).to eq(coven.name)
30
32
  expect(historical_emily.coven.name).to eq(coven.name)
31
33
  end
32
34
 
33
- it "should have a wart" do
35
+ it 'should have a wart' do
34
36
  expect(emily.warts).to eq([wart])
35
- expect(emily.history.at(Time.now).last.warts).to eq([wart.history.last])
37
+ expect(emily.history.at(Time.zone.now).last.warts).to eq([wart.history.last])
36
38
  end
37
39
 
38
- it "should allow scopes on associations" do
40
+ it 'should allow scopes on associations' do
39
41
  expect(emily.warts.very_hairy).to eq([wart])
40
42
  expect(historical_emily.warts.very_hairy).to eq([wart.history.last])
41
43
  end
42
44
 
43
- it "should allow at value on class too" do
44
- expect(Wart.history.at(Time.now).where(person: emily).count).to eq(1)
45
+ it 'should allow at value on class too' do
46
+ expect(Wart.history.at(Time.zone.now).where(person: emily).count).to eq(1)
45
47
  expect(Wart.history.at(1.minute.ago).where(person: emily).count).to eq(0)
46
48
  end
47
49
  end
48
50
 
49
- describe "when reflecting on the past" do
51
+ describe 'when reflecting on the past' do
50
52
  let(:orig_emily) { emily.history.at(@init_time).last }
51
53
 
52
- it "should have historical name" do
53
- expect(orig_emily.name).to eq("Emily")
54
+ it 'should have historical name' do
55
+ expect(orig_emily.name).to eq('Emily')
54
56
  expect(orig_emily.at_value).to eq(@init_time)
55
57
  end
56
58
 
57
- it "should not belong to a coven or have warts" do
59
+ it 'should not belong to a coven or have warts' do
58
60
  expect(orig_emily.coven).to eq(nil)
59
61
  expect(orig_emily.warts.count).to eq(0)
60
62
  end
61
63
  end
62
64
 
63
- describe "when preloading associations" do
65
+ describe 'when preloading associations' do
64
66
  let(:orig_emily) { emily.history.at(@init_time).preload(:warts).first }
65
67
 
66
68
  it 'should preload the correct time' do
@@ -68,7 +70,7 @@ describe Person do
68
70
  end
69
71
  end
70
72
 
71
- describe "when eager_loading associations" do
73
+ describe 'when eager_loading associations' do
72
74
  let(:orig_emily) { emily.history.at(@init_time).eager_load(:warts).first }
73
75
 
74
76
  it 'should include the correct time' do
@@ -76,7 +78,14 @@ describe Person do
76
78
  end
77
79
 
78
80
  it 'should generate sensible sql' do
79
- sql = emily.history.at(@init_time).eager_load(:warts).where(Wart.history.arel_table[:hairiness].gteq(2)).to_sql.split(/(FROM)|(WHERE)|(ORDER)/)
81
+ sql =
82
+ emily
83
+ .history
84
+ .at(@init_time)
85
+ .eager_load(:warts)
86
+ .where(Wart.history.arel_table[:hairiness].gteq(2))
87
+ .to_sql
88
+ .split(/(FROM)|(WHERE)|(ORDER)/)
80
89
  from = sql[2]
81
90
  where = sql[4]
82
91
 
@@ -90,15 +99,15 @@ describe Person do
90
99
  end
91
100
  end
92
101
 
93
- describe "when checking simple code values" do
94
- it "should have correct class names" do
95
- expect(emily.class.name).to eq("Person")
96
- expect(historical_emily.class.name).to eq("PersonHistory")
102
+ describe 'when checking simple code values' do
103
+ it 'should have correct class names' do
104
+ expect(emily.class.name).to eq('Person')
105
+ expect(historical_emily.class.name).to eq('PersonHistory')
97
106
 
98
107
  expect(Person.history).to eq(PersonHistory)
99
108
  end
100
109
 
101
- it "should have correct class hierarchies" do
110
+ it 'should have correct class hierarchies' do
102
111
  expect(emily.is_a?(Person)).to eq(true)
103
112
  expect(emily.is_a?(PersonHistory)).to eq(false)
104
113
 
@@ -107,8 +116,8 @@ describe Person do
107
116
  end
108
117
  end
109
118
 
110
- describe "when checking current state" do
111
- it "should have correct information" do
119
+ describe 'when checking current state' do
120
+ it 'should have correct information' do
112
121
  # ie. we shouldn't break regular ActiveRecord behaviour
113
122
  expect(Person.count).to eq(1)
114
123
  expect(Wart.count).to eq(1)
@@ -123,20 +132,41 @@ describe Person do
123
132
  end
124
133
  end
125
134
 
126
- describe "when working with STI one level deep" do
127
- let!(:broom) { Broom.create person: emily, model: "Cackler 2000" }
135
+ describe 'when working with STI one level deep' do
136
+ let!(:broom) { Broom.create person: emily, model: 'Cackler 2000' }
128
137
 
129
- it "should initialize model correctly" do
138
+ it 'should initialize model correctly' do
130
139
  expect(emily.history.last.flying_machines).to eq([broom.history.last])
131
140
  end
132
141
  end
133
142
 
134
- describe "when working with STI two levels deep" do
135
- let!(:rocket_broom) { RocketBroom.create person: emily, model: "Pyrocackler 3000X" }
143
+ describe 'when working with STI two levels deep' do
144
+ let!(:rocket_broom) { RocketBroom.create person: emily, model: 'Pyrocackler 3000X' }
136
145
 
137
- it "should initialize model correctly" do
146
+ it 'should initialize model correctly' do
138
147
  expect(emily.history.last.flying_machines).to eq([rocket_broom.history.last])
139
148
  end
140
149
  end
141
150
  end
151
+
152
+ # The following only tests non-integer ids for postgres (see schema.rb)
153
+ describe 'when spawning and aging a creature with a non-integer id' do
154
+ let!(:cat) { Cat.create name: 'Mr. Mittens', color: 'black' }
155
+
156
+ before do
157
+ cat.lives.create started_at: 3.years.ago
158
+ @init_time = Time.zone.now
159
+ cat.update name: 'Old Mr. Mittens'
160
+ cat.lives.first.update ended_at: Time.zone.now, death_reason: 'fell into cauldron'
161
+ cat.lives.create started_at: Time.zone.now
162
+ end
163
+
164
+ it 'shows one life at the beginning' do
165
+ expect(cat.history.at(@init_time).last.lives.size).to eq(1)
166
+ end
167
+
168
+ it 'shows two lives at the end' do
169
+ expect(cat.history.last.lives.size).to eq(2)
170
+ end
171
+ end
142
172
  end
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Broom < FlyingMachine
2
4
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Cat < ActiveRecord::Base
4
+ has_many :lives, class_name: 'CatLife'
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CatLife < ActiveRecord::Base
4
+ belongs_to :cat
5
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Coven < ActiveRecord::Base
2
4
  has_many :people
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class FlyingMachine < ActiveRecord::Base
2
4
  belongs_to :person
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Person < ActiveRecord::Base
2
4
  belongs_to :coven
3
5
  has_many :warts
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class RocketBroom < Broom
2
4
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Wart < ActiveRecord::Base
2
4
  belongs_to :person
3
5
 
4
- scope :very_hairy, -> {
6
+ scope :very_hairy, lambda {
5
7
  where(arel_table[:hairiness].gteq(3))
6
8
  }
7
9
  end
@@ -0,0 +1,12 @@
1
+ mysql:
2
+ adapter: mysql2
3
+ database: temporal_tables_test
4
+ host: 127.0.0.1
5
+ username: root
6
+ password: password
7
+
8
+ postgresql:
9
+ adapter: postgresql
10
+ database: temporal_tables_test
11
+ user: postgres
12
+ password:
@@ -1,22 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ postgres = ActiveRecord::Base.connection.instance_of?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
5
+ rescue NameError
6
+ postgres = false
7
+ end
8
+
1
9
  ActiveRecord::Schema.define do
2
- create_table :people, temporal: true, force: true do |t|
3
- t.belongs_to :coven
4
- t.string :name
5
- end
10
+ enable_extension 'pgcrypto' if postgres
6
11
 
7
12
  create_table :covens, force: true do |t|
8
13
  t.string :name
9
14
  end
10
15
  add_temporal_table :covens
11
16
 
17
+ create_table :people, temporal: true, force: true do |t|
18
+ t.belongs_to :coven
19
+ t.string :name
20
+ end
21
+ add_index :people, :name, unique: true
22
+
12
23
  create_table :warts, temporal: true, force: true do |t|
13
24
  t.belongs_to :person
14
- t.integer :hairiness
15
25
  end
26
+ add_column :warts, :hairiness, :integer
16
27
 
17
28
  create_table :flying_machines, temporal: true, force: true do |t|
18
29
  t.belongs_to :person
19
30
  t.string :type
20
31
  t.string :model
21
32
  end
33
+
34
+ create_table :cats, id: (postgres ? :uuid : :integer), temporal: true, force: true do |t|
35
+ t.string :name
36
+ t.string :color
37
+ end
38
+
39
+ create_table :cat_lives, id: (postgres ? :uuid : :integer), temporal: true do |t|
40
+ t.belongs_to :cat, type: (postgres ? :uuid : :integer)
41
+ t.timestamp :started_at
42
+ t.timestamp :ended_at
43
+ t.string :death_reason
44
+ end
22
45
  end
data/spec/spec_helper.rb CHANGED
@@ -1,14 +1,48 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gemika'
2
4
  require 'combustion'
5
+ require 'yaml'
3
6
 
4
- Dir["#{File.dirname(__FILE__)}/extensions/*.rb"].sort.each {|f| require f}
5
- Dir["#{File.dirname(__FILE__)}/support/*.rb"].sort.each {|f| require f}
7
+ Dir["#{File.dirname(__FILE__)}/extensions/*.rb"].sort.each { |f| require f }
8
+ Dir["#{File.dirname(__FILE__)}/support/*.rb"].sort.each { |f| require f }
9
+ READ_DATABASE_CONFIG_LOCATION = 'spec/internal/config/database.ci.yml'
10
+ WRITE_DATABASE_CONFIG_LOCATION = 'spec/internal/config/database.yml'
6
11
 
7
- Combustion.initialize! :active_record do
8
- Rails.env = TemporalTables::DatabaseAdapter.adapter_name
12
+ def adapter_name
13
+ if Gemika::Env.gem?('mysql2')
14
+ 'mysql'
15
+ else
16
+ 'postgresql'
17
+ end
9
18
  end
10
19
 
11
- DatabaseCleaner.strategy = :deletion
20
+ def database_config_from_gems(file_location)
21
+ config = YAML.load_file(file_location)
22
+ data = config.slice(adapter_name)
23
+ { Rails.env.to_s => data }
24
+ end
25
+
26
+ original_env = Rails.env
27
+
28
+ puts database_config_from_gems(READ_DATABASE_CONFIG_LOCATION)
29
+ File.write(
30
+ WRITE_DATABASE_CONFIG_LOCATION,
31
+ database_config_from_gems(READ_DATABASE_CONFIG_LOCATION).to_yaml
32
+ )
33
+
34
+ Rails.env = adapter_name
35
+ database = Gemika::Database.new
36
+ database.connect
37
+
38
+ Gemika::RSpec.configure_clean_database_before_example
39
+ Rails.env = original_env
40
+
41
+ begin
42
+ Combustion.initialize! :active_record
43
+ rescue ActiveRecord::RecordNotUnique
44
+ # noop
45
+ end
12
46
 
13
47
  RSpec.configure do |config|
14
48
  config.before(:each) do
@@ -1,9 +1,13 @@
1
- module TemporalTables::DatabaseAdapter
2
- def self.adapter_name
3
- if Gemika::Env.gem?('pg')
4
- "postgresql"
5
- elsif Gemika::Env.gem?('mysql2')
6
- "mysql"
1
+ # frozen_string_literal: true
2
+
3
+ module TemporalTables
4
+ module DatabaseAdapter
5
+ def self.adapter_name
6
+ if Gemika::Env.gem?('pg')
7
+ 'postgresql'
8
+ elsif Gemika::Env.gem?('mysql2')
9
+ 'mysql'
10
+ end
7
11
  end
8
12
  end
9
13
  end
@@ -1,24 +1,37 @@
1
- # -*- encoding: utf-8 -*-
2
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ require 'English'
4
+ lib = File.expand_path('lib', __dir__)
3
5
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
6
  require 'temporal_tables/version'
5
7
 
6
- Gem::Specification.new do |gem|
7
- gem.name = "temporal_tables"
8
- gem.version = TemporalTables::VERSION
9
- gem.authors = ["Brent Kroeker"]
10
- gem.email = ["brent@bkroeker.com"]
11
- gem.description = %q{Easily recall what your data looked like at any point in the past! TemporalTables sets up and maintains history tables to track all temporal changes to to your data.}
12
- gem.summary = %q{Tracks all history of changes to a table automatically in a history table.}
13
- gem.homepage = ""
8
+ Gem::Specification.new do |gem| # rubocop:disable Metrics/BlockLength
9
+ gem.name = 'temporal_tables'
10
+ gem.version = TemporalTables::VERSION
11
+ gem.authors = ['Brent Kroeker']
12
+ gem.email = ['brent@bkroeker.com']
13
+ gem.description = <<-DESC
14
+ Easily recall what your data looked like at any point in the past!
15
+ TemporalTables sets up and maintains history tables to track all temporal changes to to your data.
16
+ DESC
17
+ gem.summary = 'Tracks all history of changes to a table automatically in a history table.'
18
+ gem.homepage = ''
14
19
 
15
- gem.files = `git ls-files`.split($/)
16
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
- gem.require_paths = ["lib"]
20
+ gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
21
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
22
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
23
+ gem.require_paths = ['lib']
24
+ gem.required_ruby_version = '>= 2.5.0'
25
+ gem.metadata = { 'rubygems_mfa_required' => 'true' }
19
26
 
20
- gem.add_dependency "rails", ">= 5.0", "< 6.1"
21
- gem.add_development_dependency "rspec", "~> 3.4"
22
- gem.add_development_dependency "combustion", "~> 0.9.1"
23
- gem.add_development_dependency "gemika"
27
+ gem.add_dependency 'rails', '>= 6.0', '< 7.1'
28
+ gem.add_development_dependency 'combustion', '~> 1'
29
+ gem.add_development_dependency 'database_cleaner'
30
+ gem.add_development_dependency 'gemika', '~> 0.6'
31
+ gem.add_development_dependency 'mysql2'
32
+ gem.add_development_dependency 'pg'
33
+ gem.add_development_dependency 'pry'
34
+ gem.add_development_dependency 'rspec', '~> 3.4'
35
+ gem.add_development_dependency 'rubocop'
36
+ gem.metadata['rubygems_mfa_required'] = 'true'
24
37
  end