Class: Constants::ConstantLibrary

Inherits:
Object
  • Object
show all
Defined in:
lib/constants/constant_library.rb

Overview

ConstantLibrary facilitates indexing and collection of a set of values.

lib = ConstantLibrary.new('one', 'two', :three)
lib.index_by('upcase') {|value| value.to_s.upcase }
lib.indicies['upcase']      # => {'ONE' => 'one', 'TWO' => 'two', 'THREE' => :three}

lib.collect("string") {|value| value.to_s }
lib.collections['string']   # => ['one', 'two', 'three']

See Constants::Library for more details.

Defined Under Namespace

Classes: Collection, Index

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*values) ⇒ ConstantLibrary

Returns a new instance of ConstantLibrary.



119
120
121
122
123
# File 'lib/constants/constant_library.rb', line 119

def initialize(*values)
  @values = values.uniq
  @indicies = {}
  @collections = {}
end

Instance Attribute Details

#collectionsObject (readonly)

A hash of (name, collection) pairs tracking the collections in self



117
118
119
# File 'lib/constants/constant_library.rb', line 117

def collections
  @collections
end

#indiciesObject (readonly)

A hash of (name, index) pairs tracking the indicies in self



114
115
116
# File 'lib/constants/constant_library.rb', line 114

def indicies
  @indicies
end

#valuesObject (readonly)

An array of values in the library



111
112
113
# File 'lib/constants/constant_library.rb', line 111

def values
  @values
end

Instance Method Details

#[](key) ⇒ Object

Lookup values by a key. All indicies will be searched in order; the first matching value is returned. Returns nil if no matches are found.



226
227
228
229
230
231
232
# File 'lib/constants/constant_library.rb', line 226

def [](key)
  indicies.values.each do |index|
    return index[key] if index.has_key?(key)
  end

  nil
end

#add(*values) ⇒ Object

Add the specified values to self. New values are incorporated into existing indicies and collections. Returns the values added (ie values minus any already-existing values).



247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/constants/constant_library.rb', line 247

def add(*values)
  new_values = values - self.values
  self.values.concat(new_values)

  [indicies, collections].each do |stashes|
    stashes.values.each do |stash| 
      stash.stash(new_values)
    end
  end

  #new_values.each(&add_block) if add_block
  new_values
end

#add_constants_from(mod) ⇒ Object

Adds the constants from the specified module. If mod is a Class, then only constants that are a kind of mod will be added. This behavior can be altered by providing a block which each constant value; values are only included if the block evaluates to true.



265
266
267
268
269
270
271
272
# File 'lib/constants/constant_library.rb', line 265

def add_constants_from(mod)
  const_names = mod.constants.select do |const_name|
    const = mod.const_get(const_name)
    block_given? ? yield(const) : (mod.kind_of?(Class) ? const.kind_of?(mod) : true)
  end

  add(*const_names.collect {|const_name| mod.const_get(const_name) })
end

#clear(complete = false) ⇒ Object

Clears all values, from self, indicies, and collections. The indicies, and collections themselves are preserved unless complete==true.



236
237
238
239
240
241
242
# File 'lib/constants/constant_library.rb', line 236

def clear(complete=false)
  values.clear
  
  [indicies, collections].each do |stashes|
    complete ? stashes.clear : stashes.values.each {|stash| stash.clear}
  end
end

#collect(name, &block) ⇒ Object

Adds a collection to self for all values currently in self. The block is used to calculate the values in the collection. The block receives each value in self and should return one of the following:

  • a value to be pushed onto the collection

  • a [value, index] array when an alternate value should be stored in the place of value, or when the value should be at a special index in the collection. When multiple values are directed to the same index, they are stashed into an array.

  • nil to exclude the value from the collection

For example:

lib = ConstantLibrary.new('one', 'two', :three)
lib.collect("string") {|value| value.to_s }
lib.collections['string']   # => ['one', 'two', 'three']

lib.collect("length") {|value| [value, value.to_s.length] }
lib.collections['length']   # => [nil, nil, nil, ['one', 'two'], nil, :three]

Works much like index_by, except that the underlying data store for a collection is a Collection (ie an array) rather than an Index (a hash).

Raises:

  • (ArgumentError)


207
208
209
210
211
212
213
# File 'lib/constants/constant_library.rb', line 207

def collect(name, &block) # :yields: value
  raise ArgumentError.new("no block given") unless block_given?
  
  collection = Collection.new(&block)
  collections[name] = collection
  collection.stash(values)
end

#collect_attribute(attribute) ⇒ Object

Adds a collection using the attribute or method. Equivalent to:

lib.collect(attribute) {|value| value.attribute }


219
220
221
222
# File 'lib/constants/constant_library.rb', line 219

def collect_attribute(attribute)
  method = attribute.to_sym
  collect(attribute) {|value| value.send(method) }
end

#index_by(name, exclusion_value = nil, nil_value = nil, &block) ⇒ Object

Adds an index to self for all values currently in self. The block is used to specify keys for each value in self; it receives each value and should return one of the following:

  • a key

  • a [key, value] array when an alternate value should be stored in the place of value

  • the exclusion_value to exclude the value from the index

When multiple values return the same key, they are stashed into an array.

lib = ConstantLibrary.new('one', 'two', :one)
lib.index_by("string") {|value| value.to_s }
lib.indicies['string'] 
# => {
# 'one' => ['one', :one],
# 'two' => 'two'}

Existing indicies by the specified name are overwritten.

nil values

The index stores it’s data in an Index (ie a Hash) where nil_value acts as the default value returned for non-existant keys as well as the stash nil_value. Hence index_by will raise an error if you try to store the nil_value.

This behavior can be seen when the exclusion value is set to something other than nil, so that the nil value isn’t skipped outright:

# the nil will cause trouble
lib = ConstantLibrary.new(1,2,nil)
lib.index_by("error", false, nil) {|value| value }  # ! ArgumentError

Specify an alternate nil_value (and exclusion value) to index nils; a plain old Object works well.

obj = Object.new
index = lib.index_by("ok", false, obj) {|value| value }
index[1]                 # => 1
index[nil]               # => nil

# remember the nil_value is the default value
index['non-existant']    # => obj

Raises:

  • (ArgumentError)


169
170
171
172
173
174
175
# File 'lib/constants/constant_library.rb', line 169

def index_by(name, exclusion_value=nil, nil_value=nil, &block) # :yields: value
  raise ArgumentError.new("no block given") unless block_given?
  
  index = Index.new(exclusion_value, nil_value, &block)
  indicies[name] = index
  index.stash(values)
end

#index_by_attribute(attribute, exclusion_value = nil, nil_value = nil) ⇒ Object

Adds an index using the attribute or method. Equivalent to:

lib.index_by(attribute) {|value| value.attribute }


181
182
183
184
# File 'lib/constants/constant_library.rb', line 181

def index_by_attribute(attribute, exclusion_value=nil, nil_value=nil)
  method = attribute.to_sym
  index_by(attribute, exclusion_value, nil_value) {|value| value.send(method) }
end