paged_groups 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: cb8ac318e3df020ef112bcfd9a44fef6883519682be6501de014e745148b4046
4
+ data.tar.gz: 7d69dea71a15bf728052cdfe80341e24b2ac32b0bc93bf5ab3f3b0891bd66b4f
5
+ SHA512:
6
+ metadata.gz: f60342818d52bce7432752e19d852f47a8cb28ca2a9d5216b39175e1ba47e9f71b9f2a8bb970751cc59a162c3d6af140dce2e95bfed5fcea53605b1b2b0e0c09
7
+ data.tar.gz: 86a0b7432ee2cefb13aad7b9e9d13ca1e2d35f60e93ebc58b798a2700816810be09c5b5580f26c10a6144664483aea9877108f1dea44983a20de647dc1c05c95
@@ -0,0 +1,8 @@
1
+ # See http://editorconfig.org/
2
+
3
+ [*]
4
+ trim_trailing_whitespace = true
5
+ indent_style = space
6
+ indent_size = 2
7
+ insert_final_newline = true
8
+ end_of_line = lf
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ *.gem
3
+ /tmp
@@ -0,0 +1,8 @@
1
+ Metrics/LineLength:
2
+ Max: 100
3
+
4
+ Metrics/BlockLength:
5
+ ExcludedMethods: ['it', 'describe', 'context', 'let', 'specify']
6
+
7
+ AllCops:
8
+ TargetRubyVersion: 2.3
@@ -0,0 +1 @@
1
+ 2.6.0
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ rvm:
3
+ # Build on the latest stable of all supported Rubies (https://www.ruby-lang.org/en/downloads/):
4
+ - 2.3.8
5
+ - 2.4.5
6
+ - 2.5.3
7
+ - 2.6.0
8
+ cache: bundler
9
+ script:
10
+ - bundle exec rubocop
11
+ - bundle exec rspec
@@ -0,0 +1,3 @@
1
+ # 1.0.0 (January 26th, 2019)
2
+
3
+ Initial Release
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
@@ -0,0 +1,87 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ paged_groups (1.0.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.0)
10
+ coderay (1.1.2)
11
+ diff-lcs (1.3)
12
+ ffi (1.9.25)
13
+ formatador (0.2.5)
14
+ guard (2.15.0)
15
+ formatador (>= 0.2.4)
16
+ listen (>= 2.7, < 4.0)
17
+ lumberjack (>= 1.0.12, < 2.0)
18
+ nenv (~> 0.1)
19
+ notiffany (~> 0.0)
20
+ pry (>= 0.9.12)
21
+ shellany (~> 0.0)
22
+ thor (>= 0.18.1)
23
+ guard-compat (1.2.1)
24
+ guard-rspec (4.7.3)
25
+ guard (~> 2.1)
26
+ guard-compat (~> 1.1)
27
+ rspec (>= 2.99.0, < 4.0)
28
+ jaro_winkler (1.5.1)
29
+ listen (3.1.5)
30
+ rb-fsevent (~> 0.9, >= 0.9.4)
31
+ rb-inotify (~> 0.9, >= 0.9.7)
32
+ ruby_dep (~> 1.2)
33
+ lumberjack (1.0.13)
34
+ method_source (0.9.2)
35
+ nenv (0.3.0)
36
+ notiffany (0.1.1)
37
+ nenv (~> 0.1)
38
+ shellany (~> 0.0)
39
+ parallel (1.12.1)
40
+ parser (2.5.3.0)
41
+ ast (~> 2.4.0)
42
+ powerpack (0.1.2)
43
+ pry (0.12.2)
44
+ coderay (~> 1.1.0)
45
+ method_source (~> 0.9.0)
46
+ rainbow (3.0.0)
47
+ rb-fsevent (0.10.3)
48
+ rb-inotify (0.9.10)
49
+ ffi (>= 0.5.0, < 2)
50
+ rspec (3.8.0)
51
+ rspec-core (~> 3.8.0)
52
+ rspec-expectations (~> 3.8.0)
53
+ rspec-mocks (~> 3.8.0)
54
+ rspec-core (3.8.0)
55
+ rspec-support (~> 3.8.0)
56
+ rspec-expectations (3.8.2)
57
+ diff-lcs (>= 1.2.0, < 2.0)
58
+ rspec-support (~> 3.8.0)
59
+ rspec-mocks (3.8.0)
60
+ diff-lcs (>= 1.2.0, < 2.0)
61
+ rspec-support (~> 3.8.0)
62
+ rspec-support (3.8.0)
63
+ rubocop (0.59.2)
64
+ jaro_winkler (~> 1.5.1)
65
+ parallel (~> 1.10)
66
+ parser (>= 2.5, != 2.5.1.1)
67
+ powerpack (~> 0.1)
68
+ rainbow (>= 2.2.2, < 4.0)
69
+ ruby-progressbar (~> 1.7)
70
+ unicode-display_width (~> 1.0, >= 1.0.1)
71
+ ruby-progressbar (1.10.0)
72
+ ruby_dep (1.5.0)
73
+ shellany (0.0.1)
74
+ thor (0.20.3)
75
+ unicode-display_width (1.4.0)
76
+
77
+ PLATFORMS
78
+ ruby
79
+
80
+ DEPENDENCIES
81
+ guard-rspec (~> 4.7)
82
+ paged_groups!
83
+ rspec (~> 3.8)
84
+ rubocop (~> 0.59)
85
+
86
+ BUNDLED WITH
87
+ 1.17.3
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ guard :rspec, cmd: 'bundle exec rspec' do
4
+ require 'guard/rspec/dsl'
5
+ dsl = Guard::RSpec::Dsl.new(self)
6
+
7
+ # RSpec files
8
+ rspec = dsl.rspec
9
+ watch(rspec.spec_helper) { rspec.spec_dir }
10
+ watch(rspec.spec_support) { rspec.spec_dir }
11
+ watch(rspec.spec_files)
12
+
13
+ # Ruby files
14
+ ruby = dsl.ruby
15
+ dsl.watch_spec_files_for(ruby.lib_files)
16
+ end
data/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2018 Blue Marble Payroll, LLC
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,245 @@
1
+ # paged_groups
2
+
3
+ [![Build Status](https://travis-ci.org/bluemarblepayroll/paged_groups.svg?branch=master)](https://travis-ci.org/bluemarblepayroll/paged_groups)
4
+
5
+ Imagine a two-dimensional data set (first dimension being group and second dimension being record) for which you wanted to page with the following rules:
6
+
7
+ 1. Each page should roughly has the same number of records ([greedy](https://en.wikipedia.org/wiki/Greedy_algorithm))
8
+ 2. Each group should not be split between pages ([atomic](https://en.wikipedia.org/wiki/Atomicity_(database_systems)))
9
+
10
+ This library helps you page grouped-data when the grouped data can have different sizes. It provides a builder that understands how to split pages in a fashion where each page tries to conform to a maximum page size but also ensures groups are not split up.
11
+
12
+ ## Installation
13
+
14
+ To install through Rubygems:
15
+
16
+ ````
17
+ gem install install paged_groups
18
+ ````
19
+
20
+ You can also add this to your Gemfile:
21
+
22
+ ````
23
+ bundle add paged_groups
24
+ ````
25
+
26
+ ## Examples
27
+
28
+ ### Standard Use-Case
29
+
30
+ Here is an example data set containing groups with variable number of records:
31
+
32
+ ````ruby
33
+ data = [
34
+ [
35
+ { id: 1, name: 'Jordan' },
36
+ { id: 2, name: 'Pippen' },
37
+ { id: 3, name: 'Rodman' },
38
+ { id: 4, name: 'Harper' },
39
+ { id: 5, name: 'Longley' }
40
+ ],
41
+ [
42
+ { id: 6, name: 'Kukoc' }
43
+ ],
44
+ [
45
+ { id: 7, name: 'Kerr' }
46
+ ],
47
+ [
48
+ { id: 8, name: 'Buechler' }
49
+ ],
50
+ [
51
+ { id: 9, name: 'Wennington' },
52
+ { id: 10, name: 'Simpkins' }
53
+ ],
54
+ [
55
+ { id: 11, name: 'Caffey' },
56
+ { id: 12, name: 'Edwards' },
57
+ { id: 13, name: 'Salley' }
58
+ ]
59
+ ]
60
+ ````
61
+
62
+ Let's use max page size of three for this example. In the real-world a max page size of three is most likely too small but it fits our example data set above for illustration purpose; you should be able to extrapolate this out with larger sets and larger max page sizes. To page this set we would execute:
63
+
64
+ ````ruby
65
+ pages = PagedGroups.builder(page_size: 3).add(*data).all
66
+ ````
67
+
68
+ *Note:* We are using the splat (asterisk) operator to indicate each group is an argument.
69
+
70
+ our ````pages```` variable should now contain a two-dimensional array where dimension one is page and dimension two is record and would be:
71
+
72
+ ````ruby
73
+ [
74
+ [
75
+ { id: 1, name: 'Jordan' },
76
+ { id: 2, name: 'Pippen' },
77
+ { id: 3, name: 'Rodman' },
78
+ { id: 4, name: 'Harper' },
79
+ { id: 5, name: 'Longley' }
80
+ ],
81
+ [
82
+ { id: 6, name: 'Kukoc' },
83
+ { id: 7, name: 'Kerr' },
84
+ { id: 8, name: 'Buechler' }
85
+ ],
86
+ [
87
+ { id: 9, name: 'Wennington' },
88
+ { id: 10, name: 'Simpkins' }
89
+ ],
90
+ [
91
+ { id: 11, name: 'Caffey' },
92
+ { id: 12, name: 'Edwards' },
93
+ { id: 13, name: 'Salley' }
94
+ ]
95
+ ]
96
+ ````
97
+
98
+ Notice how each group was kept atomic while each page was tried to be kept as close to the max page size as possible.
99
+
100
+ ### Spacing Customization
101
+
102
+ There may be merit in placing *separator* record in between groups in the same page. This separate record can act as a spacer. You can specify this spacer row in the builder's constructor:
103
+
104
+ ````ruby
105
+ pages = PagedGroups.builder(page_size: 3, space: true, spacer: { id: nil, name: '' })
106
+ .add(*data)
107
+ .all
108
+ ````
109
+
110
+ *Note:* ````spacer```` (boolean) argument is split from ````space```` (object) to allow for spacer to be anything (even false or nil.)
111
+
112
+ Now, our resulting pages would become:
113
+
114
+ ````ruby
115
+ [
116
+ [
117
+ { id: 1, name: 'Jordan' },
118
+ { id: 2, name: 'Pippen' },
119
+ { id: 3, name: 'Rodman' },
120
+ { id: 4, name: 'Harper' },
121
+ { id: 5, name: 'Longley' }
122
+ ],
123
+ [
124
+ { id: 6, name: 'Kukoc' },
125
+ { id: nil, name: '' },
126
+ { id: 7, name: 'Kerr' }
127
+ ],
128
+ [
129
+ { id: 8, name: 'Buechler' },
130
+ { id: nil, name: '' },
131
+ { id: 9, name: 'Wennington' },
132
+ { id: 10, name: 'Simpkins' }
133
+ ],
134
+ [
135
+ { id: 11, name: 'Caffey' },
136
+ { id: 12, name: 'Edwards' },
137
+ { id: 13, name: 'Salley' }
138
+ ]
139
+ ]
140
+ ````
141
+
142
+
143
+ ### Forcing Same Page
144
+
145
+ Another customization that may come in handy is the ability to force-add groups to the current page. For example, say we wanted to add another group to our initial data set, but we want it to end up on the same page as the last records:
146
+
147
+ ````ruby
148
+ other_data = [
149
+ [
150
+ { id: 14, name: 'Jackson' },
151
+ { id: 14, name: 'Winters' }
152
+ ]
153
+ ]
154
+ pages = PagedGroups.builder(page_size: 3, space: true, spacer: { id: nil, name: '' })
155
+ .add(*data)
156
+ .add(*other_data, force: true)
157
+ .all
158
+ ````
159
+
160
+ *Note:* #add has a [fluent interface](https://en.wikipedia.org/wiki/Fluent_interface) and can be chained as illustrated above.
161
+
162
+ Now the result pages would be:
163
+
164
+ ````ruby
165
+ [
166
+ [
167
+ { id: 1, name: 'Jordan' },
168
+ { id: 2, name: 'Pippen' },
169
+ { id: 3, name: 'Rodman' },
170
+ { id: 4, name: 'Harper' },
171
+ { id: 5, name: 'Longley' }
172
+ ],
173
+ [
174
+ { id: 6, name: 'Kukoc' },
175
+ { id: nil, name: '' },
176
+ { id: 7, name: 'Kerr' }
177
+ ],
178
+ [
179
+ { id: 8, name: 'Buechler' },
180
+ { id: nil, name: '' },
181
+ { id: 9, name: 'Wennington' },
182
+ { id: 10, name: 'Simpkins' }
183
+ ],
184
+ [
185
+ { id: 11, name: 'Caffey' },
186
+ { id: 12, name: 'Edwards' },
187
+ { id: 13, name: 'Salley' },
188
+ { id: nil, name: '' },
189
+ { id: 14, name: 'Jackson' },
190
+ { id: 14, name: 'Winters' }
191
+ ]
192
+ ]
193
+ ````
194
+
195
+ ## Contributing
196
+
197
+ ### Development Environment Configuration
198
+
199
+ Basic steps to take to get this repository compiling:
200
+
201
+ 1. Install [Ruby](https://www.ruby-lang.org/en/documentation/installation/) (check paged_groups.gemspec for versions supported)
202
+ 2. Install bundler (gem install bundler)
203
+ 3. Clone the repository (git clone git@github.com:bluemarblepayroll/paged_groups.git)
204
+ 4. Navigate to the root folder (cd paged_groups)
205
+ 5. Install dependencies (bundle)
206
+
207
+ ### Running Tests
208
+
209
+ To execute the test suite run:
210
+
211
+ ````
212
+ bundle exec rspec spec --format documentation
213
+ ````
214
+
215
+ Alternatively, you can have Guard watch for changes:
216
+
217
+ ````
218
+ bundle exec guard
219
+ ````
220
+
221
+ Also, do not forget to run Rubocop:
222
+
223
+ ````
224
+ bundle exec rubocop
225
+ ````
226
+
227
+ ### Publishing
228
+
229
+ Note: ensure you have proper authorization before trying to publish new versions.
230
+
231
+ After code changes have successfully gone through the Pull Request review process then the following steps should be followed for publishing new versions:
232
+
233
+ 1. Merge Pull Request into master
234
+ 2. Update [lib/paged_groups/version.rb](https://github.com/bluemarblepayroll/paged_groups/blob/master/lib/paged_groups/version.rb) [version number](https://semver.org/)
235
+ 3. Bundle
236
+ 4. Update CHANGELOG.md
237
+ 5. Commit & Push master to remote and ensure CI builds master successfully
238
+ 6. Build the project locally: `gem build paged_groups`
239
+ 7. Publish package to NPM: `gem push paged_groups-X.gem` where X is the version to push
240
+ 8. Tag master with new version: `git tag <version>`
241
+ 9. Push tags remotely: `git push origin --tags`
242
+
243
+ ## License
244
+
245
+ This project is MIT Licensed.
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'paged_groups'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start
@@ -0,0 +1,10 @@
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 'paged_groups/paged_groups'
@@ -0,0 +1,107 @@
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 PagedGroups
11
+ # This is the Public API for this library.
12
+ class Builder
13
+ DEFAULT_PAGE_SIZE = 50
14
+
15
+ attr_reader :page_size,
16
+ :page_count,
17
+ :row_count,
18
+ :space,
19
+ :spacer
20
+
21
+ def initialize(page_size: DEFAULT_PAGE_SIZE, space: false, spacer: nil)
22
+ @page_size = page_size ? page_size.to_i : DEFAULT_PAGE_SIZE
23
+ @space = space || false
24
+ @spacer = spacer
25
+
26
+ clear
27
+ end
28
+
29
+ def add(*groups, force: false)
30
+ dirty!
31
+
32
+ groups.each { |group| insert(Array(group), force: force) }
33
+
34
+ self
35
+ end
36
+
37
+ def clear
38
+ dirty!
39
+
40
+ @pages = []
41
+ @page_count = 0
42
+ @current_page = []
43
+ @row_count = 0
44
+ end
45
+
46
+ def all
47
+ return @all if @all
48
+
49
+ @all = top? ? @pages : @pages + [@current_page]
50
+ end
51
+ alias to_a all
52
+
53
+ def to_s
54
+ "[#{self.class.name}] Page Count: #{page_count}, Row Count: #{row_count}"
55
+ end
56
+
57
+ private
58
+
59
+ def insert(rows, force: false)
60
+ cut! if start_new_page?(rows) && !force
61
+
62
+ space_if_needed
63
+
64
+ @current_page += rows
65
+
66
+ @row_count += rows.length
67
+
68
+ self
69
+ end
70
+
71
+ def not_top?
72
+ !top?
73
+ end
74
+
75
+ def top?
76
+ @current_page.empty?
77
+ end
78
+
79
+ def dirty!
80
+ @all = nil
81
+ end
82
+
83
+ def cut!
84
+ @page_count += 1
85
+ @pages << @current_page
86
+ @current_page = []
87
+
88
+ nil
89
+ end
90
+
91
+ def space_if_needed
92
+ @current_page << spacer if space && not_top?
93
+
94
+ nil
95
+ end
96
+
97
+ def start_new_page?(next_items)
98
+ proposed_current_page_length = @current_page.length + next_items.length
99
+
100
+ not_top? && proposed_current_page_length > page_size
101
+ end
102
+
103
+ def end_of_current_page?
104
+ @current_page.length >= page_size
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,21 @@
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 'builder'
11
+
12
+ # Top-level namespace for primary public API.
13
+ module PagedGroups
14
+ class << self
15
+ # This is syntactic sugar and is equivalent to: PagedGroups::Builder.new(args)
16
+ # Check the constructor signature of PagedGroups::Builder for argument definition.
17
+ def builder(*args)
18
+ ::PagedGroups::Builder.new(*args)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,12 @@
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 PagedGroups
11
+ VERSION = '1.0.0'
12
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require './lib/paged_groups/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'paged_groups'
7
+ s.version = PagedGroups::VERSION
8
+ s.summary = 'Create an evenly paged dataset of un-evenly sized groups'
9
+
10
+ s.description = <<-DESCRIPTION
11
+ This library helps you page grouped-data when the grouped data can have different sizes.
12
+ It provides a builder that understands how to split pages in a fashion where each page tries to
13
+ conform to a maximum page size (greedy) but also ensures groups are not split up (atomic.)
14
+ DESCRIPTION
15
+
16
+ s.authors = ['Matthew Ruggio']
17
+ s.email = ['mruggio@bluemarblepayroll.com']
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
21
+ s.homepage = 'https://github.com/bluemarblepayroll/paged_groups'
22
+ s.license = 'MIT'
23
+
24
+ s.required_ruby_version = '>= 2.3.8'
25
+
26
+ s.add_development_dependency('guard-rspec', '~>4.7')
27
+ s.add_development_dependency('rspec', '~> 3.8')
28
+ s.add_development_dependency('rubocop', '~> 0.59')
29
+ end
@@ -0,0 +1,64 @@
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/spec_helper'
11
+
12
+ describe ::PagedGroups::Builder do
13
+ let(:page_size) { 44 }
14
+
15
+ let(:spacer) { 'SPACER' }
16
+
17
+ let(:page_builder) do
18
+ ::PagedGroups::Builder.new(page_size: page_size, spacer: spacer, space: true)
19
+ end
20
+
21
+ let(:hundred_rows) { Array.new(100) }
22
+
23
+ let(:twenty_rows) { Array.new(20) }
24
+
25
+ subject { page_builder }
26
+
27
+ it { expect(page_builder.page_size).to eq(page_size) }
28
+
29
+ describe '#add and #all' do
30
+ it 'should page groups' do
31
+ page_builder.add(hundred_rows)
32
+
33
+ expect(page_builder.all.length).to eq(1)
34
+
35
+ page_builder.add(twenty_rows)
36
+ page_builder.add(twenty_rows)
37
+
38
+ expect(page_builder.all.length).to eq(2)
39
+
40
+ page_builder.add(twenty_rows)
41
+
42
+ expect(page_builder.all.length).to eq(3)
43
+ end
44
+
45
+ it 'should force add and space' do
46
+ page_builder.add(hundred_rows)
47
+
48
+ expect(page_builder.all.length).to eq(1)
49
+ expect(page_builder.all.first.length).to eq(100)
50
+
51
+ page_builder.add(twenty_rows, force: true)
52
+ page_builder.add(twenty_rows, force: true)
53
+
54
+ expect(page_builder.all.length).to eq(1)
55
+ expect(page_builder.all.first.length).to eq(100 + 20 * 2 + 2)
56
+
57
+ first_spacer_index = 100
58
+ second_spacer_index = 100 + 20 + 1
59
+
60
+ expect(page_builder.all.first[first_spacer_index]).to eq(spacer)
61
+ expect(page_builder.all.first[second_spacer_index]).to eq(spacer)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,157 @@
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/spec_helper'
11
+
12
+ describe ::PagedGroups do
13
+ describe 'README examples' do
14
+ let(:data) do
15
+ [
16
+ [
17
+ { id: 1, name: 'Jordan' },
18
+ { id: 2, name: 'Pippen' },
19
+ { id: 3, name: 'Rodman' },
20
+ { id: 4, name: 'Harper' },
21
+ { id: 5, name: 'Longley' }
22
+ ],
23
+ [
24
+ { id: 6, name: 'Kukoc' }
25
+ ],
26
+ [
27
+ { id: 7, name: 'Kerr' }
28
+ ],
29
+ [
30
+ { id: 8, name: 'Buechler' }
31
+ ],
32
+ [
33
+ { id: 9, name: 'Wennington' },
34
+ { id: 10, name: 'Simpkins' }
35
+ ],
36
+ [
37
+ { id: 11, name: 'Caffey' },
38
+ { id: 12, name: 'Edwards' },
39
+ { id: 13, name: 'Salley' }
40
+ ]
41
+ ]
42
+ end
43
+
44
+ let(:page_size) { 3 }
45
+
46
+ let(:spacer) { { id: nil, name: '' } }
47
+
48
+ specify 'Standard use-case example works as advertised' do
49
+ pages = PagedGroups.builder(page_size: page_size).add(*data).all
50
+
51
+ expected_pages = [
52
+ [
53
+ { id: 1, name: 'Jordan' },
54
+ { id: 2, name: 'Pippen' },
55
+ { id: 3, name: 'Rodman' },
56
+ { id: 4, name: 'Harper' },
57
+ { id: 5, name: 'Longley' }
58
+ ],
59
+ [
60
+ { id: 6, name: 'Kukoc' },
61
+ { id: 7, name: 'Kerr' },
62
+ { id: 8, name: 'Buechler' }
63
+ ],
64
+ [
65
+ { id: 9, name: 'Wennington' },
66
+ { id: 10, name: 'Simpkins' }
67
+ ],
68
+ [
69
+ { id: 11, name: 'Caffey' },
70
+ { id: 12, name: 'Edwards' },
71
+ { id: 13, name: 'Salley' }
72
+ ]
73
+ ]
74
+
75
+ expect(pages).to eq(expected_pages)
76
+ end
77
+
78
+ specify 'Spacing customization example works as advertised' do
79
+ pages = PagedGroups.builder(page_size: page_size, space: true, spacer: spacer)
80
+ .add(*data)
81
+ .all
82
+
83
+ expected_pages = [
84
+ [
85
+ { id: 1, name: 'Jordan' },
86
+ { id: 2, name: 'Pippen' },
87
+ { id: 3, name: 'Rodman' },
88
+ { id: 4, name: 'Harper' },
89
+ { id: 5, name: 'Longley' }
90
+ ],
91
+ [
92
+ { id: 6, name: 'Kukoc' },
93
+ { id: nil, name: '' },
94
+ { id: 7, name: 'Kerr' }
95
+ ],
96
+ [
97
+ { id: 8, name: 'Buechler' },
98
+ { id: nil, name: '' },
99
+ { id: 9, name: 'Wennington' },
100
+ { id: 10, name: 'Simpkins' }
101
+ ],
102
+ [
103
+ { id: 11, name: 'Caffey' },
104
+ { id: 12, name: 'Edwards' },
105
+ { id: 13, name: 'Salley' }
106
+ ]
107
+ ]
108
+
109
+ expect(pages).to eq(expected_pages)
110
+ end
111
+
112
+ specify 'Forcing same page example works as advertised' do
113
+ other_data = [
114
+ [
115
+ { id: 14, name: 'Jackson' },
116
+ { id: 14, name: 'Winters' }
117
+ ]
118
+ ]
119
+
120
+ pages = PagedGroups.builder(page_size: page_size, space: true, spacer: spacer)
121
+ .add(*data)
122
+ .add(*other_data, force: true)
123
+ .all
124
+
125
+ expected_pages = [
126
+ [
127
+ { id: 1, name: 'Jordan' },
128
+ { id: 2, name: 'Pippen' },
129
+ { id: 3, name: 'Rodman' },
130
+ { id: 4, name: 'Harper' },
131
+ { id: 5, name: 'Longley' }
132
+ ],
133
+ [
134
+ { id: 6, name: 'Kukoc' },
135
+ { id: nil, name: '' },
136
+ { id: 7, name: 'Kerr' }
137
+ ],
138
+ [
139
+ { id: 8, name: 'Buechler' },
140
+ { id: nil, name: '' },
141
+ { id: 9, name: 'Wennington' },
142
+ { id: 10, name: 'Simpkins' }
143
+ ],
144
+ [
145
+ { id: 11, name: 'Caffey' },
146
+ { id: 12, name: 'Edwards' },
147
+ { id: 13, name: 'Salley' },
148
+ { id: nil, name: '' },
149
+ { id: 14, name: 'Jackson' },
150
+ { id: 14, name: 'Winters' }
151
+ ]
152
+ ]
153
+
154
+ expect(pages).to eq(expected_pages)
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,10 @@
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 './lib/paged_groups'
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: paged_groups
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Matthew Ruggio
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-01-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: guard-rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.8'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.59'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.59'
55
+ description: |2
56
+ This library helps you page grouped-data when the grouped data can have different sizes.
57
+ It provides a builder that understands how to split pages in a fashion where each page tries to
58
+ conform to a maximum page size (greedy) but also ensures groups are not split up (atomic.)
59
+ email:
60
+ - mruggio@bluemarblepayroll.com
61
+ executables:
62
+ - console
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - ".editorconfig"
67
+ - ".gitignore"
68
+ - ".rubocop.yml"
69
+ - ".ruby-version"
70
+ - ".travis.yml"
71
+ - CHANGELOG.md
72
+ - Gemfile
73
+ - Gemfile.lock
74
+ - Guardfile
75
+ - LICENSE
76
+ - README.md
77
+ - bin/console
78
+ - lib/paged_groups.rb
79
+ - lib/paged_groups/builder.rb
80
+ - lib/paged_groups/paged_groups.rb
81
+ - lib/paged_groups/version.rb
82
+ - paged_groups.gemspec
83
+ - spec/paged_groups/builder_spec.rb
84
+ - spec/paged_groups/paged_groups_spec.rb
85
+ - spec/spec_helper.rb
86
+ homepage: https://github.com/bluemarblepayroll/paged_groups
87
+ licenses:
88
+ - MIT
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: 2.3.8
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubygems_version: 3.0.1
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: Create an evenly paged dataset of un-evenly sized groups
109
+ test_files:
110
+ - spec/paged_groups/builder_spec.rb
111
+ - spec/paged_groups/paged_groups_spec.rb
112
+ - spec/spec_helper.rb