onliest 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 231435f376731f8c8e9ea57de9c5fa72c93584f6
4
- data.tar.gz: fae174999ac03c89d9847efc9f26687cd1b9336a
3
+ metadata.gz: efb038a4ae13fe3e96144555528df22c58069f09
4
+ data.tar.gz: 253159af40687da8125e46543ffbdf28a95cb646
5
5
  SHA512:
6
- metadata.gz: 75b616b372f8431dbbebd7395fefb3c0ab8737672568f931585cb25e0d2ff7973d23ccd1cfb5d8610a9868bb80d107dc197d5a756d8a95189ab1784aee0c7b9d
7
- data.tar.gz: 7a55e1ee34960ce44e98dc0ce63c00a9cfd03462dd8b96b9c68ad1de3dede8da9619c6392acd92fd2d88a5eeaa11e4251826d032bb7acf0f09a08ccc018e6ffa
6
+ metadata.gz: a3ad14aebd918aabb5b046f4b769220ed41fa4f668371b84126e084ca6522d98f47d109adf0099af6a426610bdb99ba5b23f8f67e23e5e7b9d1a555e67160df2
7
+ data.tar.gz: 976cc81e29400a059d515b6406ceb17ce6d55a10463b839d1128ab1a21eb71325b92eb3895f6fd67fa855a352a250fed769427a8e191acb331c2bdaea504b137
@@ -0,0 +1,42 @@
1
+ require 'onliest'
2
+
3
+ class Onliest::Snowflake < Onliest
4
+ attr_reader :worker_number, :sequence
5
+
6
+ # This comes from twitter snowflake. I'm not
7
+ # sure how they arrived at this number.
8
+ # November 3, 2010 at 11:42:55
9
+ EPOCH = 1288834974657
10
+
11
+ def initialize(worker_number)
12
+ @worker_number = worker_number
13
+ @sequence = 0
14
+ @older_time = 0
15
+ super(fields: [{ bits: 1, generator: ->{ 0 } },
16
+ { bits: 41, generator: ->{ time } },
17
+ { bits: 10, generator: ->{ worker_number } },
18
+ { bits: 12, generator: ->{ sequence_nextval } }])
19
+ end
20
+
21
+ private
22
+
23
+ def sequence_nextval
24
+ i = @sequence
25
+ @sequence = @sequence.succ
26
+ i
27
+ end
28
+
29
+ def time
30
+ while (t = time_now) < @older_time
31
+ #puts @older_time
32
+ #puts t
33
+ sleep((@older_time - t) / 1000)
34
+ end
35
+ @older_time = t
36
+ t
37
+ end
38
+
39
+ def time_now
40
+ ((Time.now.to_f * 1000).to_i - EPOCH)
41
+ end
42
+ end
data/lib/onliest.rb CHANGED
@@ -24,23 +24,28 @@ class Onliest
24
24
  # +SecureRandom+. An object that implements +:random_number+
25
25
  # returning a random integer >= 0 and less than value provided as
26
26
  # the first argument.
27
- def initialize(rng = DEFAULT_RNG)
28
- @rng = rng
27
+ def initialize(rng: DEFAULT_RNG, fields: false)
28
+ @fields = fields ? fields : default_fields(rng)
29
29
  end
30
30
 
31
- # Return the unique 72-bit value
31
+ # Construct and return the unique value
32
32
  def value
33
- (some_time_bits << RANDOM_BITS) +
34
- some_random_bits
33
+ total_bits = 0
34
+ total_value = 0
35
+ @fields.reverse.each do |field|
36
+ bits = field.fetch(:bits)
37
+ field_value = Integer(field.fetch(:generator).call) & ((2**bits) - 1)
38
+ total_value += (field_value << total_bits)
39
+ total_bits += bits
40
+ end
41
+ total_value
35
42
  end
36
43
 
37
44
  private
38
45
 
39
- def some_random_bits
40
- @rng.random_number(RANDOM_BITMASK + 1)
41
- end
42
-
43
- def some_time_bits
44
- Time.now.to_i & TIME_BITMASK
46
+ def default_fields(rng)
47
+ [{ bits: TIME_BITS, generator: -> { Time.now.to_i } },
48
+ { bits: RANDOM_BITS,
49
+ generator: -> { rng.random_number(RANDOM_BITMASK + 1) } }]
45
50
  end
46
51
  end
@@ -1,8 +1,9 @@
1
- require 'minitest/autorun'
2
-
1
+ require_relative './test_setup'
3
2
  require 'onliest'
4
3
 
5
- class OnliestTest < Minitest::Unit::TestCase
4
+ # Tests for the dkjefault scheme
5
+
6
+ class OnliestDefaultTest < TestCase
6
7
  def test_generates_a_number
7
8
  assert_kind_of(Integer, Onliest.value)
8
9
  end
@@ -16,31 +17,25 @@ class OnliestTest < Minitest::Unit::TestCase
16
17
  fake_prng.expect(:random_number, value, [2**47])
17
18
  end
18
19
 
19
- def at(value)
20
- Time.stub(:now, Time.at(value)) do
21
- yield
22
- end
23
- end
24
-
25
20
  def test_with_a_time_and_a_prng
26
21
  at((2**25) + 1) do
27
22
  random_value = 2
28
- gen = Onliest.new(fake_prng(random_value))
29
- assert_equal(gen.value, (1 << 47) + random_value)
23
+ gen = Onliest.new(rng: fake_prng(random_value))
24
+ assert_equal((1 << 47) + random_value, gen.value)
30
25
  end
31
26
  end
32
27
 
33
28
  def test_the_littlest_onliest
34
29
  at(0) do
35
- gen = Onliest.new(fake_prng(0))
30
+ gen = Onliest.new(rng: fake_prng(0))
36
31
  assert_equal(gen.value, 0)
37
32
  end
38
33
  end
39
34
 
40
35
  def test_the_largest_onliest
41
36
  at(2**25 - 1) do
42
- gen = Onliest.new(fake_prng(2**47 - 1))
43
- assert_equal(gen.value, 2**72 - 1)
37
+ gen = Onliest.new(rng: fake_prng(2**47 - 1))
38
+ assert_equal(2**72 - 1, gen.value)
44
39
  end
45
40
  end
46
41
  end
@@ -0,0 +1,54 @@
1
+ require_relative './test_setup'
2
+ require 'onliest/snowflake'
3
+
4
+ class SnowflakeTests < TestCase
5
+ def worker_number
6
+ '13'
7
+ end
8
+
9
+ def generator
10
+ Onliest::Snowflake.new(worker_number)
11
+ end
12
+
13
+ def test_snowflake_sign_bit_is_zero
14
+ assert_equal(0, generator.value & (1 << 63))
15
+ end
16
+
17
+ def test_snowflake_time_with_millisecond_precision
18
+ at(1.1234 + (Onliest::Snowflake::EPOCH.to_f / 1000)) do
19
+ assert_equal(1123, generator.value >> 22)
20
+ end
21
+ end
22
+
23
+ def test_snowflake_worker_number
24
+ assert_equal(worker_number.to_i, (generator.value & (2**22 - 1)) >> 12)
25
+ end
26
+
27
+ def test_snowflake_sequence_starts_at_zero
28
+ assert_equal(0, generator.value & ((2**12 - 1)))
29
+ end
30
+
31
+ def test_snowflake_sequence_increments
32
+ at(Time.now.to_i) do
33
+ gen = generator
34
+ assert_equal(gen.value, gen.value - 1)
35
+ end
36
+ end
37
+
38
+ def test_snowflake_epoch_starts_at_1288834974_657
39
+ at(1288834974657.to_f / 1000) do
40
+ assert_equal(0, generator.value >> 22)
41
+ end
42
+ end
43
+
44
+ def test_time_always_goes_forward
45
+ gen = generator
46
+ times = [Onliest::Snowflake::EPOCH + 0.10,
47
+ Onliest::Snowflake::EPOCH,
48
+ Onliest::Snowflake::EPOCH + 0.11]
49
+
50
+ Time.stub(:now, ->{ times.shift } ) do
51
+ assert(gen.value < gen.value)
52
+ end
53
+ end
54
+ end
metadata CHANGED
@@ -1,37 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: onliest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Church
8
8
  autorequire:
9
9
  bindir: bin
10
- cert_chain:
11
- - |
12
- -----BEGIN CERTIFICATE-----
13
- MIIDaDCCAlCgAwIBAgIBATANBgkqhkiG9w0BAQUFADA9MQ8wDQYDVQQDDAZjaHJj
14
- aHIxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2NvbTAe
15
- Fw0xNDExMTcwMzU0NDZaFw0xNTExMTcwMzU0NDZaMD0xDzANBgNVBAMMBmNocmNo
16
- cjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYDY29tMIIB
17
- IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxYcGTCEi6hbbKJf8NtH1UIGg
18
- OFlMQjzp/QgN4IQV8wJbePzkm9Zfy0I19u/0Q+WmepkpwGLwEb84yiInpHpYKhVW
19
- 7MQOekiS+JxfGgXfAUtUZLLeeCe+R5IO9mZx+8PmA+S/WWaZngGuJE9vAi0Cobr7
20
- dKpsSeavB/mkE0V0jGnaUc6rJeO8sB/nzOeJ9OqxgUUI4698POpGLknhq9of//Yx
21
- 51WwQul6sItx/AELZKEM/Zuu+nvMCYFU0oM0OHMYaN5EDERjLGVXAYBTyKuUq0js
22
- kAydz6hfkrTBw8Aa/2s7w12EFq5jTBPS8fhvTFdGbveoF8HZuYV0PNEnSbhRpQID
23
- AQABo3MwcTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUQT0zqrtG
24
- cFXJ2o4qWOe8Rq2FsEEwGwYDVR0RBBQwEoEQY2hyY2hyQGdtYWlsLmNvbTAbBgNV
25
- HRIEFDASgRBjaHJjaHJAZ21haWwuY29tMA0GCSqGSIb3DQEBBQUAA4IBAQBRdlDl
26
- dXzKVcuK/w1EwgfPlI3BVMbSBGx9evofmH8pSWOV7Pqu3ZU9u91SGzMtMULVj+03
27
- SJRx2pS3sVfzTt+jPfIqQk37rfc9iYLPCwM5G5RypT3iAIM/V/rJv5+z9lYwE/76
28
- 8ZrYVUK9zx91u/xkFseEig5ZqCCZIiBGKleos2uruy+eG5On1w5ShGqIaoxQvCa0
29
- W6y4KVKgJJKunt/R+DNGrFnPFkd+gzWOyinOhQoVeHvyhslkA+ptgJSk2Q/KwTXO
30
- 3TLzfUddZ0/HMBNYO9OALcF70YnWb/usnr4lwVfhbJ+fcejAsp5Seurmhw7FeMoZ
31
- f4Rtc1iUIHYWfDpz
32
- -----END CERTIFICATE-----
33
- date: 2014-11-15 00:00:00.000000000 Z
34
- dependencies: []
10
+ cert_chain: []
11
+ date: 2015-04-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5'
35
41
  description: Generate unique values with numeric locality.
36
42
  email: chrchr@gmail.com
37
43
  executables:
@@ -39,9 +45,11 @@ executables:
39
45
  extensions: []
40
46
  extra_rdoc_files: []
41
47
  files:
42
- - lib/onliest.rb
43
48
  - bin/onliest
44
- - test/test_onliest.rb
49
+ - lib/onliest.rb
50
+ - lib/onliest/snowflake.rb
51
+ - test/test_onliest_default.rb
52
+ - test/test_onliest_snowflake.rb
45
53
  homepage: https://github.com/chrchr/onliest
46
54
  licenses:
47
55
  - MIT
@@ -52,20 +60,20 @@ require_paths:
52
60
  - lib
53
61
  required_ruby_version: !ruby/object:Gem::Requirement
54
62
  requirements:
55
- - - '>='
63
+ - - ">="
56
64
  - !ruby/object:Gem::Version
57
65
  version: '0'
58
66
  required_rubygems_version: !ruby/object:Gem::Requirement
59
67
  requirements:
60
- - - '>='
68
+ - - ">="
61
69
  - !ruby/object:Gem::Version
62
70
  version: '0'
63
71
  requirements: []
64
72
  rubyforge_project:
65
- rubygems_version: 2.0.14
73
+ rubygems_version: 2.4.5
66
74
  signing_key:
67
75
  specification_version: 4
68
76
  summary: 'Onliest: generate unique values with numeric locality'
69
77
  test_files:
70
- - test/test_onliest.rb
71
- has_rdoc:
78
+ - test/test_onliest_default.rb
79
+ - test/test_onliest_snowflake.rb
checksums.yaml.gz.sig DELETED
Binary file
data.tar.gz.sig DELETED
@@ -1,4 +0,0 @@
1
- ����o�����0�%�.��I ���?�Ү}7��
2
- �<胧�H�8�;{�,p䰰N�s��k�?���L���A_6��>����6"���+]��۸����w�#�� �s$=��_ܪRNj8�M)���`O��
3
- 
4
- ������j�B�R\i$���vG�Ŀ�1�hL P�Ys}�*��{�|���F�Rv`�h�U�11D��6e�s%�r��U�9η�o��.�0f m�J��P��/�0�oQ��$�
metadata.gz.sig DELETED
@@ -1,2 +0,0 @@
1
- U�`@
2
- hг*��Fs>��