mm_uses_uuid 0.0.1
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.
- data/.gitignore +17 -0
- data/.project +18 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/README.md +46 -0
- data/Rakefile +2 -0
- data/lib/mm_uses_uuid.rb +98 -0
- data/lib/mm_uses_uuid/bson_binary_mixin.rb +24 -0
- data/lib/mm_uses_uuid/version.rb +3 -0
- data/mm_uses_uuid.gemspec +23 -0
- data/spec/mm_uses_uuid_spec.rb +81 -0
- metadata +118 -0
data/.gitignore
ADDED
data/.project
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<projectDescription>
|
|
3
|
+
<name>mm_uses_uuid</name>
|
|
4
|
+
<comment></comment>
|
|
5
|
+
<projects>
|
|
6
|
+
</projects>
|
|
7
|
+
<buildSpec>
|
|
8
|
+
<buildCommand>
|
|
9
|
+
<name>com.aptana.ide.core.unifiedBuilder</name>
|
|
10
|
+
<arguments>
|
|
11
|
+
</arguments>
|
|
12
|
+
</buildCommand>
|
|
13
|
+
</buildSpec>
|
|
14
|
+
<natures>
|
|
15
|
+
<nature>com.aptana.ruby.core.rubynature</nature>
|
|
16
|
+
<nature>com.aptana.projects.webnature</nature>
|
|
17
|
+
</natures>
|
|
18
|
+
</projectDescription>
|
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2010 [name of plugin creator]
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
|
|
2
|
+
mm_uses_uuid plugin
|
|
3
|
+
============
|
|
4
|
+
|
|
5
|
+
Models that use this plugin use a `BSON::Binary::SUBTYPE_UUID` for the model's id field rather than the default `BSON::ObjectId`.
|
|
6
|
+
|
|
7
|
+
Requirements
|
|
8
|
+
============
|
|
9
|
+
|
|
10
|
+
- Ruby 1.9
|
|
11
|
+
- MongoMapper 0.10.1 or greater
|
|
12
|
+
|
|
13
|
+
Installation
|
|
14
|
+
=======
|
|
15
|
+
|
|
16
|
+
Add this to your Gemfile if using Bundler: `gem 'mm_uses_uuid'`
|
|
17
|
+
|
|
18
|
+
Or install the gem from the command line: `gem install mm_uses_uuid`
|
|
19
|
+
|
|
20
|
+
Usage
|
|
21
|
+
=======
|
|
22
|
+
|
|
23
|
+
Use the MongoMapper `plugin` method to add MmUsesUuid to your model, for example:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
class Group
|
|
27
|
+
include MongoMapper::Document
|
|
28
|
+
plugin MmUsesUuid
|
|
29
|
+
|
|
30
|
+
many :people, :class_name => 'Person'
|
|
31
|
+
end
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The newly instantiated model will have a randomly generated UUID. If you want to make sure that the UUID hasn't already been used
|
|
35
|
+
you can generate a new one like this:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
g = Group.new
|
|
39
|
+
g.find_new_uuid(:ensure_unique_in => Group)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This will generate random UUIDs until it finds one that isn't in the passed collection (`Group` in the example).
|
|
43
|
+
Obviously, the whole idea of random (type 4) UUIDs is that there is a tiny probability of generating duplicates.
|
|
44
|
+
For this reason, you should only consider using `:ensure_unique_in` if a duplicate UUID would be a disaster for you.
|
|
45
|
+
|
|
46
|
+
Copyright (c) 2011 PeepAll Ltd, released under the MIT license
|
data/Rakefile
ADDED
data/lib/mm_uses_uuid.rb
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
require 'mongo_mapper'
|
|
2
|
+
require_relative "mm_uses_uuid/version"
|
|
3
|
+
require_relative "mm_uses_uuid/bson_binary_mixin"
|
|
4
|
+
|
|
5
|
+
module MmUsesUuid
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
key :_id, BsonUuid
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class BsonUuid
|
|
13
|
+
def self.to_mongo(value)
|
|
14
|
+
case value
|
|
15
|
+
when String
|
|
16
|
+
BSON::Binary.new(value, BSON::Binary::SUBTYPE_UUID)
|
|
17
|
+
when BSON::Binary, NilClass
|
|
18
|
+
value
|
|
19
|
+
else
|
|
20
|
+
raise "BsonUuid cannot be of type #{value.class}. String, BSON::Binary and NilClass are the only permitted types"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.from_mongo(value)
|
|
25
|
+
value
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
module ClassMethods
|
|
30
|
+
|
|
31
|
+
def find(*args)
|
|
32
|
+
|
|
33
|
+
args.flatten!
|
|
34
|
+
if args.size > 1
|
|
35
|
+
args.map! {|id| BsonUuid.to_mongo(id)}
|
|
36
|
+
else
|
|
37
|
+
args = BsonUuid.to_mongo(args.first)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
super(args)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def new(*args)
|
|
44
|
+
new_object = super(*args)
|
|
45
|
+
new_object.find_new_uuid
|
|
46
|
+
new_object
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
module InstanceMethods
|
|
52
|
+
|
|
53
|
+
def find_new_uuid(options = {})
|
|
54
|
+
|
|
55
|
+
options = {force_safe: false}.merge(options)
|
|
56
|
+
|
|
57
|
+
if not options[:ensure_unique_in]
|
|
58
|
+
@_id, variant = make_uuid
|
|
59
|
+
#puts "assuming #{variant} UUID #{@_id} is available"
|
|
60
|
+
return
|
|
61
|
+
else
|
|
62
|
+
find_new_uuid_safely(options[:ensure_unique_in])
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def find_new_uuid_safely(coll)
|
|
68
|
+
|
|
69
|
+
@_id = nil
|
|
70
|
+
begin
|
|
71
|
+
trial_id, variant = make_uuid
|
|
72
|
+
#puts "CHECKING #{coll} collection for availability of #{variant} UUID: #{trial_id}"
|
|
73
|
+
if coll.where(:_id => trial_id).fields(:_id).first.nil?
|
|
74
|
+
@_id = trial_id
|
|
75
|
+
end
|
|
76
|
+
end while @_id.nil?
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def make_uuid
|
|
81
|
+
uuid = SecureRandom.uuid.gsub!('-', '')
|
|
82
|
+
bson_encoded_uuid = BSON::Binary.new(uuid, BSON::Binary::SUBTYPE_UUID)
|
|
83
|
+
return bson_encoded_uuid, 'random'
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def id_to_s!
|
|
87
|
+
@_id = @_id.to_s
|
|
88
|
+
self
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def id_to_s
|
|
92
|
+
copy = self.clone
|
|
93
|
+
copy.instance_variable_set '@_id', @_id.to_s
|
|
94
|
+
copy
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'bson/byte_buffer'
|
|
2
|
+
|
|
3
|
+
module BSON
|
|
4
|
+
|
|
5
|
+
class Binary < ByteBuffer
|
|
6
|
+
|
|
7
|
+
def inspect
|
|
8
|
+
string_render = self.to_s
|
|
9
|
+
if string_render.empty?
|
|
10
|
+
"<BSON::Binary:#{object_id}>"
|
|
11
|
+
else
|
|
12
|
+
string_length = string_render.length
|
|
13
|
+
if string_render.length > 32
|
|
14
|
+
"<BSON::Binary:'#{string_render[0..8]}...'}'>"
|
|
15
|
+
else
|
|
16
|
+
"<BSON::Binary:'#{string_render}'>"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
require File.expand_path('../lib/mm_uses_uuid/version', __FILE__)
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |gem|
|
|
5
|
+
gem.authors = ["Jonathan Chambers"]
|
|
6
|
+
gem.email = ["j.chambers@gmx.net"]
|
|
7
|
+
gem.description = %q{MongoMapper plugin that uses a UUID instead of the default ObjectID}
|
|
8
|
+
gem.summary = %q{UUIDs for MM}
|
|
9
|
+
gem.homepage = 'https://github.com/jmchambers/mm_uses_uuid'
|
|
10
|
+
|
|
11
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
12
|
+
gem.files = `git ls-files`.split("\n")
|
|
13
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
14
|
+
gem.name = "mm_uses_uuid"
|
|
15
|
+
gem.require_paths = ['lib']
|
|
16
|
+
gem.version = MmUsesUuid::VERSION
|
|
17
|
+
gem.license = 'MIT'
|
|
18
|
+
|
|
19
|
+
gem.add_development_dependency "rspec", "~> 2.7"
|
|
20
|
+
gem.add_development_dependency "bson_ext", "~> 1.5.0"
|
|
21
|
+
gem.add_dependency "mongo_mapper", "~> 0.10.1"
|
|
22
|
+
|
|
23
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require File.expand_path('../../lib/mm_uses_uuid', __FILE__)
|
|
2
|
+
|
|
3
|
+
describe MmUsesUuid do
|
|
4
|
+
|
|
5
|
+
before(:all) do
|
|
6
|
+
class Group
|
|
7
|
+
include MongoMapper::Document
|
|
8
|
+
plugin MmUsesUuid
|
|
9
|
+
|
|
10
|
+
many :people, :class_name => 'Person'
|
|
11
|
+
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class Person
|
|
15
|
+
include MongoMapper::Document
|
|
16
|
+
plugin MmUsesUuid
|
|
17
|
+
|
|
18
|
+
key :name
|
|
19
|
+
key :age
|
|
20
|
+
|
|
21
|
+
belongs_to :group
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
MongoMapper.connection = Mongo::Connection.new('localhost', 27017)
|
|
25
|
+
MongoMapper.database = 'mm_uses_uuid_test'
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
before(:each) do
|
|
30
|
+
#we have to use a before(:each) to get the stubbing to work :(
|
|
31
|
+
SecureRandom.stub!(:uuid).and_return(
|
|
32
|
+
"11111111-1111-4111-y111-111111111111",
|
|
33
|
+
"22222222-2222-4222-y222-222222222222",
|
|
34
|
+
"11111111-1111-4111-y111-111111111111", #we repeat these so that our safe uuid creation tests will detect a collision and be forced to search
|
|
35
|
+
"11111111-1111-4111-y111-111111111111",
|
|
36
|
+
"11111111-1111-4111-y111-111111111111",
|
|
37
|
+
"33333333-3333-4333-y333-333333333333"
|
|
38
|
+
)
|
|
39
|
+
@group = Group.create
|
|
40
|
+
@person = Person.create(name: 'Jon', age: 33)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "should cause newly initialized objects to have a BSON::Binary uuid" do
|
|
44
|
+
@group._id.should be_an_instance_of(BSON::Binary)
|
|
45
|
+
@group._id.subtype.should == BSON::Binary::SUBTYPE_UUID
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "should have a useful inspect method that shows the uuid string" do
|
|
49
|
+
@group._id.inspect.should == "<BSON::Binary:'#{@group._id.to_s}'>"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "should cause associated objects to reference the parent uuid" do
|
|
53
|
+
@group.people << @person
|
|
54
|
+
@person.group_id.should == @group._id
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "should ensure that the uuid is unique if :ensure_unique_in is set" do
|
|
58
|
+
safe_new_group = Group.new
|
|
59
|
+
safe_new_group.find_new_uuid(:ensure_unique_in => Group)
|
|
60
|
+
safe_new_group._id.to_s.should == "3333333333334333y333333333333333"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context 'finding by uuid' do
|
|
64
|
+
|
|
65
|
+
it "with a BSON::Binary uuid" do
|
|
66
|
+
found_group = Group.find(@group._id)
|
|
67
|
+
found_group._id.should == @group._id
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "with a String uuid" do
|
|
71
|
+
found_group = Group.find(@group._id.to_s)
|
|
72
|
+
found_group._id.should == @group._id
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
after(:each) do
|
|
78
|
+
Group.delete_all; Person.delete_all
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: mm_uses_uuid
|
|
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
|
+
- Jonathan Chambers
|
|
13
|
+
autorequire:
|
|
14
|
+
bindir: bin
|
|
15
|
+
cert_chain: []
|
|
16
|
+
|
|
17
|
+
date: 2011-12-05 00:00:00 +00:00
|
|
18
|
+
default_executable:
|
|
19
|
+
dependencies:
|
|
20
|
+
- !ruby/object:Gem::Dependency
|
|
21
|
+
name: rspec
|
|
22
|
+
prerelease: false
|
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
24
|
+
none: false
|
|
25
|
+
requirements:
|
|
26
|
+
- - ~>
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
segments:
|
|
29
|
+
- 2
|
|
30
|
+
- 7
|
|
31
|
+
version: "2.7"
|
|
32
|
+
type: :development
|
|
33
|
+
version_requirements: *id001
|
|
34
|
+
- !ruby/object:Gem::Dependency
|
|
35
|
+
name: bson_ext
|
|
36
|
+
prerelease: false
|
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
|
38
|
+
none: false
|
|
39
|
+
requirements:
|
|
40
|
+
- - ~>
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
segments:
|
|
43
|
+
- 1
|
|
44
|
+
- 5
|
|
45
|
+
- 0
|
|
46
|
+
version: 1.5.0
|
|
47
|
+
type: :development
|
|
48
|
+
version_requirements: *id002
|
|
49
|
+
- !ruby/object:Gem::Dependency
|
|
50
|
+
name: mongo_mapper
|
|
51
|
+
prerelease: false
|
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
|
53
|
+
none: false
|
|
54
|
+
requirements:
|
|
55
|
+
- - ~>
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
segments:
|
|
58
|
+
- 0
|
|
59
|
+
- 10
|
|
60
|
+
- 1
|
|
61
|
+
version: 0.10.1
|
|
62
|
+
type: :runtime
|
|
63
|
+
version_requirements: *id003
|
|
64
|
+
description: MongoMapper plugin that uses a UUID instead of the default ObjectID
|
|
65
|
+
email:
|
|
66
|
+
- j.chambers@gmx.net
|
|
67
|
+
executables: []
|
|
68
|
+
|
|
69
|
+
extensions: []
|
|
70
|
+
|
|
71
|
+
extra_rdoc_files: []
|
|
72
|
+
|
|
73
|
+
files:
|
|
74
|
+
- .gitignore
|
|
75
|
+
- .project
|
|
76
|
+
- Gemfile
|
|
77
|
+
- MIT-LICENSE
|
|
78
|
+
- README.md
|
|
79
|
+
- Rakefile
|
|
80
|
+
- lib/mm_uses_uuid.rb
|
|
81
|
+
- lib/mm_uses_uuid/bson_binary_mixin.rb
|
|
82
|
+
- lib/mm_uses_uuid/version.rb
|
|
83
|
+
- mm_uses_uuid.gemspec
|
|
84
|
+
- spec/mm_uses_uuid_spec.rb
|
|
85
|
+
has_rdoc: true
|
|
86
|
+
homepage: https://github.com/jmchambers/mm_uses_uuid
|
|
87
|
+
licenses:
|
|
88
|
+
- MIT
|
|
89
|
+
post_install_message:
|
|
90
|
+
rdoc_options: []
|
|
91
|
+
|
|
92
|
+
require_paths:
|
|
93
|
+
- lib
|
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
95
|
+
none: false
|
|
96
|
+
requirements:
|
|
97
|
+
- - ">="
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
segments:
|
|
100
|
+
- 0
|
|
101
|
+
version: "0"
|
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
|
+
none: false
|
|
104
|
+
requirements:
|
|
105
|
+
- - ">="
|
|
106
|
+
- !ruby/object:Gem::Version
|
|
107
|
+
segments:
|
|
108
|
+
- 0
|
|
109
|
+
version: "0"
|
|
110
|
+
requirements: []
|
|
111
|
+
|
|
112
|
+
rubyforge_project:
|
|
113
|
+
rubygems_version: 1.3.7
|
|
114
|
+
signing_key:
|
|
115
|
+
specification_version: 3
|
|
116
|
+
summary: UUIDs for MM
|
|
117
|
+
test_files: []
|
|
118
|
+
|