class TableSetter::Table

Attributes

data[R]

The Table class handles processing the yaml processing and csv loading, through table fu

facets[R]

The Table class handles processing the yaml processing and csv loading, through table fu

next_page[R]

The Table class handles processing the yaml processing and csv loading, through table fu

page[R]

The Table class handles processing the yaml processing and csv loading, through table fu

prev_page[R]

The Table class handles processing the yaml processing and csv loading, through table fu

table_opts[R]

The Table class handles processing the yaml processing and csv loading, through table fu

Public Class Methods

all() click to toggle source

Returns all the tables in the table directory. Each table is deferred so accessing the @data attribute will throw and error.

# File lib/table_setter/table.rb, line 179
def all
  tables=[]
  Dir.glob("#{TableSetter.table_path}/*.yml").each do |file|
    table = new(File.basename(file, ".yml"), :defer => true)
    tables << table if table.live
  end
  tables
end
exists?(slug) click to toggle source

Does a table with this slug exist?

# File lib/table_setter/table.rb, line 210
def exists?(slug)
  File.exists? table_path(slug)
end
fresh_yaml_time() click to toggle source

fresh_yaml_time checks each file in the tables directory and returns the newest file's modification time – there's probably a more unix-y way to do this but for now this is plenty speedy.

# File lib/table_setter/table.rb, line 191
def fresh_yaml_time
  newest_file = Dir["#{TableSetter.table_path}/*.yml"].inject do |memo, obj|
    memo_time = File.new(File.expand_path memo).mtime
    obj_time = File.new(File.expand_path obj).mtime
    if memo_time > obj_time
      memo
    else
      obj
    end
  end
  File.new(newest_file).mtime
end
new(slug, opts={:defer => false}) click to toggle source

A new Table should accept a slug, mapped to a yaml in the tables directory, optionally you can defer loading of the table until you're ready to render it.

# File lib/table_setter/table.rb, line 14
def initialize(slug, opts={:defer => false})
  options = indifferent_access YAML.load_file(Table.table_path(slug))
  @table_opts = options[:table]
  @table_opts[:slug] = slug
  @deferred = opts[:defer]
  if !@deferred
    self.load
  end
end
table_path(slug) click to toggle source

Convenience method for looking up by slug.

# File lib/table_setter/table.rb, line 205
def table_path(slug)
  "#{TableSetter.table_path}#{slug}.yml"
end

Public Instance Methods

csv_data() click to toggle source

The csv_data for the table fu instance is loaded either from the remote source or from a local file, depending on the keys present in the yaml file.

# File lib/table_setter/table.rb, line 41
def csv_data
  case
  when google_key || url then Curl::Easy.perform(uri).body_str
  when file then File.open(uri).read
  end
end
faceted?() click to toggle source
# File lib/table_setter/table.rb, line 64
def faceted?
  !@facets.nil?
end
hard_paginate?() click to toggle source

hard_paginate instructs the app to render batches of a table.

# File lib/table_setter/table.rb, line 74
def hard_paginate?
  @table_opts[:hard_paginate] == true
end
load() click to toggle source

The load method handles the actual request either to the file system or remote url. It performs the requested data manipulations form the yml file after the data has been loaded. We're keeping this explicit to control against unnecessary http requests.

# File lib/table_setter/table.rb, line 27
def load
  if @table_opts[:column_options]
    @table_opts[:column_options]['style'] ||= {}
  end
  @data = TableFu.new(csv_data, @table_opts[:column_options] || {})
  if @table_opts[:faceting]
    @data.col_opts[:ignored] = [@table_opts[:faceting][:facet_by]]
    @facets = @data.faceted_by @table_opts[:faceting][:facet_by]
  end
  @data.delete_rows! @table_opts[:dead_rows] if @table_opts[:dead_rows]
end
method_missing(method) click to toggle source

We magically need access to the top level keys like google_key, or uri for the other methods. It's a bit dangerous because everything returns nil otherwise. At some point we should eval and create methods at boot time.

# File lib/table_setter/table.rb, line 114
def method_missing(method)
  if @table_opts[method]
    @table_opts[method]
  end
end
paginate!(curr_page) click to toggle source

paginate uses TableFu's only! method to batch the table. It also computes the page attributes which are nil and meaningless otherwise.

# File lib/table_setter/table.rb, line 85
def paginate!(curr_page)
  return if !hard_paginate?
  @page = curr_page.to_i
  raise ArgumentError if @page < 1 || @page > total_pages
  adj_page = @page - 1 > 0 ? @page - 1 : 0
  @prev_page = adj_page > 0 ? adj_page : nil
  @next_page = page < total_pages ? (@page + 1) : nil
  @data.only!(adj_page * per_page..(@page * per_page - 1))
end
per_page() click to toggle source

The number of rows per page. Defaults to 20

# File lib/table_setter/table.rb, line 79
def per_page
  @table_opts[:per_page] || 20
end
sort_array() click to toggle source

A convienence method to return the sort array for table setter.

# File lib/table_setter/table.rb, line 103
def sort_array
  if @data.sorted_by
    @data.sorted_by.inject([]) do |memo, (key, value)|
      memo << [@data.columns.index(key), value == 'descending' ? 1 : 0]
    end
  end
end
sortable?() click to toggle source

A table isn't sortable by tablesorter if it's either faceted or multi-page paginated.

# File lib/table_setter/table.rb, line 69
def sortable?
  !faceted? && !hard_paginate?
end
total_pages() click to toggle source

The total pages we'll have. We need to calculate it before paginate, so that we still have the full @data.rows.length

# File lib/table_setter/table.rb, line 98
def total_pages
  @total_pages ||= (@data.rows.length / per_page.to_f).ceil
end
updated_at() click to toggle source

The real updated_at of a Table instance is the newer modification time of the csv file or the yaml file. Updates to either resource should break the cache.

# File lib/table_setter/table.rb, line 59
def updated_at
  csv_time = google_key.nil? ? modification_time(uri) : google_modification_time
  (csv_time > yaml_time ? csv_time : yaml_time).to_s
end
uri() click to toggle source

Returns a usable uri based on what sort of input we have.

# File lib/table_setter/table.rb, line 49
def uri
  case
  when google_key then "https://docs.google.com/spreadsheet/pub?key=#{google_key}&output=csv&single=true&gid=0"
  when url then url
  when file then File.expand_path("#{TableSetter.table_path}#{file}")
  end
end

Private Instance Methods

google_modification_time() click to toggle source

Returns the google modification time of the spreadsheet. The public urls don't set the last-modified header on anything, so we have to do a little dance to find out when exactly the spreadsheet was last modified. The od part of the feed url changes at whim, so we'll need to keep an eye on it. Another problem is that curb doesn't feel like parsing headers, so since a head request from google is pretty lightweight we can get away with using Net:HTTP. If for whatever reason the google modification time is busted we'll the yaml modified time.

# File lib/table_setter/table.rb, line 128
def google_modification_time
  local_url = URI.parse "http://spreadsheets.google.com/feeds/list/#{google_key}/od6/public/basic"
  web_modification_time local_url
end
indifferent_access(params) click to toggle source

Enable string or symbol key access to col_opts from sinatra.

# File lib/table_setter/table.rb, line 160
def indifferent_access(params)
  params = indifferent_hash.merge(params)
  params.each do |key, value|
    next unless value.is_a?(Hash)
    params[key] = indifferent_access(value)
  end
end
indifferent_hash() click to toggle source

Duplicate a hash's keys and convert them into symbols.

# File lib/table_setter/table.rb, line 169
def indifferent_hash
  Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
end
modification_time(path) click to toggle source

Dispatches to web_modification_time if we're dealing with a url, otherwise just stats the local file.

# File lib/table_setter/table.rb, line 145
def modification_time(path)
  is_uri = URI.parse(path)
  if !is_uri.host.nil?
    return web_modification_time is_uri
  end
  File.new(path).mtime
end
web_modification_time(local_url) click to toggle source

Returns the last-modified time from the remote server. Assumes the remote server knows how to do this. Returns the epoch if the remote is dense.

# File lib/table_setter/table.rb, line 135
def web_modification_time(local_url)
  resp = nil
  Net::HTTP.start(local_url.host, 80) do |http|
    resp = http.head(local_url.path)
  end
  resp['Last-Modified'].nil? ? Time.at(0) : Time.parse(resp['Last-Modified'])
end
yaml_time() click to toggle source

The modification time of this Table's yaml file.

# File lib/table_setter/table.rb, line 154
def yaml_time
  modification_time(Table.table_path(slug))
end