module ConstantRecord::DataLoading

Loads data either directly in the model class, or from a YAML file.

Public Instance Methods

data(attrib, reload=false) click to toggle source

Define a constant record: data id: 1, name: “California”, slug: “CA”

# File lib/constant_record.rb, line 76
def data(attrib, reload=false)
  raise ArgumentError, "#{self}.data expects a Hash of attributes" unless attrib.is_a?(Hash)
  attrib.symbolize_keys!

  unless attrib[primary_key.to_sym]
    raise ArgumentError, "#{self}.data missing primary key '#{primary_key}': #{attrib.inspect}"
  end

  # Save data definitions for reload on connection change
  @data_rows ||= []

  # Check for duplicates
  unless reload
    if old_record = @data_rows.detect{|r| r[primary_key.to_sym] == attrib[primary_key.to_sym] }
      raise ActiveRecord::RecordNotUnique,
        "Duplicate #{self} id=#{attrib[primary_key.to_sym]} found: #{attrib} vs #{old_record}"
    end
    @data_rows << attrib
  end

  # Create table dynamically based on first row of data
  create_memory_table(attrib) unless connection.table_exists?(table_name)

  # Save to in-memory table
  new_record = new(attrib)
  new_record.id = attrib[primary_key.to_sym]
  new_record.save!

  # Create Ruby constants as well, so "id: 3, name: Sky" generates SKY=3
  if new_record.respond_to?(:name) and name = new_record.name
    const_name =
      name.to_s.upcase.strip.gsub(/[-\s]+/,'_').sub(/^[0-9_]+/,'').gsub(/\W+/,'')
    const_set const_name, new_record.id unless const_defined?(const_name)
  end
end
data_file() click to toggle source
# File lib/constant_record.rb, line 43
def data_file
  @data_file || File.join(ConstantRecord.data_dir, "#{self.to_s.tableize}.yml")
end
load(reload=false) click to toggle source
# File lib/constant_record.rb, line 52
def load(reload=false)
  return if loaded? && !reload
  records = YAML.load_file(data_file)

  if !records.is_a?(Array) or records.empty?
    raise BadDataFile, "Expected array in data file #{data_file}: #{records.inspect}"
  end

  # Call our method to populate data
  @data_rows = []
  records.each{|r| data r}

  @loaded = true
end
load_data(file=nil) click to toggle source
# File lib/constant_record.rb, line 47
def load_data(file=nil)
  @data_file = file
  reload!
end
loaded?() click to toggle source
# File lib/constant_record.rb, line 71
def loaded?
  @loaded || false
end
reload!() click to toggle source
# File lib/constant_record.rb, line 67
def reload!
  load(true)
end

Protected Instance Methods

create_memory_table(attrib) click to toggle source

Create our in-memory table based on columns we have defined in our data.

# File lib/constant_record.rb, line 115
def create_memory_table(attrib)
  db_columns = {}
  attrib.each do |col,val|
    next if col.to_s == 'id' # skip pk
    db_columns[col] =
      case val
      when Integer then :integer
      when Float   then :decimal
      when Date    then :date
      when DateTime, Time then :datetime
      else :string
      end
  end

  # Create the table in memory
  connection.create_table(table_name) do |t|
    db_columns.each do |col,type|
      t.column col, type
    end
  end
end
reload_memory_table() click to toggle source

Reloads the table when the connection has changed

# File lib/constant_record.rb, line 138
def reload_memory_table
  return false unless @data_rows
  @data_rows.each{|r| data r, true}
end