uuid 2.2.0 → 2.3.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.
Files changed (7) hide show
  1. data/CHANGELOG +6 -0
  2. data/README.rdoc +24 -5
  3. data/Rakefile +0 -18
  4. data/bin/uuid +55 -0
  5. data/lib/uuid.rb +129 -2
  6. data/uuid.gemspec +3 -1
  7. metadata +29 -13
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ 2.3.0 (2010-04-07)
2
+ * Added: UUID.generator returns the current UUID generator. Particularly useful for calling
3
+ next_sequence on the generator when forking a process.
4
+ * Added: UUID::Server and UUID::Client so you can have one process serving you UUIDs.
5
+ * Added: UUID command line tool. Yay!
6
+
1
7
  2.2.0 (2010-02-18)
2
8
  * Added: set UUID.state_file = false if you cannot use a state file (e.g. shared hosting environment)
3
9
 
@@ -76,15 +76,34 @@ Engine) you can simple turn it off:
76
76
 
77
77
  State files are not portable across machines.
78
78
 
79
+ Note: when using a forking server (Unicorn, Resque, Pipemaster, etc) you don't
80
+ want your forked processes using the same sequence number. Make sure to
81
+ increment the sequence number each time a worker forks.
79
82
 
80
- == Latest and Greatest
83
+ For example, in config/unicorn.rb:
84
+
85
+ after_fork do |server, worker|
86
+ UUID.generator.next_sequence
87
+ end
88
+
89
+
90
+ == Command Line
91
+
92
+ You can run uuid from the command line, generating new UUID to stdout:
81
93
 
82
- Stable release are made through RubyForge, to upgrade simply:
94
+ $ uuid
83
95
 
84
- gem upgrade uuid
96
+ Multiple UUIDs in a sequence, separated with a newline:
85
97
 
86
- You can subscribe for notifications of new releases through the reliable-msg
87
- project page at http://rubyforge.org/projects/reliable-msg
98
+ $ uuid --count 10
99
+
100
+ You can also run client and server from the command line
101
+
102
+ $ uuid --server &
103
+ $ uuid --socket /var/lib/uuid.sock
104
+
105
+
106
+ == Latest and Greatest
88
107
 
89
108
  Source code and documentation hosted on Github: http://github.com/assaf/uuid
90
109
 
data/Rakefile CHANGED
@@ -8,24 +8,6 @@ desc "Default Task"
8
8
  task :default => :test
9
9
 
10
10
 
11
- desc "If you're building from sources, run this task first to setup the necessary dependencies"
12
- task 'setup' do
13
- missing = spec.dependencies.select { |dep| Gem::SourceIndex.from_installed_gems.search(dep).empty? }
14
- missing.each do |dep|
15
- if Gem::SourceIndex.from_installed_gems.search(dep).empty?
16
- puts "Installing #{dep.name} ..."
17
- rb_bin = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
18
- args = []
19
- args << rb_bin << '-S' << 'gem' << 'install' << dep.name
20
- args << '--version' << dep.version_requirements.to_s
21
- args << '--source' << 'http://gems.rubyforge.org'
22
- args << '--install-dir' << ENV['GEM_HOME'] if ENV['GEM_HOME']
23
- sh *args
24
- end
25
- end
26
- end
27
-
28
-
29
11
  desc "Run all test cases"
30
12
  Rake::TestTask.new do |test|
31
13
  test.verbose = true
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+ require "uuid"
3
+ require "optparse"
4
+
5
+ address = nil
6
+ count = 1
7
+ format = :default
8
+ server = false
9
+
10
+ opts = OptionParser.new("", 24, ' ') do |opts|
11
+ opts.banner = "Usage: #{File.basename($0)} [options]"
12
+
13
+ opts.separator "\nOptions:"
14
+ opts.on("-s", "--socket {HOST:PORT|PATH}",
15
+ "communicate on HOST:PORT or PATH (default: #{UUID::SOCKET_NAME})") do |value|
16
+ address = value
17
+ end
18
+
19
+ opts.on("-S", "--server", "run as a server") do |value|
20
+ server = value ? true : false
21
+ end
22
+
23
+ opts.on("-F", "--format {FORMAT}", "UUID format (client only)") do |value|
24
+ format = value.to_sym
25
+ end
26
+
27
+ opts.on("-C", "--count {COUNT}", "returns give number of UUIDs") do |value|
28
+ count = value.to_i
29
+ end
30
+
31
+ opts.on("-h", "--help", "Show this message") do
32
+ puts opts.to_s.gsub(/^.*DEPRECATED.*$/s, '')
33
+ exit
34
+ end
35
+
36
+ opts.on("-v", "--version", "Show version") do
37
+ puts "UUID v#{UUID::VERSION}"
38
+ exit
39
+ end
40
+
41
+ opts.parse! ARGV
42
+ end
43
+
44
+
45
+ if server
46
+ $stdout << "Starting UUID server on #{address}\n"
47
+ UUID::Server.new.listen(address || UUID::SOCKET_NAME)
48
+ else
49
+ UUID.server = address if address
50
+ $stdout << UUID.generate(format)
51
+ (count - 1).times do
52
+ $stdout.putc "\n"
53
+ $stdout << UUID.generate(format)
54
+ end
55
+ end
@@ -9,8 +9,7 @@
9
9
  require 'fileutils'
10
10
  require 'thread'
11
11
  require 'tmpdir'
12
-
13
- require 'rubygems'
12
+ require 'socket'
14
13
  require 'macaddr'
15
14
 
16
15
 
@@ -122,6 +121,24 @@ class UUID
122
121
  @uuid.generate format
123
122
  end
124
123
 
124
+ ##
125
+ # Returns the UUID generator used by generate. Useful if you need to mess
126
+ # with it, e.g. force next sequence when forking (e.g. Unicorn, Resque):
127
+ #
128
+ # after_fork do
129
+ # UUID.generator.next_sequence
130
+ # end
131
+ def self.generator
132
+ @uuid ||= new
133
+ end
134
+
135
+ ##
136
+ # Call this to use a UUID Server. Expects address to bind to (SOCKET_NAME is
137
+ # a good default)
138
+ def self.server=(address)
139
+ @uuid = Client.new(address) unless Client === @uuid
140
+ end
141
+
125
142
  ##
126
143
  # Creates an empty state file in /var/tmp/ruby-uuid or the windows common
127
144
  # application data directory using mode 0644. Call with a different mode
@@ -313,4 +330,114 @@ protected
313
330
  io.write [mac1, mac2, @sequence, @last_clock].pack(STATE_FILE_FORMAT)
314
331
  end
315
332
 
333
+
334
+ # You don't have to use this, it's just a good default.
335
+ SOCKET_NAME ="/var/lib/uuid.sock"
336
+
337
+ # With UUID server you don't have to worry about multiple processes
338
+ # synchronizing over the state file, calling next_sequence when forking a
339
+ # process and other things you're probably not worried about (because
340
+ # statistically they're very unlikely to break your code).
341
+ #
342
+ # But if you are worried about and thought to yourself, "what would a simple
343
+ # UUID server look like?", here's the answer. The protocol is dead simple:
344
+ # client sends a byte, server responds with a UUID. Can use TCP or domain
345
+ # sockets.
346
+ class Server
347
+
348
+ # Create new server. Nothing interesting happens until you call listen.
349
+ def initialize()
350
+ @generator = UUID.new
351
+ end
352
+
353
+ # Start the server listening on the specific address. Blocks and never
354
+ # returns. Address can be:
355
+ # - A Socket object
356
+ # - UNIX domain socket name (e.g. /var/run/uuid.sock, must start with /)
357
+ # - IP address, colon, port (e.g. localhost:1337)
358
+ def listen(address)
359
+ sock = bind(address)
360
+ while client = sock.accept
361
+ Thread.start(client) do |client|
362
+ while client.read 1
363
+ client.write @generator.generate
364
+ end
365
+ end
366
+ end
367
+ end
368
+
369
+ # Returns UNIXServer or TCPServer from address. Returns argument if not a
370
+ # string, so can pass through (see #listen).
371
+ def bind(address)
372
+ return address unless String === address
373
+ if address[0] == ?/
374
+ if File.exist?(address)
375
+ raise ArgumentError, "#{address} is not a socket" unless File.socket?(address)
376
+ File.unlink(address)
377
+ end
378
+ sock = UNIXServer.new(address)
379
+ File.chmod 0666, address
380
+ elsif address =~ /^(\d+\.\d+\.\d+\.\d+):(\d+)$/
381
+ sock = TCPServer.new($1, $2.to_i)
382
+ else
383
+ raise ArgumentError, "Don't know how to bind #{address}"
384
+ end
385
+ sock.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1) if defined?(TCP_NODELAY)
386
+ sock
387
+ end
388
+
389
+ end
390
+
391
+
392
+ # Every server needs a client. Client provides you with the single ultimate
393
+ # method: #generate. Typically you'll use this instead of the local UUID
394
+ # generator:
395
+ # UUID.server = UUID::SOCKET_NAME
396
+ class Client
397
+
398
+ def initialize(address)
399
+ @socket = connect(address)
400
+ at_exit { close }
401
+ end
402
+
403
+ # Talks to server and returns new UUID in specified format.
404
+ def generate(format = :default)
405
+ @socket.write "\0"
406
+ uuid = @socket.read(36)
407
+ return uuid if format == :default
408
+ template = FORMATS[format]
409
+ raise ArgumentError, "invalid UUID format #{format.inspect}" unless template
410
+ template % uuid.split("-").map { |p| p.to_i(16) }
411
+ end
412
+
413
+ # Returns UNIXSocket or TCPSocket from address. Returns argument if not a
414
+ # string, so can pass through.
415
+ def connect(address)
416
+ return address unless String === address
417
+ if address[0] == ?/
418
+ sock = UNIXSocket.new(address)
419
+ elsif address =~ /^(\d+\.\d+\.\d+\.\d+):(\d+)$/
420
+ sock = TCPSocket.new($1, $2.to_i)
421
+ else
422
+ raise ArgumentError, "Don't know how to connect to #{address}"
423
+ end
424
+ sock.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1) if defined?(TCP_NODELAY)
425
+ sock
426
+ end
427
+
428
+ def next_sequence #:nodoc: Stubbed to do nothing.
429
+ end
430
+
431
+ def inspect
432
+ @socket ? "Server on #{Socket.unpack_sockaddr_in(@socket.getsockname).reverse!.join(':')}" : "Connection closed"
433
+ end
434
+
435
+ # Close the socket.
436
+ def close
437
+ @socket.shutdown if @socket
438
+ @socket = nil
439
+ end
440
+
441
+ end
442
+
316
443
  end
@@ -1,6 +1,6 @@
1
1
  spec = Gem::Specification.new do |spec|
2
2
  spec.name = 'uuid'
3
- spec.version = '2.2.0'
3
+ spec.version = '2.3.0'
4
4
  spec.summary = "UUID generator"
5
5
  spec.description = <<-EOF
6
6
  UUID generator for producing universally unique identifiers based on RFC 4122
@@ -12,6 +12,8 @@ EOF
12
12
  spec.homepage = 'http://github.com/assaf/uuid'
13
13
 
14
14
  spec.files = Dir['{bin,test,lib,docs}/**/*'] + ['README.rdoc', 'MIT-LICENSE', 'Rakefile', 'CHANGELOG', 'uuid.gemspec']
15
+ spec.executables = "uuid"
16
+
15
17
  spec.has_rdoc = true
16
18
  spec.rdoc_options << '--main' << 'README.rdoc' << '--title' << 'UUID generator' << '--line-numbers'
17
19
  '--webcvs' << 'http://github.com/assaf/uuid'
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uuid
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ prerelease: false
5
+ segments:
6
+ - 2
7
+ - 3
8
+ - 0
9
+ version: 2.3.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - Assaf Arkin
@@ -10,29 +15,36 @@ autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
17
 
13
- date: 2010-02-18 00:00:00 -08:00
18
+ date: 2010-04-07 00:00:00 -07:00
14
19
  default_executable:
15
20
  dependencies:
16
21
  - !ruby/object:Gem::Dependency
17
22
  name: macaddr
18
- type: :runtime
19
- version_requirement:
20
- version_requirements: !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
21
25
  requirements:
22
26
  - - ~>
23
27
  - !ruby/object:Gem::Version
28
+ segments:
29
+ - 1
30
+ - 0
24
31
  version: "1.0"
25
- version:
26
- description: UUID generator for producing universally unique identifiers based on RFC 4122 (http://www.ietf.org/rfc/rfc4122.txt).
27
- email: assaf@labnotes.org
28
- executables: []
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description: |
35
+ UUID generator for producing universally unique identifiers based on RFC 4122
36
+ (http://www.ietf.org/rfc/rfc4122.txt).
29
37
 
38
+ email: assaf@labnotes.org
39
+ executables:
40
+ - uuid
30
41
  extensions: []
31
42
 
32
43
  extra_rdoc_files:
33
44
  - README.rdoc
34
45
  - MIT-LICENSE
35
46
  files:
47
+ - bin/uuid
36
48
  - test/test-uuid.rb
37
49
  - lib/uuid.rb
38
50
  - README.rdoc
@@ -42,6 +54,8 @@ files:
42
54
  - uuid.gemspec
43
55
  has_rdoc: true
44
56
  homepage: http://github.com/assaf/uuid
57
+ licenses: []
58
+
45
59
  post_install_message:
46
60
  rdoc_options:
47
61
  - --main
@@ -55,20 +69,22 @@ required_ruby_version: !ruby/object:Gem::Requirement
55
69
  requirements:
56
70
  - - ">="
57
71
  - !ruby/object:Gem::Version
72
+ segments:
73
+ - 0
58
74
  version: "0"
59
- version:
60
75
  required_rubygems_version: !ruby/object:Gem::Requirement
61
76
  requirements:
62
77
  - - ">="
63
78
  - !ruby/object:Gem::Version
79
+ segments:
80
+ - 0
64
81
  version: "0"
65
- version:
66
82
  requirements: []
67
83
 
68
84
  rubyforge_project:
69
- rubygems_version: 1.3.1
85
+ rubygems_version: 1.3.6
70
86
  signing_key:
71
- specification_version: 2
87
+ specification_version: 3
72
88
  summary: UUID generator
73
89
  test_files: []
74
90