cross_table 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0bcc53f43aac877f900cb638581320071b6c96a2920517c9952270a919874833
4
+ data.tar.gz: 406e52dcf8f08c8c5925b3488e04556c95170c6e5403474f12c6eb9e5bcf9c6b
5
+ SHA512:
6
+ metadata.gz: bd223cafe127ffebb432669ee586df26e0cf0c759e2ec5243c29707759612a022dcf27b12b5a9c8ed5df56d70d51ae35445d069227ed8a838a83520fd6b67325
7
+ data.tar.gz: df08520e8cf9e8eef3cb92e48ef9f9d02f0afab0e93c190d17d6f69125434990935bcae96d13ab6acda776e387b5762b1983fcd8d915eb3d6e77c02088b13efc
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.rubocop.yml ADDED
@@ -0,0 +1,10 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ Style/TrailingCommaInArrayLiteral:
4
+ Enabled: false
5
+
6
+ Style/TrailingCommaInHashLiteral:
7
+ Enabled: false
8
+
9
+ Style/YodaCondition:
10
+ Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,21 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2019-06-18 13:29:48 +0900 using RuboCop version 0.71.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 3
10
+ Metrics/AbcSize:
11
+ Max: 58
12
+
13
+ # Offense count: 3
14
+ # Configuration parameters: CountComments, ExcludedMethods.
15
+ Metrics/MethodLength:
16
+ Max: 45
17
+
18
+ # Offense count: 3
19
+ # Configuration parameters: CountKeywordArgs.
20
+ Metrics/ParameterLists:
21
+ Max: 6
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in cross_table.gemspec
6
+ gemspec
7
+
8
+ gem 'rubocop', require: false
data/Gemfile.lock ADDED
@@ -0,0 +1,36 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ cross_table (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.0)
10
+ jaro_winkler (1.5.2)
11
+ parallel (1.17.0)
12
+ parser (2.6.3.0)
13
+ ast (~> 2.4.0)
14
+ rainbow (3.0.0)
15
+ rake (10.5.0)
16
+ rubocop (0.71.0)
17
+ jaro_winkler (~> 1.5.1)
18
+ parallel (~> 1.10)
19
+ parser (>= 2.6)
20
+ rainbow (>= 2.2.2, < 4.0)
21
+ ruby-progressbar (~> 1.7)
22
+ unicode-display_width (>= 1.4.0, < 1.7)
23
+ ruby-progressbar (1.10.1)
24
+ unicode-display_width (1.6.0)
25
+
26
+ PLATFORMS
27
+ x64-mingw32
28
+
29
+ DEPENDENCIES
30
+ bundler (~> 2.0)
31
+ cross_table!
32
+ rake (~> 10.0)
33
+ rubocop
34
+
35
+ BUNDLED WITH
36
+ 2.0.1
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 masa.kunikata
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,166 @@
1
+ # CrossTable
2
+
3
+ Cross tabulation (Pivot table) utility
4
+ to convert table data to a pivot table form.
5
+
6
+ <div>
7
+
8
+ <div style="float:left;">
9
+
10
+ *Source (List table)*
11
+
12
+ |os |lang |price|
13
+ |:--- |:--- |--:|
14
+ |win |ruby |123|
15
+ |linux |ruby |12|
16
+ |mac |php |270|
17
+ |win |java |560|
18
+ |win |php |750|
19
+ |linux |java |950|
20
+ |win |java |1200|
21
+ |win |php |500|
22
+ |mac |php |10|
23
+ |mac |java |566|
24
+ |win |ruby |210|
25
+
26
+ </div>
27
+
28
+ <div style="float:left;">
29
+
30
+ &nbsp;&gt;&gt;&gt;&nbsp;
31
+
32
+ </div>
33
+
34
+ <div style="float:left;">
35
+
36
+ *Destination (Pivot table)*
37
+
38
+ | |ruby |java |php |
39
+ |:-- | --:| --:| --:|
40
+ |win | 333 |1760 |1250 |
41
+ |linux| 12 |950 |0 |
42
+ |mac | 0 |566 |280 |
43
+
44
+ </div>
45
+
46
+ </div>
47
+
48
+ <br style="clear: both;"/>
49
+
50
+ [The test code to get the sample table above.](test/cross_table_readme_sample_test.rb)
51
+
52
+
53
+ ## Installation
54
+
55
+ Add this line to your application's Gemfile:
56
+
57
+ ```ruby
58
+ gem 'cross_table'
59
+ ```
60
+
61
+ And then execute:
62
+
63
+ $ bundle
64
+
65
+ Or install it yourself as:
66
+
67
+ $ gem install cross_table
68
+
69
+ ## Usage
70
+
71
+ ### Records Count
72
+
73
+ ```ruby
74
+ require 'cross_table'
75
+
76
+ cross_tbl = CrossTable.counts_from(
77
+ recs: [], # Source List Table(Enumerable)
78
+ group_rules: [], # Grouping Rules (Array of Hash)
79
+ y_keys: [], # Y-axis Keys (Array)
80
+ x_keys: [] # X-axis Keys (Array)
81
+ ret_type: nil # Type of returned Pivot table. (nil|:xy_titles|:data_only)
82
+ )
83
+
84
+ ```
85
+
86
+ [Sample test code of CrossTable.counts_from](test/cross_table_counts_test.rb)
87
+
88
+ [Sample data and group_rule setting](test/test_sample.rb)
89
+
90
+
91
+ ### Fields Summary
92
+
93
+ ```ruby
94
+ require 'cross_table'
95
+
96
+ cross_tbl = CrossTable.sums_from(
97
+ recs: [], # Source List Table(Enumerable of Hash)
98
+ field: :fld_name # Target field name to be summarised
99
+ group_rules: [], # Grouping Rules (Array of Hash)
100
+ y_keys: [], # Y-axis Keys (Array)
101
+ x_keys: [] # X-axis Keys (Array)
102
+ ret_type: nil # Type of returned Pivot table. (nil|:xy_titles|:data_only)
103
+ )
104
+
105
+ ```
106
+
107
+ [Sample test code of CrossTable.sums_from](test/cross_table_sums_test.rb)
108
+
109
+ [Sample data and group_rule setting](test/test_sample.rb)
110
+
111
+ ### Fields Average
112
+
113
+ ```ruby
114
+ require 'cross_table'
115
+
116
+ cross_tbl = CrossTable.avgs_from(
117
+ recs: [], # Source List Table(Enumerable of Hash)
118
+ field: :fld_name # Target field name to be summarised
119
+ group_rules: [], # Grouping Rules (Array of Hash)
120
+ y_keys: [], # Y-axis Keys (Array)
121
+ x_keys: [] # X-axis Keys (Array)
122
+ ret_type: nil # Type of returned Pivot table. (nil|:xy_titles|:data_only)
123
+ )
124
+
125
+ ```
126
+
127
+ [Sample test code of CrossTable.avgs_from](test/cross_table_avgs_test.rb)
128
+
129
+ [Sample data and group_rule setting](test/test_sample.rb)
130
+
131
+ ### Arbitrary property of grouped records
132
+
133
+ ```ruby
134
+ require 'cross_table'
135
+
136
+ cross_tbl = CrossTable.from(
137
+ recs: [], # Source List Table(Enumerable of Hash)
138
+ group_rules: [], # Grouping Rules (Array of Hash)
139
+ y_keys: [], # Y-axis Keys (Array)
140
+ x_keys: [] # X-axis Keys (Array)
141
+ ret_type: nil # Type of returned Pivot table. (nil|:xy_titles|:data_only)
142
+ &aggr_proc # Proc/block to get a value from the arg "group_recs"
143
+ )
144
+
145
+ ```
146
+
147
+ [Sample test code of CrossTable.from to get a Minumum value.](test/cross_table_from_test.rb)
148
+
149
+ [Sample data and group_rule setting](test/test_sample.rb)
150
+
151
+ ### Multiple Keys Grouping
152
+
153
+ [Sample test code of using multilpe keys.](test/cross_table_multiple_keys_test.rb)
154
+
155
+
156
+ ## Development
157
+
158
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then 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).
159
+
160
+ ## Contributing
161
+
162
+ Bug reports and pull requests are welcome on GitHub at https://github.com/masa-kunikata/cross_table.
163
+
164
+ ## License
165
+
166
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+ require 'rake/testtask'
5
+ require 'rubocop/rake_task'
6
+ require 'bundler/gem_tasks'
7
+
8
+ RuboCop::RakeTask.new(:lint)
9
+
10
+ desc 'Run test_unit based test'
11
+ Rake::TestTask.new do |t|
12
+ # To run test for only one file (or file path pattern)
13
+ # $ bundle exec rake test TEST=test/test_specified_path.rb
14
+ t.libs << 'test'
15
+ t.test_files = Dir['test/**/*_test.rb']
16
+ t.verbose = true
17
+ end
18
+
19
+ task default: :test
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'cross_table/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'cross_table'
9
+ spec.version = CrossTable::VERSION
10
+ spec.authors = ['masa.kunikata']
11
+ spec.email = ['masa.kunikata@gmail.com']
12
+
13
+ spec.summary = 'cross tabulation "pivot table" utility'
14
+ spec.homepage = 'https://github.com/masa-kunikata/cross_table'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = Dir.chdir(__dir__) do
18
+ `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+ end
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ['lib']
24
+
25
+ spec.add_development_dependency 'bundler', '~> 2.0'
26
+ spec.add_development_dependency 'rake', '~> 10.0'
27
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CrossTable
4
+ # group process
5
+ module Grouping
6
+ module_function
7
+
8
+ def group(recs, group_rules, &aggr_proc)
9
+ all_titles = product_all(group_rules.map(&:keys))
10
+ all_procs = product_all(group_rules.map(&:values))
11
+
12
+ auto_dig_hash = Hash.new { |h, k| h[k] = h.class.new(&h.default_proc) }
13
+ all_titles.zip(all_procs).each do |dig_keys, filter_procs|
14
+ group_recs = filter_procs.reduce(recs) do |memo, proc|
15
+ memo.select(&proc)
16
+ end
17
+ value = aggr_proc[group_recs]
18
+
19
+ last_key = dig_keys.pop
20
+ auto_dig_hash.dig(*dig_keys).store(last_key, value)
21
+ end
22
+ auto_dig_hash
23
+ end
24
+
25
+ def counts(recs, group_rules)
26
+ group(recs, group_rules, &:count)
27
+ end
28
+
29
+ def sums(recs, field, group_rules)
30
+ group(recs, group_rules) do |group_recs|
31
+ group_recs.map { |r| r[field] }.sum
32
+ end
33
+ end
34
+
35
+ def avgs(recs, field, group_rules)
36
+ group(recs, group_rules) do |group_recs|
37
+ sum = group_recs.map { |r| r[field] }.sum
38
+ count = group_recs.count
39
+ sum.to_f / count.to_f
40
+ end
41
+ end
42
+
43
+ class << self
44
+ private
45
+
46
+ def product_all(list)
47
+ list.first.product(*list[1..-1])
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CrossTable
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cross_table/version'
4
+ require 'cross_table/grouping'
5
+
6
+ # cross tabulation (pivot table) utility
7
+ module CrossTable
8
+ module_function
9
+
10
+ def from(recs:, group_rules:, y_keys:, x_keys:, ret_type: nil, &aggr_proc)
11
+ of(Grouping.group(recs, group_rules, &aggr_proc),
12
+ y_keys: y_keys, x_keys: x_keys,
13
+ ret_type: ret_type)
14
+ end
15
+
16
+ def counts_from(recs:, group_rules:, y_keys:, x_keys:, ret_type: nil)
17
+ of(Grouping.counts(recs, group_rules),
18
+ y_keys: y_keys, x_keys: x_keys,
19
+ ret_type: ret_type)
20
+ end
21
+
22
+ def sums_from(recs:, field:, group_rules:, y_keys:, x_keys:, ret_type: nil)
23
+ of(Grouping.sums(recs, field, group_rules),
24
+ y_keys: y_keys, x_keys: x_keys,
25
+ ret_type: ret_type)
26
+ end
27
+
28
+ def avgs_from(recs:, field:, group_rules:, y_keys:, x_keys:, ret_type: nil)
29
+ of(Grouping.avgs(recs, field, group_rules),
30
+ y_keys: y_keys, x_keys: x_keys,
31
+ ret_type: ret_type)
32
+ end
33
+
34
+ def of(grouped_hash, y_keys:, x_keys:, ret_type: nil)
35
+ vals = y_keys.map do |y_dig_keys|
36
+ x_keys.map do |x_dig_keys|
37
+ grouped_hash.dig(*y_dig_keys).dig(*x_dig_keys)
38
+ end
39
+ end
40
+
41
+ case ret_type
42
+ when :data_only
43
+ return vals
44
+
45
+ when :xy_titles
46
+ return ([nil] + y_keys).zip([x_keys] + vals).map do |row_title, value_row|
47
+ [row_title] + value_row
48
+ end
49
+ end
50
+
51
+ y_keys.map.zip(
52
+ vals.map do |row|
53
+ x_keys.zip(row).to_h
54
+ end
55
+ ).to_h
56
+ end
57
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cross_table
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - masa.kunikata
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-06-19 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: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description:
42
+ email:
43
+ - masa.kunikata@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - ".rubocop.yml"
50
+ - ".rubocop_todo.yml"
51
+ - Gemfile
52
+ - Gemfile.lock
53
+ - LICENSE.txt
54
+ - README.md
55
+ - Rakefile
56
+ - cross_table.gemspec
57
+ - lib/cross_table.rb
58
+ - lib/cross_table/grouping.rb
59
+ - lib/cross_table/version.rb
60
+ homepage: https://github.com/masa-kunikata/cross_table
61
+ licenses:
62
+ - MIT
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubygems_version: 3.0.2
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: cross tabulation "pivot table" utility
83
+ test_files: []