mongoid_token_r 4.0.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.
- 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
|
+
[](http://travis-ci.org/thetron/mongoid_token)
|
4
|
+
[](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
|