transient_record 1.0.0 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +35 -18
  3. data/lib/transient_record.rb +147 -108
  4. metadata +19 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9567dc6a94b5693ba7522664172ec95257734f81820307ed705d1a8a55323aef
4
- data.tar.gz: 82833fbb5361c27361347d89b38fb709a102fa5be820be30710a5b1debc061de
3
+ metadata.gz: 5307d695a68a4250343b0cb8866055f626153fcebde0f0bf69213ef791c777e1
4
+ data.tar.gz: 8b0185a7d93b93c179ccf69dc8cc497a4012f9dca66e1bf3d90decddf2375963
5
5
  SHA512:
6
- metadata.gz: 2a5ce0b5c9859a9e88ee78b119891cbc8f2daaa930db25a52fb14a6e93723d1d91e850a67f99fd70b8c1ccda80a52f206bb83a529f8cd52e1e11c9e9fe89c657
7
- data.tar.gz: 3c64275220d6138377788c9e294b3f67f5285801ac977e03933489a65654604248a757feeca210cd7b642c01d08941e534d510f9814c252d1d5e8885b298f4d7
6
+ metadata.gz: 43af400d4dccdfeebd0d5a01c7d7631fb2e43b00453b76fafd7e2e0f2f41bea66b0aa4abdbf057a3139d7dd06d903e5f54ba90c02994f7e44b9449a205729013
7
+ data.tar.gz: 3c84c3764e9b8c65c1703062b6f1e4ce4a60d89823f6472a9d20ac7b6157073bb3b8082304597f01617c87e084ca361fd5407546b3d9ddecd0796d8120a8d5ad
data/README.md CHANGED
@@ -16,22 +16,19 @@ Installing Transient Record is a two-step process.
16
16
  You can include Transient Record in your `Gemfile`:
17
17
 
18
18
  ```ruby
19
+ # Add the following to use the most recent release:
19
20
  gem "transient_record", group: :test
21
+
22
+ # Alternatively, you can use the most recent development version:
23
+ gem "transient_record", github: "gregnavis/transient_record", group: :test
20
24
  ```
21
25
 
26
+ Don't forget to run `bundle install`.
27
+
22
28
  The above assumes it'll be used for testing purposes only, hence the `test`
23
29
  group. However, if you intend to use the gem in other circumstances then you may
24
30
  need to adjust the group accordingly.
25
31
 
26
- If you'd like to use the latest development release then use the line below
27
- instead:
28
-
29
- ```ruby
30
- gem "transient_record", github: "gregnavis/transient_record", group: :test
31
- ```
32
-
33
- After modifying `Gemfile`, run `bundle install`.
34
-
35
32
  ### Step 2: Integrating with the Test Suite
36
33
 
37
34
  After installing the gem, Transient Record must be integrated with the test
@@ -39,6 +36,9 @@ suite. `TransientRecord.cleanup` must be called around every test case: before
39
36
  (to prepare a clean database state for the test case) and after (to leave the
40
37
  database in a clean state).
41
38
 
39
+ **Transient Record is not prepared to work with parallel test suites, so ensure
40
+ tests that use it run sequentially.**
41
+
42
42
  The snippet below demonstrates integrations with various testing libraries:
43
43
 
44
44
  ```ruby
@@ -79,7 +79,24 @@ end
79
79
  ## Usage
80
80
 
81
81
  Transient Record can be used to create temporary tables and, optionally, models
82
- backed by them.
82
+ backed by them. First, you need to define a Transient Record **context**.
83
+
84
+ A context is a module associated to a specific Active Record base class (like
85
+ `ActiveRecord::Base` or `ApplicationRecord`) that's used to connect to the
86
+ database and as a base class for transient models. Contexts are needed to
87
+ support multiple databases, as Active Record organizes database connections
88
+ around base classes. Consult [the Rails Guides](https://guides.rubyonrails.org/active_record_multiple_databases.html#setting-up-your-application) to learn more
89
+ about using Active Record with multiple databases.
90
+
91
+ **If you connect to only one database then you need just one context for
92
+ `ActiveRecord::Base`**.
93
+
94
+ A context is a Ruby module used to define transient tables and models. Here's
95
+ how a context for `ActiveRecord::Base` can be defined:
96
+
97
+ ```ruby
98
+ Primary = TransientRecord.context_for ActiveRecord::Base
99
+ ```
83
100
 
84
101
  A table can be created by calling `create_table`: a thin wrapper around the
85
102
  method of the same name in Active Record. The only difference is the method
@@ -87,10 +104,11 @@ in Transient Record implemented a fluent interface that allows calling
87
104
  `define_model` on the return value.
88
105
 
89
106
  For example, the statement below creates a table named `users` with two one
90
- string column `name` and one integer column `age`:
107
+ string column `name` and one integer column `age` using the `Primary` context
108
+ introduced above:
91
109
 
92
110
  ```ruby
93
- create_table :users do |t|
111
+ Primary.create_table :users do |t|
94
112
  t.string :name, null: false
95
113
  t.integer :age, null: false
96
114
  end
@@ -101,18 +119,18 @@ for details.
101
119
 
102
120
  In order to define a model backed by that table `define_model` can be called
103
121
  **on the return value** of `create_table` with a block containing the model
104
- class body. For example, to define
122
+ class body. For example, to define
105
123
 
106
124
  ```ruby
107
- create_table :users do |t|
125
+ Primary.create_table :users do |t|
108
126
  # ...
109
127
  end.define_model do
110
128
  validates :email, presence: true
111
129
  end
112
130
  ```
113
131
 
114
- Models are automatically assigned to constants in `TransientRecord::Models`. The
115
- example above creates `TransientRecord::Models::User`, and is equivalent to:
132
+ Models are automatically assigned to constants. In the example above, the user
133
+ model is assigned to `Primary::User` via code roughly equivalent to:
116
134
 
117
135
  ```ruby
118
136
  class TransientRecord::Models::User < ActiveRecord::Base
@@ -129,8 +147,7 @@ reason it was decided to use regular tables with an explicit cleanup step.
129
147
 
130
148
  Transient Record may not work properly in parallelized test suites, e.g. if two
131
149
  test workers attempt to create a table with the same name then it's likely to
132
- result in an error. Full support for parallelism **is** on the roadmap, so feel
133
- free to report any errors and contribute updates.
150
+ result in an error.
134
151
 
135
152
  ## Author
136
153
 
@@ -2,80 +2,127 @@
2
2
 
3
3
  # Transient Record helps define transient tables and Active Record models.
4
4
  #
5
- # Defining a transient table and model is a two-step process:
5
+ # It's essential to understand Transient Record Contexts in order to use the
6
+ # library effectively. Let's start the discussion with how Active Record handles
7
+ # connections.
6
8
  #
7
- # 1. {#create_table} to create the table.
8
- # 2. {#define_model} to define the model.
9
+ # Active Record organizes connection pools around classes. Connecting to
10
+ # multiple databases requires defining multiple abstract classes. For example:
11
+ #
12
+ # class ApplicationRecord < ActiveRecord::Base
13
+ # end
14
+ #
15
+ # class AnalyticsRecord < ApplicationRecord
16
+ # self.abstract_class = true
17
+ #
18
+ # connects_to database: { writing: :analytics }
19
+ # end
20
+ #
21
+ # In this case, +ApplicationRecord.connection+ returns a connection to the
22
+ # primary database and +AnalyticsRecord.connection+ returns a connection to the
23
+ # other database.
24
+ #
25
+ # A context is related to an Active Record base class that's used to access the
26
+ # database directly and to define transient models. After defining an Active
27
+ # Record base class, a context can be created by calling {.context_for} and
28
+ # **must** be assigned to a constant.
29
+ #
30
+ # After the context is created, you can create tables and models by calling
31
+ # {Context#create_table} and {Context#define_model}. When you're done, call
32
+ # {.cleanup} to drop all transient tables and models
33
+ #
34
+ # @example Creating a table and a model
35
+ # # Define the context for classes using ActiveRecord::Base to connect. It's
36
+ # # a constant defined outside of the test suite.
37
+ # Primary = TransientRecord.context_for ActiveRecord::Base
9
38
  #
10
- # @example Creating a table without a model
11
39
  # # #create_table is a wrapper around #create_table in Active Record, and
12
40
  # # works almost exactly like the that method.
13
- # TransientRecord.create_table :users do |t|
14
- # t.string :email, null: false
15
- # end
16
- #
17
- # @example Creating a table and a model using fluent interface
18
- # # The difference between #create_table and its Active Record counterpart is
19
- # # the return value: Transient Record allows calling #define_model on it.
20
- # TransientRecord.create_table :users do |t|
41
+ # Primary.create_table :users do |t|
21
42
  # t.string :email, null: false
22
43
  # end.define_model do
23
44
  # validates :email, presence: true
24
45
  # end
25
46
  #
26
- # # The transient model can be referenced via TransientRecord::Models::User.
27
- # # For example, a new user instance can be instantiated via:
28
- # user = TransientRecord::Models::User.new email: nil
47
+ # # Instantiate the model
48
+ # user = Primary::User.new email: nil
49
+ #
50
+ # # Clean up when done.
51
+ # TransientRecord.cleanup
29
52
  #
30
- # @example Creating a table and a model with regular interface
31
- # # Assuming the users table has been created (using Transient Record or
32
- # # another method), a User model can be defined via:
33
- # TransientRecord.define_model :User do
53
+ # @example Defining a model for a pre-existing table
54
+ # Primary = TransientRecord.context_for ActiveRecord::Base
55
+ #
56
+ # Primary.define_model :User do
34
57
  # validates :email, presence: true
35
58
  # end
36
- module TransientRecord
59
+ #
60
+ # user = Primary::User.new email: nil
61
+ #
62
+ # @example Creating a table and a model in another database
63
+ # #
64
+ # Analytics = TransientRecord.context_for AnalyticsRecord
65
+ #
66
+ # Analytics.create_table :events do |t|
67
+ # # ...
68
+ # end.define_model do
69
+ # # ...
70
+ # end
71
+ #
72
+ # event = Analytics::Event.new
73
+ class TransientRecord
37
74
  # Transient Record version number.
38
- VERSION = "1.0.0"
75
+ VERSION = "2.0.0.rc1"
39
76
 
40
- # A module where all temporary models are defined.
41
- #
42
- # Models defined via {TransientRecord.define_model}, {TransientRecord#define_model}
43
- # or {ModelDefinitionProxy#define_model} are put here in order to avoid
44
- # polluting the top-level namespace, potentially conflicting with identically
45
- # named constants defined elsewhere.
46
- #
47
- # @example
48
- # # If a transient users table and its corresponding User model are defined then ...
49
- # TransientRecord.create_table :users do |t|
50
- # t.string :email, null: false
51
- # end.define_model do
52
- # validates :email, presence: true
53
- # end
54
- #
55
- # # ... the user model can be referenced via:
56
- # TransientRecord::Models::User
57
- module Models
58
- # Remove all constants from the module.
77
+ # A class representing Transient Record errors.
78
+ class Error < RuntimeError; end
79
+
80
+ # A mapping of Active Record base classes to TransientRecord::Contexts.
81
+ @contexts = {}
82
+
83
+ class << self
84
+ # Creates a namespace for tables and models corresponding to the given base
85
+ # class.
59
86
  #
60
- # This method is used by {TransientRecord.cleanup} to undefine temporary
61
- # model classes.
87
+ # Active Record sets up connection pools for abstract Active Record model
88
+ # classes.
62
89
  #
63
- # @api private
64
- def self.remove_all_consts
65
- constants.each { |name| remove_const name }
90
+ # @param base_class [Class] class inheriting from {::ActiveRecord::Base}
91
+ # @return [Module] module where transient models will be defined; the module
92
+ # extends {Context}, so it's instance methods can be called on the module.
93
+ def context_for base_class
94
+ @contexts[base_class] ||= Context.create base_class
66
95
  end
67
- end
68
96
 
69
- def create_table *args, &block
70
- TransientRecord.create_table(*args, &block)
97
+ def cleanup
98
+ @contexts.each_value(&:cleanup)
99
+ nil
100
+ end
71
101
  end
72
102
 
73
- def define_model *args, &block
74
- TransientRecord.define_model(*args, &block)
75
- end
103
+ # A module for creating Transient Record contexts.
104
+ #
105
+ # A context is a Ruby module (created via +Module.new+) and extended with
106
+ # {Context}. This means instance methods below should be called as module
107
+ # methods on a context, **not** as instance methods.
108
+ module Context
109
+ # Creates a context corresponding to the specified base class.
110
+ #
111
+ # @param base_class [Class] Active Record class to use to connect to the
112
+ # database and as a base class for models.
113
+ #
114
+ # @return [Module] context module used as a namespace for models
115
+ #
116
+ # @api private
117
+ def self.create base_class
118
+ Module.new do
119
+ extend Context
120
+ @base_class = base_class
121
+ @transient_tables = []
122
+ end
123
+ end
76
124
 
77
- class << self
78
- # Create a transient table.
125
+ # Creates a transient table.
79
126
  #
80
127
  # This method can be considered to be a wrapper around +#create_table+ in
81
128
  # Active Record, as it forwards its arguments and the block.
@@ -87,130 +134,122 @@ module TransientRecord
87
134
  # +temporary: true+ via options, which Active Record will recognized out of
88
135
  # the box.
89
136
  #
90
- # Transient tables must be dropped explicitly by calling {.cleanup}.
137
+ # Transient tables must be dropped explicitly by calling {.cleanup} or
138
+ # {#cleanup}.
91
139
  #
92
140
  # @param table_name [String, Symbol] name of the table to create.
93
141
  # @param options [Hash] options to use during table creation; they are
94
142
  # forwarded as is to +create_table+ in Active Record.
95
143
  #
96
- # @yield [table] table definition forwarded to +create_table+ in Active
97
- # Record.
144
+ # @yield [table] table definition block forwarded to +create_table+ in
145
+ # Active Record.
98
146
  #
99
147
  # @return [ModelDefinitionProxy]
100
148
  #
101
149
  # @see https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-create_table Documentation for #create_table in Ruby on Rails
102
150
  def create_table table_name, options = {}, &block
103
151
  table_name = table_name.to_sym
152
+ @transient_tables << table_name
104
153
 
105
- ::ActiveRecord::Migration.suppress_messages do
106
- ::ActiveRecord::Migration.create_table table_name, **options, &block
107
- end
154
+ @base_class.connection.create_table table_name, **options, &block
108
155
 
109
- # Return a proxy object allowing the caller to chain #define_model
110
- # right after creating a table so that it can be followed by the model
111
- # definition.
112
- ModelDefinitionProxy.new table_name
156
+ ModelDefinitionProxy.new self, table_name
113
157
  end
114
158
 
115
- # Define a transient Active Record model.
159
+ # Defines a transient Active Record model.
116
160
  #
117
161
  # Calling this method is roughly equivalent to defining a class inheriting
118
- # from +ActiveRecord::Base+ with class body defined by the block passed to
119
- # the method.
162
+ # from the class the context corresponds to and with class body defined by
163
+ # the block passed to the method.
120
164
  #
121
- # Transient models must be removed explicitly by calling {.cleanup}.
165
+ # Transient models must be removed explicitly by calling {.cleanup} or
166
+ # {#cleanup}.
122
167
  #
123
168
  # @example
169
+ # Primary = TransientRecord.context_for ApplicationRecord
170
+ #
124
171
  # # The following method call ...
125
- # TransientRecord.define_model(:User) do
172
+ # Primary.define_model(:User) do
126
173
  # validates :email, presence: true
127
174
  # end
128
175
  #
129
176
  # # ... is roughly equivalent to this class definition.
130
- # class TransientRecord::Models::User < ActiveRecord::Base
177
+ # class Primary::User < ApplicationRecord
131
178
  # validates :email, presence: true
132
179
  # end
133
180
  #
134
181
  #
135
182
  # @param model_name [String, Symbol] name of model to define.
136
- # @param base_class [Class] model base class.
137
183
  #
138
- # @yield expects the class body to be passed via the block
184
+ # @yield class definition
139
185
  #
140
186
  # @return [nil]
141
- def define_model model_name, base_class = ::ActiveRecord::Base, &block
142
- model_name = model_name.to_sym
143
-
144
- # Normally, when a class is defined via `class MyClass < MySuperclass` the
145
- # .name class method returns the name of the class when called from within
146
- # the class body. However, anonymous classes defined via Class.new DO NOT
147
- # HAVE NAMES. They're assigned names when they're assigned to a constant.
148
- # If we evaluated the class body, passed via block here, in the class
149
- # definition below then some Active Record macros would break
150
- # (e.g. has_and_belongs_to_many) due to nil name.
151
- #
152
- # We solve the problem by defining an empty model class first, assigning to
153
- # a constant to ensure a name is assigned, and then reopening the class to
154
- # give it a non-trivial body.
155
- klass = Class.new base_class
156
- Models.const_set model_name, klass
187
+ def define_model model_name, &block
188
+ klass = Class.new @base_class
189
+ const_set model_name, klass
157
190
 
158
191
  klass.class_eval(&block) if block_given?
159
192
 
160
193
  nil
161
194
  end
162
195
 
163
- # Drop transient tables and models.
196
+ # Drops transient tables and models.
164
197
  #
165
- # This method **MUST** be called after every test cases that used Transient
166
- # Record, as it's responsible for ensuring a clean slate for the next run.
167
- # It does the following:
198
+ # Calling this method removes all models and drops all tables created within
199
+ # this context. Instead of calling this method, you usually should
200
+ # {.cleanup} to cleanup **all** contexts.
168
201
  #
169
- # 1. Remove all models defined via {.define_model}.
170
- # 2. Drop all tables created via {.create_table}.
171
- # 3. Start garbage collection.
202
+ # Calling this method does the following:
172
203
  #
173
- # The last step is to ensure model classes are actually removed, and won't
174
- # appear among the descendants hierarchy of +ActiveRecord::Base+.
204
+ # 1. Remove all models defined via {#define_model}.
205
+ # 2. Drop all tables created via {#create_table}.
206
+ # 3. Run garbage collection to ensure model classes are truly removed. This
207
+ # may be needed in some versions of Active Record.
175
208
  #
176
209
  # @return [nil]
177
210
  def cleanup
178
- Models.remove_all_consts
211
+ constants.each { |name| remove_const name }
179
212
 
180
- connection = ::ActiveRecord::Base.connection
181
- tables_to_remove = connection.tables
213
+ tables_to_remove = @transient_tables
182
214
  drop_attempts = tables_to_remove.count * (1 + tables_to_remove.count) / 2
183
215
 
184
216
  drop_attempts.times do
185
- table = tables_to_remove.shift
217
+ table = tables_to_remove.pop
186
218
  break if table.nil?
187
219
 
188
220
  begin
189
- connection.drop_table table, force: :cascade, if_exists: true
221
+ @base_class.connection.drop_table table, force: :cascade, if_exists: true
190
222
  rescue ActiveRecord::InvalidForeignKey, ActiveRecord::StatementInvalid
191
223
  # ActiveRecord::StatementInvalid is raised by MySQL when attempting to
192
224
  # drop a table that has foreign keys referring to it.
193
- tables_to_remove << table
225
+ tables_to_remove.unshift(table)
194
226
  end
195
227
  end
196
228
 
229
+ if !@transient_tables.empty?
230
+ raise Error.new(<<~ERROR)
231
+ The following transient tables could not be removed: #{@transient_tables.join(', ')}.
232
+ ERROR
233
+ end
234
+
197
235
  GC.start
198
236
 
199
237
  nil
200
238
  end
201
239
  end
202
240
 
203
- # A model definition proxy is a helper class used to implement a fluent
204
- # interface to callers allowing them to create a table and its corresponding
241
+ # A model definition proxy is a helper class implementing a fluent
242
+ # interface allowing callers to create a table and its corresponding
205
243
  # model in close succession. It's marked private as there's no need for
206
- # callers to access it.
244
+ # callers to access it directly.
207
245
  class ModelDefinitionProxy
208
- def initialize table_name
209
- @table_name = table_name.to_s
246
+ def initialize context, table_name
247
+ @context = context
248
+ @table_name = table_name
210
249
  end
211
250
 
212
251
  def define_model &block
213
- TransientRecord.define_model @table_name.classify, &block
252
+ @context.define_model @table_name.to_s.classify, &block
214
253
  end
215
254
  end
216
255
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: transient_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Greg Navis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-24 00:00:00.000000000 Z
11
+ date: 2023-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -28,98 +28,98 @@ dependencies:
28
28
  name: mysql2
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: 0.5.3
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: 0.5.3
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: pg
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: 1.1.4
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: 1.1.4
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: sqlite3
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: 1.5.4
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: 1.5.4
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: 12.3.3
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: 12.3.3
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: yard
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: 0.9.28
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: 0.9.28
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rubocop
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - "~>"
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
103
  version: 1.43.0
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - "~>"
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: 1.43.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rubocop-rake
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - "~>"
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
117
  version: 0.6.0
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - "~>"
122
+ - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: 0.6.0
125
125
  description:
@@ -148,11 +148,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
148
148
  version: 2.4.0
149
149
  required_rubygems_version: !ruby/object:Gem::Requirement
150
150
  requirements:
151
- - - ">="
151
+ - - ">"
152
152
  - !ruby/object:Gem::Version
153
- version: '0'
153
+ version: 1.3.1
154
154
  requirements: []
155
- rubygems_version: 3.2.33
155
+ rubygems_version: 3.4.10
156
156
  signing_key:
157
157
  specification_version: 4
158
158
  summary: Define transient tables and Active Record models for testing purposes.