hash_math 0.0.1 → 1.0.0.pre.alpha

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 634c0b1692a46994e23fc56cc31346a128182d19da45adaa8913d23898d91b5b
4
- data.tar.gz: 7cf7a06c956965072b2dcb0dfe4e8bbccd962a44380c60289d9e9b377d7c8f6a
3
+ metadata.gz: 298a64b54732cd96f7145ecba9b7e3a8e1424e4513609c75269cff8de9ebd039
4
+ data.tar.gz: 1fa6896667948c39b05169e232fd916d20a35ac6415e068195560a2552c2051d
5
5
  SHA512:
6
- metadata.gz: e5dfeff921d808b1f77d7e303a076ca5a6d3f50760fb7b9296332c443950679858c3498ba6e2629fbe13cdc5fbc5de5cc5c4a74d491299c434d14b529ef46a29
7
- data.tar.gz: bc92933f546e34bdb244215e715a690db94cf3d85ff156e05c5383406ab831616162567b6862be89ad6e555d77a64504988f760e2b197825013d21e7e8966351
6
+ metadata.gz: 7867d22fc5bd88a24adb3031706302621e5e3f2c8aae353cfe83e323fd8b7ba0d25afb86f1403c9e796899b90df6789a823a0139d833ed5ac87d899edef11d44
7
+ data.tar.gz: cc6703151537b76d44bd322e11a4b698e0829de8c250707611475b9959b7a30260c9aee328bedfea956db6142f339e57d5ca790294006378d4d65bd4f293b58f
@@ -1,3 +1,11 @@
1
+ # 1.0.0-alpha (September 16th, 2019)
2
+
3
+ Added initial implementation of:
4
+
5
+ * HashMath::Matrix
6
+ * HashMath::Record
7
+ * HashMath::Table
8
+
1
9
  # 0.0.1 (September 16th, 2019)
2
10
 
3
11
  Published initial shell. Library has no functionality yet.
data/README.md CHANGED
@@ -2,4 +2,238 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/hash_math.svg)](https://badge.fury.io/rb/hash_math) [![Build Status](https://travis-ci.org/bluemarblepayroll/hash_math.svg?branch=master)](https://travis-ci.org/bluemarblepayroll/hash_math) [![Maintainability](https://api.codeclimate.com/v1/badges/9f9a504b3f5df199a253/maintainability)](https://codeclimate.com/github/bluemarblepayroll/hash_math/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/9f9a504b3f5df199a253/test_coverage)](https://codeclimate.com/github/bluemarblepayroll/hash_math/test_coverage) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
4
 
5
- Under Construction.
5
+ Ruby's Hash data structure is ubiquitous and highly flexible. This library contains common Hash patterns widely used within our code-base:
6
+
7
+ * Matrix: build a hash up then expand into hash products
8
+ * Record: define a list of keys and base value to use as a blueprint for hashes
9
+ * Table: key-value pair two-dimensional array of hash builder
10
+
11
+ See examples for more information on each data structure.
12
+
13
+ ## Installation
14
+
15
+ To install through Rubygems:
16
+
17
+ ````bash
18
+ gem install install hash_math
19
+ ````
20
+
21
+ You can also add this to your Gemfile:
22
+
23
+ ````bash
24
+ bundle add hash_math
25
+ ````
26
+
27
+ ## Examples
28
+
29
+ ### Matrix: The Hash Combination Calculator
30
+
31
+ HashMath::Matrix is a key-value builder that outputs all the different hash combinations.
32
+
33
+ Say we have this type of matrix:
34
+
35
+ ````ruby
36
+ {
37
+ a: [1,2,3],
38
+ b: [4,5,6],
39
+ c: [7,8,9]
40
+ }
41
+ ````
42
+
43
+ We could code this as:
44
+
45
+ ````ruby
46
+ matrix = HashMath::Matrix.new
47
+ matrix.add_each(:a, [1,2,3])
48
+ matrix.add_each(:b, [4,5,6])
49
+ matrix.add_each(:c, [7,8,9])
50
+ ````
51
+
52
+ Note: you can also call `Matrix#add` to only add a single value instead of add_each.
53
+
54
+ and get the combinations by calling to_a:
55
+
56
+ ````ruby
57
+ combinations = matrix.to_a
58
+ ````
59
+
60
+ which would yield the following hashes:
61
+
62
+ ````ruby
63
+ [
64
+ { a: 1, b: 4, c: 7 },
65
+ { a: 1, b: 4, c: 8 },
66
+ { a: 1, b: 4, c: 9 },
67
+ { a: 1, b: 5, c: 7 },
68
+ { a: 1, b: 5, c: 8 },
69
+ { a: 1, b: 5, c: 9 },
70
+ { a: 1, b: 6, c: 7 },
71
+ { a: 1, b: 6, c: 8 },
72
+ { a: 1, b: 6, c: 9 },
73
+
74
+ { a: 2, b: 4, c: 7 },
75
+ { a: 2, b: 4, c: 8 },
76
+ { a: 2, b: 4, c: 9 },
77
+ { a: 2, b: 5, c: 7 },
78
+ { a: 2, b: 5, c: 8 },
79
+ { a: 2, b: 5, c: 9 },
80
+ { a: 2, b: 6, c: 7 },
81
+ { a: 2, b: 6, c: 8 },
82
+ { a: 2, b: 6, c: 9 },
83
+
84
+ { a: 3, b: 4, c: 7 },
85
+ { a: 3, b: 4, c: 8 },
86
+ { a: 3, b: 4, c: 9 },
87
+ { a: 3, b: 5, c: 7 },
88
+ { a: 3, b: 5, c: 8 },
89
+ { a: 3, b: 5, c: 9 },
90
+ { a: 3, b: 6, c: 7 },
91
+ { a: 3, b: 6, c: 8 },
92
+ { a: 3, b: 6, c: 9 },
93
+ ]
94
+ ````
95
+
96
+ Notes:
97
+
98
+ * Matrix implements Ruby's Enumerable, which means you have the ability to iterate over each hash combination like you would any other Enumerable object.
99
+ * Values can be arrays and it still works. For example, `#add` (singular form) will honor the array data type: `matrix.add(:a, [1,2,3])` is **not** the same as: `matrix.add_each(:a, [1,2,3])` but it **is** the same as: `matrix.add(:a, [[1,2,3]])`
100
+ * Keys are type-sensitive and work just like Hash keys work.
101
+
102
+ ### Record: The Hash Prototype
103
+
104
+ HashMath::Record generates a prototype hash and ensures all derived hashes conform to its shape.
105
+
106
+ Say we have a person hash, for example:
107
+
108
+ ````ruby
109
+ {
110
+ id: 1,
111
+ name: 'Matt',
112
+ location: 'Chicago'
113
+ }
114
+ ````
115
+
116
+ we could create a record modeling this:
117
+
118
+ ````ruby
119
+ record = HashMath::Record.new(%i[id name location], 'UNKNOWN')
120
+ ````
121
+
122
+ Then, we could shape all other hashes using it to ensure each key is populated. If a key is not populated, the base value will be used ('UNKNOWN' in our case.) For example:
123
+
124
+ ````ruby
125
+ records = [
126
+ record.make(id: 1, name: 'Matt', location: 'Chicago', dob: nil),
127
+ record.make(id: 2, age: 24),
128
+ record.make(id: 3, location: 'Los Angeles')
129
+ ]
130
+ ````
131
+
132
+ Note: The keys `dob` and `age` appeared in the input but will be ignored as they do not conform to the Record. You could make this strict and raise an error by calling `#make!` instead of `#make`.
133
+
134
+ our `records` would now equate to:
135
+
136
+ ````ruby
137
+ [
138
+ { id: 1, name: 'Matt', location: 'Chicago' },
139
+ { id: 2, name: 'UNKNOWN', location: 'UNKNOWN' },
140
+ { id: 3, name: 'UNKNOWN', location: 'Los Angeles' },
141
+ ]
142
+ ````
143
+
144
+ Notes:
145
+
146
+ * keys are type-sensitive and works just like Hash keys work.
147
+
148
+ ### Table: The Double Hash (Hash of Hashes)
149
+
150
+ HashMath::Table builds on top of HashMath::Record. It constructs a table data-structure using a key-value pair builder method: `#add(row_id, field_id, key, value)`. It ultimately outputs an array of Row objects where each Row object has a row_id and fields (field_id => value) hash. The value proposition here is you can iterate over a key-value pair and construct each row any way you wish.
151
+
152
+ Building on our Record example above:
153
+
154
+ ````ruby
155
+ record = HashMath::Record.new(%i[name location], 'UNKNOWN')
156
+
157
+ table = HashMath::Table.new(record)
158
+ .add(1, :name, 'Matt')
159
+ .add(1, :location, 'Chicago')
160
+ .add(2, :name, 'Nick')
161
+ .add(3, :location, 'Los Angeles')
162
+ .add(2, :name 'Nicholas') # notice the secondary call to "2, :name"
163
+
164
+ rows = table.to_a
165
+ ````
166
+
167
+ which would set our variable `rows` to:
168
+
169
+ ````ruby
170
+ [
171
+ HashMath::Row.new(1, { name: 'Matt', location: 'Chicago' }),
172
+ HashMath::Row.new(2, { name: 'Nicholas', location: 'UNKNOWN' }),
173
+ HashMath::Row.new(3, { name: 'UNKNOWN', location: 'Los Angeles' })
174
+ ]
175
+ ````
176
+
177
+ Notes:
178
+
179
+ * `#add` will throw a KeyOutOfBoundsError if the key is not found.
180
+ * key is type-sensitive and works just like Hash keys work.
181
+
182
+ ## Contributing
183
+
184
+ ### Development Environment Configuration
185
+
186
+ Basic steps to take to get this repository compiling:
187
+
188
+ 1. Install [Ruby](https://www.ruby-lang.org/en/documentation/installation/) (check hash_math.gemspec for versions supported)
189
+ 2. Install bundler (gem install bundler)
190
+ 3. Clone the repository (git clone git@github.com:bluemarblepayroll/hash_math.git)
191
+ 4. Navigate to the root folder (cd hash_math)
192
+ 5. Install dependencies (bundle)
193
+
194
+ ### Running Tests
195
+
196
+ To execute the test suite and code-coverage tool, run:
197
+
198
+ ````bash
199
+ bundle exec rspec spec --format documentation
200
+ ````
201
+
202
+ Alternatively, you can have Guard watch for changes:
203
+
204
+ ````bash
205
+ bundle exec guard
206
+ ````
207
+
208
+ Also, do not forget to run Rubocop:
209
+
210
+ ````bash
211
+ bundle exec rubocop
212
+ ````
213
+
214
+ or run all three in one command:
215
+
216
+ ````bash
217
+ bundle exec rake
218
+ ````
219
+
220
+ ### Publishing
221
+
222
+ Note: ensure you have proper authorization before trying to publish new versions.
223
+
224
+ After code changes have successfully gone through the Pull Request review process then the following steps should be followed for publishing new versions:
225
+
226
+ 1. Merge Pull Request into master
227
+ 2. Update `lib/hash_math/version.rb` using [semantic versioning](https://semver.org/)
228
+ 3. Install dependencies: `bundle`
229
+ 4. Update `CHANGELOG.md` with release notes
230
+ 5. Commit & push master to remote and ensure CI builds master successfully
231
+ 6. Run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
232
+
233
+ ## Code of Conduct
234
+
235
+ Everyone interacting in this codebase, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/bluemarblepayroll/hash_math/blob/master/CODE_OF_CONDUCT.md).
236
+
237
+ ## License
238
+
239
+ This project is MIT Licensed.
@@ -7,6 +7,11 @@
7
7
  # LICENSE file in the root directory of this source tree.
8
8
  #
9
9
 
10
+ require_relative 'hash_math/matrix'
11
+ require_relative 'hash_math/record'
12
+ require_relative 'hash_math/table'
13
+
10
14
  # Top-level namespace
11
15
  module HashMath
16
+ class KeyOutOfBoundsError < StandardError; end
12
17
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'matrix/key_value_pair'
11
+
12
+ module HashMath
13
+ # A Matrix allows you to build up a hash of key and values, then it will generate the
14
+ # product of all values.
15
+ class Matrix
16
+ extend Forwardable
17
+ include Enumerable
18
+
19
+ def_delegators :pair_products, :each
20
+
21
+ def initialize
22
+ @pairs_by_key = {}
23
+
24
+ freeze
25
+ end
26
+
27
+ def add_each(key, vals)
28
+ tap { kvp(key).add_each(vals) }
29
+ end
30
+
31
+ def add(key, val)
32
+ tap { kvp(key).add(val) }
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :pairs_by_key
38
+
39
+ def kvp(key)
40
+ pairs_by_key[key] ||= KeyValuePair.new(key)
41
+ end
42
+
43
+ def pair_products
44
+ pair_groups = pairs_by_key.values.map(&:pairs)
45
+
46
+ products = pair_groups.inject(pair_groups.shift) { |memo, f| memo.product(f) }
47
+ &.map { |f| f.is_a?(KeyValuePair::Pair) ? [f] : f.flatten } || []
48
+
49
+ products.map { |pairs| recombine(pairs) }
50
+ end
51
+
52
+ def recombine(pairs)
53
+ pairs.each_with_object({}) { |p, memo| memo[p.key] = p.value }
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module HashMath
11
+ class Matrix
12
+ # A hash-like structure that allows you to gradually build up keys.
13
+ class KeyValuePair
14
+ Pair = Struct.new(:key, :value)
15
+
16
+ attr_reader :key, :value
17
+
18
+ def initialize(key)
19
+ @key = key
20
+ @value = Set.new
21
+
22
+ freeze
23
+ end
24
+
25
+ def add_each(vals)
26
+ tap { vals.each { |val| add(val) } }
27
+ end
28
+
29
+ def add(val)
30
+ tap { value << val }
31
+ end
32
+
33
+ def pairs
34
+ value.map { |value| Pair.new(key, value) }
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module HashMath
11
+ # A Record serves as a prototype for a Hash. It will allow the output of hashes
12
+ # conforming to a strict (#make!) or non-strict (#make) shape.
13
+ class Record
14
+ extend Forwardable
15
+
16
+ def_delegators :prototype, :key?, :keys
17
+
18
+ def initialize(keys = [], base_value = nil)
19
+ @prototype = keys.map { |key| [key, base_value] }.to_h
20
+
21
+ freeze
22
+ end
23
+
24
+ def make!(hash = {})
25
+ make(hash, true)
26
+ end
27
+
28
+ def make(hash = {}, bound = false)
29
+ hash.each_with_object(shallow_copy_prototype) do |(key, value), memo|
30
+ next unless assert_key_in_bounds(key, bound)
31
+
32
+ memo[key] = value
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :prototype
39
+
40
+ # raise error if key is not in key set and bound is true
41
+ # return true if key is in key set and bound is false
42
+ # return false if key is not in key set and bound is false
43
+ def assert_key_in_bounds(key, bound)
44
+ raise KeyOutOfBoundsError, "[#{key}] for: #{keys}" if not_key?(key) && bound
45
+
46
+ key?(key)
47
+ end
48
+
49
+ def not_key?(key)
50
+ !key?(key)
51
+ end
52
+
53
+ def shallow_copy_prototype
54
+ {}.merge(prototype)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module HashMath
11
+ # The main data structure for a virtual table that can be treated as a key-value builder.
12
+ # Basically, it is a hash with a default 'prototype' assigned to it, which serves as the
13
+ # base record. Then, #add is called over and over passing in row_id, field_id, and value,
14
+ # which gives it enough information to pinpoint where to insert the data (memory-wise.)
15
+ # Imagine a two-dimensional table where X is the field_id axis and row is the Y axis.
16
+ # Since it is essentially backed by a hash, the row_id and field_id can be anything that
17
+ # implements #hash, #eql? and #== properly.
18
+ class Table
19
+ extend Forwardable
20
+ include Enumerable
21
+
22
+ Row = Struct.new(:row_id, :fields)
23
+
24
+ attr_reader :lookup, :record
25
+
26
+ def_delegators :record, :keys, :key?
27
+
28
+ def initialize(record)
29
+ raise ArgumentError, 'record is required' unless record
30
+
31
+ @lookup = {}
32
+ @record = record
33
+
34
+ freeze
35
+ end
36
+
37
+ def add(row_id, field_id, value)
38
+ raise KeyOutOfBoundsError, "field_id: #{field_id} not allowed." unless key?(field_id)
39
+
40
+ tap { set(row_id, field_id, value) }
41
+ end
42
+
43
+ def each
44
+ return enum_for(:each) unless block_given?
45
+
46
+ lookup.map do |row_id, fields|
47
+ Row.new(row_id, record.make!(fields)).tap { |row| yield(row) }
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def row(row_id)
54
+ lookup[row_id] ||= {}
55
+ end
56
+
57
+ def set(row_id, field_id, value)
58
+ row(row_id)[field_id] = value
59
+ end
60
+ end
61
+ end
@@ -8,5 +8,5 @@
8
8
  #
9
9
 
10
10
  module HashMath
11
- VERSION = '0.0.1'
11
+ VERSION = '1.0.0-alpha'
12
12
  end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require 'spec_helper'
11
+
12
+ describe HashMath::Matrix do
13
+ let(:examples) do
14
+ {
15
+ {} => [],
16
+ { a: :b } => [
17
+ { a: :b }
18
+ ],
19
+ { a: 'a1', b: 'b1', c: 'c1' } => [
20
+ { a: 'a1', b: 'b1', c: 'c1' }
21
+ ],
22
+ { a: %w[a1 a2], b: 'b1', c: 'c1' } => [
23
+ { a: 'a1', b: 'b1', c: 'c1' },
24
+ { a: 'a2', b: 'b1', c: 'c1' }
25
+ ],
26
+ { a: %w[a1 a2], b: %w[b1 b2], c: 'c1' } => [
27
+ { a: 'a1', b: 'b1', c: 'c1' },
28
+ { a: 'a1', b: 'b2', c: 'c1' },
29
+ { a: 'a2', b: 'b1', c: 'c1' },
30
+ { a: 'a2', b: 'b2', c: 'c1' }
31
+ ],
32
+ { a: %w[a1 a2], b: %w[b1 b2], c: %w[c1 c2] } => [
33
+ { a: 'a1', b: 'b1', c: 'c1' },
34
+ { a: 'a1', b: 'b1', c: 'c2' },
35
+ { a: 'a1', b: 'b2', c: 'c1' },
36
+ { a: 'a1', b: 'b2', c: 'c2' },
37
+
38
+ { a: 'a2', b: 'b1', c: 'c1' },
39
+ { a: 'a2', b: 'b1', c: 'c2' },
40
+ { a: 'a2', b: 'b2', c: 'c1' },
41
+ { a: 'a2', b: 'b2', c: 'c2' }
42
+ ]
43
+ }
44
+ end
45
+
46
+ specify '#produce generates correct matrix-expanded hashes' do
47
+ examples.each_pair do |hash, expanded_hashes|
48
+ subject = described_class.new
49
+
50
+ hash.each_pair do |k, v|
51
+ v.is_a?(Array) ? subject.add_each(k, v) : subject.add(k, v)
52
+ end
53
+
54
+ expect(subject.to_a).to eq(expanded_hashes)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require 'spec_helper'
11
+
12
+ describe HashMath::Record do
13
+ let(:base_value) { '*' }
14
+
15
+ let(:examples) do
16
+ {
17
+ { a: :b } => { a: :b, c: base_value, 'a' => base_value, 'c' => base_value },
18
+ { c: :d } => { a: base_value, c: :d, 'a' => base_value, 'c' => base_value },
19
+ { 'a' => :b } => { a: base_value, c: base_value, 'a' => :b, 'c' => base_value },
20
+ { 'c' => :d } => { a: base_value, c: base_value, 'a' => base_value, 'c' => :d }
21
+ }
22
+ end
23
+
24
+ subject do
25
+ described_class.new(examples.keys.map(&:keys).flatten, base_value)
26
+ end
27
+
28
+ describe '#initialize' do
29
+ it 'derives prototype' do
30
+ expected = {
31
+ a: base_value,
32
+ c: base_value,
33
+ 'a' => base_value,
34
+ 'c' => base_value
35
+ }
36
+
37
+ expect(subject.make).to eq(expected)
38
+ end
39
+ end
40
+
41
+ describe '#make' do
42
+ it 'generates correct hashes' do
43
+ examples.each_pair do |hash, normalized_hash|
44
+ expect(subject.make(hash)).to eq(normalized_hash)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require 'spec_helper'
11
+
12
+ describe HashMath::Table do
13
+ RowId = Struct.new(:id1, :id2)
14
+ FieldId = Struct.new(:name1, :name2)
15
+
16
+ let(:base_value) { 'NOT_ADDED' }
17
+
18
+ context 'with simple row and field id types' do
19
+ let(:prototype) do
20
+ HashMath::Record.new(%i[name age location], base_value)
21
+ end
22
+
23
+ subject { described_class.new(prototype) }
24
+
25
+ it 'works for integer row_id and symbol field_id' do
26
+ subject.add(1, :name, 'matt')
27
+ subject.add(2, :age, 990)
28
+ subject.add(3, :location, 'earth')
29
+
30
+ rows = subject.to_a
31
+
32
+ expected = [
33
+ described_class::Row.new(1, name: 'matt', age: base_value, location: base_value),
34
+ described_class::Row.new(2, name: base_value, age: 990, location: base_value),
35
+ described_class::Row.new(3, name: base_value, age: base_value, location: 'earth')
36
+ ]
37
+
38
+ expect(rows).to eq(expected)
39
+ end
40
+
41
+ it 'raises KeyOutOfBoundsError if field_id is not defined in the record' do
42
+ expect { subject.add(4, 'name', '') }.to raise_error(HashMath::KeyOutOfBoundsError)
43
+ expect { subject.add(4, :something_else, '') }.to raise_error(HashMath::KeyOutOfBoundsError)
44
+ end
45
+ end
46
+
47
+ context 'with more complex object subclass row and field id types' do
48
+ let(:prototype) do
49
+ HashMath::Record.new(
50
+ [
51
+ FieldId.new(:name, :first),
52
+ FieldId.new(:address, :st1)
53
+ ],
54
+ base_value
55
+ )
56
+ end
57
+
58
+ subject { described_class.new(prototype) }
59
+
60
+ it 'works for more complex row_id and field_id' do
61
+ subject.add(RowId.new(1, 2), FieldId.new(:name, :first), 'matt')
62
+ subject.add(RowId.new(3, 4), FieldId.new(:name, :first), 'nick')
63
+ subject.add(RowId.new(5, 6), FieldId.new(:name, :first), 'sam')
64
+
65
+ subject.add(RowId.new(1, 2), FieldId.new(:address, :st1), 'mag mile')
66
+ subject.add(RowId.new(3, 4), FieldId.new(:address, :st1), 'saturn ln.')
67
+
68
+ rows = subject.to_a
69
+
70
+ expected = [
71
+ described_class::Row.new(
72
+ RowId.new(1, 2),
73
+ FieldId.new(:name, :first) => 'matt',
74
+ FieldId.new(:address, :st1) => 'mag mile'
75
+ ),
76
+ described_class::Row.new(
77
+ RowId.new(3, 4),
78
+ FieldId.new(:name, :first) => 'nick',
79
+ FieldId.new(:address, :st1) => 'saturn ln.'
80
+ ),
81
+ described_class::Row.new(
82
+ RowId.new(5, 6),
83
+ FieldId.new(:name, :first) => 'sam',
84
+ FieldId.new(:address, :st1) => base_value
85
+ )
86
+ ]
87
+
88
+ expect(rows).to eq(expected)
89
+ end
90
+ end
91
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hash_math
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0.pre.alpha
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ruggio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-16 00:00:00.000000000 Z
11
+ date: 2019-09-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: guard-rspec
@@ -132,7 +132,14 @@ files:
132
132
  - bin/console
133
133
  - hash_math.gemspec
134
134
  - lib/hash_math.rb
135
+ - lib/hash_math/matrix.rb
136
+ - lib/hash_math/matrix/key_value_pair.rb
137
+ - lib/hash_math/record.rb
138
+ - lib/hash_math/table.rb
135
139
  - lib/hash_math/version.rb
140
+ - spec/hash_math/matrix_spec.rb
141
+ - spec/hash_math/record_spec.rb
142
+ - spec/hash_math/table_spec.rb
136
143
  - spec/spec_helper.rb
137
144
  homepage: https://github.com/bluemarblepayroll/hash_math
138
145
  licenses:
@@ -149,13 +156,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
149
156
  version: 2.3.8
150
157
  required_rubygems_version: !ruby/object:Gem::Requirement
151
158
  requirements:
152
- - - ">="
159
+ - - ">"
153
160
  - !ruby/object:Gem::Version
154
- version: '0'
161
+ version: 1.3.1
155
162
  requirements: []
156
163
  rubygems_version: 3.0.3
157
164
  signing_key:
158
165
  specification_version: 4
159
166
  summary: Hash-based data structures and algorithms
160
167
  test_files:
168
+ - spec/hash_math/matrix_spec.rb
169
+ - spec/hash_math/record_spec.rb
170
+ - spec/hash_math/table_spec.rb
161
171
  - spec/spec_helper.rb