Module: DataMapper::Sweatshop::Unique

Included in:
DataMapper::Sweatshop
Defined in:
lib/dm-sweatshop/unique.rb

Defined Under Namespace

Classes: TooManyTriesException

Instance Method Summary collapse

Instance Method Details

#unique(key = nil, &block) ⇒ Object

Yields a value to the block. The value is unique for each invocation with the same block. Alternatively, you may provide an explicit key to identify the block.

If a block with no parameter is supplied, unique keeps track of previous invocations, and will continue yielding until a unique value is generated. If a unique value is not generated after @UniqueWorker::MAX_TRIES@, an exception is raised.

ParseTree is required unless an explicit key is provided

(1..3).collect { unique {|x| x }}     # => [0, 1, 2]
(1..3).collect { unique {|x| x + 1 }} # => [1, 2, 3]
(1..3).collect { unique {|x| x }}     # => [3, 4, 5] # Continued on from above
(1..3).collect { unique(:a) {|x| x }} # => [0, 1, 2] # Explicit key overrides block identity

a = [1, 1, 1, 2, 2, 3]
(1..3).collect { unique { a.shift }}  # => [1, 2, 3]
(1..3).collect { unique { 1 }}        # raises TooManyTriesException

return <Object> the return value of the block



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/dm-sweatshop/unique.rb', line 27

def unique(key = nil, &block)
  if block.arity < 1
    UniqueWorker.unique_map ||= {}

    key ||= UniqueWorker.key_for(&block)
    set = UniqueWorker.unique_map[key] || Set.new
    result = block[]
    tries = 0
    while set.include?(result)
      result = block[]
      tries += 1

      raise TooManyTriesException.new("Could not generate unique value after #{tries} attempts") if tries >= UniqueWorker::MAX_TRIES
    end
    set << result
    UniqueWorker.unique_map[key] = set
  else
    UniqueWorker.count_map ||= Hash.new() { 0 }

    key ||= UniqueWorker.key_for(&block)
    result = block[UniqueWorker.count_map[key]]
    UniqueWorker.count_map[key] += 1
  end

  result
end