chair 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cfab2cfe22182e362af7c3958e7c20d906f69510
4
+ data.tar.gz: 8fdc21582f8c3f8af34c03a0c1af94fa1826e88f
5
+ SHA512:
6
+ metadata.gz: d74dc734076ed87b19b1f5f12c71d8f3118c8539e38dfc2954f71a5000eae1f73e1c977248bafe1c8dac850f924a23c5645297318b989a5d58490c1856e81deb
7
+ data.tar.gz: a7b060604bcb97cef3cfb5f15272747493bbe5fe4221b6b0e3d00fd4c0150451c86f4c380a14c293e5e8eb8516883a4699906131c5f93c15e1bc77d26d59993d
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ /.idea
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ cache: bundler
3
+ rvm:
4
+ - ruby-2.1
5
+ - ruby-2.0
6
+ - ruby-1.9
7
+ - jruby-19mode
8
+ - rbx-2
9
+
10
+ addons:
11
+ code_climate:
12
+ repo_token: e3c6971d651290d13581ade555fc07abb89a8bf956342399f1c9949c51e34c4c
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in chairs.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem "codeclimate-test-reporter", group: :test, require: nil
8
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Katherine Whitlock
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # Chair
2
+ [![Build Status](http://img.shields.io/travis/toroidal-code/chairs/master.svg?style=flat)](https://travis-ci.org/toroidal-code/chairs)
3
+ [![Code Climate](https://img.shields.io/codeclimate/github/toroidal-code/chairs.png?style=flat)](https://codeclimate.com/github/toroidal-code/chairs)
4
+ [![Coverage](https://img.shields.io/codeclimate/coverage/github/toroidal-code/chairs.png?style=flat)](https://codeclimate.com/github/toroidal-code/chairs)
5
+
6
+ > Me: What's the first thing you think of when I say 'Tables'?
7
+ > J: 'Chair'.
8
+
9
+ Chair is a simple Table class for Ruby, with an associated Row class.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'chairs'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install chairs
24
+
25
+ ## Usage
26
+
27
+ ```irb
28
+ >> require 'chairs'
29
+ => true
30
+ >> t = Table.new :title
31
+ => #<Table:0x0000000162ee08>
32
+ >> t.set_primary_key! :title
33
+ => :title
34
+ >> t.insert! title: 'Looking for Alaska'
35
+ => #<Row:0x007feb28035be0>
36
+ >> t.find_by_title('Looking for Alaska')
37
+ >> ["Looking for Alaska"]
38
+ >> t.add_column! :author
39
+ => true
40
+ >> t.insert! title: 'An Abundance of Katherines', author: 'John Green'
41
+ => #<Row>
42
+ >> t.add_index! :author
43
+ => true
44
+ >> t.find_by_title('Looking for Alaska')[:author] = 'John Green'
45
+ => 'John Green'
46
+ >> t.find_by_author('John Green').to_a
47
+ => ["An Abundance of Katherines", "John Green"]
48
+ >> t.find_by_title('An Abundance of Katherines')[:author] = 'John Green'
49
+ => "John Green"
50
+ >> r = t.where_author_is 'John Green'
51
+ => [#<Row>, #<Row>]
52
+ >> r.map {|r| r.to_a}
53
+ => [["An Abundance of Katherines", "John Green"], ["Looking for Alaska", "John Green"]]
54
+ ```
55
+
56
+ ## Contributing
57
+
58
+ 1. Fork it ( https://github.com/toroidal-code/chairs/fork )
59
+ 2. Create your feature branch (`git checkout -b features/my-new-feature`)
60
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
61
+ 4. Push to the branch (`git push origin features/my-new-feature`)
62
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new('spec')
5
+
6
+ # If you want to make this the default task
7
+ task :default => :spec
data/chairs.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'chair/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'chair'
8
+ spec.version = Chair::VERSION
9
+ spec.date = '2014-06-04'
10
+ spec.summary = "Tables!"
11
+ spec.description = "A pure ruby table implementation with arbitray column indices"
12
+ spec.authors = ["Katherine Whitlock"]
13
+ spec.email = 'toroidalcode@gmail.com'
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.homepage = 'http://github.com/toroidal-code/chair'
17
+ spec.license = 'MIT'
18
+
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.6'
24
+ spec.add_development_dependency 'rake'
25
+ spec.add_development_dependency 'rspec'
26
+ end
data/demo.rb ADDED
@@ -0,0 +1,4 @@
1
+ table = Table.new [:title, :author]
2
+ table.where do |row|
3
+ row[:title]
4
+ end
data/lib/chair/row.rb ADDED
@@ -0,0 +1,62 @@
1
+ class Row
2
+
3
+ # Create a new cell
4
+ # @param table [Table] the table holding this row
5
+ # @param id [Fixnum] the array index of this row in the interal 2D array
6
+ def initialize(table, id)
7
+ @row_id = id
8
+ @table = table
9
+ @row = []
10
+ end
11
+
12
+ # Get a cell based on the column name
13
+ # @return [Object, nil] the value in the cell, can be nil
14
+ def [](col)
15
+ idx = @table.send(:get_column_id, col)
16
+ @row[idx]
17
+ end
18
+
19
+ # Assign a new value to one of the cells in the row
20
+ # @param col [Symbol] the column name to add to
21
+ # @param value [Object] the value to assign
22
+ # @return [Object] the assigned value
23
+ def []=(col, value)
24
+ idx = @table.send(:get_column_id, col)
25
+ if @table.indices.include? col
26
+ if @table.instance_variable_get("@#{col}_index_map".to_sym)[value].nil?
27
+ @table.instance_variable_get("@#{col}_index_map".to_sym)[value] = Set.new
28
+ end
29
+ @table.instance_variable_get("@#{col}_index_map")[value] =
30
+ @table.instance_variable_get("@#{col}_index_map")[value] << @row_id
31
+ end
32
+ @row[idx] = value
33
+ end
34
+
35
+ def empty?
36
+ @row.empty?
37
+ end
38
+
39
+ # Create a hash of the data based on the columns
40
+ # @return [Hash<Symbol, Object>] the data in the row
41
+ def to_hash
42
+ map = {}
43
+ @table.columns.each do |col|
44
+ idx = @table.send(:get_column_id, col)
45
+ map[col] = row[idx]
46
+ end
47
+ map
48
+ end
49
+
50
+ # Convert the row data to an array
51
+ # @return [Array<Object>] the data in the row
52
+ def to_a
53
+ @row
54
+ end
55
+
56
+ # Compare Row instances based on internal representation
57
+ # @param other [Object] the object to compare to
58
+ # @return [Bool] whether or not the objects are the same
59
+ def eql?(other)
60
+ @row.eql?(other.instance_variable_get("@row"))
61
+ end
62
+ end
@@ -0,0 +1,258 @@
1
+ require 'set'
2
+
3
+ # @author Katherine Whitlock <toroidalcode@gmail.com>
4
+ # @attr_reader primary_key [Symbol] the primary key of the table
5
+ # @attr_reader indices [Set<Symbol>] the set of indices for the table
6
+ class Table
7
+ attr_reader :primary_key, :indices
8
+
9
+ # Creates a new Table object
10
+ # @param columns [Symbol] columns to insert into the table at initialization
11
+ def initialize(*columns)
12
+ @table = []
13
+ @columns = {}
14
+ @columns_id_counter = 0
15
+ add_columns!(*columns)
16
+ @primary_key = nil
17
+ @indices = Set.new
18
+ end
19
+
20
+ # Add a new column to the table.
21
+ # @param column [Symbol] the column name to add
22
+ # @raise [ArgumentError] if the column name is not a symbol
23
+ # @return [Bool] whether or not we successfully added the new column
24
+ def add_column!(column)
25
+ case column
26
+ when Symbol
27
+ else raise ArgumentError, "Column name should be Symbol not #{column.class}"
28
+ end
29
+
30
+ if @columns.include? column
31
+ false
32
+ else
33
+ @columns[column] = @columns_id_counter
34
+ @columns_id_counter += 1
35
+ true
36
+ end
37
+ end
38
+
39
+ # Add multiple columns to the table
40
+ # @param columns [Symbol] the columns to add
41
+ # @return [Bool] whether or not all of the columns were successfully added
42
+ def add_columns!(*columns)
43
+ result = true
44
+ columns.each { |c| result &&= add_column!(c) }
45
+ result
46
+ end
47
+
48
+ # Retrieve the current columns
49
+ # @return [Array<Symbol>] the columns in the table
50
+ def columns
51
+ @columns.keys
52
+ end
53
+
54
+ # Add a new index to the table
55
+ # @param column [Symbol] the column to create the index on
56
+ # @return [Bool] whether or not we added the index
57
+ def add_index!(column)
58
+ result = false
59
+ get_column_id(column)
60
+ unless instance_variable_defined?("@#{column}_index_map".to_sym)
61
+ instance_variable_set("@#{column}_index_map".to_sym, {})
62
+ result ||= true
63
+ end
64
+
65
+ unless @indices.include? column
66
+ @indices = @indices << column
67
+ result ||= true
68
+ end
69
+
70
+ build_index column
71
+ result
72
+ end
73
+
74
+ # Remove an index from the table
75
+ # @param column [Symbol] the column to remove the index from
76
+ # @return [Bool] whether or not the column was successfully removed
77
+ def remove_index!(column)
78
+ result = false
79
+ if instance_variable_defined?("@#{column}_index_map".to_sym)
80
+ remove_instance_variable("@#{column}_index_map")
81
+ result ||= true
82
+ end
83
+ if @indices.include? column
84
+ @indices = @indices.delete column
85
+ result ||= true
86
+ end
87
+ result
88
+ end
89
+
90
+ # Insert a new row of data into the column
91
+ # @param args [Hash] the columns to insert
92
+ # @return [Row, nil] the row inserted, or nil if the row was empty
93
+ def insert!(args = {})
94
+ row = Row.new(self, @table.size)
95
+ args.each_pair do |col, value|
96
+ # If there's a primary_key defined
97
+ if has_primary_key? and columns.include? col and @primary_key == col
98
+ @pk_map[value] = @table.size
99
+ end
100
+ row[col] = value
101
+ end
102
+ unless row.empty?
103
+ @table << row
104
+ row
105
+ end
106
+ end
107
+
108
+ # Method_missing is used to dispatch to find_by_* and where_*_is
109
+ # @param method_sym [Symbol] the method called
110
+ def method_missing(method_sym, *arguments, &block)
111
+ # the first argument is a Symbol, so you need to_s it if you want to pattern match
112
+ if method_sym.to_s =~ /^find_by_(.*)$/
113
+ find_by($1.to_sym => arguments.first)
114
+ elsif method_sym.to_s =~ /^where_(.*)_is$/
115
+ where($1.to_sym => arguments.first)
116
+ else
117
+ super
118
+ end
119
+ end
120
+
121
+ # The number of rows in the table
122
+ # @return [Fixnum] the size
123
+ def size
124
+ @table.size
125
+ end
126
+
127
+ alias_method :count, :size
128
+
129
+ # Finds a row by searching based on primary key
130
+ # @param pk [Object] The primary key to look up using
131
+ # @return [Row,nil] The row that matches
132
+ def find(pk)
133
+ if has_primary_key?
134
+ idx = @pk_map[pk]
135
+ @table[idx]
136
+ else nil
137
+ end
138
+ end
139
+
140
+ # Search for rows based on given data
141
+ # @param args [Hash<Symbol, Object>] the data to search for
142
+ # @return [Array<Row>, nil] the matching rows, can be nil
143
+ def where(args)
144
+ # Try and find a primary key
145
+ if has_primary_key? and args.keys.include? @primary_key
146
+ idx = @pk_map[args[@primary_key]]
147
+ return [@table[idx]]
148
+ end
149
+ indexed_cols = find_valid_indices(args.keys)
150
+
151
+ results = @table.to_set
152
+
153
+ # First restrict the query as far as we can with indices
154
+ unless indexed_cols.empty?
155
+ indexed_cols.each do |col|
156
+ results = restrict_with_index(col, args[col], results)
157
+ end
158
+ end
159
+
160
+ # Then, perform table scans for the rest of the restrictions
161
+ # Removed the indexed columns
162
+ args = args.reject { |col, val| indexed_cols.include? col }
163
+ #slow O(N) find
164
+ args.each_pair do |col, val|
165
+ results = restrict_with_table_scan(col, val, results)
166
+ end
167
+ results.to_a
168
+ end
169
+
170
+ # Find a row based on the data given
171
+ # @param args [Hash<Symbol, Object>] the data to search for
172
+ # @return [Row, nil] the matching row, can be nil
173
+ def find_by(args)
174
+ where(args).first
175
+ end
176
+
177
+ # Scan the table to find rows
178
+ # @param args [Hash<Symbol, Object>] the rows to find
179
+ # @return [Array<Row>] the rows found
180
+ def table_scan(args)
181
+ results = @table.to_set
182
+ options.each_pair do |col, value|
183
+ results = restrict_with_table_scan(col, value, results)
184
+ end
185
+ results.to_a
186
+ end
187
+
188
+ # Set the primary key of the table.
189
+ # @param column [Symbol] the column to be primary key
190
+ # @return [Symbol, nil] the primary key assigned. can be nil if the column doesn't exist
191
+ def set_primary_key!(column)
192
+ unless @columns.has_key? column
193
+ return nil
194
+ end
195
+ @pk_map = {}
196
+ @primary_key = column
197
+ end
198
+
199
+ # Does this table have a primary key?
200
+ # @return [Bool] whether or not there is a primary key
201
+ def has_primary_key?
202
+ not @primary_key.nil?
203
+ end
204
+
205
+ protected
206
+ def get_column_id(name)
207
+ id = @columns[name]
208
+ if id.nil?
209
+ raise ArgumentError, "No such column #{name}"
210
+ end
211
+ id
212
+ end
213
+
214
+ def find_valid_indices(cols)
215
+ @indices.intersection(cols).to_a
216
+ end
217
+
218
+ def restrict_with_index(key, value, initial=@table.to_set)
219
+ idx_map = instance_variable_get("@#{key}_index_map".to_sym)
220
+ unless idx_map.has_key? value
221
+ return Set.new
222
+ end
223
+ row_idxs = idx_map[value]
224
+ if row_idxs.nil?
225
+ return Set.new
226
+ end
227
+ rows = @table.values_at *row_idxs
228
+ initial.intersection rows
229
+ end
230
+
231
+ def restrict_with_table_scan(col, value, initial=@table.to_set)
232
+ initial.keep_if { |row| row[col] == value }
233
+ end
234
+
235
+ def select(col, table = @table, &block)
236
+ col_id = get_column_id(col)
237
+ table.select do |row|
238
+ block(col)
239
+ end
240
+ end
241
+
242
+ # Scan the table and add all the rows to the index
243
+ # @param column [Symbol] the column to construct the index for
244
+ def build_index(column)
245
+ ivar_name = "@#{column}_index_map".to_sym
246
+ @table.each_with_index do |row, idx|
247
+ val = row[column]
248
+ unless val.nil?
249
+ if instance_variable_get(ivar_name)[val].nil?
250
+ instance_variable_get(ivar_name)[val] = Set.new
251
+ end
252
+ instance_variable_get(ivar_name)[val] =
253
+ instance_variable_get(ivar_name)[val] << idx
254
+ end
255
+ end
256
+ return
257
+ end
258
+ end
@@ -0,0 +1,3 @@
1
+ module Chair
2
+ VERSION = "1.0.0"
3
+ end
data/lib/chair.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'chair/version'
2
+ require 'chair/table'
3
+ require 'chair/row'
@@ -0,0 +1,11 @@
1
+ require 'codeclimate-test-reporter'
2
+ CodeClimate::TestReporter.start
3
+
4
+ require 'bundler/setup'
5
+ Bundler.setup
6
+
7
+ require 'chair' # and any other gems you need
8
+
9
+
10
+ RSpec.configure do |config|
11
+ end
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ describe Table do
4
+ subject(:table) { Table.new :id, :title, :author }
5
+
6
+ describe 'finds by' do
7
+ it 'primary key' do
8
+ table.set_primary_key! :title
9
+ table.insert! id: 0, title: 'War and Peace', author: 'Leo Tolstoy'
10
+ expect(table.find('War and Peace').to_a).to eq([0, 'War and Peace', 'Leo Tolstoy'])
11
+ end
12
+
13
+ it 'index to use restrict_with_index' do
14
+ table.set_primary_key! :id
15
+ table.add_index! :title
16
+ table.insert! id: 0, title: 'War and Peace', author: 'Leo Tolstoy'
17
+ expect(table).to receive(:restrict_with_index)
18
+ table.find_by(title: 'War and Peace')
19
+ end
20
+
21
+ it 'index with method_missing to use restrict_with_index' do
22
+ table.set_primary_key! :id
23
+ table.add_index! :title
24
+ table.insert! id: 0, title: 'War and Peace', author: 'Leo Tolstoy'
25
+ expect(table).to receive(:restrict_with_index)
26
+ table.find_by_title('War and Peace')
27
+ end
28
+
29
+ it 'index to return a row' do
30
+ table.set_primary_key! :id
31
+ table.add_index! :title
32
+ table.insert! id: 0, title: 'War and Peace', author: 'Leo Tolstoy'
33
+ row = table.find_by(title: 'War and Peace')
34
+ expect(row.to_a).to eq([0, 'War and Peace', 'Leo Tolstoy'])
35
+ end
36
+
37
+ it 'index with method_missing to return a row' do
38
+ table.set_primary_key! :id
39
+ table.add_index! :title
40
+ table.insert! id: 0, title: 'War and Peace', author: 'Leo Tolstoy'
41
+ row = table.find_by_title('War and Peace')
42
+ expect(row.to_a).to eq([0, 'War and Peace', 'Leo Tolstoy'])
43
+ end
44
+
45
+ it 'table scan' do
46
+ table.insert! id: 0, title: 'War and Peace', author: 'Leo Tolstoy'
47
+ expect(table.find_by_title('War and Peace').to_a).to eq([0, 'War and Peace', 'Leo Tolstoy'])
48
+ end
49
+ end
50
+
51
+ describe 'searches using' do
52
+ it 'primary key' do
53
+ table.set_primary_key! :title
54
+ table.insert! id: 0, title: 'War and Peace', author: 'Leo Tolstoy'
55
+ expect(table.where(title: 'War and Peace').first.to_a).to eq([0, 'War and Peace', 'Leo Tolstoy'])
56
+ end
57
+
58
+ it 'dispatch with method_missing' do
59
+ table.set_primary_key! :title
60
+ table.insert! id: 0, title: 'War and Peace', author: 'Leo Tolstoy'
61
+ expect(table.where_title_is('War and Peace').first.to_a).to eq([0, 'War and Peace', 'Leo Tolstoy'])
62
+ end
63
+
64
+ it 'table scan' do
65
+ table.insert! id: 0, title: 'War and Peace', author: 'Leo Tolstoy'
66
+ expect(table.where_title_is('War and Peace').first.to_a).to eq([0, 'War and Peace', 'Leo Tolstoy'])
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ describe Table do
4
+ describe 'initializes' do
5
+ it 'with 0 columns by default' do
6
+ table = Table.new
7
+ expect(table.columns.count).to eq(0)
8
+ end
9
+
10
+ it 'with 0 rows by default' do
11
+ table = Table.new
12
+ expect(table.size).to eq(0)
13
+ end
14
+
15
+ it 'with columns given' do
16
+ table = Table.new :title, :author, :isbn
17
+ expect(table.columns).to eq([:title, :author, :isbn])
18
+ end
19
+
20
+ it 'with no primary key' do
21
+ table = Table.new
22
+ expect(table.has_primary_key?).to eq(false)
23
+ end
24
+
25
+ it 'with no indices' do
26
+ table = Table.new
27
+ expect(table.indices.size).to eq(0)
28
+ end
29
+ end
30
+
31
+ it 'adds a column' do
32
+ table = Table.new
33
+ expect {
34
+ table.add_column!(:title)
35
+ }.to change{ table.columns.count }.by(1)
36
+ end
37
+
38
+ it 'raises an ArgumentError if the name is not a symbol' do
39
+ table = Table.new
40
+ expect{
41
+ table.add_column!('Title')
42
+ }.to raise_error(ArgumentError)
43
+ end
44
+
45
+ it 'doesn\'t add column with the same name' do
46
+ table = Table.new :title
47
+ expect {
48
+ table.add_column!(:title)
49
+ }.to_not change{ table.columns.count }
50
+ end
51
+
52
+ it 'adds multiple columns' do
53
+ table = Table.new
54
+ expect {
55
+ table.add_columns! :title, :author
56
+ }.to change {table.columns.count}.by(2)
57
+ end
58
+
59
+ it 'inserts a row' do
60
+ table = Table.new :title
61
+ expect {
62
+ table.insert!({title: "Gone with the Wind"})
63
+ }.to change { table.size }.by(1)
64
+ end
65
+
66
+ it 'sets the primary key' do
67
+ table = Table.new :title
68
+ expect {
69
+ table.set_primary_key! :title
70
+ }.to change {table.primary_key}.from(nil).to(:title)
71
+ end
72
+
73
+ it "doesn't set the primary key if it's not a column" do
74
+ table = Table.new
75
+ expect{
76
+ table.set_primary_key! :title
77
+ }.not_to change{table.primary_key}.from(nil)
78
+ end
79
+
80
+ it 'adds an index' do
81
+ table = Table.new :title
82
+ expect {
83
+ table.add_index! :title
84
+ }.to change {table.indices.size}.by(1)
85
+ end
86
+
87
+ it 'deletes an index' do
88
+ table = Table.new :title
89
+ table.add_index! :title
90
+ expect {
91
+ table.remove_index! :title
92
+ }.to change {table.indices.size}.by(-1)
93
+ end
94
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chair
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Katherine Whitlock
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: A pure ruby table implementation with arbitray column indices
56
+ email: toroidalcode@gmail.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - ".gitignore"
62
+ - ".rspec"
63
+ - ".travis.yml"
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - chairs.gemspec
69
+ - demo.rb
70
+ - lib/chair.rb
71
+ - lib/chair/row.rb
72
+ - lib/chair/table.rb
73
+ - lib/chair/version.rb
74
+ - spec/spec_helper.rb
75
+ - spec/table_search_spec.rb
76
+ - spec/table_spec.rb
77
+ homepage: http://github.com/toroidal-code/chair
78
+ licenses:
79
+ - MIT
80
+ metadata: {}
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 2.2.2
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: Tables!
101
+ test_files:
102
+ - spec/spec_helper.rb
103
+ - spec/table_search_spec.rb
104
+ - spec/table_spec.rb
105
+ has_rdoc: