hash_math 0.0.1 → 1.0.0.pre.alpha

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 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