torid 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: []