Class: Attributor::SmartAttributeSelector

Inherits:
Object
  • Object
show all
Defined in:
lib/attributor/smart_attribute_selector.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(reqs, attributes, values) ⇒ SmartAttributeSelector

Returns a new instance of SmartAttributeSelector.



6
7
8
9
10
11
12
# File 'lib/attributor/smart_attribute_selector.rb', line 6

def initialize( reqs , attributes, values)
  @reqs = reqs.dup
  @accepted = []
  @banned = []
  @remaining = attributes.dup
  @keys_with_values = values.each_with_object([]){|(k,v),populated| populated.push(k) unless v == nil}
end

Instance Attribute Details

#acceptedObject

Returns the value of attribute accepted.



3
4
5
# File 'lib/attributor/smart_attribute_selector.rb', line 3

def accepted
  @accepted
end

#bannedObject

Returns the value of attribute banned.



3
4
5
# File 'lib/attributor/smart_attribute_selector.rb', line 3

def banned
  @banned
end

#keys_with_valuesObject (readonly)

Returns the value of attribute keys_with_values.



4
5
6
# File 'lib/attributor/smart_attribute_selector.rb', line 4

def keys_with_values
  @keys_with_values
end

#remainingObject

Returns the value of attribute remaining.



3
4
5
# File 'lib/attributor/smart_attribute_selector.rb', line 3

def remaining
  @remaining
end

#reqsObject

Returns the value of attribute reqs.



3
4
5
# File 'lib/attributor/smart_attribute_selector.rb', line 3

def reqs
  @reqs
end

Instance Method Details

#processObject



14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/attributor/smart_attribute_selector.rb', line 14

def process
  process_required
  process_exclusive
  process_exactly
  process_at_least
  process_at_most
  # Just add the ones that haven't been explicitly rejected
  self.accepted += self.remaining
  self.remaining = []
  self.accepted.uniq!
  self.accepted
end

#process_at_leastObject



50
51
52
53
54
55
56
57
58
# File 'lib/attributor/smart_attribute_selector.rb', line 50

def process_at_least
  self.reqs = reqs.each_with_object([]) do |req, rest|
    if req[:type] == :at_least
      process_at_least_set(Array.new(req[:attributes]), req[:count])
    else
      rest.push req
    end
  end
end

#process_at_least_set(at_least_set, count) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/attributor/smart_attribute_selector.rb', line 97

def process_at_least_set( at_least_set, count)
  feasible = at_least_set - banned # available ones to pick (that are not banned)
  preferred = (feasible & keys_with_values)[0,count]
  # Add more if not enough
  pick = if preferred.size < count
    preferred + (feasible - preferred)[0,count-preferred.size]
  else
    preferred
  end

  unless pick.size == count
    raise UnfeasibleRequirementsError
  end
  self.accepted += pick
  self.remaining -= pick
end

#process_at_mostObject



60
61
62
63
64
65
66
67
68
# File 'lib/attributor/smart_attribute_selector.rb', line 60

def process_at_most
 self.reqs = reqs.each_with_object([]) do |req, rest|
   if req[:type] == :at_most && req[:count] > 1 # count=1 is already handled in exclusive
     process_at_most_set(Array.new(req[:attributes]), req[:count])
   else
     rest.push req
   end
 end
end

#process_at_most_set(set, count) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/attributor/smart_attribute_selector.rb', line 114

def process_at_most_set( set, count)
  ceil=(count+1)/2
  feasible = set - banned # available ones to pick (that are not banned)
  preferred = (feasible & keys_with_values)[0,ceil]

  pick = if preferred.size < ceil
    preferred + (feasible - preferred)[0,(ceil)-preferred.size]
  else
    preferred
  end

  self.accepted += pick
  self.remaining -= pick
end

#process_exactlyObject



70
71
72
73
74
75
76
77
78
# File 'lib/attributor/smart_attribute_selector.rb', line 70

def process_exactly
 self.reqs = reqs.each_with_object([]) do |req, rest|
   if req[:type] == :exactly && req[:count] > 1 # count=1 is already handled in exclusive
     process_exactly_set(Array.new(req[:attributes]), req[:count])
   else
     rest.push req
   end
 end
end

#process_exactly_set(set, count) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/attributor/smart_attribute_selector.rb', line 129

def process_exactly_set( set, count)
  feasible = set - banned # available ones to pick (that are not banned)
  preferred = (feasible & keys_with_values)[0,count]

  pick = if preferred.size < count
    preferred + (feasible - preferred)[0,count-preferred.size]
  else
    preferred
  end

  unless pick.size == count
    raise UnfeasibleRequirementsError
  end

  self.accepted += pick
  self.remaining -= pick
end

#process_exclusiveObject



38
39
40
41
42
43
44
45
46
47
48
# File 'lib/attributor/smart_attribute_selector.rb', line 38

def process_exclusive
  self.reqs = reqs.each_with_object([]) do |req, rest|
    if req[:type] == :exclusive ||
      (req[:type] == :exactly && req[:count] == 1 ) ||
      (req[:type] == :at_most && req[:count] == 1 )
      process_exclusive_set(Array.new(req[:attributes]))
    else
      rest.push req
    end
  end
end

#process_exclusive_set(exclusive_set) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/attributor/smart_attribute_selector.rb', line 82

def process_exclusive_set( exclusive_set )
  feasible = exclusive_set - banned # available ones to pick (that are not banned)
  # Try to favor attributes that come in with some values, otherwise get the first feasible one
  preferred = feasible & keys_with_values
  pick = (preferred.size == 0 ? feasible : preferred).first

  if pick
    self.accepted.push( pick )
  else
    raise UnfeasibleRequirementsError unless exclusive_set.empty?
  end
  self.banned += (feasible - [pick])
  self.remaining -= exclusive_set
end

#process_requiredObject



27
28
29
30
31
32
33
34
35
36
# File 'lib/attributor/smart_attribute_selector.rb', line 27

def process_required
  self.reqs = reqs.each_with_object([]) do |req, rest|
    if req[:type] == :all
      self.accepted += req[:attributes]
      self.remaining -= req[:attributes]
    else
      rest.push req
    end
  end
end