Class: Splashy::Buckets

Inherits:
Object
  • Object
show all
Defined in:
lib/splashy/buckets.rb

Instance Method Summary collapse

Constructor Details

#initialize(wanted_distribution, wanted_count = nil) ⇒ Buckets

wanted_distribution - A Hash of desired distributions:

{ :a => 0.2, :b => 0.5, :c => 0.3 }

wanted_count - (optional) Maximum total elements to be selected.

otherwise, the maximum size set is selected.


7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/splashy/buckets.rb', line 7

def initialize( wanted_distribution, wanted_count=nil )
  unless wanted_distribution.values.inject(0){ |m,v| m + v } == 1.0
    raise ArgumentError.new( "Distribution must sum to 1.0" )
  end
  @wanted_distribution = wanted_distribution
  @wanted_count = wanted_count
  @buckets = {}
  @wanted_distribution.keys.each do |bucket_name|
    @buckets[bucket_name] = Bucket.new( bucket_name )
  end
  @total_count = 0
end

Instance Method Details

#add(bucket_name, element) ⇒ Object

Public: Add a single element to a bucket.



45
46
47
48
49
50
51
# File 'lib/splashy/buckets.rb', line 45

def add( bucket_name, element )
  unless @wanted_distribution[bucket_name]
    raise ArgumentError.new( "#{bucket_name.inspect} is not a valid bucket." )
  end
  @buckets[bucket_name] << element
  @total_count += 1
end

#fill(bucket_name = nil, &block) ⇒ Object

Public: Put elements into buckets with a block.

bucket_name - If supplied, all yielded elements will be added to that

bucket.

&block - A block that returns (if ‘bucket_name` is not supplied) an

Array: [bucket_name, element]. If `bucket_name` is supplied, only
the element needs to be returned.

Examples

fill { return [bucket_name, element] }
fill( :bucket_name ) { return element }


32
33
34
35
36
37
38
39
40
41
42
# File 'lib/splashy/buckets.rb', line 32

def fill( bucket_name = nil, &block )
  if bucket_name
    while element = yield( @total_count )
      self.add( bucket_name, element )
    end
  else
    while pair = yield( @total_count )
      self.add( *pair )
    end
  end
end

#neediest_bucketsObject

Array of the buckets that need more elements to match the desired distribution, sorted descending by how much more they need.



85
86
87
88
89
# File 'lib/splashy/buckets.rb', line 85

def neediest_buckets
  multipliers = self.needed_multipliers( self._select_all, @wanted_distribution ).to_a
  multipliers.sort! { |a, b| b[1] <=> a[1] } # Sort on multiplier descending
  multipliers.map{ |bucket_name, multiplier| bucket_name }
end

#satisfied?Boolean

Public

Returns true if the conditions (distribution and, optionally, count) are satisfied enough to do a final selection of elements.

Returns:

  • (Boolean)


57
58
59
60
61
62
63
64
# File 'lib/splashy/buckets.rb', line 57

def satisfied?
  begin
    self.assert_satisfied!
    true
  rescue DistributionUnsatisfiedError => e
    false
  end
end

#select(opts = {}) ⇒ Object

Public: Return a distribution of elements based on the desired distribution. If a satisfactory distribution is not possible, a DistributionUnsatisfiedError is raised.

Returns a Hash of elements matching the desired distribution, keyed by the bucket names.



72
73
74
75
76
77
78
79
80
81
# File 'lib/splashy/buckets.rb', line 72

def select( opts = {} )
  self.assert_satisfied!
  opts = { :random => false }.merge( opts )
  
  selected = self._select_wanted( opts[:random] )
  
  # Sometimes we need to fudge by a few to meet the `@wanted_count`
  selected = self.trim( selected, @wanted_count ) if @wanted_count
  selected
end