tafel 0.1.0 → 0.3.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.
Files changed (5) hide show
  1. data/CHANGELOG.txt +5 -0
  2. data/README.md +114 -1
  3. data/lib/tafel.rb +139 -16
  4. data/tafel.gemspec +3 -3
  5. metadata +5 -5
data/CHANGELOG.txt CHANGED
@@ -2,6 +2,11 @@
2
2
  = tafel CHANGELOG.txt
3
3
 
4
4
 
5
+ == tafel 0.3.0 released 2016-05-02
6
+
7
+ - settle on .flatten, .to_vtable and to_htable
8
+
9
+
5
10
  == tafel 0.1.0 released 2016-04-10
6
11
 
7
12
  - initial (empty) release
data/README.md CHANGED
@@ -1,7 +1,120 @@
1
1
 
2
2
  # tafel
3
3
 
4
- # license
4
+ [![Build Status](https://secure.travis-ci.org/jmettraux/tafel.svg)](http://travis-ci.org/jmettraux/tafel)
5
+ [![Gem Version](https://badge.fury.io/rb/tafel.svg)](http://badge.fury.io/rb/tafel)
6
+
7
+ A Ruby library to turn pieces of data into arrays of arrays (tables).
8
+
9
+ ## interface
10
+
11
+ ### Tafel .to_htable .to_h
12
+
13
+ Turns the argument into a table where keys are arrayed horizontally.
14
+
15
+ ```ruby
16
+ require 'tafel'
17
+
18
+ #
19
+ # hash of hashes
20
+
21
+ Tafel.to_h(
22
+ {
23
+ 'USD' => { code: 'USD', change: 1.0, min: 500, status: 'active' },
24
+ 'EUR' => { code: 'EUR', change: 1.07, status: 'active' },
25
+ 'CHF' => { code: 'CHF', change: 1.08, min: 700 }
26
+ }
27
+ )
28
+ # ==>
29
+ [
30
+ [ :key, :code, :change, :min, :status ],
31
+ [ 'USD', 'USD', 1.0, 500, 'active' ],
32
+ [ 'EUR', 'EUR', 1.07, nil, 'active' ],
33
+ [ 'CHF', 'CHF', 1.08, 700, nil ]
34
+ ]
35
+
36
+ #
37
+ # array of hashes
38
+
39
+ Tafel.to_htable(
40
+ [
41
+ { a: 1, b: 2 },
42
+ { a: 3, b: 4, c: 5 },
43
+ { a: 6, c: 7 }
44
+ ]
45
+ )
46
+ # ==>
47
+ [
48
+ [ :a, :b, :c ],
49
+ [ 1, 2, nil ],
50
+ [ 3, 4, 5 ],
51
+ [ 6, nil, 7 ]
52
+ ]
53
+
54
+ #
55
+ # plain hash
56
+
57
+ Tafel.to_htable(
58
+ { a: 3, b: 4, c: 5 }
59
+ )
60
+ # ==>
61
+ [
62
+ [ :a, :b, :c ],
63
+ [ 3, 4, 5 ]
64
+ ]
65
+ ```
66
+
67
+ ### Tafel .to_vtable .to_v
68
+
69
+ Turns the argument into a table where keys are arrayed vertically.
70
+
71
+ It leaves non-array and no-hash instances as is.
72
+
73
+ ```ruby
74
+ require 'tafel'
75
+
76
+ Tafel.to_v(
77
+ { interpreter: 'Leo Ferre', song: { name: "C'est extra", year: 1969 } }
78
+ )
79
+ # ==>
80
+ [
81
+ [ :interpret, 'Leo Ferre' ],
82
+ [ :song, [ [ :name, "C'est extra" ], [ :year, 1969 ] ] ]
83
+ ]
84
+ ```
85
+
86
+ It accepts a limit integer parameter defaulting to -1 (recurse entirely). For example:
87
+
88
+ ```ruby
89
+ Tafel.to_v(
90
+ { interpreter: 'Leo Ferre', song: { name: "C'est extra", year: 1969 } },
91
+ 1
92
+ )
93
+ # ==>
94
+ [
95
+ [ :interpret, 'Leo Ferre' ],
96
+ [ :song, { name: "C'est extra", year: 1969 } ]
97
+ ]
98
+ ```
99
+
100
+ ### Tafel.flatten
101
+
102
+ Turns nested tables into a single table.
103
+
104
+ ```ruby
105
+ require 'tafel'
106
+
107
+ Tafel.flatten(
108
+ [ [ 0, 1 ],
109
+ [ 2, [ [ 3, 4 ], [ 5, 6 ] ] ] ]
110
+ )
111
+ # -->
112
+ [ [ 0, 1, nil ],
113
+ [ 2, 3, 4 ],
114
+ [ nil, 5, 6 ] ]
115
+ ```
116
+
117
+ ## license
5
118
 
6
119
  MIT, see LICENSE.txt
7
120
 
data/lib/tafel.rb CHANGED
@@ -25,35 +25,158 @@
25
25
 
26
26
  module Tafel
27
27
 
28
- VERSION = '0.1.0'
28
+ VERSION = '0.3.0'
29
29
 
30
- def self.turn(data)
30
+ def self.table?(o)
31
31
 
32
- data = to_array(data)
32
+ o.is_a?(Array) && o.all? { |r| r.is_a?(Array) }
33
+ end
34
+
35
+ # .to_vtable: keys are arrayed vertically (y explosion)
36
+ # .to_htable: keys are arrayed horizontally (x explosion)
37
+
38
+ def self.to_vtable(x, limit=-1)
39
+
40
+ return x if limit == 0
41
+
42
+ case x
43
+ when Hash then x.to_a.collect { |k, v| [ k, to_vtable(v, limit - 1) ] }
44
+ when Array then x.collect { |e| [ to_vtable(e) ] }
45
+ else x
46
+ end
47
+ end
48
+
49
+ def self.to_htable(x)
50
+
51
+ kla0 = narrow_class(x)
52
+
53
+ kla1 = nil
54
+ if kla0
55
+ vs = x.respond_to?(:values) ? x.values : x
56
+ kla = narrow_class(vs.first)
57
+ kla1 = vs.all? { |v| kla ? v.is_a?(kla) : false } ? kla : nil
58
+ end
59
+
60
+ #p [ kla0, kla1 ]
61
+ case [ kla0, kla1 ]
62
+ when [ Hash, Hash ] then to_h_hash_hash(x)
63
+ when [ Array, Hash ] then to_h_array_hash(x)
64
+ when [ Hash, nil ] then to_h_hash(x)
65
+ else x
66
+ end
67
+ end
68
+
69
+ class << self
70
+ alias to_v to_vtable
71
+ alias to_h to_htable
72
+ end
73
+
74
+ def self.flatten(table)
75
+
76
+ fail ArgumentError.new('not a table') unless table?(table)
77
+
78
+ flat = true
79
+
80
+ table =
81
+ table.collect { |r|
82
+ r.collect { |c| next c unless table?(c); flat = false; flatten(c) }
83
+ }
84
+
85
+ return table if flat
86
+
87
+ ss = table.collect { |r| r.collect { |c| size(c) } }
88
+
89
+ ss.each do |row|
90
+ maxh = row.collect { |cell| cell[1] }.max
91
+ maxh = maxh < 1 ? 1 : maxh
92
+ row.each { |cell| cell[1] = maxh }
93
+ end
94
+ ss.collect { |row| row.size }.max.times do |x|
95
+ maxw = ss.collect { |row| cell = row[x]; cell ? cell[0] : 1 }.max
96
+ maxw = maxw < 1 ? 1 : maxw
97
+ ss.each { |row| cell = row[x]; cell[0] = maxw if cell }
98
+ end
99
+
100
+ w = ss.first.collect(&:first).reduce(&:+)
101
+ h = ss.collect { |row| row[0].last }.reduce(&:+)
102
+
103
+ a = Array.new(h) { Array.new(w) }
33
104
 
34
- if data.all? { |row| row.is_a?(Array) }
35
- data
36
- elsif data.all? { |row| row.is_a?(Hash) }
37
- turn_array_of_hashes(data)
105
+ iterate(ss) do |x, y, s|
106
+
107
+ left = x > 0 ? ss[y][x - 1] : nil
108
+ above = y > 0 ? ss[y - 1][x] : nil
109
+
110
+ woff = left ? left[2] + left[0] : 0
111
+ hoff = above ? above[3] + above[1] : 0
112
+
113
+ s.push(woff, hoff)
114
+
115
+ copy(a, woff, hoff, table[y][x])
116
+ end
117
+
118
+ a
119
+ end
120
+
121
+ protected # well...
122
+
123
+ def self.size(o)
124
+
125
+ table?(o) ? [ o.collect { |r| r.size }.max, o.size ] : [ 0, 0 ]
126
+ end
127
+
128
+ def self.copy(target, woff, hoff, source)
129
+
130
+ if table?(source)
131
+ iterate(source) { |x, y, v| target[hoff + y][woff + x] = v }
38
132
  else
39
- nil
133
+ target[hoff][woff] = source
40
134
  end
41
135
  end
42
136
 
43
- protected
137
+ def self.iterate(table)
44
138
 
45
- def self.to_array(data)
139
+ table.first.size.times do |x|
140
+ table.size.times do |y|
141
+ yield(x, y, table[y][x])
142
+ end
143
+ end
144
+ end
145
+
146
+ def self.narrow_class(x)
46
147
 
47
- data
48
- #return data.values if data.is_a?(Hash)
49
- #return Array[data]
148
+ return Array if x.is_a?(Array)
149
+ return Hash if x.is_a?(Hash)
150
+ nil
50
151
  end
51
152
 
52
- def self.turn_array_of_hashes(data)
153
+ def self.to_h_hash_hash(h)
154
+
155
+ keys = h.values.inject([ :key ]) { |ks, v| ks.concat(v.keys) }.uniq
156
+ table = [ keys ]
157
+
158
+ h.each do |k, v|
159
+ table << keys[1..-1].inject([ k ]) { |row, key| row << v[key]; row }
160
+ end
161
+
162
+ table
163
+ end
53
164
 
54
- keys = data.inject([]) { |a, row| a.concat(row.keys) }.uniq
165
+ def self.to_h_hash(h)
166
+
167
+ [ h.keys, h.inject([]) { |a, (k, v)| a << v; a } ]
168
+ end
169
+
170
+ def self.to_h_array_hash(a)
171
+
172
+ keys = a.inject([]) { |ks, h| ks.concat(h.keys) }.uniq
173
+ table = [ keys ]
174
+
175
+ a.each do |h|
176
+ table << keys.inject([]) { |row, key| row << h[key]; row }
177
+ end
55
178
 
56
- [ keys ] + data.collect { |row| keys.collect { |k| row[k] } }
179
+ table
57
180
  end
58
181
  end
59
182
 
data/tafel.gemspec CHANGED
@@ -10,13 +10,13 @@ Gem::Specification.new do |s|
10
10
  s.platform = Gem::Platform::RUBY
11
11
  s.authors = [ 'John Mettraux' ]
12
12
  s.email = [ 'jmettraux@gmail.com' ]
13
- s.homepage = 'http://github.com/jmettraux/raabro'
13
+ s.homepage = 'http://github.com/jmettraux/tafel'
14
14
  s.rubyforge_project = 'rufus'
15
15
  s.license = 'MIT'
16
- s.summary = 'something to turn data into an array of arrays'
16
+ s.summary = 'something to turn data into arrays of arrays'
17
17
 
18
18
  s.description = %{
19
- Something to turn data (JSON) into an array of arrays (CSV)
19
+ Something to turn data into arrays of arrays (suitable for CSV).
20
20
  }.strip
21
21
 
22
22
  #s.files = `git ls-files`.split("\n")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tafel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-04-09 00:00:00.000000000 Z
12
+ date: 2016-05-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -27,7 +27,7 @@ dependencies:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: 2.13.0
30
- description: Something to turn data (JSON) into an array of arrays (CSV)
30
+ description: Something to turn data into arrays of arrays (suitable for CSV).
31
31
  email:
32
32
  - jmettraux@gmail.com
33
33
  executables: []
@@ -40,7 +40,7 @@ files:
40
40
  - CHANGELOG.txt
41
41
  - LICENSE.txt
42
42
  - README.md
43
- homepage: http://github.com/jmettraux/raabro
43
+ homepage: http://github.com/jmettraux/tafel
44
44
  licenses:
45
45
  - MIT
46
46
  post_install_message:
@@ -64,5 +64,5 @@ rubyforge_project: rufus
64
64
  rubygems_version: 1.8.23.2
65
65
  signing_key:
66
66
  specification_version: 3
67
- summary: something to turn data into an array of arrays
67
+ summary: something to turn data into arrays of arrays
68
68
  test_files: []