torid 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e6dacf1ffa7be13c30286d37766f06b04cfef520
4
+ data.tar.gz: eb17f8af92781af966f8575148346990b0c055a5
5
+ SHA512:
6
+ metadata.gz: ab397dcae732b089f5f5eba45c17dd1362fb4928a48fa30b9275c226e91cacd37f6c6248dd6dc26cc1d6ebe56b188f4d6e313670312a8f6811cea60f6c7b5f7e
7
+ data.tar.gz: 0265870e23051dfce0d1953c336447bd82e45129d34ca3156fcc4f4f701d329faad1e0f0b03612b4188189481734ba625f94ac2895f8dae54a1276fcff9048e2
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,46 @@
1
+ # Hi there!
2
+
3
+ I see you are interested in contributing. That is wonderful. I love
4
+ contributions.
5
+
6
+ I guarantee that there are bugs in this software. And I guarantee that there is
7
+ a feature you want that is not in here yet. As such, any and all bugs reports
8
+ are gratefully accepted, bugfixes even more so. Helping out with bugs is the
9
+ easiest way to contribute.
10
+
11
+
12
+ ## The Quick Version
13
+
14
+ * Have a [GitHub Account][].
15
+ * Search the [GitHub Issues][] and see if your issue already present. If so
16
+ add your comments, :thumbsup:, etc.
17
+ * Issue not there? Not a problem, open up a [new issue][].
18
+ * **Bug reports** please be as detailed as possible. Include:
19
+ * full ruby engine and version: `ruby -e 'puts RUBY_DESCRIPTION'`
20
+ * operating system and version
21
+ * version of torid `ruby -rubygems -e "require 'torid'; puts Torid::VERSION"`
22
+ * as much detail about the bug as possible so I can replicate it. Feel free
23
+ to link in a [gist][]
24
+ * **New Feature**
25
+ * What the new feature should do.
26
+ * What benefit the new feature brings to the project.
27
+ * Fork the [repo][].
28
+ * Create a new branch for your issue: `git checkout -b issue/my-issue`
29
+ * Lovingly craft your contribution:
30
+ * `rake develop` to get started, or if you prefer bundler `rake develop:using_bundler && bundle`.
31
+ * `rake test` to run tests
32
+ * Make sure that `rake test` passes. It's important, I said it twice.
33
+ * Add yourself to the contributors section below.
34
+ * Submit your [pull request][].
35
+
36
+ # Contributors
37
+
38
+ * [Jeremy Hinegardner](https://github.com/copiousfreetime)
39
+ * [Kevin Barnes](https://github.com/vinbarnes)
40
+
41
+ [GitHub Account]: https://github.com/signup/free "GitHub Signup"
42
+ [GitHub Issues]: https://github.com/copiousfreetime/torid/issues "Torid Issues"
43
+ [new issue]: https://github.com/copiousfreetime/torid/issues/new "New Torid Issue"
44
+ [gist]: https://gist.github.com/ "New Gist"
45
+ [repo]: https://github.com/copiousfreetime/torid "Torid Repo"
46
+ [pull request]: https://help.github.com/articles/using-pull-requests "Using Pull Requests"
data/HISTORY.md ADDED
@@ -0,0 +1,5 @@
1
+ # Torid Changelog
2
+ ## Version 1.0.0
3
+
4
+ * Initial Release - Yeah!
5
+
data/LICENSE ADDED
@@ -0,0 +1,16 @@
1
+ ISC LICENSE - http://opensource.org/licenses/isc-license.txt
2
+
3
+ Copyright (c) 2013 Jeremy Hinegardner
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+
data/Manifest.txt ADDED
@@ -0,0 +1,18 @@
1
+ CONTRIBUTING.md
2
+ HISTORY.md
3
+ LICENSE
4
+ Manifest.txt
5
+ README.md
6
+ Rakefile
7
+ lib/torid.rb
8
+ lib/torid/clock.rb
9
+ lib/torid/generator.rb
10
+ lib/torid/uuid.rb
11
+ tasks/default.rake
12
+ tasks/this.rb
13
+ test/test_clock.rb
14
+ test/test_generator.rb
15
+ test/test_helper.rb
16
+ test/test_torid.rb
17
+ test/test_uuid.rb
18
+ test/test_version.rb
data/README.md ADDED
@@ -0,0 +1,100 @@
1
+ ## Torid
2
+
3
+ * [Homepage](https://github.com/copiousfreetime/torid/)
4
+ * [Github Project](https://github.com/copiousfreetime/torid)
5
+ * email jeremy at copiousfreetime dot org
6
+
7
+ ## DESCRIPTION
8
+
9
+ Temporally Ordered IDs. Generate universally unique identifiers (UUID)
10
+ that sort lexically in time order.
11
+
12
+ Torid exists to solve the problem of generating UUIDs that when ordered
13
+ lexically, they are also ordered temporally. I needed a way to generate ids for
14
+ events that are entering a system with the following criteria:
15
+
16
+ 1. Fast ID generation
17
+ 2. No central coordinating server/system
18
+ 3. No local storage
19
+ 4. Library code, that is multiple apps on the same machine can use the same code
20
+ and they will not generate duplicate ids
21
+ 5. Eventually stored in a UUID field in a database. So 128bit ids are totally
22
+ fine.
23
+
24
+ The IDs that Torid generates are 128bit IDs made up of 2, 64bit parts.
25
+
26
+ * 64bit microsecond level UNIX timestamp
27
+ * 64bit hash of the system hostname, process id and a random value.
28
+
29
+ ## EXAMPLES
30
+
31
+ #### Using the defaults
32
+
33
+ ```ruby
34
+ require 'torid'
35
+
36
+ uuid = Torid.uuid
37
+ uuid.to_s # => "0004fda4-318e-f380-5a45-5321cd065b02"
38
+ uuid.bytes # => "\x00\x04\xFD\xA41\x8E\xF3\x80ZES!\xCD\x06[\x02"
39
+ ```
40
+
41
+ #### Using your own instance of a Generator
42
+
43
+ ```ruby
44
+ require 'torid'
45
+
46
+ generator = Torid::Generator.new
47
+ uuid = generator.next
48
+
49
+ uuid.to_s # => "0004fda4-3f42-3d01-4731-5a4aa8ddd6c3"
50
+ uuid.bytes # => "\x00\x04\xFD\xA4?B=\x01G1ZJ\xA8\xDD\xD6\xC3"
51
+ ```
52
+
53
+ ## CREDITS / RESOURCES
54
+
55
+ The vast majority of the credit and research stems from:
56
+
57
+ * [jondot's](https://github.com/jondot) blog post on [Fast ID Generation](http://blog.paracode.com/2012/04/16/fast-id-generation-part-1/) served to solidify my thoughts on the criteria I needed in an ID generation system.
58
+ * This let me to [Boundary's Flake](http://boundary.com/blog/2012/01/12/flake-a-decentralized-k-ordered-unique-id-generator-in-erlang/)
59
+ * [James Golick's](https://github.com/jamesgolick) [lexical_uuid](https://github.com/jamesgolick/lexical_uuid), which if I had found a day earlier, I might be using instead of creating this.
60
+
61
+ You could consider Torid to be a reimplementation of [lexical_uuid](https://github.com/jamesgolick/lexical_uuid). It definately steals some code from it and [simple_uuid](https://github.com/cassandra-rb/simple_uuid)
62
+
63
+ Blog posts around ID generation:
64
+
65
+ * [Wikipedia UUID](http://en.wikipedia.org/wiki/Universally_unique_identifier)
66
+ * [RFC 4122](http://tools.ietf.org/html/rfc4122)
67
+ * [Fast ID Generation Part I](http://blog.paracode.com/2012/04/16/fast-id-generation-part-1/)
68
+ * [Boundary's Flake Project](http://boundary.com/blog/2012/01/12/flake-a-decentralized-k-ordered-unique-id-generator-in-erlang/)
69
+ * [Flickr's Ticket Server](http://code.flickr.net/2010/02/08/ticket-servers-distributed-unique-primary-keys-on-the-cheap/)
70
+ * [Twitter Snowflake](https://blog.twitter.com/2010/announcing-snowflake)
71
+ * [Sharding & ID's at Instagram](http://instagram-engineering.tumblr.com/post/10853187575/sharding-ids-at-instagram)
72
+
73
+ Libraries implementing similar approaches:
74
+
75
+ * [simple_uuid](https://github.com/cassandra-rb/simple_uuid)
76
+ * [uuid](https://github.com/assaf/uuid)
77
+ * [flake](http://github.com/boundary/flake)
78
+ * [BSON Object ID](https://github.com/mongodb/bson-ruby/blob/master/lib/bson/object_id.rb) and in [C](https://github.com/mongodb/bson-ruby/blob/master/ext/bson/native.c)
79
+ * [ffi-uuid](https://github.com/mmullis/ffi-uuid)
80
+ * [lexical_uuid](https://github.com/jamesgolick/lexical_uuid)
81
+
82
+ ## ISC LICENSE
83
+
84
+ http://opensource.org/licenses/isc-license.txt
85
+
86
+ Copyright (c) 2014 Jeremy Hinegardner
87
+
88
+ Permission to use, copy, modify, and/or distribute this software for any
89
+ purpose with or without fee is hereby granted, provided that the above
90
+ copyright notice
91
+ and this permission notice appear in all copies.
92
+
93
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
94
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
95
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
96
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
97
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
98
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
99
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
100
+
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ # vim: syntax=ruby
2
+ load 'tasks/this.rb'
3
+
4
+ This.name = "torid"
5
+ This.author = "Jeremy Hinegardner"
6
+ This.email = "jeremy@copiousfreetime.org"
7
+ This.homepage = "http://github.com/copiousfreetime/#{ This.name }"
8
+
9
+ This.ruby_gemspec do |spec|
10
+ spec.add_dependency( 'fnv', '~> 0.2' )
11
+
12
+ spec.add_development_dependency( 'rake' , '~> 10.1')
13
+ spec.add_development_dependency( 'minitest' , '~> 5.0' )
14
+ spec.add_development_dependency( 'rdoc' , '~> 4.0' )
15
+ end
16
+
17
+ load 'tasks/default.rake'
data/lib/torid.rb ADDED
@@ -0,0 +1,22 @@
1
+ # Torid - Temporally Ordered IDs. Generate universally unique identifiers (UUID)
2
+ # that sort lexically in time order.
3
+ module Torid
4
+ # Public: The Version of the Torid library as a String
5
+ VERSION = "1.0.0"
6
+
7
+ # Public: return the next Torid::UUID from the default Generator
8
+ #
9
+ # This is just a shortcut to Torid::Generator.next
10
+ #
11
+ # Example:
12
+ #
13
+ # Torid.uuid # => Torid::UUID
14
+ #
15
+ # Returns a Torid::UUID
16
+ def self.uuid
17
+ Torid::Generator.next
18
+ end
19
+ end
20
+ require 'torid/clock'
21
+ require 'torid/uuid'
22
+ require 'torid/generator'
@@ -0,0 +1,65 @@
1
+ require 'thread'
2
+ module Torid
3
+ # Internal: A source for non-duplicate microsecond timestamps.
4
+ #
5
+ # Clock generates microsecond UNIX timestamps and guarantees that once a Clock
6
+ # instance is created, `Clock#tick` will never return the same value twice for
7
+ # that instance.
8
+ #
9
+ # This is effectively a reimplementation of
10
+ # https://github.com/jamesgolick/lexical_uuid/blob/master/lib/increasing_microsecond_clock.rb
11
+ # combined with
12
+ # https://github.com/jamesgolick/lexical_uuid/blob/master/lib/time_ext.rb
13
+ #
14
+ class Clock
15
+
16
+ # Internal: Return the current microsecond UNIX timstamp
17
+ #
18
+ # Example:
19
+ #
20
+ # Clock.stamp => 1404774462369341
21
+ #
22
+ # Returns an Integer
23
+ def self.stamp
24
+ now = Time.now
25
+ (now.to_f * 1_000_000).floor
26
+ end
27
+
28
+ # Internal: Create a new Clock
29
+ #
30
+ # prev_stamp - An initial value for the previous timestamp (default:
31
+ # Clock.stamp)
32
+ # mutex - The synchronizing object to use
33
+ def initialize( prev_stamp = Clock.stamp, mutex = Mutex.new )
34
+ @prev_stamp = prev_stamp
35
+ @mutex = mutex
36
+ end
37
+
38
+ # Internal: Return the next tick of the clock.
39
+ #
40
+ # Return the next tick of the clock, which will be a Clock.stamp value. This
41
+ # method will continue to return ever increasing values from when it was
42
+ # created.
43
+ #
44
+ # Returns an Integer.
45
+ def tick
46
+ @mutex.synchronize do
47
+ new_stamp = Clock.stamp
48
+ @prev_stamp = if new_stamp > @prev_stamp then
49
+ new_stamp
50
+ else
51
+ @prev_stamp + 1
52
+ end
53
+ end
54
+ end
55
+
56
+ # Internal: The default instance to use for generating ticks
57
+ @instance = Clock.new
58
+
59
+ # Internal: Return the next `#tick` of the default Clock.
60
+ #
61
+ def self.tick
62
+ @instance.tick
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,82 @@
1
+ require 'fnv'
2
+ require 'socket'
3
+ require 'securerandom'
4
+ require 'torid/clock'
5
+ require 'torid/uuid'
6
+
7
+ module Torid
8
+ # Public: A class that will generate unique identifiers.
9
+ #
10
+ # Torid::Generator is the class that is used to generate Torid::UUID
11
+ # instances.
12
+ #
13
+ # Example:
14
+ #
15
+ # Torid::Generator.next # => Torid::UUID
16
+ #
17
+ # generator = Torid::Generator.new
18
+ # generator.next # => Torid::UUID
19
+ #
20
+ class Generator
21
+ # Internal: The Clock instance used to get 64bit timestamps
22
+ attr_reader :clock
23
+
24
+ # Internal: The Node id of this instance
25
+ attr_reader :node_id
26
+
27
+ # Internal: Create a new Torid UUID Generator
28
+ #
29
+ # clock - an object that responds to `#tick` and returns a 64bit integer.
30
+ # (default: Torid::Clock)
31
+ # node_id - the 64bit node id of this node. (default: Generator.node_id)
32
+ #
33
+ def initialize( clock = Torid::Clock, node_id = Generator.node_id )
34
+ @clock = clock
35
+ @node_id = node_id
36
+ end
37
+
38
+ # Public: Return the next UUID from this generator
39
+ #
40
+ # Returns Torid::UUID
41
+ def next
42
+ Torid::UUID.new( @clock.tick, @node_id )
43
+ end
44
+
45
+
46
+ # Internal: Generate a unique node identifier.
47
+ #
48
+ # Uses the first hostname of the system, the process id, some random bytes
49
+ # and hashes them all together using the non-cryptographic FNV hash.
50
+ #
51
+ # http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
52
+ #
53
+ # This method is copeid from
54
+ # https://github.com/jamesgolick/lexical_uuid/blob/master/lib/lexical_uuid.rb#L14
55
+ # with the random bytes added by me.
56
+ #
57
+ # Returns a 64 bit Integer
58
+ def self.create_node_id
59
+ hostname = Socket.gethostbyname( Socket.gethostname ).first
60
+ pid = Process.pid
61
+ random = SecureRandom.hex( 16 )
62
+ FNV.new.fnv1a_64("#{hostname}-#{pid}-#{random}")
63
+ end
64
+
65
+ # Internal: The default generator used by the system.
66
+ @instance = ::Torid::Generator.new( Torid::Clock, Generator.create_node_id )
67
+
68
+ # Public: Return the node id of the default Generator instance
69
+ #
70
+ # Returns a 64 bit Integer
71
+ def self.node_id
72
+ @instance.node_id
73
+ end
74
+
75
+ # Public: Return the next UUID from the default Generator
76
+ #
77
+ # Returns a Torid::UUID
78
+ def self.next
79
+ @instance.next
80
+ end
81
+ end
82
+ end
data/lib/torid/uuid.rb ADDED
@@ -0,0 +1,138 @@
1
+ module Torid
2
+ # Public: Represents a UUID generated by Torid
3
+ #
4
+ # Torid::UUID wraps 2 64bit Integer values and can convert them back and forth
5
+ # between raw bytes and the canonical UUID form of 32 lowercase hexadecimal
6
+ # lowercase hexadecimal digits, displayed in five groups separated by hyphens,
7
+ # in the form 8-4-4-4-12 for a total of 36 characters (32 alphanumeric
8
+ # characters and four hyphens)
9
+ #
10
+ # Since internally, Torid::UUID's represent a 64bit microsecond timestamp and
11
+ # a 'node_id', those data fields are also able to be returned as a Time
12
+ # instance or an Integer respectively.
13
+ #
14
+ # Examples
15
+ #
16
+ # uuid = Torid.uuid
17
+ # uuid.to_s # => "0004fda3-8c73-5e0f-bae4-e9c86e3684a5"
18
+ # uuid.bytes # => "\x00\x04\xFD\xA3\x8Cs^\x0F\xBA\xE4\xE9\xC8n6\x84\xA5"
19
+ #
20
+ # uuid.timestamp # => Time
21
+ # uuid.node_id # => Integer
22
+ class UUID
23
+
24
+ # Public: Create a Torid::UUID from an existing String.
25
+ #
26
+ # The String can either be a 16 byte binary string, or a 36byte hexadecimal
27
+ # UUID in the 8-4-4-4-12 format.
28
+ #
29
+ # Examples
30
+ #
31
+ # Torid::UUID.from( "0004fda3-8c73-5e0f-bae4-e9c86e3684a5" ) # => Torid::UUID
32
+ # Torid::UUID.from( "\x00\x04\xFD\xA3\x8Cs^\x0F\xBA\xE4\xE9\xC8n6\x84\xA5" ) # => Torid::UUID
33
+ #
34
+ # Returns a Torid::UUID
35
+ # Raises ArgumentError if the String is not convertable to a UUID.
36
+ def self.from( str )
37
+ case str.bytesize
38
+ when 36
39
+ from_string( str )
40
+ when 16
41
+ from_bytes( str )
42
+ else
43
+ raise ArgumentError, "UUID can only be loaded from a 16 byte binary string or a 36 byte formatted UUID string."
44
+ end
45
+ end
46
+
47
+ # Internal: Create a new UUID from an existing string in the 8-4-4-4-12 format
48
+ #
49
+ # Copied from lexical_uuid
50
+ #
51
+ # Returns a Torid::UUID
52
+ def self.from_string( str )
53
+ hex = str.split('-').join
54
+ bytes = Array( hex ).pack("H32")
55
+ from_bytes( bytes )
56
+ end
57
+
58
+ # Internal: Create a new UUID from an existing 16 byte String
59
+ #
60
+ # Copied from lexical_uuid
61
+ #
62
+ # Returns a Torid::UUID
63
+ def self.from_bytes( bytes )
64
+ time_high, time_low, node_high, node_low = bytes.unpack("NNNN")
65
+ timestamp = ( time_high << 32 ) | time_low
66
+ node_id = ( node_high << 32 ) | node_low
67
+ new( timestamp, node_id )
68
+ end
69
+
70
+ # Public: The 64bit microsecond UNIX timestamp
71
+ attr_reader :timestamp
72
+
73
+ # Public: The 64bit node id
74
+ attr_reader :node_id
75
+
76
+ # Internal: Create a new UUID.
77
+ #
78
+ # UUID's should only be created by calling one of the public methods that
79
+ # generate id's. See `Torid.uuid` or `Torid::Generator.next`. This
80
+ # constructor should not be called by users of this library.
81
+ #
82
+ # timestamp - an Integer value representing UNIX timestamp in microseconds
83
+ # node_id - an Integer value representing the unique node id where this
84
+ # UUID is generatoed
85
+ #
86
+ def initialize( timestamp = nil, node_id = nil )
87
+ @timestamp = timestamp
88
+ @node_id = node_id
89
+ @bytes = nil
90
+ @time = nil
91
+ end
92
+
93
+ # Public: Return the Time value the internal microsecond timestamp
94
+ # represents.
95
+ #
96
+ # Examples
97
+ #
98
+ # uuid.time # => Time
99
+ #
100
+ # Returns a Time instance
101
+ def time
102
+ @time ||= Time.at( timestamp / 1_000_000.0 )
103
+ end
104
+
105
+ # Public: Return the UUID as 16 bytes of raw data.
106
+ #
107
+ # Copied from lexical_uuid
108
+ #
109
+ # Examples
110
+ #
111
+ # uuid.bytes # => "\x00\x04\xFD\xA3\x8Cs^\x0F\xBA\xE4\xE9\xC8n6\x84\xA5"
112
+ #
113
+ # Returns a binary String
114
+ def bytes
115
+ @bytes ||= [ @timestamp >> 32,
116
+ @timestamp & 0xFFFF_FFFF,
117
+ @node_id >> 32,
118
+ @node_id & 0xFFFF_FFFF ].pack("NNNN")
119
+ end
120
+
121
+ # Public: Return the hexadecimal UUID string representation. This is the
122
+ # standard 8-4-4-4-12 UUID string representation.
123
+ #
124
+ # Copied from simple_uuid via lexical_uuid.
125
+ #
126
+ # Examples
127
+ #
128
+ # uuid.to_s # => "0004fda3-8c73-5e0f-bae4-e9c86e3684a5"
129
+ #
130
+ # Returns a String
131
+ def to_s
132
+ elements = bytes.unpack("NnnCCa6")
133
+ node = elements[-1].unpack('C*')
134
+ elements[-1] = '%02x%02x%02x%02x%02x%02x' % node
135
+ "%08x-%04x-%04x-%02x%02x-%s" % elements
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,276 @@
1
+ # vim: syntax=ruby
2
+ require 'rake/clean'
3
+ require 'digest'
4
+ #------------------------------------------------------------------------------
5
+ # If you want to Develop on this project just run 'rake develop' and you'll
6
+ # have all you need to get going. If you want to use bundler for development,
7
+ # then run 'rake develop:using_bundler'
8
+ #------------------------------------------------------------------------------
9
+ namespace :develop do
10
+
11
+ # Install all the development and runtime dependencies of this gem using the
12
+ # gemspec.
13
+ task :default do
14
+ require 'rubygems/dependency_installer'
15
+ installer = ::Gem::DependencyInstaller.new
16
+
17
+ This.set_coverage_gem
18
+
19
+ puts "Installing gem depedencies needed for development"
20
+ This.platform_gemspec.dependencies.each do |dep|
21
+ if dep.matching_specs.empty? then
22
+ puts "Installing : #{dep}"
23
+ installer.install dep
24
+ else
25
+ puts "Skipping : #{dep} -> already installed #{dep.matching_specs.first.full_name}"
26
+ end
27
+ end
28
+ puts "\n\nNow run 'rake test'"
29
+ end
30
+
31
+ # Create a Gemfile that just references the gemspec
32
+ file 'Gemfile' => :gemspec do
33
+ File.open( "Gemfile", "w+" ) do |f|
34
+ f.puts "# DO NOT EDIT - This file is automatically generated"
35
+ f.puts "# Make changes to Manifest.txt and/or Rakefile and regenerate"
36
+ f.puts 'source "https://rubygems.org/"'
37
+ f.puts 'gemspec'
38
+ end
39
+ end
40
+
41
+ desc "Create a bundler Gemfile"
42
+ task :using_bundler => 'Gemfile' do
43
+ puts "Now you can 'bundle'"
44
+ end
45
+
46
+ # Gemfiles are build artifacts
47
+ CLOBBER << FileList['Gemfile*']
48
+ end
49
+ desc "Boostrap development"
50
+ task :develop => "develop:default"
51
+
52
+ #------------------------------------------------------------------------------
53
+ # Minitest - standard TestTask
54
+ #------------------------------------------------------------------------------
55
+ begin
56
+ require 'rake/testtask'
57
+ Rake::TestTask.new( :test ) do |t|
58
+ t.ruby_opts = %w[ -w -rubygems ]
59
+ t.libs = %w[ lib spec test ]
60
+ t.pattern = "{test,spec}/**/{test_*,*_spec}.rb"
61
+ end
62
+
63
+ task :test_requirements
64
+ task :test => :test_requirements
65
+ task :default => :test
66
+ rescue LoadError
67
+ This.task_warning( 'test' )
68
+ end
69
+
70
+ #------------------------------------------------------------------------------
71
+ # RDoc - standard rdoc rake task, although we must make sure to use a more
72
+ # recent version of rdoc since it is the one that has 'tomdoc' markup
73
+ #------------------------------------------------------------------------------
74
+ begin
75
+ gem 'rdoc' # otherwise we get the wrong task from stdlib
76
+ require 'rdoc/task'
77
+ RDoc::Task.new do |t|
78
+ t.markup = 'tomdoc'
79
+ t.rdoc_dir = 'doc'
80
+ t.main = 'README.md'
81
+ t.title = "#{This.name} #{This.version}"
82
+ t.rdoc_files.include( FileList['*.{rdoc,md,txt}'], FileList['ext/**/*.c'],
83
+ FileList['lib/**/*.rb'] )
84
+ end
85
+ rescue StandardError, LoadError
86
+ This.task_warning( 'rdoc' )
87
+ end
88
+
89
+ #------------------------------------------------------------------------------
90
+ # Coverage - optional code coverage, rcov for 1.8 and simplecov for 1.9, so
91
+ # for the moment only rcov is listed.
92
+ #------------------------------------------------------------------------------
93
+ if RUBY_VERSION < "1.9.0"
94
+ begin
95
+ require 'rcov/rcovtask'
96
+ Rcov::RcovTask.new( 'coverage' ) do |t|
97
+ t.libs << 'spec'
98
+ t.pattern = 'spec/**/*_spec.rb'
99
+ t.verbose = true
100
+ t.rcov_opts << "-x ^/" # remove all the global files
101
+ t.rcov_opts << "--sort coverage" # so we see the worst files at the top
102
+ end
103
+ rescue LoadError
104
+ This.task_warning( 'rcov' )
105
+ end
106
+ else
107
+ begin
108
+ require 'simplecov'
109
+ desc 'Run tests with code coverage'
110
+ task :coverage do
111
+ ENV['COVERAGE'] = 'true'
112
+ Rake::Task[:test].execute
113
+ end
114
+ CLOBBER << FileList["coverage"]
115
+ rescue LoadError
116
+ This.task_warning( 'simplecov' )
117
+ end
118
+ end
119
+
120
+ #------------------------------------------------------------------------------
121
+ # Manifest - We want an explicit list of thos files that are to be packaged in
122
+ # the gem. Most of this is from Hoe.
123
+ #------------------------------------------------------------------------------
124
+ namespace 'manifest' do
125
+ desc "Check the manifest"
126
+ task :check => :clean do
127
+ files = FileList["**/*", ".*"].exclude( This.exclude_from_manifest ).to_a.sort
128
+ files = files.select{ |f| File.file?( f ) }
129
+
130
+ tmp = "Manifest.tmp"
131
+ File.open( tmp, 'w' ) do |f|
132
+ f.puts files.join("\n")
133
+ end
134
+
135
+ begin
136
+ sh "diff -du Manifest.txt #{tmp}"
137
+ ensure
138
+ rm tmp
139
+ end
140
+ puts "Manifest looks good"
141
+ end
142
+
143
+ desc "Generate the manifest"
144
+ task :generate => :clean do
145
+ files = %x[ git ls-files ].split("\n").sort
146
+ files.reject! { |f| f =~ This.exclude_from_manifest }
147
+ File.open( "Manifest.txt", "w" ) do |f|
148
+ f.puts files.join("\n")
149
+ end
150
+ end
151
+ end
152
+
153
+ #------------------------------------------------------------------------------
154
+ # Fixme - look for fixmes and report them
155
+ #------------------------------------------------------------------------------
156
+ namespace :fixme do
157
+ task :default => 'manifest:check' do
158
+ This.manifest.each do |file|
159
+ next if file == __FILE__
160
+ next unless file =~ %r/(txt|rb|md|rdoc|css|html|xml|css)\Z/
161
+ puts "FIXME: Rename #{file}" if file =~ /fixme/i
162
+ IO.readlines( file ).each_with_index do |line, idx|
163
+ prefix = "FIXME: #{file}:#{idx+1}".ljust(42)
164
+ puts "#{prefix} => #{line.strip}" if line =~ /fixme/i
165
+ end
166
+ end
167
+ end
168
+
169
+ def fixme_project_root
170
+ This.project_path( '../fixme' )
171
+ end
172
+
173
+ def fixme_project_path( subtree )
174
+ fixme_project_root.join( subtree )
175
+ end
176
+
177
+ def local_fixme_files
178
+ This.manifest.select { |p| p =~ %r|^tasks/| }
179
+ end
180
+
181
+ def outdated_fixme_files
182
+ local_fixme_files.reject do |local|
183
+ upstream = fixme_project_path( local )
184
+ Digest::SHA256.file( local ) == Digest::SHA256.file( upstream )
185
+ end
186
+ end
187
+
188
+ def fixme_up_to_date?
189
+ outdated_fixme_files.empty?
190
+ end
191
+
192
+ desc "See if the fixme tools are outdated"
193
+ task :outdated => :release_check do
194
+ if fixme_up_to_date? then
195
+ puts "Fixme files are up to date."
196
+ else
197
+ outdated_fixme_files.each do |f|
198
+ puts "#{f} is outdated"
199
+ end
200
+ end
201
+ end
202
+
203
+ desc "Update outdated fixme files"
204
+ task :update => :release_check do
205
+ if fixme_up_to_date? then
206
+ puts "Fixme files are already up to date."
207
+ else
208
+ puts "Updating fixme files:"
209
+ outdated_fixme_files.each do |local|
210
+ upstream = fixme_project_path( local )
211
+ puts " * #{local}"
212
+ FileUtils.cp( upstream, local )
213
+ end
214
+ puts "Use your git commands as appropriate."
215
+ end
216
+ end
217
+ end
218
+ desc "Look for fixmes and report them"
219
+ task :fixme => "fixme:default"
220
+
221
+ #------------------------------------------------------------------------------
222
+ # Gem Specification
223
+ #------------------------------------------------------------------------------
224
+ # Really this is only here to support those who use bundler
225
+ desc "Build the #{This.name}.gemspec file"
226
+ task :gemspec do
227
+ File.open( This.gemspec_file, "wb+" ) do |f|
228
+ f.puts "# DO NOT EDIT - This file is automatically generated"
229
+ f.puts "# Make changes to Manifest.txt and/or Rakefile and regenerate"
230
+ f.write This.platform_gemspec.to_ruby
231
+ end
232
+ end
233
+
234
+ # the gemspec is also a dev artifact and should not be kept around.
235
+ CLOBBER << This.gemspec_file.to_s
236
+
237
+ # .rbc files from ruby 2.0
238
+ CLOBBER << FileList["**/*.rbc"]
239
+
240
+ # The standard gem packaging task, everyone has it.
241
+ require 'rubygems/package_task'
242
+ ::Gem::PackageTask.new( This.platform_gemspec ) do
243
+ # nothing
244
+ end
245
+
246
+ #------------------------------------------------------------------------------
247
+ # Release - the steps we go through to do a final release, this is pulled from
248
+ # a compbination of mojombo's rakegem, hoe and hoe-git
249
+ #
250
+ # 1) make sure we are on the master branch
251
+ # 2) make sure there are no uncommitted items
252
+ # 3) check the manifest and make sure all looks good
253
+ # 4) build the gem
254
+ # 5) do an empty commit to have the commit message of the version
255
+ # 6) tag that commit as the version
256
+ # 7) push master
257
+ # 8) push the tag
258
+ # 7) pus the gem
259
+ #------------------------------------------------------------------------------
260
+ task :release_check do
261
+ unless `git branch` =~ /^\* master$/
262
+ abort "You must be on the master branch to release!"
263
+ end
264
+ unless `git status` =~ /^nothing to commit/m
265
+ abort "Nope, sorry, you have unfinished business"
266
+ end
267
+ end
268
+
269
+ desc "Create tag v#{This.version}, build and push #{This.platform_gemspec.full_name} to rubygems.org"
270
+ task :release => [ :release_check, 'manifest:check', :gem ] do
271
+ sh "git commit --allow-empty -a -m 'Release #{This.version}'"
272
+ sh "git tag -a -m 'v#{This.version}' v#{This.version}"
273
+ sh "git push origin master"
274
+ sh "git push origin v#{This.version}"
275
+ sh "gem push pkg/#{This.platform_gemspec.full_name}.gem"
276
+ end
data/tasks/this.rb ADDED
@@ -0,0 +1,214 @@
1
+ require 'pathname'
2
+
3
+ # Public: A Class containing all the metadata and utilities needed to manage a
4
+ # ruby project.
5
+ class ThisProject
6
+ # The name of this project
7
+ attr_accessor :name
8
+
9
+ # The author's name
10
+ attr_accessor :author
11
+
12
+ # The email address of the author(s)
13
+ attr_accessor :email
14
+
15
+ # The homepage of this project
16
+ attr_accessor :homepage
17
+
18
+ # The regex of files to exclude from the manifest
19
+ attr_accessor :exclude_from_manifest
20
+
21
+ # The hash of Gem::Specifications keyed' by platform
22
+ attr_accessor :gemspecs
23
+
24
+ # Public: Initialize ThisProject
25
+ #
26
+ # Yields self
27
+ def initialize(&block)
28
+ @exclude_from_manifest = %r/\.(git|DS_Store)|^(doc|coverage|pkg|tmp|Gemfile(\.lock)?)|^[^\/]+\.gemspec|\.(swp|jar|bundle|so|rvmrc)$|~$/
29
+ @gemspecs = Hash.new
30
+ yield self if block_given?
31
+ end
32
+
33
+ # Public: return the version of ThisProject
34
+ #
35
+ # Search the ruby files in the project looking for the one that has the
36
+ # version string in it. This does not eval any code in the project, it parses
37
+ # the source code looking for the string.
38
+ #
39
+ # Returns a String version
40
+ def version
41
+ [ "lib/#{ name }.rb", "lib/#{ name }/version.rb" ].each do |v|
42
+ path = project_path( v )
43
+ line = path.read[/^\s*VERSION\s*=\s*.*/]
44
+ if line then
45
+ return line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
46
+ end
47
+ end
48
+ end
49
+
50
+ # Internal: Return a section of an RDoc file with the given section name
51
+ #
52
+ # path - the relative path in the project of the file to parse
53
+ # section_name - the section out of the file from which to parse data
54
+ #
55
+ # Retuns the text of the section as an array of paragrphs.
56
+ def section_of( file, section_name )
57
+ re = /^[=#]+ (.*)$/
58
+ sectional = project_path( file )
59
+ parts = sectional.read.split( re )[1..-1]
60
+ parts.map! { |p| p.strip }
61
+
62
+ sections = Hash.new
63
+ Hash[*parts].each do |k,v|
64
+ sections[k] = v.split("\n\n")
65
+ end
66
+ return sections[section_name]
67
+ end
68
+
69
+ # Internal: print out a warning about the give task
70
+ def task_warning( task )
71
+ warn "WARNING: '#{task}' tasks are not defined. Please run 'rake develop'"
72
+ end
73
+
74
+ # Internal: Return the full path to the file that is relative to the project
75
+ # root.
76
+ #
77
+ # path - the relative path of the file from the project root
78
+ #
79
+ # Returns the Pathname of the file
80
+ def project_path( *relative_path )
81
+ project_root.join( *relative_path )
82
+ end
83
+
84
+ # Internal: The absolute path of this file
85
+ #
86
+ # Returns the Pathname of this file.
87
+ def this_file_path
88
+ Pathname.new( __FILE__ ).expand_path
89
+ end
90
+
91
+ # Internal: The root directory of this project
92
+ #
93
+ # This is defined as being the directory that is in the path of this project
94
+ # that has the first Rakefile
95
+ #
96
+ # Returns the Pathname of the directory
97
+ def project_root
98
+ this_file_path.ascend do |p|
99
+ rakefile = p.join( 'Rakefile' )
100
+ return p if rakefile.exist?
101
+ end
102
+ end
103
+
104
+ # Internal: Returns the contents of the Manifest.txt file as an array
105
+ #
106
+ # Returns an Array of strings
107
+ def manifest
108
+ manifest_file = project_path( "Manifest.txt" )
109
+ abort "You need a Manifest.txt" unless manifest_file.readable?
110
+ manifest_file.readlines.map { |l| l.strip }
111
+ end
112
+
113
+ # Internal: Return the files that define the extensions
114
+ #
115
+ # Returns an Array
116
+ def extension_conf_files
117
+ manifest.grep( /extconf.rb\Z/ )
118
+ end
119
+
120
+ # Internal: Returns the gemspace associated with the current ruby platform
121
+ def platform_gemspec
122
+ gemspecs[platform]
123
+ end
124
+
125
+ def core_gemspec
126
+ Gem::Specification.new do |spec|
127
+ spec.name = name
128
+ spec.version = version
129
+ spec.author = author
130
+ spec.email = email
131
+ spec.homepage = homepage
132
+
133
+ spec.summary = summary
134
+ spec.description = description
135
+ spec.license = license
136
+
137
+ spec.files = manifest
138
+ spec.executables = spec.files.grep(/^bin/) { |f| File.basename(f) }
139
+ spec.test_files = spec.files.grep(/^spec/)
140
+
141
+ spec.extra_rdoc_files += spec.files.grep(/(txt|rdoc|md)$/)
142
+ spec.rdoc_options = [ "--main" , 'README.md',
143
+ "--markup", "tomdoc" ]
144
+ end
145
+ end
146
+
147
+ # Internal: Return the gemspec for the ruby platform
148
+ def ruby_gemspec( core = core_gemspec, &block )
149
+ yielding_gemspec( 'ruby', core, &block )
150
+ end
151
+
152
+ # Internal: Return the gemspec for the jruby platform
153
+ def java_gemspec( core = core_gemspec, &block )
154
+ yielding_gemspec( 'java', core, &block )
155
+ end
156
+
157
+ # Internal: give an initial spec and a key, create a new gemspec based off of
158
+ # it.
159
+ #
160
+ # This will force the new gemspecs 'platform' to be that of the key, since the
161
+ # only reason you would have multiple gemspecs at this point is to deal with
162
+ # different platforms.
163
+ def yielding_gemspec( key, core )
164
+ spec = gemspecs[key] ||= core.dup
165
+ spec.platform = key
166
+ yield spec if block_given?
167
+ return spec
168
+ end
169
+
170
+ # Internal: Set the recovery gem development dependency
171
+ #
172
+ # These are dynamically set since they cannot be hard coded as there is
173
+ # no way to ship them correctly in the gemspec
174
+ #
175
+ # Returns nothing.
176
+ def set_coverage_gem
177
+ if RUBY_VERSION < "1.9.0"
178
+ platform_gemspec.add_development_dependency( 'rcov', '~> 1.0.0' )
179
+ else
180
+ platform_gemspec.add_development_dependency( 'simplecov', '~> 0.8.2' )
181
+ end
182
+ end
183
+
184
+ # Internal: Return the platform of ThisProject at the current moment in time.
185
+ def platform
186
+ (RUBY_PLATFORM == "java") ? 'java' : Gem::Platform::RUBY
187
+ end
188
+
189
+ # Internal: Return the DESCRIPTION section of the README.rdoc file
190
+ def description_section
191
+ section_of( 'README.md', 'DESCRIPTION')
192
+ end
193
+
194
+ # Internal: Return the summary text from the README
195
+ def summary
196
+ description_section.first
197
+ end
198
+
199
+ # Internal: Return the full description text from the README
200
+ def description
201
+ description_section.join(" ").tr("\n", ' ').gsub(/[{}]/,'').gsub(/\[[^\]]+\]/,'') # strip rdoc
202
+ end
203
+
204
+ def license
205
+ "ISC"
206
+ end
207
+
208
+ # Internal: The path to the gemspec file
209
+ def gemspec_file
210
+ project_path( "#{ name }.gemspec" )
211
+ end
212
+ end
213
+
214
+ This = ThisProject.new
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+ require 'torid/clock'
3
+
4
+ module Torid
5
+ class ClockTest < ::Minitest::Test
6
+ def test_tick_is_after_stamp
7
+ stamp = Clock.stamp
8
+ tick = Clock.tick
9
+ assert( tick > stamp )
10
+ end
11
+
12
+ def test_tick_follows_clock_not_time
13
+ stamp = Clock.stamp
14
+ future = stamp + 10_000_000
15
+ clock = Clock.new( future )
16
+ tick = clock.tick
17
+ assert_equal( future + 1, tick )
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,42 @@
1
+ require 'test_helper'
2
+ require 'torid/generator'
3
+
4
+ module Torid
5
+ class GeneratorTest < ::Minitest::Test
6
+
7
+ def test_can_set_clock_on_initialize
8
+ g = Torid::Generator.new( 'clock' )
9
+ assert_equal( 'clock', g.clock )
10
+ end
11
+
12
+ def test_can_set_node_id_on_initialize
13
+ g = Torid::Generator.new( 'clock', 'node-id' )
14
+ assert_equal( 'clock', g.clock )
15
+ assert_equal( 'node-id', g.node_id)
16
+ end
17
+
18
+ def test_default_clock_is_set_on_initializes
19
+ g = Torid::Generator.new
20
+ assert_equal( Torid::Clock, g.clock )
21
+ end
22
+
23
+ def test_default_node_id_is_set_on_initialize
24
+ g = Torid::Generator.new
25
+ assert( g.node_id > 0 )
26
+ end
27
+
28
+ def test_clocks_tick_is_called_on_next
29
+ clock = ::Minitest::Mock.new
30
+ clock.expect( :tick, 42 )
31
+ g = Torid::Generator.new( clock )
32
+ g.next
33
+ clock.verify
34
+ end
35
+
36
+ def test_default_instance_creates_uuid
37
+ uuid = Torid::Generator.next
38
+ assert_instance_of( Torid::UUID, uuid )
39
+ end
40
+ end
41
+ end
42
+
@@ -0,0 +1,5 @@
1
+ require 'simplecov' rescue nil
2
+ SimpleCov.start if ENV['COVERAGE']
3
+ gem 'minitest'
4
+ require 'minitest/autorun'
5
+ require 'minitest/pride'
@@ -0,0 +1,12 @@
1
+ require 'test_helper'
2
+ require 'torid'
3
+
4
+ module Torid
5
+ class ToridTest < ::Minitest::Test
6
+ def test_torid_generates_uuid
7
+ uuid = Torid.uuid
8
+ assert_instance_of( Torid::UUID, uuid)
9
+ assert_equal( Torid::Generator.node_id, uuid.node_id )
10
+ end
11
+ end
12
+ end
data/test/test_uuid.rb ADDED
@@ -0,0 +1,58 @@
1
+ require 'test_helper'
2
+ require 'torid/uuid'
3
+
4
+ module Torid
5
+ class UUIDTest < ::Minitest::Test
6
+
7
+ def setup
8
+ @timestamp = 1404617330909742
9
+ @node_id = 42
10
+ @bytes = [ @timestamp >> 32, @timestamp & 0xFFFF_FFFF,
11
+ @node_id >> 32, @node_id & 0XFFFF_FFFF ].pack("NNNN")
12
+ @guid = "0004fd7d-f50d-e22e-0000-00000000002a"
13
+ end
14
+
15
+ def test_round_trips_bytes
16
+ uuid = ::Torid::UUID.from( @bytes)
17
+ assert_equal( @bytes, uuid.bytes )
18
+ end
19
+
20
+ def test_extracts_timestamp_from_bytes
21
+ uuid = ::Torid::UUID.from( @bytes)
22
+ assert_equal( @timestamp, uuid.timestamp )
23
+ end
24
+
25
+ def test_extracts_node_id_from_bytes
26
+ uuid = ::Torid::UUID.from( @bytes)
27
+ assert_equal( @node_id , uuid.node_id )
28
+ end
29
+
30
+ def test_round_trips_uuid_string
31
+ uuid = ::Torid::UUID.from( @guid )
32
+ assert_equal( uuid.to_s, uuid.to_s )
33
+ end
34
+
35
+ def test_extracts_timestamp_from_uuid
36
+ uuid = ::Torid::UUID.from( @guid )
37
+ assert_equal( @timestamp, uuid.timestamp )
38
+ end
39
+
40
+ def test_extracts_node_id_from_uuid
41
+ uuid = ::Torid::UUID.from( @guid )
42
+ assert_equal( @node_id , uuid.node_id )
43
+ end
44
+
45
+ def test_create_from_raises_error
46
+ assert_raises( ArgumentError ) do
47
+ ::Torid::UUID.from( "abcdef" )
48
+ end
49
+ end
50
+
51
+ def test_creates_a_time_from_uuid
52
+ time = Time.at( @timestamp / 1_000_000.0 )
53
+ uuid = ::Torid::UUID.from( @guid )
54
+ assert_equal( time, uuid.time )
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,11 @@
1
+ require 'test_helper'
2
+ require 'torid'
3
+
4
+ module Torid
5
+ class VersionTest < ::Minitest::Test
6
+ def test_has_the_proper_format
7
+ assert_match( /\A\d+\.\d+\.\d+\Z/, Torid::VERSION)
8
+ assert_match( /\A\d+\.\d+\.\d+\Z/, Torid::VERSION.to_s)
9
+ end
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: torid
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jeremy Hinegardner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fnv
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.1'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rdoc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '4.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '4.0'
69
+ description: 'Temporally Ordered IDs. Generate universally unique identifiers (UUID)
70
+ that sort lexically in time order. Torid exists to solve the problem of generating
71
+ UUIDs that when ordered lexically, they are also ordered temporally. I needed a
72
+ way to generate ids for events that are entering a system with the following criteria:
73
+ 1. Fast ID generation 2. No central coordinating server/system 3. No local storage
74
+ 4. Library code, that is multiple apps on the same machine can use the same code and
75
+ they will not generate duplicate ids 5. Eventually stored in a UUID field in a database.
76
+ So 128bit ids are totally fine. The IDs that Torid generates are 128bit IDs made
77
+ up of 2, 64bit parts. * 64bit microsecond level UNIX timestamp * 64bit hash of the
78
+ system hostname, process id and a random value.'
79
+ email: jeremy@copiousfreetime.org
80
+ executables: []
81
+ extensions: []
82
+ extra_rdoc_files:
83
+ - CONTRIBUTING.md
84
+ - HISTORY.md
85
+ - Manifest.txt
86
+ - README.md
87
+ files:
88
+ - CONTRIBUTING.md
89
+ - HISTORY.md
90
+ - LICENSE
91
+ - Manifest.txt
92
+ - README.md
93
+ - Rakefile
94
+ - lib/torid.rb
95
+ - lib/torid/clock.rb
96
+ - lib/torid/generator.rb
97
+ - lib/torid/uuid.rb
98
+ - tasks/default.rake
99
+ - tasks/this.rb
100
+ - test/test_clock.rb
101
+ - test/test_generator.rb
102
+ - test/test_helper.rb
103
+ - test/test_torid.rb
104
+ - test/test_uuid.rb
105
+ - test/test_version.rb
106
+ homepage: http://github.com/copiousfreetime/torid
107
+ licenses:
108
+ - ISC
109
+ metadata: {}
110
+ post_install_message:
111
+ rdoc_options:
112
+ - "--main"
113
+ - README.md
114
+ - "--markup"
115
+ - tomdoc
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ requirements: []
129
+ rubyforge_project:
130
+ rubygems_version: 2.2.2
131
+ signing_key:
132
+ specification_version: 4
133
+ summary: Temporally Ordered IDs. Generate universally unique identifiers (UUID) that
134
+ sort lexically in time order.
135
+ test_files: []