fractional_indexing 0.1.1 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ec000613bb56c79ff44198f1fc0e45be734922f89c22b5ce9fb5ec5ec0ae2df
4
- data.tar.gz: ead7373a2c426ff75274a5b0fb87cf3f5e8332075ae4e2c70fa071d1795c5ea8
3
+ metadata.gz: 764de1e81ced54924f6f5f5c6e5e24a07e31fa761c0b6bc0f7a697ae16676051
4
+ data.tar.gz: ae443a576b2a888e6ba4af29cd13609629ebcd90eb14ad06c13ed34664e6164a
5
5
  SHA512:
6
- metadata.gz: 8914f607fd7028a06c1082901baa30aba1330f354643af03cf1a2b99985cd239378ba96aebf17c8a241bf2dbab2550fb9111086047e45456998a07392e1494af
7
- data.tar.gz: 2b2996841ca207d20a26670d30f4dffeef721334ab6ceb2a5143abd543f400ee43b8289867c5057c8827e4f5ddf7d934003316ca13cccad133b7c6b14c5a5cff
6
+ metadata.gz: 6a0ff4c208d23826268ec6d29e3f53dd8d1b1e9d8420556efd5a5cf520a8d3f08db11b0eb185da48247e512cdf1a5fafb39503d9a004b390030dbf3daf85e27a
7
+ data.tar.gz: 3bd8c4184d9dbafacfa1055ed17fbad178e08262418b98a4e4edfe652bf7469963ae5e537990c3b6d47ae8f9af0f707ac73a048ea440ace2538f5c5f251f5c63
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fractional_indexing (0.1.0)
4
+ fractional_indexing (0.1.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -11,6 +11,7 @@ GEM
11
11
 
12
12
  PLATFORMS
13
13
  x86_64-darwin-20
14
+ x86_64-linux
14
15
 
15
16
  DEPENDENCIES
16
17
  fractional_indexing!
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/fractional_indexing/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "fractional_indexing"
7
+ spec.version = FractionalIndexing::VERSION
8
+ spec.authors = ["Andreas Alin"]
9
+ spec.email = ["andreas.alin@gmail.com"]
10
+
11
+ spec.summary = "Fractional Indexing in Ruby"
12
+ spec.homepage = "https://github.com/aalin/fractional_indexing.rb"
13
+ spec.license = " CC0-1.0"
14
+ spec.required_ruby_version = ">= 2.6.0"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = spec.homepage
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(__dir__) do
22
+ `git ls-files -z`.split("\x0").reject do |f|
23
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|circleci)|appveyor)})
24
+ end
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FractionalIndexing
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.2"
5
5
  end
@@ -25,22 +25,16 @@ module FractionalIndexing
25
25
  # digits is a string such as '0123456789' for base 10. Digits must be in
26
26
  # ascending character code order!
27
27
  raise Error, "#{a} >= #{b}" if b && a >= b
28
- raise Error, "trailing zero" if (a[-1] == "0") || (b && (b[-1] == "0"))
28
+ raise Error, "trailing zero" if a.end_with?("0") || b&.end_with?("0")
29
+
29
30
  if b
30
31
  # remove longest common prefix. pad `a` with 0s as we
31
32
  # go. note that we don't need to pad `b`, because it can't
32
33
  # end before `a` while traversing the common prefix.
33
- n = 0
34
- a = a.ljust(b.length, "0")
35
- for i in 0..(b.length - 1)
36
- if a[i] == b[i]
37
- n += 1
38
- else
39
- break
40
- end
34
+ n = b.each_char.with_index.count { |c, i| (a[i] || "0") == c }
35
+ if n > 0
36
+ return b[0...n] + midpoint(a[n..], b[n..], digits)
41
37
  end
42
-
43
- return b[0..(n - 1)] + midpoint(a[n..-1], b[n..-1], digits) if n > 0
44
38
  end
45
39
 
46
40
  # first digits (or lack of digit) are different
@@ -50,6 +44,7 @@ module FractionalIndexing
50
44
  min_digit = (0.5 * (digit_a + digit_b)).round
51
45
  return digits[min_digit]
52
46
  else
47
+ # first digits are consecutive
53
48
  if b && b.length > 1
54
49
  return b[0]
55
50
  else
@@ -59,45 +54,51 @@ module FractionalIndexing
59
54
  # given, for example, midpoint('49', '5'), return
60
55
  # '4' + midpoint('9', null), which will become
61
56
  # '4' + '9' + midpoint('', null), which is '495'
62
- digit_a = a.empty? ? 0 : digits.index(a[0])
63
- return digits[digit_a] + midpoint(a[1..-1], nil, digits)
57
+ return digits[digit_a] + midpoint(a[1..], nil, digits)
64
58
  end
65
59
  end
66
60
  end
67
61
 
68
- def self.validate_integer(i)
69
- unless i.length == get_integer_length(i[0])
70
- raise Error, "invalid integer part of order key: #{i}"
62
+ def self.validate_integer(int)
63
+ unless int.length == get_integer_length(int[0])
64
+ raise Error, "invalid integer part of order key: #{int}"
71
65
  end
72
66
  end
73
67
 
74
68
  def self.get_integer_length(head)
75
- if ('a'..'z').cover?(head)
76
- return head.ord - 'a'.ord + 2
77
- elsif ('A'..'Z').cover?(head)
78
- return 'Z'.ord - head.ord + 2
69
+ case head
70
+ in 'a'..'z'
71
+ head.ord - 'a'.ord + 2
72
+ in 'A'..'Z'
73
+ 'Z'.ord - head.ord + 2
74
+ else
75
+ raise Error, "invalid order key head: #{head}"
79
76
  end
80
- raise Error, "invalid order key head: " + head
81
77
  end
82
78
 
83
79
  def self.get_integer_part(key)
84
80
  integer_part_length = get_integer_length(key[0])
85
- raise Error, "invalid order key: #{key}" if integer_part_length > key.size
86
81
 
87
- key[0...integer_part_length]
82
+ if integer_part_length > key.length
83
+ raise Error, "invalid order key: #{key}"
84
+ end
85
+
86
+ key.slice(0, integer_part_length)
88
87
  end
89
88
 
90
89
  def self.validate_order_key(key)
91
- raise Error, "invalid order key: #{key}" if key == SMALLEST_INTEGER
90
+ if key == SMALLEST_INTEGER
91
+ raise Error, "invalid order key: #{key}"
92
+ end
92
93
 
93
94
  # get_integer_part() will throw if the first character is bad,
94
95
  # or the key is too short. we'd call it to check these things
95
96
  # even if we didn't need the result
96
97
  i = get_integer_part(key)
97
98
  f = key[i.size..]
98
- raise Error, "invalid order key: #{key}" if f[-1] == "0"
99
-
100
- nil
99
+ if f.end_with?("0")
100
+ raise Error, "invalid order key: #{key}"
101
+ end
101
102
  end
102
103
 
103
104
  def self.increment_integer(x, digits)
@@ -126,12 +127,16 @@ module FractionalIndexing
126
127
  else
127
128
  digs.pop
128
129
  end
129
- return h + digs.join
130
+ h + digs.join
130
131
  else
131
- return head + digs.join
132
+ head + digs.join
132
133
  end
133
134
  end
134
135
 
136
+ def self.increment_integer!(x, digits)
137
+ increment_integer(x, digits) or raise(Error, "cannot increment anymore")
138
+ end
139
+
135
140
  def self.decrement_integer(x, digits)
136
141
  validate_integer(x)
137
142
  head, *digs = x.chars
@@ -152,53 +157,61 @@ module FractionalIndexing
152
157
  elsif head == 'A'
153
158
  return nil
154
159
  end
155
- h = (head.ord - 1).chr
160
+ h = head.ord.pred.chr
156
161
  if h < 'Z'
157
162
  digs.push(digits[-1])
158
163
  else
159
164
  digs.pop
160
165
  end
161
- return h + digs.join
166
+ h + digs.join
162
167
  else
163
- return head + digs.join
168
+ head + digs.join
164
169
  end
165
170
  end
166
171
 
172
+ def self.decrement_integer!(x, digits)
173
+ decrement_integer(x, digits) or raise(Error, "cannot decrement anymore")
174
+ end
175
+
167
176
  def self.generate_key_between(a, b, digits = BASE_62_DIGITS)
168
177
  validate_order_key(a) if a
169
178
  validate_order_key(b) if b
170
- raise "a >= b" if a && b && a >= b
179
+ raise "#{a.inspect} >= #{b.inspect}" if a && b && a >= b
180
+
181
+ unless a
182
+ return INTEGER_ZERO unless b
171
183
 
172
- if a == nil
173
- return INTEGER_ZERO if b == nil
174
184
  ib = get_integer_part(b)
175
- fb = b[ib.length..-1]
176
- return ib + midpoint("", fb, digits) if ib == SMALLEST_INTEGER
177
- return ib if ib < b
178
- res = decrement_integer(ib, digits)
179
- raise "cannot decrement any more" if res == nil
180
- return res
185
+ if ib == SMALLEST_INTEGER
186
+ fb = b[ib.length..]
187
+ return ib + midpoint("", fb, digits)
188
+ elsif ib < b
189
+ return ib
190
+ else
191
+ return decrement_integer!(ib, digits)
192
+ end
181
193
  end
182
194
 
183
- if b == nil
195
+ unless b
184
196
  ia = get_integer_part(a)
185
- fa = a[ia.length..-1]
186
- i = increment_integer(ia, digits)
187
- return ia + midpoint(fa, nil, digits) if i == nil
188
- return i
197
+ fa = a[ia.length..]
198
+ return increment_integer(ia, digits) || (ia + midpoint(fa, nil, digits))
189
199
  end
190
200
 
191
201
  ia = get_integer_part(a)
192
- fa = a[ia.length..-1]
202
+ fa = a[ia.length..]
193
203
  ib = get_integer_part(b)
194
- fb = b[ib.length..-1]
195
- return ia + midpoint(fa, fb, digits) if ia == ib
196
- i = increment_integer(ia, digits)
197
- raise "cannot increment any more" if i == nil
204
+ fb = b[ib.length..]
205
+
206
+ if ia == ib
207
+ return ia + midpoint(fa, fb, digits)
208
+ end
209
+
210
+ i = increment_integer!(ia, digits)
198
211
 
199
212
  return i if i < b
200
213
 
201
- return ia + midpoint(fa, nil, digits)
214
+ ia + midpoint(fa, nil, digits)
202
215
  end
203
216
 
204
217
  # Returns an array of n distinct keys in sorted order.
@@ -206,42 +219,26 @@ module FractionalIndexing
206
219
  # If one or the other is nil, returns consecutive "integer"
207
220
  # keys. Otherwise, returns relatively short keys between.
208
221
  def self.generate_n_keys_between(a, b, n, digits = BASE_62_DIGITS)
209
- return [] if n.zero?
210
-
211
- return [generate_key_between(a, b, digits)] if n == 1
212
-
213
- unless b
214
- c = generate_key_between(a, b, digits)
215
- result = [c]
216
- (n - 1).times do
217
- c = generate_key_between(c, b, digits)
218
- result << c
219
- end
220
- return result
222
+ if n == 0
223
+ return []
224
+ elsif n == 1
225
+ return [generate_key_between(a, b, digits)]
221
226
  end
222
227
 
223
- unless a
224
- c = generate_key_between(a, b, digits)
225
- result = [c]
226
- (n - 1).times do
227
- c = generate_key_between(a, c, digits)
228
- result << c
229
- end
230
- return result.reverse
231
- end
228
+ return n.times.map do
229
+ a = generate_key_between(a, b, digits)
230
+ end unless b
232
231
 
233
- mid = n / 2
232
+ return n.times.map do
233
+ b = generate_key_between(a, b, digits)
234
+ end.reverse unless a
235
+
236
+ mid = (n / 2).floor
234
237
  c = generate_key_between(a, b, digits)
235
238
  [
236
- *generate_n_keys_between(a, c, mid.floor, digits),
239
+ *generate_n_keys_between(a, c, mid, digits),
237
240
  c,
238
- *generate_n_keys_between(c, b, n - mid.floor - 1, digits)
241
+ *generate_n_keys_between(c, b, n - mid - 1, digits)
239
242
  ]
240
243
  end
241
-
242
- # Rounds a float to an integer using decimal.Decimal.quantize with
243
- # decimal.ROUND_HALF_UP rounding method.
244
- def self.round_half_up(n)
245
- (n.to_d.round(0, half: :up)).to_i
246
- end
247
244
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fractional_indexing
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Alin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-04-07 00:00:00.000000000 Z
11
+ date: 2023-04-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -22,6 +22,7 @@ files:
22
22
  - LICENSE
23
23
  - README.md
24
24
  - Rakefile
25
+ - fractional_indexing.gemspec
25
26
  - lib/fractional_indexing.rb
26
27
  - lib/fractional_indexing/version.rb
27
28
  - sig/fractional_indexing.rbs