fractional_indexer 0.3.1 → 0.4.1
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/README.md +276 -34
- data/lib/fractional_indexer/order_key.rb +10 -6
- data/lib/fractional_indexer/version.rb +1 -1
- data/lib/fractional_indexer.rb +12 -1
- metadata +12 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 647cdf5b4ac5ad3835667390221cfb694a37be44b50f494326ecc1a4d5a75b75
|
|
4
|
+
data.tar.gz: 3496c2e7f1132bb5699a26d614e9a66999733caeddd4b4d0c463cdcf2977848b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fdac9f7b6ebee39cdf765b81d5cb5c739632e1ad0b7de48e1b28f465a60a0b0afbdf1157ffe5df3f9ebddddca0d5b7d6c96323b5d80424e138ee36abcc1624da
|
|
7
|
+
data.tar.gz: 28bd39cf30678fed311bf1b9908ac76824b079859fa755bd8c2b181147ef3646dccbca8f257ee3ac763f0d2cff3f9f54b64bc398243d6ddcf7a3539a11da2155
|
data/README.md
CHANGED
|
@@ -3,13 +3,45 @@
|
|
|
3
3
|
[](https://codecov.io/gh/kazu-2020/fractional_indexer)
|
|
4
4
|
[](https://github.com/kazu-2020/fractional_indexer/actions/workflows/ruby.yml)
|
|
5
5
|
|
|
6
|
-
>
|
|
6
|
+
> Efficient data insertion and sorting through fractional indexing
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
## Overview
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Fractional Indexer is a Ruby gem that implements **fractional indexing** for managing ordered sequences. Instead of using integer positions that require reindexing on insertion, it uses string-based keys that allow inserting items anywhere without affecting existing items.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
### Why Fractional Indexing?
|
|
13
|
+
|
|
14
|
+
**Traditional integer indexing** requires shifting all subsequent items when inserting:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
Before: [A:1] [B:2] [C:3]
|
|
18
|
+
↓
|
|
19
|
+
Insert X between A and B
|
|
20
|
+
↓
|
|
21
|
+
After: [A:1] [X:2] [B:3] [C:4] ← B and C must be updated!
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Fractional indexing** generates a key between existing keys without reindexing:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
Before: [A:"a0"] [B:"a1"] [C:"a2"]
|
|
28
|
+
↓
|
|
29
|
+
Insert X between A and B
|
|
30
|
+
↓
|
|
31
|
+
After: [A:"a0"] [X:"a0V"] [B:"a1"] [C:"a2"] ← No changes to B or C!
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Key Features
|
|
35
|
+
|
|
36
|
+
- **No reindexing required** - Insert items between any two existing items
|
|
37
|
+
- **String-based keys** - Avoids floating-point precision issues
|
|
38
|
+
- **Configurable base** - Supports base-10, base-62 (default), and base-94
|
|
39
|
+
- **Multiple key generation** - Generate multiple keys at once for batch operations
|
|
40
|
+
|
|
41
|
+
This gem implements the concepts from "[Realtime editing of ordered sequences](https://www.figma.com/blog/realtime-editing-of-ordered-sequences/#fractional-indexing)" (Figma Engineering Blog).
|
|
42
|
+
|
|
43
|
+
> [!TIP]
|
|
44
|
+
> **Using Rails?** Check out [narabikae](https://github.com/kazu-2020/narabikae) - an Active Record integration that makes fractional indexing as simple as `task.move_to_position_after(other_task)`
|
|
13
45
|
|
|
14
46
|
## Installation
|
|
15
47
|
|
|
@@ -21,100 +53,310 @@ gem 'fractional_indexer'
|
|
|
21
53
|
|
|
22
54
|
And then execute:
|
|
23
55
|
|
|
24
|
-
|
|
56
|
+
```sh
|
|
57
|
+
bundle
|
|
58
|
+
```
|
|
25
59
|
|
|
26
60
|
Or install it yourself as:
|
|
27
61
|
|
|
28
|
-
|
|
62
|
+
```sh
|
|
63
|
+
gem install fractional_indexer
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Quick Start
|
|
29
67
|
|
|
30
|
-
|
|
68
|
+
```ruby
|
|
69
|
+
require 'fractional_indexer'
|
|
70
|
+
|
|
71
|
+
# Step 1: Generate your first key
|
|
72
|
+
first_key = FractionalIndexer.generate_key
|
|
73
|
+
# => "a0"
|
|
74
|
+
|
|
75
|
+
# Step 2: Generate the next key (for appending)
|
|
76
|
+
second_key = FractionalIndexer.generate_key(prev_key: first_key)
|
|
77
|
+
# => "a1"
|
|
31
78
|
|
|
32
|
-
|
|
79
|
+
# Step 3: Insert between two keys
|
|
80
|
+
middle_key = FractionalIndexer.generate_key(prev_key: first_key, next_key: second_key)
|
|
81
|
+
# => "a0V"
|
|
33
82
|
|
|
34
|
-
|
|
83
|
+
# Result: first_key < middle_key < second_key
|
|
84
|
+
# "a0" < "a0V" < "a1"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## How It Works
|
|
88
|
+
|
|
89
|
+
### Order Key Structure
|
|
90
|
+
|
|
91
|
+
An order key consists of two parts: an **integer part** and an optional **fractional part**.
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
"a3012"
|
|
95
|
+
│└┬┘└┬┘
|
|
96
|
+
│ │ └── Fractional Part: "012" (optional, for fine-grained positioning)
|
|
97
|
+
│ └───── Integer Digits: "3" (the numeric value)
|
|
98
|
+
└─────── Prefix: "a" (indicates 1-digit positive integer)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Prefix rules:**
|
|
102
|
+
- `a` to `z`: Positive integers (a=1 digit, b=2 digits, ..., z=26 digits)
|
|
103
|
+
- `A` to `Z`: Negative integers (used for keys "before" zero)
|
|
104
|
+
|
|
105
|
+
**Examples:**
|
|
106
|
+
|
|
107
|
+
| Key | Integer Part | Fractional Part | Meaning |
|
|
108
|
+
|-----|-------------|-----------------|---------|
|
|
109
|
+
| `a5` | `a5` | (none) | Positive 1-digit: 5 |
|
|
110
|
+
| `b12` | `b12` | (none) | Positive 2-digit: 12 |
|
|
111
|
+
| `a3V` | `a3` | `V` | Between a3 and a4 |
|
|
112
|
+
| `Zz` | `Zz` | (none) | Largest negative number |
|
|
113
|
+
|
|
114
|
+
### Key Generation Flow
|
|
35
115
|
|
|
36
|
-
The
|
|
116
|
+
The following diagram shows how `generate_key` determines which operation to perform:
|
|
117
|
+
|
|
118
|
+
```mermaid
|
|
119
|
+
flowchart TD
|
|
120
|
+
A[generate_key] --> B{prev_key and next_key?}
|
|
121
|
+
B -->|Both nil| C["Return 'a0'<br/>(initial key)"]
|
|
122
|
+
B -->|Only prev_key| D["Increment<br/>(next key after prev)"]
|
|
123
|
+
B -->|Only next_key| E["Decrement<br/>(key before next)"]
|
|
124
|
+
B -->|Both provided| F["Midpoint<br/>(key between both)"]
|
|
125
|
+
|
|
126
|
+
D --> G["a0 → a1 → a2 → ..."]
|
|
127
|
+
E --> H["... → Zy → Zz → a0"]
|
|
128
|
+
F --> I["a0, a2 → a1<br/>a0, a1 → a0V"]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Usage
|
|
132
|
+
|
|
133
|
+
### Basic Usage
|
|
134
|
+
|
|
135
|
+
#### Generating a Single Key
|
|
37
136
|
|
|
38
137
|
```ruby
|
|
39
138
|
require 'fractional_indexer'
|
|
40
139
|
|
|
41
|
-
#
|
|
140
|
+
# Create the first order key (when no keys exist)
|
|
42
141
|
FractionalIndexer.generate_key
|
|
43
142
|
# => "a0"
|
|
44
143
|
|
|
45
|
-
#
|
|
144
|
+
# Increment: generate key after a given key
|
|
46
145
|
FractionalIndexer.generate_key(prev_key: 'a0')
|
|
47
146
|
# => "a1"
|
|
48
147
|
|
|
49
|
-
#
|
|
148
|
+
# Decrement: generate key before a given key
|
|
50
149
|
FractionalIndexer.generate_key(next_key: 'a0')
|
|
51
150
|
# => "Zz"
|
|
52
151
|
|
|
53
|
-
# between
|
|
152
|
+
# Between: generate key between two keys
|
|
54
153
|
FractionalIndexer.generate_key(prev_key: 'a0', next_key: 'a2')
|
|
55
154
|
# => "a1"
|
|
56
|
-
|
|
57
|
-
# prev_key should be less than next_key
|
|
58
|
-
FractionalIndexer.generate_key(prev_key: 'a2', next_key: 'a1')
|
|
59
|
-
# => error
|
|
60
|
-
FractionalIndexer.generate_key(prev_key: 'a1', next_key: 'a1')
|
|
61
|
-
# => error
|
|
62
155
|
```
|
|
63
156
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
To generate multiple order keys, use the `FractionalIndexer.generate_keys` method.
|
|
157
|
+
#### Generating Multiple Keys
|
|
67
158
|
|
|
68
159
|
```ruby
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
# generate n order keys that sequentially follow a given prev_key.
|
|
160
|
+
# Generate 5 keys after "b11"
|
|
72
161
|
FractionalIndexer.generate_keys(prev_key: "b11", count: 5)
|
|
73
162
|
# => ["b12", "b13", "b14", "b15", "b16"]
|
|
74
163
|
|
|
75
|
-
#
|
|
164
|
+
# Generate 5 keys before "b11"
|
|
76
165
|
FractionalIndexer.generate_keys(next_key: "b11", count: 5)
|
|
77
166
|
# => ["b0w", "b0x", "b0y", "b0z", "b10"]
|
|
78
167
|
|
|
79
|
-
#
|
|
168
|
+
# Generate 5 keys between "b10" and "b11"
|
|
80
169
|
FractionalIndexer.generate_keys(prev_key: "b10", next_key: "b11", count: 5)
|
|
81
170
|
# => ["b108", "b10G", "b10V", "b10d", "b10l"]
|
|
82
171
|
```
|
|
83
172
|
|
|
84
|
-
|
|
173
|
+
#### Error Handling
|
|
174
|
+
|
|
175
|
+
```ruby
|
|
176
|
+
# prev_key must be less than next_key
|
|
177
|
+
FractionalIndexer.generate_key(prev_key: 'a2', next_key: 'a1')
|
|
178
|
+
# => raises error
|
|
179
|
+
|
|
180
|
+
# prev_key and next_key cannot be equal
|
|
181
|
+
FractionalIndexer.generate_key(prev_key: 'a1', next_key: 'a1')
|
|
182
|
+
# => raises error
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Practical Examples
|
|
186
|
+
|
|
187
|
+
#### Example 1: Task List Management
|
|
188
|
+
|
|
189
|
+
```ruby
|
|
190
|
+
# Managing a todo list with fractional indexing
|
|
191
|
+
tasks = []
|
|
192
|
+
|
|
193
|
+
# Add initial tasks
|
|
194
|
+
tasks << { id: 1, title: "Write code", position: FractionalIndexer.generate_key }
|
|
195
|
+
tasks << { id: 2, title: "Write tests", position: FractionalIndexer.generate_key(prev_key: tasks.last[:position]) }
|
|
196
|
+
tasks << { id: 3, title: "Deploy", position: FractionalIndexer.generate_key(prev_key: tasks.last[:position]) }
|
|
197
|
+
|
|
198
|
+
tasks.each { |t| puts "#{t[:position]}: #{t[:title]}" }
|
|
199
|
+
# a0: Write code
|
|
200
|
+
# a1: Write tests
|
|
201
|
+
# a2: Deploy
|
|
202
|
+
|
|
203
|
+
# Insert "Code review" between "Write tests" and "Deploy"
|
|
204
|
+
new_position = FractionalIndexer.generate_key(
|
|
205
|
+
prev_key: tasks[1][:position], # "a1"
|
|
206
|
+
next_key: tasks[2][:position] # "a2"
|
|
207
|
+
)
|
|
208
|
+
tasks << { id: 4, title: "Code review", position: new_position }
|
|
209
|
+
|
|
210
|
+
# Sort by position
|
|
211
|
+
tasks.sort_by! { |t| t[:position] }
|
|
212
|
+
tasks.each { |t| puts "#{t[:position]}: #{t[:title]}" }
|
|
213
|
+
# a0: Write code
|
|
214
|
+
# a1: Write tests
|
|
215
|
+
# a1V: Code review ← Inserted without changing other positions!
|
|
216
|
+
# a2: Deploy
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
#### Example 2: Prepending and Appending
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
# Start with a middle item
|
|
223
|
+
items = [{ name: "B", pos: FractionalIndexer.generate_key }]
|
|
224
|
+
# items[0][:pos] => "a0"
|
|
225
|
+
|
|
226
|
+
# Append to the end (only prev_key)
|
|
227
|
+
items << { name: "C", pos: FractionalIndexer.generate_key(prev_key: items.last[:pos]) }
|
|
228
|
+
# items[1][:pos] => "a1"
|
|
229
|
+
|
|
230
|
+
# Prepend to the beginning (only next_key)
|
|
231
|
+
items.unshift({ name: "A", pos: FractionalIndexer.generate_key(next_key: items.first[:pos]) })
|
|
232
|
+
# items[0][:pos] => "Zz"
|
|
233
|
+
|
|
234
|
+
items.sort_by { |i| i[:pos] }.each { |i| puts "#{i[:pos]}: #{i[:name]}" }
|
|
235
|
+
# Zz: A
|
|
236
|
+
# a0: B
|
|
237
|
+
# a1: C
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
#### Example 3: Batch Insertion
|
|
241
|
+
|
|
242
|
+
```ruby
|
|
243
|
+
# Insert 5 items between two existing items at once
|
|
244
|
+
existing = [
|
|
245
|
+
{ name: "First", pos: "a0" },
|
|
246
|
+
{ name: "Last", pos: "a1" }
|
|
247
|
+
]
|
|
248
|
+
|
|
249
|
+
# Generate 5 keys between "a0" and "a1"
|
|
250
|
+
new_positions = FractionalIndexer.generate_keys(
|
|
251
|
+
prev_key: existing[0][:pos],
|
|
252
|
+
next_key: existing[1][:pos],
|
|
253
|
+
count: 5
|
|
254
|
+
)
|
|
255
|
+
# => ["a08", "a0G", "a0V", "a0d", "a0l"]
|
|
256
|
+
|
|
257
|
+
new_items = new_positions.map.with_index do |pos, i|
|
|
258
|
+
{ name: "Item #{i + 1}", pos: pos }
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
all_items = (existing + new_items).sort_by { |i| i[:pos] }
|
|
262
|
+
all_items.each { |i| puts "#{i[:pos]}: #{i[:name]}" }
|
|
263
|
+
# a0: First
|
|
264
|
+
# a08: Item 1
|
|
265
|
+
# a0G: Item 2
|
|
266
|
+
# a0V: Item 3
|
|
267
|
+
# a0d: Item 4
|
|
268
|
+
# a0l: Item 5
|
|
269
|
+
# a1: Last
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
#### Example 4: Key Growth Over Time
|
|
273
|
+
|
|
274
|
+
When repeatedly inserting at the same position, keys grow longer to maintain precision:
|
|
85
275
|
|
|
86
|
-
|
|
276
|
+
```ruby
|
|
277
|
+
# Repeatedly insert at the beginning
|
|
278
|
+
key = FractionalIndexer.generate_key # => "a0"
|
|
279
|
+
puts "Initial: #{key}"
|
|
87
280
|
|
|
88
|
-
|
|
281
|
+
5.times do |i|
|
|
282
|
+
key = FractionalIndexer.generate_key(prev_key: key, next_key: "a1")
|
|
283
|
+
puts "Insert #{i + 1}: #{key}"
|
|
284
|
+
end
|
|
89
285
|
|
|
90
|
-
|
|
286
|
+
# Initial: a0
|
|
287
|
+
# Insert 1: a0V
|
|
288
|
+
# Insert 2: a0l
|
|
289
|
+
# Insert 3: a0t
|
|
290
|
+
# Insert 4: a0x
|
|
291
|
+
# Insert 5: a0z
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Configuration
|
|
295
|
+
|
|
296
|
+
### Base System
|
|
297
|
+
|
|
298
|
+
You can configure the base (number system) used to represent each digit. The possible values are `:base_10`, `:base_62` (default), and `:base_94`.
|
|
299
|
+
|
|
300
|
+
| Base | Characters | Use Case |
|
|
301
|
+
|------|-----------|----------|
|
|
302
|
+
| `:base_10` | `0-9` | Debugging, human-readable |
|
|
303
|
+
| `:base_62` | `0-9`, `A-Z`, `a-z` | General use (default) |
|
|
304
|
+
| `:base_94` | All printable ASCII | Maximum density |
|
|
91
305
|
|
|
92
306
|
```ruby
|
|
93
307
|
require 'fractional_indexer'
|
|
94
308
|
|
|
309
|
+
# Base 10 (for debugging)
|
|
95
310
|
FractionalIndexer.configure do |config|
|
|
96
311
|
config.base = :base_10
|
|
97
312
|
end
|
|
98
313
|
FractionalIndexer.configuration.digits.join
|
|
99
314
|
# => "0123456789"
|
|
100
315
|
|
|
316
|
+
# Base 62 (default)
|
|
101
317
|
FractionalIndexer.configure do |config|
|
|
102
318
|
config.base = :base_62
|
|
103
319
|
end
|
|
104
320
|
FractionalIndexer.configuration.digits.join
|
|
105
321
|
# => "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
|
106
322
|
|
|
323
|
+
# Base 94 (maximum density)
|
|
107
324
|
FractionalIndexer.configure do |config|
|
|
108
325
|
config.base = :base_94
|
|
109
326
|
end
|
|
110
327
|
FractionalIndexer.configuration.digits.join
|
|
111
|
-
# => "!\"
|
|
328
|
+
# => "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## Related Projects
|
|
332
|
+
|
|
333
|
+
### narabikae
|
|
334
|
+
|
|
335
|
+
If you're using **Ruby on Rails** with **Active Record**, check out [narabikae](https://github.com/kazu-2020/narabikae) - a gem that integrates Fractional Indexer directly into your models for seamless ordering.
|
|
336
|
+
|
|
337
|
+
```ruby
|
|
338
|
+
class Task < ApplicationRecord
|
|
339
|
+
narabikae :position, size: 200
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# Move a task after another
|
|
343
|
+
task.move_to_position_after(other_task)
|
|
344
|
+
|
|
345
|
+
# Move a task before another
|
|
346
|
+
task.move_to_position_before(other_task)
|
|
347
|
+
|
|
348
|
+
# Move a task between two others
|
|
349
|
+
task.move_to_position_between(task_a, task_b)
|
|
112
350
|
```
|
|
113
351
|
|
|
114
352
|
## Contributing
|
|
115
353
|
|
|
116
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/kazu-2020/fractional_indexer
|
|
354
|
+
Bug reports and pull requests are welcome on GitHub at <https://github.com/kazu-2020/fractional_indexer>.
|
|
117
355
|
|
|
118
356
|
## License
|
|
119
357
|
|
|
120
358
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
359
|
+
|
|
360
|
+
## Acknowledgments
|
|
361
|
+
|
|
362
|
+
This gem was implemented based on the excellent article "[Implementing Fractional Indexing](https://observablehq.com/@dgreensp/implementing-fractional-indexing)" by David Greenspan. Thank you for the clear explanation and reference implementation!
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
module FractionalIndexer
|
|
4
4
|
class OrderKey
|
|
5
5
|
INTEGER_BASE_DIGIT = 2
|
|
6
|
-
POSITIVE_SIGNS = ("a".."z")
|
|
7
|
-
NEGATIVE_SIGNS = ("A".."Z")
|
|
6
|
+
POSITIVE_SIGNS = ("a".."z")
|
|
7
|
+
NEGATIVE_SIGNS = ("A".."Z")
|
|
8
8
|
|
|
9
9
|
attr_reader :key
|
|
10
10
|
|
|
@@ -58,6 +58,10 @@ module FractionalIndexer
|
|
|
58
58
|
integer == minimum_integer
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
+
def minimum?
|
|
62
|
+
minimum_integer? && fractional.empty?
|
|
63
|
+
end
|
|
64
|
+
|
|
61
65
|
def present?
|
|
62
66
|
!(key.nil? || key.empty?)
|
|
63
67
|
end
|
|
@@ -78,14 +82,14 @@ module FractionalIndexer
|
|
|
78
82
|
"z#{digits.last * POSITIVE_SIGNS.count}"
|
|
79
83
|
end
|
|
80
84
|
|
|
81
|
-
def raise_error(description = nil)
|
|
82
|
-
raise Error, "invalid order key: '#{key}' description: #{description}"
|
|
83
|
-
end
|
|
84
|
-
|
|
85
85
|
def minimum_integer
|
|
86
86
|
"A#{digits.first * POSITIVE_SIGNS.count}"
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
+
def raise_error(description = nil)
|
|
90
|
+
raise Error, "invalid order key: '#{key}' description: #{description}"
|
|
91
|
+
end
|
|
92
|
+
|
|
89
93
|
def valid_fractional?(fractional)
|
|
90
94
|
!fractional.end_with?(digits.first)
|
|
91
95
|
end
|
data/lib/fractional_indexer.rb
CHANGED
|
@@ -91,9 +91,20 @@ module FractionalIndexer
|
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
def self.decrement(order_key)
|
|
94
|
+
# NOTE: edge case
|
|
95
|
+
# If an Order key does not have a fractional part and its integer part is equal to
|
|
96
|
+
# the minimum value (for example, in base_62: 'A00000000000000000000000000'),
|
|
97
|
+
# further decrement operations become impossible and will fail.
|
|
98
|
+
# However, this situation is typically unlikely to occur.
|
|
99
|
+
if order_key.minimum?
|
|
100
|
+
raise Error, "order key not decremented: #{order_key} is the minimum value"
|
|
101
|
+
end
|
|
94
102
|
return order_key.integer + Midpointer.execute("", order_key.fractional) if order_key.minimum_integer?
|
|
95
103
|
|
|
96
|
-
order_key.integer < order_key.key ? order_key.integer : order_key.decrement
|
|
104
|
+
decremented_order_key = OrderKey.new(order_key.integer < order_key.key ? order_key.integer : order_key.decrement)
|
|
105
|
+
return decremented_order_key.integer + Midpointer.execute if decremented_order_key.minimum?
|
|
106
|
+
|
|
107
|
+
decremented_order_key.key
|
|
97
108
|
end
|
|
98
109
|
|
|
99
110
|
def self.increment(order_key)
|
metadata
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fractional_indexer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
bindir: exe
|
|
7
|
+
- matazou
|
|
8
|
+
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies: []
|
|
13
12
|
description: |
|
|
14
13
|
FractionalIndexer is a Ruby gem designed to leverage fractional indexing for ordering within lists or data structures.
|
|
15
14
|
it enables efficient sorting and insertion of large volumes of data.
|
|
16
15
|
email:
|
|
17
|
-
-
|
|
16
|
+
- 64774307+kazu-2020@users.noreply.github.com
|
|
18
17
|
executables: []
|
|
19
18
|
extensions: []
|
|
20
19
|
extra_rdoc_files: []
|
|
@@ -32,9 +31,12 @@ homepage: https://github.com/kazu-2020/fractional_indexer
|
|
|
32
31
|
licenses:
|
|
33
32
|
- MIT
|
|
34
33
|
metadata:
|
|
34
|
+
homepage_uri: https://github.com/kazu-2020/fractional_indexer
|
|
35
|
+
changelog_uri: https://github.com/kazu-2020/fractional_indexer/releases
|
|
36
|
+
bug_tracker_uri: https://github.com/kazu-2020/fractional_indexer/issues
|
|
35
37
|
source_code_uri: https://github.com/kazu-2020/fractional_indexer
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
allowed_push_host: https://rubygems.org/
|
|
39
|
+
rubygems_mfa_required: 'true'
|
|
38
40
|
rdoc_options: []
|
|
39
41
|
require_paths:
|
|
40
42
|
- lib
|
|
@@ -42,15 +44,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
42
44
|
requirements:
|
|
43
45
|
- - ">="
|
|
44
46
|
- !ruby/object:Gem::Version
|
|
45
|
-
version: '
|
|
47
|
+
version: '3.1'
|
|
46
48
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
47
49
|
requirements:
|
|
48
50
|
- - ">="
|
|
49
51
|
- !ruby/object:Gem::Version
|
|
50
52
|
version: '0'
|
|
51
53
|
requirements: []
|
|
52
|
-
rubygems_version: 3.
|
|
53
|
-
signing_key:
|
|
54
|
+
rubygems_version: 3.6.7
|
|
54
55
|
specification_version: 4
|
|
55
56
|
summary: efficient data insertion and sorting through fractional indexing
|
|
56
57
|
test_files: []
|