Skip to content

Commit

Permalink
Add method for ensuring unique values (#752)
Browse files Browse the repository at this point in the history
Add a method to Faker::Base that wraps the existing class and ensures
that the responses are unique.
  • Loading branch information
jonmast authored and stympy committed Dec 17, 2016
1 parent aecadb8 commit 0d64f88
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 1 deletion.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ development.

### NOTE

* While Faker generates data at random, returned values are not guaranteed to be unique.
* While Faker generates data at random, returned values are not guaranteed to be unique by default.
You must explicity specify when you require unique values, see [details](#ensuring-unique-values).
* This is the `master` branch of Faker and may contain changes that are not yet released.
Please refer the README of your version for the available methods.
List of all versions is [available here](https://github.com/stympy/faker/releases).
Expand Down Expand Up @@ -79,6 +80,12 @@ Faker::Name.name #=> "Christophe Bartell"
Faker::Internet.email #=> "kirsten.greenholt@corkeryfisher.info"
```

####Ensuring unique values
Prefix your method call with `unique`. For example:
```ruby
Faker::Name.unique.name # This will return a unique name every time it is called
```

### Faker::Address
-----------------

Expand Down
5 changes: 5 additions & 0 deletions lib/faker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ def rand_in_range(from, to)
from, to = to, from if to < from
Random.new.rand(from..to)
end

def unique(max_retries = 10_000)
@unique_generator ||= UniqueGenerator.new(self, max_retries)
end
end
end
end
Expand Down Expand Up @@ -239,3 +243,4 @@ def rand_in_range(from, to)
require 'extensions/symbol'

require 'helpers/char'
require 'helpers/unique_generator'
24 changes: 24 additions & 0 deletions lib/helpers/unique_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module Faker
class UniqueGenerator
def initialize(generator, max_retries)
@generator = generator
@max_retries = max_retries
@previous_results = Hash.new { |hash, key| hash[key] = Set.new }
end

def method_missing(name, *arguments)
@max_retries.times do
result = @generator.public_send(name, *arguments)

next if @previous_results[[name, arguments]].include?(result)

@previous_results[[name, arguments]] << result
return result
end

raise RetryLimitExceeded
end

RetryLimitExceeded = Class.new(StandardError)
end
end
8 changes: 8 additions & 0 deletions test/test_faker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,12 @@ def test_regexify
end
end

def test_unique
unique_numbers = 8.times.map do
Faker::Base.unique.numerify('#')
end

assert_equal(unique_numbers.uniq, unique_numbers)
end

end
27 changes: 27 additions & 0 deletions test/test_faker_unique_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
require File.expand_path(File.dirname(__FILE__) + '/test_helper.rb')

class TestFakerUniqueGenerator < Test::Unit::TestCase

def test_generates_unique_values
generator = Faker::UniqueGenerator.new(Faker::Base, 10_000)

result = [generator.rand_in_range(1, 2), generator.rand_in_range(1, 2)]
assert_equal([1, 2], result.sort)
end

def test_returns_error_when_retries_exceeded
stubbed_generator = Object.new
def stubbed_generator.test
1
end

generator = Faker::UniqueGenerator.new(stubbed_generator, 3)

generator.test

assert_raises Faker::UniqueGenerator::RetryLimitExceeded do
generator.test
end
end

end

0 comments on commit 0d64f88

Please sign in to comment.