chair 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: