differential 1.0.5 → 1.0.6

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
  SHA1:
3
- metadata.gz: 338faf87efae2afbc60eaa95b20fbfe0cddbf410
4
- data.tar.gz: 91afe0b117f23e33f86be2df86169fa23111152c
3
+ metadata.gz: fa747f8e377b675d626c4c49cd31f84a73ca9bf8
4
+ data.tar.gz: 4c3af655ca69988cffa9928a3debb84eaeb8206b
5
5
  SHA512:
6
- metadata.gz: 6a27dc65828848113eba8c0128ac39d791e2962e29ec7cfaa44e01bba160a057f5fff7b1d43d35de3fad9337316d67d75a6033e733810f41f7dd55f2d6c7c812
7
- data.tar.gz: fd0615b537efe24c4df38615abe47f082447dc3299d60724978aac18e6c0d4c926a9dbf694bf06677fafbf630d7349c24894755036df6f45601dbe8a5b65cc4b
6
+ metadata.gz: 6758f520698fa56574aa43b44e52a798db2c116200abea0ecbae1f14df36171d8f407e4755522ff70b95ac6328fc6117511a2efa11c8552bea0ed59e7d167eb9
7
+ data.tar.gz: b9e7a247c19f542fdc06783b324612d4a1d7ee6f7f8c43ece8f2925a175be1b13b0ac113cd852138f1d412eb621b0f2951a85685cfa1b2f353a9bc5e54e9b4f3
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  .DS_Store
2
2
  *.gem
3
+ /tmp
data/.travis.yml CHANGED
@@ -2,11 +2,9 @@ language: ruby
2
2
  rvm:
3
3
  - 2.3.1
4
4
  - 2.3.7
5
+ - 2.3.8
6
+ - 2.6.0
5
7
  cache: bundler
6
8
  script:
7
9
  - bundle exec rubocop
8
10
  - bundle exec rspec
9
- notifications:
10
- hipchat:
11
- rooms:
12
- secure: OpIo19mre1zR5gJlr1T7BD/jVBYadikM49ueC4HWPt3Wln6LlNM3G1gcXVw4A5Ppd7p+6251aOhLHA44HdjXSo+VrhfgiFO9tfkyNuVIrLxeZr/eQwEnv1JJlPJdL/y2sGsBS5WRIgo+txIkLflQ0zoDpvnR6zkWRaRYZcRWo+X9Q890VHRR0emHURX5Kqsi5sJjHac69uIRbEAtlvdd1KnfNXF6+2udMnH6Kb4BxrSUp6voQ+VTyTGM4f2uMInxvjTVNzCCLgb4zBa5KwZNjjLRXWwIsWC0jVia0IRNskaeoFkFQxsVb33kq55t8XxR/ZuHUr5exFUazPnEc3ht9L/GOCYX4qFwbVPyxwyVZ64hHLx3E5g4ozlVCvBH3MDqkoasep7x+Ml8RuA6lSM2hIM88Eo5g98wpXW2WPiHUTxbtIc/2qKTmMKPZI+J23tuR7kza/5kGyPlqKA5OXr++0MFIUtFhWs1iSSQnq0Anssfxd1EhXPKqR/vqpQVgNSpv/cJOMQInPHSkvcq7kMRQWxka9uXHFT1+YH3kYCsAB30bdp8IPMNKQuemGhqS7GZXke9M32Yx9TKykGyAkzv6NGSc1pUAEViGHuydm6mTdvXYBfTQ3ZE6SIP+Rx5/WCyAyPerADPMI26enlFzzSPucdVU8wErceH1Uq7AleVNFw=
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## 1.0.6 (January 11, 2019)
2
+
3
+ - Added Data Peeking for groups and items (group#data_peek, item#data_peek methods).
4
+ - Changed precision of Totals a_sigma, b_sigma, and delta to be BigDecimal with precision of 6.
5
+
6
+ ## 1.0.5 (January 11, 2019)
7
+
8
+ - Added lexicographic ID sorting (report#sorted_groups and group#sorted_items methods.)
9
+
1
10
  ## 1.0.4 (December 21, 2018)
2
11
 
3
12
  - Adjusted reader so it stores multipart ID's properly in the ID's data field.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- differential (1.0.5)
4
+ differential (1.0.6)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -184,7 +184,33 @@ reader_config = {
184
184
  }
185
185
  ```
186
186
 
187
- In this example we are showing that a unique identifier for an employee is not just the employee's ID, but also the companies ID. The above configuration would output a dataset that is grouped by transport type and direction (i.e. Outbound Train, Inbound Train, Outbound Car, etc...) and lists each unique employee per company in each group.
187
+ In this example we are showing that a unique identifier for an employee is not just the employee's ID, but also the companies ID. The above configuration would output a dataset that is grouped by transport type and direction (i.e. Outbound Train, Inbound Train, Outbound Car, etc...) and lists each unique employee per company in each group.
188
+
189
+ ### Data Peeking
190
+
191
+ *Raw data* is defined as the initial dataset(s) passed into Differential#calculate. The consumer application defines this raw data and what Differential does is parses, interprets, and pivots it based on the configuration sent in. By the time Differential is complete you will end up with a completely different result set than initially passed in. This does not mean you cannot trace back the raw data.
192
+
193
+ You still have access to the raw data after the data has been consumed and calculated within a report. An example of accessing this on a specific item would be:
194
+
195
+ ````
196
+ item.data_peek(:name)
197
+ ````
198
+
199
+ In the above example, the item would the first record added (precedence to side A, then B) and execute the field on the record's data value. If the data value is a hash, it will send it through the brackets [] method, if the data value is an object, it will check to see if it responds to field and call it if it can.
200
+
201
+ If you want to only check one side, you can also specify the side:
202
+
203
+ ````
204
+ item.data_peek(:name, ::Differential::Calculator::Side::A) # item.data_peek(:name, :a)
205
+ item.data_peek(:name, ::Differential::Calculator::Side::B) # item.data_peek(:name, :b)
206
+ ````
207
+
208
+ Data peeking also works at the group level, where it will look at the first item added:
209
+
210
+ ````
211
+ group.data_peek(:name)
212
+ ````
213
+
188
214
 
189
215
  ## Contributing
190
216
 
@@ -45,8 +45,17 @@ module Differential
45
45
  self
46
46
  end
47
47
 
48
+ def data_peek(field, side = nil)
49
+ first_item&.data_peek(field, side)
50
+ end
51
+
48
52
  private
49
53
 
54
+ def first_item
55
+ # first() will return an array: [key, value], but we just want the value.
56
+ @items_by_id.first&.last
57
+ end
58
+
50
59
  def upsert_item(record, side)
51
60
  item_id_key = record.id.value
52
61
  item_id = record.id
@@ -40,8 +40,30 @@ module Differential
40
40
  self
41
41
  end
42
42
 
43
+ def data_peek(field, side = nil)
44
+ data_object = record_peek(side)&.data
45
+
46
+ return nil unless data_object
47
+
48
+ if data_object.respond_to?(field)
49
+ data_object.send(field)
50
+ elsif data_object.respond_to?(:[])
51
+ data_object[field]
52
+ end
53
+ end
54
+
43
55
  private
44
56
 
57
+ def record_peek(side)
58
+ if [nil, A].include?(side) && a_records.any?
59
+ a_records
60
+ elsif [nil, B].include?(side) && b_records.any?
61
+ b_records
62
+ else
63
+ []
64
+ end.first
65
+ end
66
+
45
67
  def account_for_record(record, side)
46
68
  case side
47
69
  when A
@@ -16,15 +16,17 @@ module Differential
16
16
  class Totals
17
17
  include ::Differential::Calculator::Side
18
18
 
19
+ DIGITS = 6
20
+
19
21
  attr_reader :a_sigma,
20
22
  :a_size,
21
23
  :b_sigma,
22
24
  :b_size
23
25
 
24
26
  def initialize
25
- @a_sigma = 0
27
+ @a_sigma = BigDecimal(0, DIGITS)
26
28
  @a_size = 0
27
- @b_sigma = 0
29
+ @b_sigma = BigDecimal(0, DIGITS)
28
30
  @b_size = 0
29
31
  end
30
32
 
@@ -8,6 +8,7 @@
8
8
  #
9
9
 
10
10
  require 'forwardable'
11
+ require 'bigdecimal'
11
12
 
12
13
  require_relative 'calculator/calculator'
13
14
  require_relative 'parser/parser'
@@ -8,5 +8,5 @@
8
8
  #
9
9
 
10
10
  module Differential
11
- VERSION = '1.0.5'
11
+ VERSION = '1.0.6'
12
12
  end
@@ -41,4 +41,15 @@ describe ::Differential::Calculator::Group do
41
41
 
42
42
  expect(actual_ids).to eq(expected_ids)
43
43
  end
44
+
45
+ it 'should peek at data based on first item it finds' do
46
+ record = ::Differential::Parser::Record.new(id: '1',
47
+ group_id: group_id,
48
+ value: 1,
49
+ data: { name: 'Millie' })
50
+
51
+ group.add(record, ::Differential::Calculator::Side::A)
52
+
53
+ expect(group.data_peek(:name)).to eq(record.data[:name])
54
+ end
44
55
  end
@@ -10,11 +10,153 @@
10
10
  require './spec/spec_helper'
11
11
 
12
12
  describe ::Differential::Calculator::Item do
13
- let(:id) { 'matt' }
13
+ let(:id) { '1' }
14
14
 
15
15
  let(:item) { ::Differential::Calculator::Item.new(id) }
16
16
 
17
17
  it 'should initialize correctly' do
18
18
  expect(item.id).to eq(id)
19
19
  end
20
+
21
+ context 'data peeking' do
22
+ let(:matt_data_hash) { { name: 'matt' } }
23
+
24
+ let(:matt_data_object) { OpenStruct.new(matt_data_hash) }
25
+
26
+ let(:matt_record) do
27
+ ::Differential::Parser::Record.new(
28
+ id: '1',
29
+ group_id: '1',
30
+ value: 1,
31
+ data: matt_data_hash
32
+ )
33
+ end
34
+
35
+ let(:matt_record_with_data_object) do
36
+ ::Differential::Parser::Record.new(
37
+ id: '1',
38
+ group_id: '1',
39
+ value: 1,
40
+ data: matt_data_object
41
+ )
42
+ end
43
+
44
+ let(:nick_record) do
45
+ ::Differential::Parser::Record.new(
46
+ id: '1',
47
+ group_id: '1',
48
+ value: 2,
49
+ data: { name: 'nick' }
50
+ )
51
+ end
52
+
53
+ let(:sam_record) do
54
+ ::Differential::Parser::Record.new(
55
+ id: '1',
56
+ group_id: '1',
57
+ value: 3,
58
+ data: { name: 'sam' }
59
+ )
60
+ end
61
+
62
+ let(:katie_record) do
63
+ ::Differential::Parser::Record.new(
64
+ id: '1',
65
+ group_id: '1',
66
+ value: 4,
67
+ data: { name: 'katie' }
68
+ )
69
+ end
70
+
71
+ it 'should work when data is an object' do
72
+ item.add(matt_record_with_data_object, ::Differential::Calculator::Side::A)
73
+
74
+ expect(item.data_peek(:name)).to eq(matt_data_object.name)
75
+ end
76
+
77
+ it 'should work when data is a hash' do
78
+ item.add(matt_record, ::Differential::Calculator::Side::A)
79
+
80
+ expect(item.data_peek(:name)).to eq(matt_data_hash[:name])
81
+ end
82
+
83
+ context 'when side is nil' do
84
+ it 'should peek side A when both sides have records' do
85
+ item.add(matt_record, ::Differential::Calculator::Side::A)
86
+ item.add(nick_record, ::Differential::Calculator::Side::A)
87
+ item.add(sam_record, ::Differential::Calculator::Side::B)
88
+ item.add(katie_record, ::Differential::Calculator::Side::B)
89
+
90
+ expect(item.data_peek(:name)).to eq(matt_record.data[:name])
91
+ end
92
+
93
+ it 'should peek side A when only side A has records' do
94
+ item.add(matt_record, ::Differential::Calculator::Side::A)
95
+ item.add(nick_record, ::Differential::Calculator::Side::A)
96
+
97
+ expect(item.data_peek(:name)).to eq(matt_record.data[:name])
98
+ end
99
+
100
+ it 'should peek side B when only side B has records' do
101
+ item.add(sam_record, ::Differential::Calculator::Side::B)
102
+ item.add(katie_record, ::Differential::Calculator::Side::B)
103
+
104
+ expect(item.data_peek(:name)).to eq(sam_record.data[:name])
105
+ end
106
+ end
107
+
108
+ context 'when side is A' do
109
+ let(:side) { ::Differential::Calculator::Side::A }
110
+
111
+ it 'should peek side A when both sides have records' do
112
+ item.add(matt_record, ::Differential::Calculator::Side::A)
113
+ item.add(nick_record, ::Differential::Calculator::Side::A)
114
+ item.add(sam_record, ::Differential::Calculator::Side::B)
115
+ item.add(katie_record, ::Differential::Calculator::Side::B)
116
+
117
+ expect(item.data_peek(:name, side)).to eq(matt_record.data[:name])
118
+ end
119
+
120
+ it 'should peek side A when only side A has records' do
121
+ item.add(matt_record, ::Differential::Calculator::Side::A)
122
+ item.add(nick_record, ::Differential::Calculator::Side::A)
123
+
124
+ expect(item.data_peek(:name, side)).to eq(matt_record.data[:name])
125
+ end
126
+
127
+ it 'should return nil when only side B has records' do
128
+ item.add(sam_record, ::Differential::Calculator::Side::B)
129
+ item.add(katie_record, ::Differential::Calculator::Side::B)
130
+
131
+ expect(item.data_peek(:name, side)).to eq(nil)
132
+ end
133
+ end
134
+
135
+ context 'when side is B' do
136
+ let(:side) { ::Differential::Calculator::Side::B }
137
+
138
+ it 'should peek side B when both sides have records' do
139
+ item.add(matt_record, ::Differential::Calculator::Side::A)
140
+ item.add(nick_record, ::Differential::Calculator::Side::A)
141
+ item.add(sam_record, ::Differential::Calculator::Side::B)
142
+ item.add(katie_record, ::Differential::Calculator::Side::B)
143
+
144
+ expect(item.data_peek(:name, side)).to eq(sam_record.data[:name])
145
+ end
146
+
147
+ it 'should peek side B when only side B has records' do
148
+ item.add(sam_record, ::Differential::Calculator::Side::B)
149
+ item.add(katie_record, ::Differential::Calculator::Side::B)
150
+
151
+ expect(item.data_peek(:name, side)).to eq(sam_record.data[:name])
152
+ end
153
+
154
+ it 'should return nil when only side A has records' do
155
+ item.add(matt_record, ::Differential::Calculator::Side::A)
156
+ item.add(nick_record, ::Differential::Calculator::Side::A)
157
+
158
+ expect(item.data_peek(:name, side)).to eq(nil)
159
+ end
160
+ end
161
+ end
20
162
  end
data/spec/spec_helper.rb CHANGED
@@ -7,4 +7,6 @@
7
7
  # LICENSE file in the root directory of this source tree.
8
8
  #
9
9
 
10
+ require 'ostruct'
11
+
10
12
  require './lib/differential'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: differential
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 1.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ruggio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-27 00:00:00.000000000 Z
11
+ date: 2019-01-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: guard-rspec