Class: TableSetter::Table

Inherits:
Object
  • Object
show all
Defined in:
lib/table_setter/table.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(slug, opts = {:defer => false}) ⇒ Table

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.



14
15
16
17
18
19
20
21
22
# 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

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method) ⇒ Object

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.



114
115
116
117
118
# File 'lib/table_setter/table.rb', line 114

def method_missing(method)
  if @table_opts[method]
    @table_opts[method]
  end
end

Instance Attribute Details

#dataObject (readonly)

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



10
11
12
# File 'lib/table_setter/table.rb', line 10

def data
  @data
end

#facetsObject (readonly)

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



10
11
12
# File 'lib/table_setter/table.rb', line 10

def facets
  @facets
end

#next_pageObject (readonly)

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



10
11
12
# File 'lib/table_setter/table.rb', line 10

def next_page
  @next_page
end

#pageObject (readonly)

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



10
11
12
# File 'lib/table_setter/table.rb', line 10

def page
  @page
end

#prev_pageObject (readonly)

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



10
11
12
# File 'lib/table_setter/table.rb', line 10

def prev_page
  @prev_page
end

#table_optsObject (readonly)

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



10
11
12
# File 'lib/table_setter/table.rb', line 10

def table_opts
  @table_opts
end

Class Method Details

.allObject

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



179
180
181
182
183
184
185
186
# 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) ⇒ Boolean

Does a table with this slug exist?

Returns:

  • (Boolean)


210
211
212
# File 'lib/table_setter/table.rb', line 210

def exists?(slug)
  File.exists? table_path(slug)
end

.fresh_yaml_timeObject

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.



191
192
193
194
195
196
197
198
199
200
201
202
# 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

.table_path(slug) ⇒ Object

Convenience method for looking up by slug.



205
206
207
# File 'lib/table_setter/table.rb', line 205

def table_path(slug)
  "#{TableSetter.table_path}#{slug}.yml"
end

Instance Method Details

#csv_dataObject

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.



41
42
43
44
45
46
# 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?Boolean

Returns:

  • (Boolean)


64
65
66
# File 'lib/table_setter/table.rb', line 64

def faceted?
  !@facets.nil?
end

#hard_paginate?Boolean

hard_paginate instructs the app to render batches of a table.

Returns:

  • (Boolean)


74
75
76
# File 'lib/table_setter/table.rb', line 74

def hard_paginate?
  @table_opts[:hard_paginate] == true
end

#loadObject

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.



27
28
29
30
31
32
33
34
35
36
37
# 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

#paginate!(curr_page) ⇒ Object

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

Raises:

  • (ArgumentError)


85
86
87
88
89
90
91
92
93
# 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_pageObject

The number of rows per page. Defaults to 20



79
80
81
# File 'lib/table_setter/table.rb', line 79

def per_page
  @table_opts[:per_page] || 20
end

#sort_arrayObject

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



103
104
105
106
107
108
109
# 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?Boolean

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

Returns:

  • (Boolean)


69
70
71
# File 'lib/table_setter/table.rb', line 69

def sortable?
  !faceted? && !hard_paginate?
end

#total_pagesObject

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



98
99
100
# File 'lib/table_setter/table.rb', line 98

def total_pages
  @total_pages ||= (@data.rows.length / per_page.to_f).ceil
end

#updated_atObject

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.



59
60
61
62
# 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

#uriObject

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



49
50
51
52
53
54
55
# 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