transient_record 1.0.0.rc1
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 +7 -0
- data/MIT-LICENSE.txt +20 -0
- data/README.md +137 -0
- data/lib/transient_record.rb +218 -0
- metadata +159 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 05ecb3ea508a5454c5a108e2f46ef5e0a390a4467aa5a965db12094bf955dfaf
|
4
|
+
data.tar.gz: 39d965ea81d0ca307db1c0559c91fe5713df7a44206b5893470e617a479f851c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b04aa876557bcfe4488a42f97786c3abdfe6d4621fe6e9956708e005fc0b5a0f51c13fa65e5261c7ce89186e0691107f0c9ce3ce0e998796ef20425a0800d79f
|
7
|
+
data.tar.gz: 934d8eb96dc127056a33e1907649eaf17dbb0b01902345c3f48cfdb6c495da976c63221aadf5070ba7b5d9aad4e92c557277462a25ac5109458821d9dbc0542c
|
data/MIT-LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2023 Greg Navis
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
# Transient Record
|
2
|
+
|
3
|
+
`transient-record` is a gem to define temporary tables and Active Record models
|
4
|
+
for testing purposes. It's a great tool for testing **generic Active Record code
|
5
|
+
and libraries**.
|
6
|
+
|
7
|
+
The library was extracted from [active_record_doctor](https://github.com/gregnavis/active_record_doctor)
|
8
|
+
to allow reuse.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Installing Transient Record is a two-step process.
|
13
|
+
|
14
|
+
### Step 1: Installing the Gem
|
15
|
+
|
16
|
+
You can include Transient Record in your `Gemfile`:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem "transient_record", group: :test
|
20
|
+
```
|
21
|
+
|
22
|
+
The above assumes it'll be used for testing purposes only, hence the `test`
|
23
|
+
group. However, if you intend to use the gem in other circumstances then you may
|
24
|
+
need to adjust the group accordingly.
|
25
|
+
|
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
|
+
### Step 2: Integrating with the Test Suite
|
36
|
+
|
37
|
+
After installing the gem, Transient Record must be integrated with the test
|
38
|
+
suite. `TransientRecord.cleanup` must be called around every test case: before
|
39
|
+
(to prepare a clean database state for the test case) and after (to leave the
|
40
|
+
database in a clean state).
|
41
|
+
|
42
|
+
The snippet below demonstrates integrations with various testing libraries:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
# When using Minitest
|
46
|
+
class TransientRecordTest < Minitest::Test
|
47
|
+
def before
|
48
|
+
TransientRecord.cleanup
|
49
|
+
end
|
50
|
+
|
51
|
+
def after
|
52
|
+
TransientRecord.cleanup
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# When using Minitest::Spec
|
57
|
+
class TransientRecordTest < Minitest::Spec
|
58
|
+
before do
|
59
|
+
TransientRecord.cleanup
|
60
|
+
end
|
61
|
+
|
62
|
+
after do
|
63
|
+
TransientRecord.cleanup
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# When using RSpec
|
68
|
+
RSpec.describe TransientRecord do
|
69
|
+
before(:each) do
|
70
|
+
TransientRecord.cleanup
|
71
|
+
end
|
72
|
+
|
73
|
+
after(:each) do
|
74
|
+
TransientRecord.cleanup
|
75
|
+
end
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
## Usage
|
80
|
+
|
81
|
+
Transient Record can be used to create temporary tables and, optionally, models
|
82
|
+
backed by them.
|
83
|
+
|
84
|
+
A table can be created by calling `create_table`: a thin wrapper around the
|
85
|
+
method of the same name in Active Record. The only difference is the method
|
86
|
+
in Transient Record implemented a fluent interface that allows calling
|
87
|
+
`define_model` on the return value.
|
88
|
+
|
89
|
+
For example, the statement below creates a table named `users` with two one
|
90
|
+
string column `name` and one integer column `age`:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
create_table :users do |t|
|
94
|
+
t.string :name, null: false
|
95
|
+
t.integer :age, null: false
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
Refer to [Ruby on Rails API documentation](https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html)
|
100
|
+
for details.
|
101
|
+
|
102
|
+
In order to define a model backed by that table `define_model` can be called
|
103
|
+
**on the return value** of `create_table` with a block containing the model
|
104
|
+
class body. For example, to define
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
create_table :users do |t|
|
108
|
+
# ...
|
109
|
+
end.define_model do
|
110
|
+
validates :email, presence: true
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
Models are automatically assigned to constants in `TransientRecord::Models`. The
|
115
|
+
example above creates `TransientRecord::Models::User`, and is equivalent to:
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
class TransientRecord::Models::User < ActiveRecord::Base
|
119
|
+
validates :email, presence: true
|
120
|
+
end
|
121
|
+
```
|
122
|
+
|
123
|
+
## Caveats and Limitations
|
124
|
+
|
125
|
+
Transient Record does **NOT** default to using temporary tables (created via
|
126
|
+
`CREATE TEMPORARY TABLE`) because of their second-class status in Active Record.
|
127
|
+
For example, temporary table are not listed by the `tables` method. For this
|
128
|
+
reason it was decided to use regular tables with an explicit cleanup step.
|
129
|
+
|
130
|
+
Transient Record may not work properly in parallelized test suites, e.g. if two
|
131
|
+
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.
|
134
|
+
|
135
|
+
## Author
|
136
|
+
|
137
|
+
This gem is developed and maintained by [Greg Navis](http://www.gregnavis.com).
|
@@ -0,0 +1,218 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Transient Record helps define transient tables and Active Record models.
|
4
|
+
#
|
5
|
+
# Defining a transient table and model is a two-step process:
|
6
|
+
#
|
7
|
+
# 1. {#create_table} to create the table.
|
8
|
+
# 2. {#define_model} to define the model.
|
9
|
+
#
|
10
|
+
# @example Creating a table without a model
|
11
|
+
# # #create_table is a wrapper around #create_table in Active Record, and
|
12
|
+
# # 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|
|
21
|
+
# t.string :email, null: false
|
22
|
+
# end.define_model do
|
23
|
+
# validates :email, presence: true
|
24
|
+
# end
|
25
|
+
#
|
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
|
29
|
+
#
|
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
|
34
|
+
# validates :email, presence: true
|
35
|
+
# end
|
36
|
+
module TransientRecord
|
37
|
+
# Transient Record version number.
|
38
|
+
VERSION = "1.0.0.rc1"
|
39
|
+
|
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.
|
59
|
+
#
|
60
|
+
# This method is used by {TransientRecord.cleanup} to undefine temporary
|
61
|
+
# model classes.
|
62
|
+
#
|
63
|
+
# @api private
|
64
|
+
def self.remove_all_consts
|
65
|
+
constants.each { |name| remove_const name }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def create_table *args, &block
|
70
|
+
TransientRecord.create_table(*args, &block)
|
71
|
+
end
|
72
|
+
|
73
|
+
def define_model *args, &block
|
74
|
+
TransientRecord.define_model(*args, &block)
|
75
|
+
end
|
76
|
+
|
77
|
+
class << self
|
78
|
+
# Create a transient table.
|
79
|
+
#
|
80
|
+
# This method can be considered to be a wrapper around +#create_table+ in
|
81
|
+
# Active Record, as it forwards its arguments and the block.
|
82
|
+
#
|
83
|
+
# Transient tables are **not** made temporary in the database (in other
|
84
|
+
# words, they are **not** created using +CREATE TEMPORARY TABLE+), because
|
85
|
+
# temporary tables are treated differently by Active Record. For example,
|
86
|
+
# they aren't listed by +#tables+. If a temporary table is needed then pass
|
87
|
+
# +temporary: true+ via options, which Active Record will recognized out of
|
88
|
+
# the box.
|
89
|
+
#
|
90
|
+
# Transient tables must be dropped explicitly by calling {.cleanup}.
|
91
|
+
#
|
92
|
+
# @param table_name [String, Symbol] name of the table to create.
|
93
|
+
# @param options [Hash] options to use during table creation; they are
|
94
|
+
# forwarded as is to +create_table+ in Active Record.
|
95
|
+
#
|
96
|
+
# @yield [table] table definition forwarded to +create_table+ in Active
|
97
|
+
# Record.
|
98
|
+
#
|
99
|
+
# @return [ModelDefinitionProxy]
|
100
|
+
#
|
101
|
+
# @see https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-create_table Documentation for #create_table in Ruby on Rails
|
102
|
+
def create_table table_name, options = {}, &block
|
103
|
+
table_name = table_name.to_sym
|
104
|
+
|
105
|
+
::ActiveRecord::Migration.suppress_messages do
|
106
|
+
::ActiveRecord::Migration.create_table table_name, **options, &block
|
107
|
+
end
|
108
|
+
|
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
|
113
|
+
end
|
114
|
+
|
115
|
+
# Define a transient Active Record model.
|
116
|
+
#
|
117
|
+
# 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.
|
120
|
+
#
|
121
|
+
# Transient models must be removed explicitly by calling {.cleanup}.
|
122
|
+
#
|
123
|
+
# @example
|
124
|
+
# # The following method call ...
|
125
|
+
# TransientRecord.define_model(:User) do
|
126
|
+
# validates :email, presence: true
|
127
|
+
# end
|
128
|
+
#
|
129
|
+
# # ... is roughly equivalent to this class definition.
|
130
|
+
# class TransientRecord::Models::User < ActiveRecord::Base
|
131
|
+
# validates :email, presence: true
|
132
|
+
# end
|
133
|
+
#
|
134
|
+
#
|
135
|
+
# @param model_name [String, Symbol] name of model to define.
|
136
|
+
# @param base_class [Class] model base class.
|
137
|
+
#
|
138
|
+
# @yield expects the class body to be passed via the block
|
139
|
+
#
|
140
|
+
# @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
|
157
|
+
|
158
|
+
klass.class_eval(&block) if block_given?
|
159
|
+
|
160
|
+
nil
|
161
|
+
end
|
162
|
+
|
163
|
+
# Drop transient tables and models.
|
164
|
+
#
|
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:
|
168
|
+
#
|
169
|
+
# 1. Remove all models defined via {.define_model}.
|
170
|
+
# 2. Drop all tables created via {.create_table}.
|
171
|
+
# 3. Start garbage collection.
|
172
|
+
#
|
173
|
+
# The last step is to ensure model classes are actually removed, and won't
|
174
|
+
# appear among the descendants hierarchy of +ActiveRecord::Base+.
|
175
|
+
#
|
176
|
+
# @return [nil]
|
177
|
+
def cleanup
|
178
|
+
Models.remove_all_consts
|
179
|
+
|
180
|
+
connection = ::ActiveRecord::Base.connection
|
181
|
+
tables_to_remove = connection.tables
|
182
|
+
drop_attempts = tables_to_remove.count * (1 + tables_to_remove.count) / 2
|
183
|
+
|
184
|
+
drop_attempts.times do
|
185
|
+
table = tables_to_remove.shift
|
186
|
+
break if table.nil?
|
187
|
+
|
188
|
+
begin
|
189
|
+
connection.drop_table table, force: :cascade, if_exists: true
|
190
|
+
rescue ActiveRecord::InvalidForeignKey, ActiveRecord::StatementInvalid
|
191
|
+
# ActiveRecord::StatementInvalid is raised by MySQL when attempting to
|
192
|
+
# drop a table that has foreign keys referring to it.
|
193
|
+
tables_to_remove << table
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
GC.start
|
198
|
+
|
199
|
+
nil
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
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
|
205
|
+
# model in close succession. It's marked private as there's no need for
|
206
|
+
# callers to access it.
|
207
|
+
class ModelDefinitionProxy
|
208
|
+
def initialize table_name
|
209
|
+
@table_name = table_name.to_s
|
210
|
+
end
|
211
|
+
|
212
|
+
def define_model &block
|
213
|
+
TransientRecord.define_model @table_name.classify, &block
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
private_constant :ModelDefinitionProxy
|
218
|
+
end
|
metadata
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: transient_record
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0.rc1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Greg Navis
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-01-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.2.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mysql2
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.5.3
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.5.3
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pg
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.1.4
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.1.4
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sqlite3
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.5.4
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.5.4
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 12.3.3
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 12.3.3
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: yard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.9.28
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.9.28
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 1.43.0
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.43.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop-rake
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.6.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.6.0
|
125
|
+
description:
|
126
|
+
email:
|
127
|
+
- contact@gregnavis.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- MIT-LICENSE.txt
|
133
|
+
- README.md
|
134
|
+
- lib/transient_record.rb
|
135
|
+
homepage: https://github.com/gregnavis/transient_record
|
136
|
+
licenses:
|
137
|
+
- MIT
|
138
|
+
metadata:
|
139
|
+
rubygems_mfa_required: 'true'
|
140
|
+
post_install_message:
|
141
|
+
rdoc_options: []
|
142
|
+
require_paths:
|
143
|
+
- lib
|
144
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
145
|
+
requirements:
|
146
|
+
- - ">="
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: 2.4.0
|
149
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - ">"
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: 1.3.1
|
154
|
+
requirements: []
|
155
|
+
rubygems_version: 3.2.33
|
156
|
+
signing_key:
|
157
|
+
specification_version: 4
|
158
|
+
summary: Define transient tables and Active Record models for testing purposes.
|
159
|
+
test_files: []
|