uuid_it 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # UuidIt
2
+
3
+ You need to assign UUIDs to your Model? Simply uuid_it by adding one line of code.
4
+
5
+ For actually generating the uuids this plugin uses spectra's ruby-uuid (http://github.com/spectra/ruby-uuid) whih is
6
+ based on ruby-uuid (http://raa.ruby-lang.org/project/ruby-uuid/).
7
+
8
+ ## Installation
9
+
10
+ script/plugin install git://github.com/aduffeck/uuid_it.git
11
+ script/generate uuid_it
12
+ rake db:migrate
13
+
14
+
15
+ ## Usage
16
+
17
+ class Car < ActiveRecord::Base
18
+ uuid_it
19
+ end
20
+
21
+ @car.uuid # "9e5edacc-7163-11df-92bb-2d0a2c4dcb1c"
22
+
23
+ ## Credits
24
+
25
+ Copyright (c) 2010 André Duffeck, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require "rake/gempackagetask"
5
+
6
+ desc 'Default: run unit tests.'
7
+ task :default => :test
8
+
9
+ desc 'Test the uuid_it plugin.'
10
+ Rake::TestTask.new(:test) do |t|
11
+ t.libs << 'lib'
12
+ t.libs << 'test'
13
+ t.pattern = 'test/**/*_test.rb'
14
+ t.verbose = true
15
+ end
16
+
17
+ desc 'Generate documentation for the uuid_it plugin.'
18
+ Rake::RDocTask.new(:rdoc) do |rdoc|
19
+ rdoc.rdoc_dir = 'rdoc'
20
+ rdoc.title = 'UuidIt'
21
+ rdoc.options << '--line-numbers' << '--inline-source'
22
+ rdoc.rdoc_files.include('README')
23
+ rdoc.rdoc_files.include('lib/**/*.rb')
24
+ end
25
+
26
+ Rake::GemPackageTask.new(eval(File.read("uuid_it.gemspec"))) { |pkg| }
@@ -0,0 +1,14 @@
1
+ class CreateUuids < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :uuids do |t|
4
+ t.string :uuid
5
+ t.integer :uuidable_id
6
+ t.string :uuidable_type, :limit => 40
7
+ end
8
+ add_index :uuids, :uuidable_id
9
+ end
10
+
11
+ def self.down
12
+ drop_table :uuids
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ class UuidItGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ m.migration_template('create_uuids.rb', "db/migrate", :migration_file_name => 'create_uuids')
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,387 @@
1
+ #!/usr/bin/env ruby
2
+ ### http://mput.dip.jp/mput/uuid.txt
3
+
4
+ # Copyright(c) 2005 URABE, Shyouhei.
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this code, to deal in the code without restriction, including without
8
+ # limitation the rights to use, copy, modify, merge, publish, distribute,
9
+ # sublicense, and/or sell copies of the code, and to permit persons to whom the
10
+ # code is furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the code.
14
+ #
15
+ # THE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE CODE OR THE USE OR OTHER DEALINGS IN THE
21
+ # CODE.
22
+ #
23
+ # 2009-02-20: Modified by Pablo Lorenzoni <pablo@propus.com.br> to correctly
24
+ # include the version in the raw_bytes.
25
+
26
+
27
+ require 'digest/md5'
28
+ require 'digest/sha1'
29
+ require 'tmpdir'
30
+
31
+ # Pure ruby UUID generator, which is compatible with RFC4122
32
+ UUID = Struct.new :raw_bytes
33
+
34
+ class UUID
35
+ private_class_method :new
36
+
37
+ class << self
38
+ def mask19 v, str # :nodoc
39
+ nstr = str.bytes.to_a
40
+ version = [0, 16, 32, 48, 64, 80][v]
41
+ nstr[6] &= 0b00001111
42
+ nstr[6] |= version
43
+ # nstr[7] &= 0b00001111
44
+ # nstr[7] |= 0b01010000
45
+ nstr[8] &= 0b00111111
46
+ nstr[8] |= 0b10000000
47
+ str = ''
48
+ nstr.each { |s| str << s.chr }
49
+ str
50
+ end
51
+
52
+ def mask18 v, str # :nodoc
53
+ version = [0, 16, 32, 48, 64, 80][v]
54
+ str[6] &= 0b00001111
55
+ str[6] |= version
56
+ # str[7] &= 0b00001111
57
+ # str[7] |= 0b01010000
58
+ str[8] &= 0b00111111
59
+ str[8] |= 0b10000000
60
+ str
61
+ end
62
+
63
+ def mask v, str
64
+ if RUBY_VERSION >= "1.9.0"
65
+ return mask19 v, str
66
+ else
67
+ return mask18 v, str
68
+ end
69
+ end
70
+ private :mask, :mask18, :mask19
71
+
72
+ # UUID generation using SHA1. Recommended over create_md5.
73
+ # Namespace object is another UUID, some of them are pre-defined below.
74
+ def create_sha1 str, namespace
75
+ sha1 = Digest::SHA1.new
76
+ sha1.update namespace.raw_bytes
77
+ sha1.update str
78
+ sum = sha1.digest
79
+ raw = mask 5, sum[0..15]
80
+ ret = new raw
81
+ ret.freeze
82
+ ret
83
+ end
84
+ alias :create_v5 :create_sha1
85
+
86
+ # UUID generation using MD5 (for backward compat.)
87
+ def create_md5 str, namespace
88
+ md5 = Digest::MD5.new
89
+ md5.update namespace.raw_bytes
90
+ md5.update str
91
+ sum = md5.digest
92
+ raw = mask 3, sum[0..16]
93
+ ret = new raw
94
+ ret.freeze
95
+ ret
96
+ end
97
+ alias :create_v3 :create_md5
98
+
99
+ # UUID generation using random-number generator. From it's random
100
+ # nature, there's no warranty that the created ID is really universaly
101
+ # unique.
102
+ def create_random
103
+ rnd = [
104
+ rand(0x100000000),
105
+ rand(0x100000000),
106
+ rand(0x100000000),
107
+ rand(0x100000000),
108
+ ].pack "N4"
109
+ raw = mask 4, rnd
110
+ ret = new raw
111
+ ret.freeze
112
+ ret
113
+ end
114
+ alias :create_v4 :create_random
115
+
116
+ def read_state fp # :nodoc:
117
+ fp.rewind
118
+ Marshal.load fp.read
119
+ end
120
+
121
+ def write_state fp, c, m # :nodoc:
122
+ fp.rewind
123
+ str = Marshal.dump [c, m]
124
+ fp.write str
125
+ end
126
+
127
+ private :read_state, :write_state
128
+ STATE_FILE = 'ruby-uuid'
129
+
130
+ # create the "version 1" UUID with current system clock, current UTC
131
+ # timestamp, and the IEEE 802 address (so-called MAC address).
132
+ #
133
+ # Speed notice: it's slow. It writes some data into hard drive on every
134
+ # invokation. If you want to speed this up, try remounting tmpdir with a
135
+ # memory based filesystem (such as tmpfs). STILL slow? then no way but
136
+ # rewrite it with c :)
137
+ def create clock=nil, time=nil, mac_addr=nil
138
+ c = t = m = nil
139
+ Dir.chdir Dir.tmpdir do
140
+ unless FileTest.exist? STATE_FILE then
141
+ # Generate a pseudo MAC address because we have no pure-ruby way
142
+ # to know the MAC address of the NIC this system uses. Note
143
+ # that cheating with pseudo arresses here is completely legal:
144
+ # see Section 4.5 of RFC4122 for details.
145
+ sha1 = Digest::SHA1.new
146
+ 256.times do
147
+ r = [rand(0x100000000)].pack "N"
148
+ sha1.update r
149
+ end
150
+ str = sha1.digest
151
+ r = rand 14 # 20-6
152
+ node = str[r, 6] || str
153
+ if RUBY_VERSION >= "1.9.0"
154
+ nnode = node.bytes.to_a
155
+ nnode[0] |= 0x01
156
+ node = ''
157
+ nnode.each { |s| node << s.chr }
158
+ else
159
+ node[0] |= 0x01 # multicast bit
160
+ end
161
+ k = rand 0x40000
162
+ open STATE_FILE, 'w' do |fp|
163
+ fp.flock IO::LOCK_EX
164
+ write_state fp, k, node
165
+ fp.chmod 0o777 # must be world writable
166
+ end
167
+ end
168
+ open STATE_FILE, 'r+' do |fp|
169
+ fp.flock IO::LOCK_EX
170
+ c, m = read_state fp
171
+ c = clock % 0x4000 if clock
172
+ m = mac_addr if mac_addr
173
+ t = time
174
+ if t.nil? then
175
+ # UUID epoch is 1582/Oct/15
176
+ tt = Time.now
177
+ t = tt.to_i*10000000 + tt.tv_usec*10 + 0x01B21DD213814000
178
+ end
179
+ c = c.succ # important; increment here
180
+ write_state fp, c, m
181
+ end
182
+ end
183
+
184
+ tl = t & 0xFFFF_FFFF
185
+ tm = t >> 32
186
+ tm = tm & 0xFFFF
187
+ th = t >> 48
188
+ th = th & 0x0FFF
189
+ th = th | 0x1000
190
+ cl = c & 0xFF
191
+ ch = c & 0x3F00
192
+ ch = ch >> 8
193
+ ch = ch | 0x80
194
+ pack tl, tm, th, cl, ch, m
195
+ end
196
+ alias :create_v1 :create
197
+
198
+ # A simple GUID parser: just ignores unknown characters and convert
199
+ # hexadecimal dump into 16-octet object.
200
+ def parse obj
201
+ str = obj.to_s.sub %r/\Aurn:uuid:/, ''
202
+ str.gsub! %r/[^0-9A-Fa-f]/, ''
203
+ raw = str[0..31].lines.to_a.pack 'H*'
204
+ ret = new raw
205
+ ret.freeze
206
+ ret
207
+ end
208
+
209
+ # The 'primitive constructor' of this class
210
+ # Note UUID.pack(uuid.unpack) == uuid
211
+ def pack tl, tm, th, ch, cl, n
212
+ raw = [tl, tm, th, ch, cl, n].pack "NnnCCa6"
213
+ ret = new raw
214
+ ret.freeze
215
+ ret
216
+ end
217
+ end
218
+
219
+ # The 'primitive deconstructor', or the dual to pack.
220
+ # Note UUID.pack(uuid.unpack) == uuid
221
+ def unpack
222
+ raw_bytes.unpack "NnnCCa6"
223
+ end
224
+
225
+ # Generate the string representation (a.k.a GUID) of this UUID
226
+ def to_s
227
+ a = unpack
228
+ tmp = a[-1].unpack 'C*'
229
+ a[-1] = sprintf '%02x%02x%02x%02x%02x%02x', *tmp
230
+ "%08x-%04x-%04x-%02x%02x-%s" % a
231
+ end
232
+ alias guid to_s
233
+
234
+ # Convert into a RFC4122-comforming URN representation
235
+ def to_uri
236
+ "urn:uuid:" + self.to_s
237
+ end
238
+ alias urn to_uri
239
+
240
+ # Convert into 128-bit unsigned integer
241
+ # Typically a Bignum instance, but can be a Fixnum.
242
+ def to_int
243
+ tmp = self.raw_bytes.unpack "C*"
244
+ tmp.inject do |r, i|
245
+ r * 256 | i
246
+ end
247
+ end
248
+ alias to_i to_int
249
+
250
+ # Gets the version of this UUID
251
+ # returns nil if bad version
252
+ def version
253
+ a = unpack
254
+ v = (a[2] & 0xF000).to_s(16)[0].chr.to_i
255
+ return v if (1..5).include? v
256
+ return nil
257
+ end
258
+
259
+ # Two UUIDs are said to be equal if and only if their (byte-order
260
+ # canonicalized) integer representations are equivallent. Refer RFC4122 for
261
+ # details.
262
+ def == other
263
+ to_i == other.to_i
264
+ end
265
+
266
+ include Comparable
267
+ # UUIDs are comparable (don't know what benefits are there, though).
268
+ def <=> other
269
+ to_s <=> other.to_s
270
+ end
271
+
272
+ # Pre-defined UUID Namespaces described in RFC4122 Appendix C.
273
+ NameSpace_DNS = parse "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
274
+ NameSpace_URL = parse "6ba7b811-9dad-11d1-80b4-00c04fd430c8"
275
+ NameSpace_OID = parse "6ba7b812-9dad-11d1-80b4-00c04fd430c8"
276
+ NameSpace_X500 = parse "6ba7b814-9dad-11d1-80b4-00c04fd430c8"
277
+
278
+ # The Nil UUID in RFC4122 Section 4.1.7
279
+ Nil = parse "00000000-0000-0000-0000-000000000000"
280
+ end
281
+
282
+ __END__
283
+ if __FILE__ == $0 then
284
+ require 'test/unit'
285
+
286
+ class TC_UUID < Test::Unit::TestCase
287
+ def test_v1
288
+ u1 = UUID.create
289
+ u2 = UUID.create
290
+ assert_not_equal u1, u2
291
+ end
292
+
293
+ def test_v1_repeatability
294
+ u1 = UUID.create 1, 2, "345678"
295
+ u2 = UUID.create 1, 2, "345678"
296
+ assert_equal u1, u2
297
+ end
298
+
299
+ def test_v3
300
+ u1 = UUID.create_md5 "foo", UUID::NameSpace_DNS
301
+ u2 = UUID.create_md5 "foo", UUID::NameSpace_DNS
302
+ u3 = UUID.create_md5 "foo", UUID::NameSpace_URL
303
+ assert_equal u1, u2
304
+ assert_not_equal u1, u3
305
+ end
306
+
307
+ def test_v5
308
+ u1 = UUID.create_sha1 "foo", UUID::NameSpace_DNS
309
+ u2 = UUID.create_sha1 "foo", UUID::NameSpace_DNS
310
+ u3 = UUID.create_sha1 "foo", UUID::NameSpace_URL
311
+ assert_equal u1, u2
312
+ assert_not_equal u1, u3
313
+ end
314
+
315
+ def test_v4
316
+ # This test is not perfect, because the random nature of version 4
317
+ # UUID it is not always true that the three objects below really
318
+ # differ. But in real life it's enough to say we're OK when this
319
+ # passes.
320
+ u1 = UUID.create_random
321
+ u2 = UUID.create_random
322
+ u3 = UUID.create_random
323
+ assert_not_equal u1.raw_bytes, u2.raw_bytes
324
+ assert_not_equal u1.raw_bytes, u3.raw_bytes
325
+ assert_not_equal u2.raw_bytes, u3.raw_bytes
326
+ end
327
+
328
+ def test_pack
329
+ u1 = UUID.pack 0x6ba7b810, 0x9dad, 0x11d1, 0x80, 0xb4,
330
+ "\000\300O\3240\310"
331
+ assert_equal UUID::NameSpace_DNS, u1
332
+ end
333
+
334
+ def test_unpack
335
+ tl, tm, th, cl, ch, m = UUID::NameSpace_DNS.unpack
336
+ assert_equal 0x6ba7b810, tl
337
+ assert_equal 0x9dad, tm
338
+ assert_equal 0x11d1, th
339
+ assert_equal 0x80, cl
340
+ assert_equal 0xb4, ch
341
+ assert_equal "\000\300O\3240\310", m
342
+ end
343
+
344
+ def test_parse
345
+ u1 = UUID.pack 0x6ba7b810, 0x9dad, 0x11d1, 0x80, 0xb4,
346
+ "\000\300O\3240\310"
347
+ u2 = UUID.parse "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
348
+ u3 = UUID.parse "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
349
+ assert_equal u1, u2
350
+ assert_equal u1, u3
351
+ end
352
+
353
+ def test_to_s
354
+ u1 = UUID.parse "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
355
+ assert_equal "6ba7b810-9dad-11d1-80b4-00c04fd430c8", u1.to_s
356
+ end
357
+
358
+ def test_to_i
359
+ u1 = UUID.parse "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
360
+ assert_equal 0x6ba7b8109dad11d180b400c04fd430c8, u1.to_i
361
+ end
362
+
363
+ def test_version
364
+ u1 = UUID.create_v1
365
+ assert_equal 1, u1.version
366
+ u3 = UUID.create_v3 "foo", UUID::NameSpace_DNS
367
+ assert_equal 3, u3.version
368
+ u4 = UUID.create_v4
369
+ assert_equal 4, u4.version
370
+ u5 = UUID.create_v5 "foo", UUID::NameSpace_DNS
371
+ assert_equal 5, u5.version
372
+ end
373
+ end
374
+ end
375
+
376
+
377
+
378
+ # Local Variables:
379
+ # mode: ruby
380
+ # code: utf-8
381
+ # indent-tabs-mode: t
382
+ # tab-width: 3
383
+ # ruby-indent-level: 3
384
+ # fill-column: 79
385
+ # default-justification: full
386
+ # End:
387
+ # vi: ts=3 sw=3
@@ -0,0 +1,3 @@
1
+ class Uuid < ::ActiveRecord::Base
2
+ belongs_to :uuidable, :polymorphic => true
3
+ end
data/lib/uuid_it.rb ADDED
@@ -0,0 +1,35 @@
1
+ require File.join(File.dirname(__FILE__), "uuid_it", "uuid.rb")
2
+ require File.join(File.dirname(__FILE__), "ruby-uuid", "uuid.rb")
3
+
4
+ module ActiveRecord
5
+ module Acts
6
+
7
+ module UuidIt
8
+ def uuid_it
9
+ class_eval do
10
+ send :include, InstanceMethods
11
+ has_one :uuid_object, :as => :uuidable, :class_name => "Uuid", :dependent => :destroy
12
+ after_create :assign_uuid
13
+ end
14
+ end
15
+
16
+ module InstanceMethods
17
+ def uuid
18
+ assign_uuid unless self.uuid_object
19
+ self.uuid_object.uuid
20
+ end
21
+
22
+ def assign_uuid
23
+ return if Uuid.find_by_uuidable_type_and_uuidable_id(self.class.name, self.id)
24
+ uuid = Uuid.new(:uuidable_id => self.id, :uuidable_type => self.class.name)
25
+ uuid.uuid = UUID.create.to_s
26
+ uuid.save
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ ActiveRecord::Base.class_eval do
34
+ extend ActiveRecord::Acts::UuidIt
35
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'uuid_it'
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+ require 'active_support/test_case'
@@ -0,0 +1,8 @@
1
+ require 'test_helper'
2
+
3
+ class UuidItTest < ActiveSupport::TestCase
4
+ # Replace this with your real tests.
5
+ test "the truth" do
6
+ assert true
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: uuid_it
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - "Andr\xC3\xA9 Duffeck"
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-06-06 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: " You need to assign UUIDs to your model? UuidIt makes it as simple adding one line of code to the according models. \n"
22
+ email:
23
+ - aduffeck@suse.de
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - lib/uuid_it/uuid.rb
32
+ - lib/ruby-uuid/uuid.rb
33
+ - lib/uuid_it.rb
34
+ - README.md
35
+ - Rakefile
36
+ - rails/init.rb
37
+ - generators/uuid_it/templates/create_uuids.rb
38
+ - generators/uuid_it/uuid_it_generator.rb
39
+ - test/test_helper.rb
40
+ - test/uuid_it_test.rb
41
+ has_rdoc: true
42
+ homepage: http://aduffeck.github.com/uuid_it
43
+ licenses: []
44
+
45
+ post_install_message:
46
+ rdoc_options: []
47
+
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
56
+ version: "0"
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ requirements: []
65
+
66
+ rubyforge_project:
67
+ rubygems_version: 1.3.6
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: A Rails plugin for easily assigning UUIDs to your models..
71
+ test_files:
72
+ - test/uuid_it_test.rb