Skip to content

Commit

Permalink
Merge pull request #6 from DannyBen/add/hash-row-access
Browse files Browse the repository at this point in the history
Add support for accessing rows by `table[colname: value]`
  • Loading branch information
DannyBen committed Jun 22, 2023
2 parents f18ffbd + cc25630 commit d37f169
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 19 deletions.
9 changes: 5 additions & 4 deletions Runfile
@@ -1,8 +1,9 @@
require "byebug"
require "lp"
require 'byebug'
require 'lp'
require 'true_table'

title "TrueTable Developer Toolbelt"
summary "Runfile tasks for building the TrueTable gem"
title 'TrueTable Developer Toolbelt'
summary 'Runfile tasks for building the TrueTable gem'

import_gem 'runfile-tasks/gem'
import_gem 'runfile-tasks/yard'
Expand Down
54 changes: 43 additions & 11 deletions lib/true_table.rb
Expand Up @@ -51,12 +51,20 @@ def -(other)

# Returns a row or a column
def [](key)
key.is_a?(Symbol) ? col(key) : super
case key
when Symbol then col(key)
when Hash then row(key)
else super
end
end

# Adds or updates a row or a column
def []=(key, value)
key.is_a?(Symbol) ? add_col(key.to_sym, value) : super
case key
when Symbol then add_col(key.to_sym, value)
when Hash then add_row(key, value)
else super
end
end

# Returns a deep copy of self
Expand Down Expand Up @@ -134,19 +142,29 @@ def each_col
# Iterates over rows
alias each_row each_with_index

# Returns a row or a column
def fetch(key, *default)
if key.is_a?(Symbol)
if headers.include? key
col(key.to_sym)
elsif default.any?
default.first
elsif block_given?
yield key
case key
when Symbol
if headers.include?(key) then col(key.to_sym)
elsif default.any? then default.first
elsif block_given? then yield key
else
raise IndexError, "row :#{key} does not exist"
raise IndexError, "col :#{key} does not exist"
end

when Hash
result = row(key)
if result then result
elsif default.any? then default.first
elsif block_given? then yield key
else
raise IndexError, "row #{key} does not exist"
end

else
super

end
end

Expand All @@ -155,6 +173,11 @@ def headers
first.keys
end

# Returns a short inspection string
def inspect
"<#{self.class}:#{object_id} size=#{size} headers=#{headers}>"
end

# Returns a new table with intersecting rows
def intersection(*others)
self.class.new super
Expand Down Expand Up @@ -191,7 +214,12 @@ def rotate(count = 1)
end

# Returns a row
alias row []
def row(key)
key.is_a?(Hash) ? find { |x| x[key.first.first] == key.first.last } : self[key]
end

# Returns all rows
alias rows to_a

# Saves the table as a CSV file
def save_csv(path)
Expand Down Expand Up @@ -286,4 +314,8 @@ def add_col(key, values)
self[i][key] = value
end
end

def add_row(key, values)
row(key).merge! values
end
end
33 changes: 29 additions & 4 deletions spec/true_table/true_table_spec.rb
Expand Up @@ -86,6 +86,12 @@
expect(subject[:population][3]).to eq 2
end
end

context 'with a hash key' do
it 'returns a row' do
expect(subject[year: 2023][:population]).to eq 2
end
end
end

describe '#[]=' do
Expand All @@ -102,6 +108,13 @@
expect(subject[1]).to eq({ population: 20_000, year: 2021, infected: 1_980_000 })
end
end

context 'with a hash key' do
it 'adds the row' do
subject[year: 2023] = { population: 23 }
expect(subject[:population]).to eq [2_000_000, 20_000, 200, 23]
end
end
end

describe '#clone' do
Expand Down Expand Up @@ -439,9 +452,7 @@

describe '#minmax' do
it 'returns a two element array with min and max rows' do
result = subject.minmax do |a, b|
a[:population] <=> b[:population]
end
result = subject.minmax_by { |a| a[:population] }
expect(result[0][:year]).to eq 2023
expect(result[1][:year]).to eq 2020
end
Expand Down Expand Up @@ -527,6 +538,20 @@
end
end

describe '#row' do
context 'with an integer key' do
it 'returns a row' do
expect(subject[2][:population]).to eq 200
end
end

context 'with a hash key' do
it 'returns a row' do
expect(subject[year: 2023][:population]).to eq 2
end
end
end

describe '#rotate' do
it 'offsets the rows to the top' do
expect(subject.rotate(2)[0][:year]).to eq 2022
Expand Down Expand Up @@ -654,7 +679,7 @@

describe '#sort!' do
it 'sorts the table in place' do
subject.sort! { |a, b| a[:population] <=> b[:population] }
subject.sort_by! { |a| a[:population] }

expect(subject[0][:population]).to eq 2
expect(subject[3][:population]).to eq 2_000_000
Expand Down

0 comments on commit d37f169

Please sign in to comment.