activerecord-ghosts 0.0.1 → 0.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +90 -6
- data/CHANGELOG.md +4 -4
- data/README.md +155 -40
- data/Rakefile +3 -3
- data/lib/activerecord/ghosts/has_ghosts.rb +6 -4
- data/lib/activerecord/ghosts/version.rb +1 -1
- metadata +4 -123
- data/.standard.yml +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe8b3f46f4b831bfcd1d4888fe2144cdb52c215ea813ea27f26c6dcf2fd3d149
|
4
|
+
data.tar.gz: 9ad32054f18d87b1e8093ca59c5224e5c9e338eb339a84ea6fcf1a7f70d1ff2f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 56ee0da960929690055279b63f855cbb1eb3589e96c1d49a09455cba153b9355cdd3a7c9a202ca16b378f45a2c78dd2593283c44949f0f85983c5df3bd512c78
|
7
|
+
data.tar.gz: 841c0cf442f89b45db533a340c8b66ad3e1c1e8057e572160959098f756e66de29cadfda9192b1b1d4dce15610530c88018c248a0776b245a1e08d5e9b24afec
|
data/.rubocop.yml
CHANGED
@@ -1,25 +1,109 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
plugins:
|
2
|
+
- rubocop-rspec
|
3
3
|
|
4
4
|
AllCops:
|
5
5
|
TargetRubyVersion: 3.4
|
6
6
|
NewCops: enable
|
7
|
+
SuggestExtensions: false
|
7
8
|
Exclude:
|
8
9
|
- 'vendor/**/*'
|
9
|
-
- 'tmp/**/*'
|
10
10
|
- 'bin/**/*'
|
11
|
+
- 'tmp/**/*'
|
12
|
+
- 'spec/dummy/**/*'
|
13
|
+
|
14
|
+
# Disable some overly strict rules
|
15
|
+
Style/Documentation:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
Style/StringLiterals:
|
19
|
+
EnforcedStyle: double_quotes
|
20
|
+
|
21
|
+
Style/StringLiteralsInInterpolation:
|
22
|
+
EnforcedStyle: double_quotes
|
11
23
|
|
12
|
-
# Allow longer lines in specs
|
13
24
|
Layout/LineLength:
|
25
|
+
Max: 120
|
14
26
|
Exclude:
|
15
27
|
- 'spec/**/*'
|
28
|
+
- '*.gemspec'
|
16
29
|
|
17
|
-
# Allow longer blocks in specs
|
18
30
|
Metrics/BlockLength:
|
19
31
|
Exclude:
|
20
32
|
- 'spec/**/*'
|
33
|
+
- '*.gemspec'
|
34
|
+
- 'Rakefile'
|
35
|
+
AllowedMethods:
|
36
|
+
- 'class_methods'
|
21
37
|
|
22
|
-
# Allow longer methods in specs
|
23
38
|
Metrics/MethodLength:
|
39
|
+
Max: 30
|
40
|
+
Exclude:
|
41
|
+
- 'spec/**/*'
|
42
|
+
|
43
|
+
Metrics/ClassLength:
|
44
|
+
Max: 120
|
24
45
|
Exclude:
|
25
46
|
- 'spec/**/*'
|
47
|
+
|
48
|
+
Metrics/AbcSize:
|
49
|
+
Max: 40
|
50
|
+
Exclude:
|
51
|
+
- 'spec/**/*'
|
52
|
+
|
53
|
+
Metrics/CyclomaticComplexity:
|
54
|
+
Max: 15
|
55
|
+
|
56
|
+
Metrics/PerceivedComplexity:
|
57
|
+
Max: 15
|
58
|
+
|
59
|
+
# RSpec specific
|
60
|
+
RSpec/ExampleLength:
|
61
|
+
Max: 30
|
62
|
+
|
63
|
+
RSpec/MultipleExpectations:
|
64
|
+
Max: 10
|
65
|
+
|
66
|
+
RSpec/NestedGroups:
|
67
|
+
Max: 4
|
68
|
+
|
69
|
+
RSpec/DescribeClass:
|
70
|
+
Exclude:
|
71
|
+
- 'spec/integration/**/*'
|
72
|
+
- 'spec/**/*compatibility*'
|
73
|
+
- 'spec/**/*integration*'
|
74
|
+
|
75
|
+
RSpec/SpecFilePathFormat:
|
76
|
+
Enabled: false
|
77
|
+
|
78
|
+
RSpec/IndexedLet:
|
79
|
+
Enabled: false
|
80
|
+
|
81
|
+
RSpec/StubbedMock:
|
82
|
+
Enabled: false
|
83
|
+
|
84
|
+
RSpec/MessageSpies:
|
85
|
+
Enabled: false
|
86
|
+
|
87
|
+
RSpec/IdenticalEqualityAssertion:
|
88
|
+
Enabled: false
|
89
|
+
|
90
|
+
RSpec/ExpectActual:
|
91
|
+
Enabled: false
|
92
|
+
|
93
|
+
Style/FrozenStringLiteralComment:
|
94
|
+
Enabled: true
|
95
|
+
EnforcedStyle: always
|
96
|
+
|
97
|
+
# Disable gemspec cops that conflict with gem practices
|
98
|
+
Gemspec/DevelopmentDependencies:
|
99
|
+
Enabled: false
|
100
|
+
|
101
|
+
Gemspec/RequireMFA:
|
102
|
+
Enabled: false
|
103
|
+
|
104
|
+
# Allow predicate method names
|
105
|
+
Naming/PredicateName:
|
106
|
+
Enabled: false
|
107
|
+
|
108
|
+
Naming/VariableNumber:
|
109
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## [0.0.2] - 2025-08-26
|
9
|
+
|
10
|
+
- Minor fixes of dependencies
|
11
|
+
|
8
12
|
## [0.0.1] - 2025-08-25
|
9
13
|
|
10
14
|
### Added
|
@@ -23,7 +27,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
23
27
|
- Works with ActiveRecord associations and scopes
|
24
28
|
- Efficient batching for large datasets via enumerators
|
25
29
|
- Custom inspect output for ghost records
|
26
|
-
|
27
|
-
## [0.0.1] - 2025-08-25
|
28
|
-
|
29
|
-
- Initial release
|
data/README.md
CHANGED
@@ -1,18 +1,13 @@
|
|
1
1
|
# ActiveRecord::Ghosts 👻
|
2
2
|
|
3
3
|
"Virtual rows" for ActiveRecord models.
|
4
|
-
Fill in the gaps in your
|
5
|
-
If it doesn't, you'll see a warning:
|
6
|
-
|
7
|
-
```
|
8
|
-
[activerecord-ghosts] ⚠️ Column :level on progress_levels has no leading index. Ghost queries may be slow.
|
9
|
-
``` work with **ghost records** that behave like AR objects but aren’t persisted.
|
4
|
+
Fill in the gaps in your sequences and work with **ghost records** that behave like AR objects but aren't persisted.
|
10
5
|
|
11
6
|
---
|
12
7
|
|
13
8
|
## ✨ Features
|
14
9
|
|
15
|
-
- Define a sequence column (like `number`).
|
10
|
+
- Define a sequence column (like `level`, `number`).
|
16
11
|
- Query with a range and get **real + ghost records**.
|
17
12
|
- Chain with `where` / scopes.
|
18
13
|
- Works with `Enumerator` for infinite series.
|
@@ -24,13 +19,13 @@ If it doesn't, you'll see a warning:
|
|
24
19
|
|
25
20
|
**Requirements:**
|
26
21
|
- Ruby 3.4.0+
|
27
|
-
- Rails 7.
|
22
|
+
- Rails 7.2+
|
28
23
|
|
29
24
|
Add to your Gemfile:
|
30
25
|
|
31
26
|
```ruby
|
32
27
|
gem "activerecord-ghosts"
|
33
|
-
|
28
|
+
```
|
34
29
|
|
35
30
|
and run:
|
36
31
|
|
@@ -40,83 +35,205 @@ bundle install
|
|
40
35
|
|
41
36
|
---
|
42
37
|
|
43
|
-
##
|
38
|
+
## 🏗 Setup
|
39
|
+
|
40
|
+
### Database Schema
|
41
|
+
|
42
|
+
Your model needs an **integer column** for the sequence field. This column should be indexed for performance.
|
44
43
|
|
45
|
-
|
44
|
+
```ruby
|
45
|
+
# Example migration
|
46
|
+
class CreateProgressLevels < ActiveRecord::Migration[7.2]
|
47
|
+
def change
|
48
|
+
create_table :progress_levels do |t|
|
49
|
+
t.references :user, null: false, foreign_key: true
|
50
|
+
t.integer :level, null: false # ← Ghost sequence column
|
51
|
+
t.integer :points, default: 0
|
52
|
+
t.timestamps
|
53
|
+
end
|
54
|
+
|
55
|
+
# Index for performance (IMPORTANT!)
|
56
|
+
add_index :progress_levels, [:user_id, :level], unique: true
|
57
|
+
# OR simple index if no associations:
|
58
|
+
# add_index :progress_levels, :level
|
59
|
+
end
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
### Model Configuration
|
46
64
|
|
47
65
|
```ruby
|
48
66
|
class ProgressLevel < ApplicationRecord
|
49
67
|
belongs_to :user
|
50
|
-
|
68
|
+
|
69
|
+
# Enable ghosts on the integer sequence column
|
70
|
+
has_ghosts :level, start: 1 # Optional: custom start value (default: 1)
|
71
|
+
|
72
|
+
validates :level, presence: true, uniqueness: { scope: :user_id }
|
73
|
+
end
|
74
|
+
|
75
|
+
# Alternative start values:
|
76
|
+
class Invoice < ApplicationRecord
|
77
|
+
has_ghosts :number, start: 1000 # Start from 1000 instead of 1
|
51
78
|
end
|
79
|
+
|
80
|
+
# Usage with custom start:
|
81
|
+
Invoice.ghosts.take(3) # Will generate ghosts starting from 1000, 1001, 1002...
|
52
82
|
```
|
53
83
|
|
84
|
+
**Requirements:**
|
85
|
+
- ✅ Ghost column must be **integer type**
|
86
|
+
- ✅ Ghost column should have an **index** (composite or simple)
|
87
|
+
- ✅ Index should have ghost column as **leading column** for best performance
|
88
|
+
|
54
89
|
---
|
55
90
|
|
56
|
-
|
91
|
+
## 🛠 Usage
|
92
|
+
|
93
|
+
### 1. Basic ghost series
|
57
94
|
|
58
95
|
```ruby
|
59
|
-
|
60
|
-
|
96
|
+
# Assuming you have levels 1, 2, 5 in database
|
97
|
+
ProgressLevel.ghosts(1..6).map { |level| [level.level, level.ghost?] }
|
98
|
+
# => [[1, false], [2, false], [3, true], [4, true], [5, false], [6, true]]
|
61
99
|
```
|
62
100
|
|
63
|
-
Here:
|
64
|
-
|
65
|
-
* Levels `1` and `2` exist in DB → `ghost? == false`
|
66
|
-
* Levels `3..5` don't exist → ghost objects (`ghost? == true`)
|
67
|
-
|
68
101
|
---
|
69
102
|
|
70
|
-
###
|
103
|
+
### 2. With associations and scoping
|
71
104
|
|
72
105
|
For a specific user:
|
73
106
|
|
74
107
|
```ruby
|
75
108
|
user = User.find(1)
|
76
|
-
|
77
|
-
#
|
78
|
-
|
79
|
-
#
|
80
|
-
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
109
|
+
|
110
|
+
# Get levels 1-5 for this user (mix of real + ghost records)
|
111
|
+
user.progress_levels.ghosts(1..5).each do |level|
|
112
|
+
puts "Level #{level.level}: #{level.ghost? ? 'Missing' : 'Completed'} (#{level.points} points)"
|
113
|
+
end
|
114
|
+
# Output:
|
115
|
+
# Level 1: Completed (100 points)
|
116
|
+
# Level 2: Completed (150 points)
|
117
|
+
# Level 3: Missing (0 points) ← Ghost inherits default values
|
118
|
+
# Level 4: Missing (0 points) ← Ghost inherits default values
|
119
|
+
# Level 5: Missing (0 points) ← Ghost inherits default values
|
84
120
|
|
85
121
|
# Alternative syntax:
|
86
|
-
ProgressLevel.where(user_id: user.id).ghosts(1..5)
|
122
|
+
ProgressLevel.where(user_id: user.id).ghosts(1..5)
|
87
123
|
```
|
88
124
|
|
89
|
-
|
125
|
+
**Key insight:** Ghost records automatically inherit `where` conditions and model defaults!
|
90
126
|
|
91
127
|
---
|
92
128
|
|
93
|
-
###
|
129
|
+
### 3. Infinite series
|
94
130
|
|
95
|
-
Without arguments, `.ghosts` returns an **Enumerator
|
131
|
+
Without arguments, `.ghosts` returns an **Enumerator** that starts from the `start` value:
|
96
132
|
|
97
133
|
```ruby
|
134
|
+
# With default start: 1
|
98
135
|
ProgressLevel.ghosts.take(3).map { |level| [level.level, level.ghost?] }
|
99
136
|
# => [[1, false], [2, false], [3, true]]
|
137
|
+
|
138
|
+
# With custom start: 1000
|
139
|
+
class Invoice < ApplicationRecord
|
140
|
+
has_ghosts :number, start: 1000
|
141
|
+
end
|
142
|
+
|
143
|
+
Invoice.ghosts.take(3).map { |inv| [inv.number, inv.ghost?] }
|
144
|
+
# => [[1000, true], [1001, true], [1002, true]] # Starts from 1000!
|
100
145
|
```
|
101
146
|
|
102
|
-
You can `each`, `each_slice`, etc.
|
103
|
-
|
147
|
+
You can `each`, `each_slice`, etc. Records are lazily loaded batch by batch.
|
148
|
+
|
149
|
+
---
|
150
|
+
|
151
|
+
## 📋 Supported Column Types & Limitations
|
152
|
+
|
153
|
+
### ✅ Supported Ghost Columns
|
154
|
+
- **Integer columns only** - `t.integer :level`, `t.bigint :number`, etc.
|
155
|
+
- Must contain **sequential numeric values** (1, 2, 3... or 10, 20, 30...)
|
156
|
+
- Works with any integer range (`1..100`, `0..10`, `-5..5`)
|
157
|
+
|
158
|
+
### ❌ Not Supported
|
159
|
+
- String columns (`t.string :name`)
|
160
|
+
- Date/DateTime columns (`t.date :created_on`)
|
161
|
+
- UUID columns (`t.uuid :external_id`)
|
162
|
+
- Non-sequential data
|
163
|
+
|
164
|
+
### 🎯 Perfect Use Cases
|
165
|
+
```ruby
|
166
|
+
# ✅ Game levels (1, 2, 3, 4, 5...)
|
167
|
+
class PlayerLevel
|
168
|
+
has_ghosts :level # integer column
|
169
|
+
end
|
170
|
+
|
171
|
+
# ✅ Invoice numbers (1, 2, 3... or 1000, 1001, 1002...)
|
172
|
+
class Invoice
|
173
|
+
has_ghosts :number # integer column
|
174
|
+
end
|
175
|
+
|
176
|
+
# ✅ Chapter numbers in a book
|
177
|
+
class Chapter
|
178
|
+
has_ghosts :chapter_number # integer column
|
179
|
+
end
|
180
|
+
|
181
|
+
# ❌ Don't use for non-sequential data
|
182
|
+
class User
|
183
|
+
has_ghosts :email # ❌ String - won't work
|
184
|
+
has_ghosts :created_at # ❌ DateTime - not sequential
|
185
|
+
end
|
186
|
+
```
|
104
187
|
|
105
188
|
---
|
106
189
|
|
107
190
|
## ⚠️ Performance note
|
108
191
|
|
109
|
-
For best performance, ensure the ghosted column (e.g. `:
|
110
|
-
If it doesn
|
192
|
+
For best performance, ensure the ghosted column (e.g. `:level`) has an **index**.
|
193
|
+
If it doesn't, you'll see a warning:
|
111
194
|
|
112
195
|
```
|
113
|
-
[activerecord-ghosts] ⚠️ Column :
|
196
|
+
[activerecord-ghosts] ⚠️ Column :level on progress_levels has no leading index. Ghost queries may be slow.
|
114
197
|
```
|
115
198
|
|
116
199
|
Composite indexes are fine if your ghost column is the **leading** column.
|
117
200
|
|
118
201
|
---
|
119
202
|
|
203
|
+
## ❓ FAQ
|
204
|
+
|
205
|
+
### Q: Can I use string/UUID columns as ghost fields?
|
206
|
+
**A:** No, only integer columns are supported. Ghost records fill numeric gaps in sequences.
|
207
|
+
|
208
|
+
### Q: Do ghost records get saved to the database?
|
209
|
+
**A:** No! Ghost records exist only in memory. They behave like ActiveRecord objects but `.persisted?` returns `false`.
|
210
|
+
|
211
|
+
### Q: Can I modify ghost records?
|
212
|
+
**A:** Yes! You can call `.save!` on a ghost record to persist it to the database. After saving, `.ghost?` will return `false`.
|
213
|
+
|
214
|
+
### Q: How do I handle gaps in my sequence?
|
215
|
+
**A:** That's exactly what this gem does! It fills gaps with virtual records.
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
# You have records [1, 2, 5, 8] in database
|
219
|
+
Model.ghosts(1..10).map(&:id)
|
220
|
+
# Returns: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
221
|
+
# Where 3, 4, 6, 7, 9, 10 are ghosts
|
222
|
+
```
|
223
|
+
|
224
|
+
### Q: What about performance with large ranges?
|
225
|
+
**A:** Use the enumerator version for infinite sequences:
|
226
|
+
|
227
|
+
```ruby
|
228
|
+
# ✅ Memory efficient - loads in batches
|
229
|
+
Model.ghosts.take(1000)
|
230
|
+
|
231
|
+
# ❌ Avoid large ranges - loads all at once
|
232
|
+
Model.ghosts(1..1000000)
|
233
|
+
```
|
234
|
+
|
235
|
+
---
|
236
|
+
|
120
237
|
## 📦 Development
|
121
238
|
|
122
239
|
Clone and setup:
|
@@ -145,8 +262,6 @@ This gem uses **RubyGems.org Trusted Publishing** for secure, automated releases
|
|
145
262
|
2. Commit and create tag: `git tag v0.1.1 && git push --tags`
|
146
263
|
3. GitHub Actions automatically publishes to RubyGems.org
|
147
264
|
|
148
|
-
See [TRUSTED_PUBLISHING.md](TRUSTED_PUBLISHING.md) for setup details.
|
149
|
-
|
150
265
|
### Running Tests
|
151
266
|
|
152
267
|
```bash
|
data/Rakefile
CHANGED
@@ -11,9 +11,10 @@ module ActiveRecord
|
|
11
11
|
def has_ghosts(field_name, start: 1)
|
12
12
|
include ActiveRecord::Ghosts::GhostRecord
|
13
13
|
|
14
|
-
# ⚠️
|
14
|
+
# ⚠️ Check index (leading column)
|
15
15
|
unless connection.indexes(table_name).any? { |i| i.columns.first == field_name.to_s }
|
16
|
-
warn "[activerecord-ghosts] ⚠️ Column :#{field_name} on #{table_name} has no leading index.
|
16
|
+
warn "[activerecord-ghosts] ⚠️ Column :#{field_name} on #{table_name} has no leading index. " \
|
17
|
+
"Ghost queries may be slow."
|
17
18
|
end
|
18
19
|
|
19
20
|
define_singleton_method(:ghosts) do |*args, **opts|
|
@@ -30,7 +31,7 @@ module ActiveRecord
|
|
30
31
|
def ghosts_implementation(relation, field_name, start, *args, **opts)
|
31
32
|
range = extract_range(args, opts)
|
32
33
|
|
33
|
-
# 1)
|
34
|
+
# 1) No range → infinite Enumerator
|
34
35
|
unless range
|
35
36
|
return Enumerator.new do |yielder|
|
36
37
|
n = start
|
@@ -52,7 +53,7 @@ module ActiveRecord
|
|
52
53
|
end
|
53
54
|
end
|
54
55
|
|
55
|
-
# 2)
|
56
|
+
# 2) With range → fixed array
|
56
57
|
records = relation.where(field_name => range).index_by(&field_name)
|
57
58
|
defaults = relation.where_values_hash.symbolize_keys.merge(opts[:default] || {})
|
58
59
|
|
@@ -70,6 +71,7 @@ module ActiveRecord
|
|
70
71
|
def extract_range(args, opts)
|
71
72
|
return args.first if args.first.is_a?(Range)
|
72
73
|
return (opts[:from]..opts[:to]) if opts[:from] && opts[:to]
|
74
|
+
|
73
75
|
nil
|
74
76
|
end
|
75
77
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-ghosts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ilya Kovalenko
|
@@ -15,132 +15,14 @@ dependencies:
|
|
15
15
|
requirements:
|
16
16
|
- - ">="
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: '
|
18
|
+
version: '7.2'
|
19
19
|
type: :runtime
|
20
20
|
prerelease: false
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
22
22
|
requirements:
|
23
23
|
- - ">="
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version: '
|
26
|
-
- !ruby/object:Gem::Dependency
|
27
|
-
name: rspec
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
29
|
-
requirements:
|
30
|
-
- - "~>"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '3.0'
|
33
|
-
type: :development
|
34
|
-
prerelease: false
|
35
|
-
version_requirements: !ruby/object:Gem::Requirement
|
36
|
-
requirements:
|
37
|
-
- - "~>"
|
38
|
-
- !ruby/object:Gem::Version
|
39
|
-
version: '3.0'
|
40
|
-
- !ruby/object:Gem::Dependency
|
41
|
-
name: rspec-rails
|
42
|
-
requirement: !ruby/object:Gem::Requirement
|
43
|
-
requirements:
|
44
|
-
- - ">="
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '0'
|
47
|
-
type: :development
|
48
|
-
prerelease: false
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - ">="
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '0'
|
54
|
-
- !ruby/object:Gem::Dependency
|
55
|
-
name: rails
|
56
|
-
requirement: !ruby/object:Gem::Requirement
|
57
|
-
requirements:
|
58
|
-
- - ">="
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: '7.0'
|
61
|
-
- - "<"
|
62
|
-
- !ruby/object:Gem::Version
|
63
|
-
version: '9.0'
|
64
|
-
type: :development
|
65
|
-
prerelease: false
|
66
|
-
version_requirements: !ruby/object:Gem::Requirement
|
67
|
-
requirements:
|
68
|
-
- - ">="
|
69
|
-
- !ruby/object:Gem::Version
|
70
|
-
version: '7.0'
|
71
|
-
- - "<"
|
72
|
-
- !ruby/object:Gem::Version
|
73
|
-
version: '9.0'
|
74
|
-
- !ruby/object:Gem::Dependency
|
75
|
-
name: sqlite3
|
76
|
-
requirement: !ruby/object:Gem::Requirement
|
77
|
-
requirements:
|
78
|
-
- - "~>"
|
79
|
-
- !ruby/object:Gem::Version
|
80
|
-
version: '1.4'
|
81
|
-
type: :development
|
82
|
-
prerelease: false
|
83
|
-
version_requirements: !ruby/object:Gem::Requirement
|
84
|
-
requirements:
|
85
|
-
- - "~>"
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
version: '1.4'
|
88
|
-
- !ruby/object:Gem::Dependency
|
89
|
-
name: database_cleaner-active_record
|
90
|
-
requirement: !ruby/object:Gem::Requirement
|
91
|
-
requirements:
|
92
|
-
- - ">="
|
93
|
-
- !ruby/object:Gem::Version
|
94
|
-
version: '0'
|
95
|
-
type: :development
|
96
|
-
prerelease: false
|
97
|
-
version_requirements: !ruby/object:Gem::Requirement
|
98
|
-
requirements:
|
99
|
-
- - ">="
|
100
|
-
- !ruby/object:Gem::Version
|
101
|
-
version: '0'
|
102
|
-
- !ruby/object:Gem::Dependency
|
103
|
-
name: factory_bot
|
104
|
-
requirement: !ruby/object:Gem::Requirement
|
105
|
-
requirements:
|
106
|
-
- - ">="
|
107
|
-
- !ruby/object:Gem::Version
|
108
|
-
version: '0'
|
109
|
-
type: :development
|
110
|
-
prerelease: false
|
111
|
-
version_requirements: !ruby/object:Gem::Requirement
|
112
|
-
requirements:
|
113
|
-
- - ">="
|
114
|
-
- !ruby/object:Gem::Version
|
115
|
-
version: '0'
|
116
|
-
- !ruby/object:Gem::Dependency
|
117
|
-
name: rubocop
|
118
|
-
requirement: !ruby/object:Gem::Requirement
|
119
|
-
requirements:
|
120
|
-
- - "~>"
|
121
|
-
- !ruby/object:Gem::Version
|
122
|
-
version: '1.21'
|
123
|
-
type: :development
|
124
|
-
prerelease: false
|
125
|
-
version_requirements: !ruby/object:Gem::Requirement
|
126
|
-
requirements:
|
127
|
-
- - "~>"
|
128
|
-
- !ruby/object:Gem::Version
|
129
|
-
version: '1.21'
|
130
|
-
- !ruby/object:Gem::Dependency
|
131
|
-
name: standard
|
132
|
-
requirement: !ruby/object:Gem::Requirement
|
133
|
-
requirements:
|
134
|
-
- - ">="
|
135
|
-
- !ruby/object:Gem::Version
|
136
|
-
version: 1.35.1
|
137
|
-
type: :development
|
138
|
-
prerelease: false
|
139
|
-
version_requirements: !ruby/object:Gem::Requirement
|
140
|
-
requirements:
|
141
|
-
- - ">="
|
142
|
-
- !ruby/object:Gem::Version
|
143
|
-
version: 1.35.1
|
25
|
+
version: '7.2'
|
144
26
|
description: ActiveRecord::Ghosts allows you to define a sequence column and query
|
145
27
|
with ranges to get real + ghost records. Ghost records behave like AR objects but
|
146
28
|
aren't persisted, perfect for filling gaps in sequences like levels, numbers, etc.
|
@@ -152,7 +34,6 @@ extra_rdoc_files: []
|
|
152
34
|
files:
|
153
35
|
- ".rspec"
|
154
36
|
- ".rubocop.yml"
|
155
|
-
- ".standard.yml"
|
156
37
|
- CHANGELOG.md
|
157
38
|
- CODE_OF_CONDUCT.md
|
158
39
|
- LICENSE.txt
|
@@ -186,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
186
67
|
- !ruby/object:Gem::Version
|
187
68
|
version: '0'
|
188
69
|
requirements: []
|
189
|
-
rubygems_version: 3.6.
|
70
|
+
rubygems_version: 3.6.9
|
190
71
|
specification_version: 4
|
191
72
|
summary: Virtual rows for ActiveRecord models - fill in the gaps in your sequences
|
192
73
|
with ghost records
|
data/.standard.yml
DELETED