mongoid_token_r 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.autotest +0 -0
- data/.gitignore +5 -0
- data/.rspec +1 -0
- data/.travis.yml +18 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +242 -0
- data/Rakefile +2 -0
- data/benchmarks/benchmark.rb +49 -0
- data/lib/mongoid/token.rb +81 -0
- data/lib/mongoid/token/collision_resolver.rb +37 -0
- data/lib/mongoid/token/collisions.rb +33 -0
- data/lib/mongoid/token/exceptions.rb +16 -0
- data/lib/mongoid/token/finders.rb +15 -0
- data/lib/mongoid/token/generator.rb +80 -0
- data/lib/mongoid/token/options.rb +78 -0
- data/lib/mongoid_token.rb +1 -0
- data/lib/version.rb +3 -0
- data/mongoid_token.gemspec +23 -0
- data/spec/mongoid/token/collisions_spec.rb +101 -0
- data/spec/mongoid/token/exceptions_spec.rb +4 -0
- data/spec/mongoid/token/finders_spec.rb +30 -0
- data/spec/mongoid/token/generator_spec.rb +57 -0
- data/spec/mongoid/token/options_spec.rb +102 -0
- data/spec/mongoid/token_spec.rb +287 -0
- data/spec/spec_helper.rb +29 -0
- metadata +92 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f6d694b67ef23128e4d6dc9d2eb5f9392e1a9843
|
4
|
+
data.tar.gz: 17ed3109121d5e9d64228409a87452ffe7d4c717
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 01575418d36384691b95b59325bdebc7a4e1fe2491d94c145cc04e9b6007d833ddbe5da50af294737d18da232e63301e3ca17d2515188c4e177d09726336fda7
|
7
|
+
data.tar.gz: e642f422be0838e003b05d212e23f26bd00a627787eeaef95d8cf25f9ddf322859111ec5b20202b581d252a9ed9e7a3322e2b1f6a2d89c5a27476b0221b21f8d
|
data/.autotest
ADDED
File without changes
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
language: ruby
|
2
|
+
|
3
|
+
rvm:
|
4
|
+
- 1.9.3
|
5
|
+
- 2.0.0
|
6
|
+
- 2.1.0
|
7
|
+
- 2.1.1
|
8
|
+
|
9
|
+
gemfile:
|
10
|
+
- Gemfile
|
11
|
+
|
12
|
+
services:
|
13
|
+
- mongodb
|
14
|
+
|
15
|
+
env:
|
16
|
+
- CODECLIMATE_REPO_TOKEN=b216164ab66da464aa02fe5b862811ba0526c8dc7ea291ebe53056be4b6b5e1f
|
17
|
+
|
18
|
+
script: "bundle exec rspec"
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Nicholas Bruning
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,242 @@
|
|
1
|
+
# Mongoid::Token - Short snappy tokens for Mongoid documents
|
2
|
+
|
3
|
+
[![Build Status](https://secure.travis-ci.org/thetron/mongoid_token.png)](http://travis-ci.org/thetron/mongoid_token)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/thetron/mongoid_token.png)](https://codeclimate.com/github/thetron/mongoid_token)
|
5
|
+
|
6
|
+
This library is a quick and simple way to generate unique, random tokens
|
7
|
+
for your mongoid documents, in the cases where you can't, or don't want
|
8
|
+
to use slugs, or the default MongoDB ObjectIDs.
|
9
|
+
|
10
|
+
Mongoid::Token can help turn this:
|
11
|
+
|
12
|
+
http://bestappever.com/video/4dcfbb3c6a4f1d4c4a000012
|
13
|
+
|
14
|
+
Into something more like this:
|
15
|
+
|
16
|
+
http://bestappever.com/video/8tmQ9p
|
17
|
+
|
18
|
+
|
19
|
+
## Getting started
|
20
|
+
|
21
|
+
In your gemfile, add:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
# For mongoid < 5
|
25
|
+
gem 'mongoid_token', '~> 3.0.0'
|
26
|
+
|
27
|
+
# For mongoid >= 5
|
28
|
+
gem 'mongoid_token', '~> 4.0.0'
|
29
|
+
```
|
30
|
+
|
31
|
+
Then update your bundle
|
32
|
+
|
33
|
+
$ bundle install
|
34
|
+
|
35
|
+
In your Mongoid documents, just add `include Mongoid::Token` and the
|
36
|
+
`token` method will take care of all the setup, like so:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
class Person
|
40
|
+
include Mongoid::Document
|
41
|
+
include Mongoid::Token
|
42
|
+
|
43
|
+
field :name
|
44
|
+
|
45
|
+
token
|
46
|
+
end
|
47
|
+
|
48
|
+
```
|
49
|
+
|
50
|
+
And that's it! There's lots of configuration options too - which are all
|
51
|
+
listed [below](#configuration). By default, the `token` method will
|
52
|
+
create tokens 4 characters long, containing random alphanumeric characters.
|
53
|
+
|
54
|
+
__Note:__ Mongoid::Token leverages Mongoid's 'safe mode' by
|
55
|
+
automatically creating a unique index on your documents using the token
|
56
|
+
field. In order to take advantage of this feature (and ensure that your
|
57
|
+
documents always have unique tokens) remember to create your indexes.
|
58
|
+
|
59
|
+
## Using without Rails
|
60
|
+
|
61
|
+
If you're using Mongoid without Rails, remember to:
|
62
|
+
|
63
|
+
require 'mongoid_token'
|
64
|
+
|
65
|
+
in your app
|
66
|
+
|
67
|
+
## Finders
|
68
|
+
|
69
|
+
By default, the gem will add a convenience `find_by_[token name]` method, to
|
70
|
+
make it a tiny bit simpler to query by your tokens. If you'd rather it didn't,
|
71
|
+
you can disable these with the
|
72
|
+
[`skip_finders` configuration option](#skip-finders-skip_finders).
|
73
|
+
|
74
|
+
The methods accept either a single token, or an array of tokens:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
Video.find_by_token("x3v98") # If your token was named 'token'
|
78
|
+
Account.find_by_account_number(["ACC-123456", "ACC-567890"]) # If your token was named 'account_number'
|
79
|
+
```
|
80
|
+
|
81
|
+
## Configuration
|
82
|
+
|
83
|
+
### Tokens
|
84
|
+
|
85
|
+
As of `Mongoid::Token` 2.0.0, you can now choose between two different
|
86
|
+
systems for managing how your tokens look.
|
87
|
+
|
88
|
+
For simple setup, you can use
|
89
|
+
combination of the [`length`](#length-length) and [`contains`](#contains-contains), which modify the length and
|
90
|
+
types of characters to use.
|
91
|
+
|
92
|
+
For when you need to generate more complex tokens, you can use the
|
93
|
+
[`pattern`](#patterns-pattern) option, which allows for very low-level control of the precise
|
94
|
+
structure of your tokens, as well as allowing for static strings, like
|
95
|
+
prefixes, infixes or suffixes.
|
96
|
+
|
97
|
+
#### Length (`:length`)
|
98
|
+
|
99
|
+
This one is easy, it's just an integer.
|
100
|
+
|
101
|
+
__Example:__
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
token :length => 6 # Tokens are now of length 6
|
105
|
+
token :length => 12 # Whow, whow, whow. Slow down egghead.
|
106
|
+
```
|
107
|
+
|
108
|
+
You get the idea.
|
109
|
+
|
110
|
+
The only caveat here is that if used in combination with the
|
111
|
+
`:contains => :numeric` option, tokens may vary in length _up to_ the
|
112
|
+
specified length.
|
113
|
+
|
114
|
+
#### Contains (`:contains`)
|
115
|
+
|
116
|
+
Contains has 7 different options:
|
117
|
+
|
118
|
+
* `:alphanumeric` - contains uppercase & lowercase characters, as well
|
119
|
+
as numbers
|
120
|
+
* `:alpha` - contains only uppercase & lowercase characters
|
121
|
+
* `:alpha_upper` - contains only uppercase letters
|
122
|
+
* `:alpha_lower` - contains only lowercase letters
|
123
|
+
* `:numeric` - integer, length may be shorter than `:length`
|
124
|
+
* `:fixed_numeric` - integer, but will always be of length `:length`
|
125
|
+
* `:fixed_numeric_no_leading_zeros` - same as `:fixed_numeric`, but will
|
126
|
+
never start with zeros
|
127
|
+
* `:fixed_hex_numeric` - hex integer, but will always be of length `:length`
|
128
|
+
* `:fixed_hex_numeric_no_leading_zeros` - same as `:fixed_hex_numeric`, but will
|
129
|
+
never start with zeros
|
130
|
+
|
131
|
+
__Examples:__
|
132
|
+
```ruby
|
133
|
+
token :contains => :alpha_upper, :length => 8
|
134
|
+
token :contains => :fixed_numeric
|
135
|
+
```
|
136
|
+
|
137
|
+
#### Patterns (`:pattern`)
|
138
|
+
|
139
|
+
New in 2.0.0, patterns allow you fine-grained control over how your
|
140
|
+
tokens look. It's great for generating random data that has a
|
141
|
+
requirements to also have some basic structure. If you use the
|
142
|
+
`:pattern` option, it will override both the `:length` and `:contains`
|
143
|
+
options.
|
144
|
+
|
145
|
+
This was designed to operate in a similar way to something like `strftime`,
|
146
|
+
if the syntax offends you - please open an issue, I'd love to get some
|
147
|
+
feedback here and better refine how these are generated.
|
148
|
+
|
149
|
+
Any characters in the string are treated as static, except those that are
|
150
|
+
proceeded by a `%`. Those special characters represent a single, randomly
|
151
|
+
generated character, and are as follows:
|
152
|
+
|
153
|
+
* `%s` - any uppercase, lowercase, or numeric character
|
154
|
+
* `%w` - any uppercase, or lowercase character
|
155
|
+
* `%c` - any lowercase character
|
156
|
+
* `%C` - any uppercase character
|
157
|
+
* `%d` - any digit
|
158
|
+
* `%D` - any non-zero digit
|
159
|
+
|
160
|
+
__Example:__
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
token :pattern => "PRE-%C%C-%d%d%d%d" # Generates something like: 'PRE-ND-3485'
|
164
|
+
```
|
165
|
+
|
166
|
+
You can also add a repetition modifier, which can help improve readability on
|
167
|
+
more complex patterns. You simply add any integer after the letter.
|
168
|
+
|
169
|
+
__Examples:__
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
token :pattern => "APP-%d6" # Generates something like; "APP-638924"
|
173
|
+
```
|
174
|
+
|
175
|
+
### Field Name (`:field_name`)
|
176
|
+
|
177
|
+
This allows you to change the field name used by `Mongoid::Token`
|
178
|
+
(default is `:token`). This is particularly handy when you're wanting to
|
179
|
+
use multiple tokens one a single document.
|
180
|
+
|
181
|
+
__Examples:__
|
182
|
+
```ruby
|
183
|
+
token :length => 6
|
184
|
+
token :field_name => :sharing_token, :length => 12
|
185
|
+
token :field_name => :yet_another
|
186
|
+
```
|
187
|
+
|
188
|
+
|
189
|
+
### Skip Finders (`:skip_finders`)
|
190
|
+
|
191
|
+
This will prevent the gem from creating the extra `find_by_*` methods.
|
192
|
+
|
193
|
+
__Example:__
|
194
|
+
```ruby
|
195
|
+
token :skip_finders => true
|
196
|
+
```
|
197
|
+
|
198
|
+
|
199
|
+
### Override to_param (`:override_to_param`)
|
200
|
+
|
201
|
+
By default, `Mongoid::Token` will override to_param, to make it an easy
|
202
|
+
drop-in replacement for the default ObjectIDs. If needed, you can turn
|
203
|
+
this behaviour off:
|
204
|
+
|
205
|
+
__Example:__
|
206
|
+
```ruby
|
207
|
+
token :override_to_param => false
|
208
|
+
```
|
209
|
+
|
210
|
+
|
211
|
+
### Retry Count (`:retry_count`)
|
212
|
+
|
213
|
+
In the event of a token collision, this gem will attempt to try three
|
214
|
+
more times before raising a `Mongoid::Token::CollisionRetriesExceeded`
|
215
|
+
error. If you're wanting it to try harder, or less hard, then this
|
216
|
+
option is for you.
|
217
|
+
|
218
|
+
__Examples:__
|
219
|
+
```ruby
|
220
|
+
token :retry_count => 9
|
221
|
+
token :retry_count => 0
|
222
|
+
```
|
223
|
+
|
224
|
+
# Notes
|
225
|
+
|
226
|
+
If you find a problem, please [submit an issue](http://github.com/thetron/mongoid_token/issues) (and a failing test, if
|
227
|
+
you can). Pull requests and feature requests are always welcome and
|
228
|
+
greatly appreciated.
|
229
|
+
|
230
|
+
Thanks to everyone that has contributed to this gem over the past year.
|
231
|
+
Many, many thanks - you guys rawk.
|
232
|
+
|
233
|
+
|
234
|
+
## Contributors:
|
235
|
+
|
236
|
+
Thanks to everyone who has provided support for this gem over the years.
|
237
|
+
In particular: [olliem](https://github.com/olliem),
|
238
|
+
[msolli](https://github.com/msolli),
|
239
|
+
[siong1987](https://github.com/siong1987),
|
240
|
+
[stephan778](https://github.com/stephan778),
|
241
|
+
[eagleas](https://github.com/eagleas), and
|
242
|
+
[jamesotron](https://github.com/jamesotron).
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
$: << File.expand_path("../../lib", __FILE__)
|
2
|
+
|
3
|
+
require 'database_cleaner'
|
4
|
+
require 'mongoid'
|
5
|
+
require 'mongoid_token'
|
6
|
+
require 'benchmark'
|
7
|
+
|
8
|
+
Mongoid.configure do |config|
|
9
|
+
config.connect_to("mongoid_token_benchmark")
|
10
|
+
end
|
11
|
+
|
12
|
+
DatabaseCleaner.strategy = :truncation
|
13
|
+
|
14
|
+
# start benchmarks
|
15
|
+
|
16
|
+
TOKEN_LENGTH = 8
|
17
|
+
|
18
|
+
class Link
|
19
|
+
include Mongoid::Document
|
20
|
+
include Mongoid::Token
|
21
|
+
field :url
|
22
|
+
token :length => TOKEN_LENGTH, :contains => :alphanumeric
|
23
|
+
end
|
24
|
+
|
25
|
+
class NoTokenLink
|
26
|
+
include Mongoid::Document
|
27
|
+
field :url
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_link(token = true)
|
31
|
+
if token
|
32
|
+
Link.create(:url => "http://involved.com.au")
|
33
|
+
else
|
34
|
+
NoTokenLink.create(:url => "http://involved.com.au")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Link.destroy_all
|
39
|
+
Link.create_indexes
|
40
|
+
num_records = [1, 50, 100, 1000, 2000, 3000, 4000]
|
41
|
+
puts "-- Alphanumeric token of length #{TOKEN_LENGTH} (#{62**TOKEN_LENGTH} possible tokens)"
|
42
|
+
Benchmark.bm do |b|
|
43
|
+
num_records.each do |qty|
|
44
|
+
b.report("#{qty.to_s.rjust(5, " ")} records "){ qty.times{ create_link(false) } }
|
45
|
+
b.report("#{qty.to_s.rjust(5, " ")} records tok"){ qty.times{ create_link } }
|
46
|
+
Link.destroy_all
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'mongoid/token/exceptions'
|
2
|
+
require 'mongoid/token/options'
|
3
|
+
require 'mongoid/token/generator'
|
4
|
+
require 'mongoid/token/finders'
|
5
|
+
require 'mongoid/token/collision_resolver'
|
6
|
+
|
7
|
+
module Mongoid
|
8
|
+
module Token
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def initialize_copy(source)
|
13
|
+
super(source)
|
14
|
+
self.token = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def token(*args)
|
18
|
+
options = Mongoid::Token::Options.new(args.extract_options!)
|
19
|
+
|
20
|
+
add_token_field_and_index(options)
|
21
|
+
add_token_collision_resolver(options)
|
22
|
+
set_token_callbacks(options)
|
23
|
+
|
24
|
+
define_custom_finders(options) if options.skip_finders? == false
|
25
|
+
override_to_param(options) if options.override_to_param?
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def add_token_field_and_index(options)
|
30
|
+
self.field options.field_name, :type => String, :default => default_value(options)
|
31
|
+
self.index({ options.field_name => 1 }, { :unique => true, :sparse => true })
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_token_collision_resolver(options)
|
35
|
+
resolver = Mongoid::Token::CollisionResolver.new(self, options.field_name, options.retry_count)
|
36
|
+
resolver.create_new_token = Proc.new do |document|
|
37
|
+
document.send(:create_token, options.field_name, options.pattern)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def define_custom_finders(options)
|
42
|
+
Finders.define_custom_token_finder_for(self, options.field_name)
|
43
|
+
end
|
44
|
+
|
45
|
+
def set_token_callbacks(options)
|
46
|
+
set_callback(:create, :before) do |document|
|
47
|
+
document.create_token_if_nil options.field_name, options.pattern
|
48
|
+
end
|
49
|
+
|
50
|
+
set_callback(:save, :before) do |document|
|
51
|
+
document.create_token_if_nil options.field_name, options.pattern
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def override_to_param(options)
|
56
|
+
self.send(:define_method, :to_param) do
|
57
|
+
self.send(options.field_name) || super()
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def default_value(options)
|
62
|
+
options.generate_on_init && Mongoid::Token::Generator.generate(options.pattern) || nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
def create_token(field_name, pattern)
|
68
|
+
self.send :"#{field_name.to_s}=", self.generate_token(pattern)
|
69
|
+
end
|
70
|
+
|
71
|
+
def create_token_if_nil(field_name, pattern)
|
72
|
+
if self[field_name.to_sym].blank?
|
73
|
+
self.create_token field_name, pattern
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def generate_token(pattern)
|
78
|
+
Mongoid::Token::Generator.generate pattern
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|