ntable 0.1.2 → 0.1.3
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.
- data/History.rdoc +5 -0
- data/Version +1 -1
- data/lib/ntable.rb +1 -0
- data/lib/ntable/construction.rb +32 -14
- data/lib/ntable/index_wrapper.rb +73 -0
- data/lib/ntable/structure.rb +18 -6
- data/lib/ntable/table.rb +21 -4
- data/test/tc_basic_values.rb +21 -0
- data/test/tc_nested_object.rb +16 -0
- metadata +2 -1
data/History.rdoc
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
=== 0.1.3 / 2012-09-10
|
2
|
+
|
3
|
+
* Creating a table from a nested object, using a label conversion procedure, tended to fail with NoSuchCellError. Fixed and added test cases.
|
4
|
+
* Support cell lookup using the 0-based row index as well as the label.
|
5
|
+
|
1
6
|
=== 0.1.2 / 2012-09-09
|
2
7
|
|
3
8
|
I took a long look at ntable's interface, and the usage patterns of my own personal projects that depended on it, and decided some simplification was needed.
|
data/Version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.3
|
data/lib/ntable.rb
CHANGED
data/lib/ntable/construction.rb
CHANGED
@@ -34,6 +34,7 @@
|
|
34
34
|
;
|
35
35
|
|
36
36
|
|
37
|
+
require 'set'
|
37
38
|
require 'json'
|
38
39
|
|
39
40
|
|
@@ -41,6 +42,8 @@ module NTable
|
|
41
42
|
|
42
43
|
|
43
44
|
@numeric_sort = ::Proc.new{ |a_, b_| a_.to_f <=> b_.to_f }
|
45
|
+
@integer_sort = ::Proc.new{ |a_, b_| a_.to_i <=> b_.to_i }
|
46
|
+
@string_sort = ::Proc.new{ |a_, b_| a_.to_s <=> b_.to_s }
|
44
47
|
|
45
48
|
|
46
49
|
class << self
|
@@ -148,22 +151,36 @@ module NTable
|
|
148
151
|
stringify_ = field_[:stringify] || stringify_by_default_
|
149
152
|
objectify_ ||= objectify_by_default_ unless stringify_
|
150
153
|
if objectify_
|
151
|
-
|
152
|
-
|
154
|
+
if objectify_.respond_to?(:call)
|
155
|
+
h_ = ::Set.new
|
156
|
+
ai_.keys.each do |k_|
|
157
|
+
nv_ = objectify_.call(k_)
|
158
|
+
ai_[k_] = nv_
|
159
|
+
h_ << nv_
|
160
|
+
end
|
161
|
+
labels_ = h_.to_a
|
162
|
+
else
|
163
|
+
labels_ = ai_.keys
|
164
|
+
end
|
153
165
|
klass_ = ObjectAxis
|
154
166
|
else
|
155
|
-
h_ = {}
|
156
167
|
stringify_ = nil unless stringify_.respond_to?(:call)
|
157
|
-
|
158
|
-
|
159
|
-
|
168
|
+
h_ = ::Set.new
|
169
|
+
ai_.keys.each do |k_|
|
170
|
+
nv_ = (stringify_ ? stringify_.call(k_) : k_).to_s
|
171
|
+
ai_[k_] = nv_
|
172
|
+
h_ << nv_
|
160
173
|
end
|
161
|
-
labels_ = h_.
|
174
|
+
labels_ = h_.to_a
|
162
175
|
klass_ = LabeledAxis
|
163
176
|
end
|
164
177
|
if (sort_ = field_[:sort])
|
165
178
|
if sort_.respond_to?(:call)
|
166
179
|
func_ = sort_
|
180
|
+
elsif sort_ == :string
|
181
|
+
func_ = @string_sort
|
182
|
+
elsif sort_ == :integer
|
183
|
+
func_ = @integer_sort
|
167
184
|
elsif sort_ == :numeric
|
168
185
|
func_ = @numeric_sort
|
169
186
|
else
|
@@ -178,7 +195,7 @@ module NTable
|
|
178
195
|
struct_.add(axis_, name_) if axis_
|
179
196
|
end
|
180
197
|
table_ = Table.new(struct_, :fill => opts_[:fill])
|
181
|
-
_populate_nested_values(table_, [], obj_)
|
198
|
+
_populate_nested_values(table_, [], axis_data_, obj_)
|
182
199
|
table_
|
183
200
|
end
|
184
201
|
|
@@ -191,16 +208,16 @@ module NTable
|
|
191
208
|
set_ = ai_
|
192
209
|
else
|
193
210
|
set_ = axis_data_[index_] = {}
|
194
|
-
(ai_[0]...ai_[1]).each{ |i_| set_[i_] =
|
211
|
+
(ai_[0]...ai_[1]).each{ |i_| set_[i_] = i_ } if ::Array === ai_
|
195
212
|
end
|
196
213
|
obj_.each do |k_, v_|
|
197
|
-
set_[k_] =
|
214
|
+
set_[k_] = k_
|
198
215
|
_populate_nested_axes(axis_data_, index_+1, v_)
|
199
216
|
end
|
200
217
|
when ::Array
|
201
218
|
if ::Hash === ai_
|
202
219
|
obj_.each_with_index do |v_, i_|
|
203
|
-
ai_[i_] =
|
220
|
+
ai_[i_] = i_
|
204
221
|
_populate_nested_axes(axis_data_, index_+1, v_)
|
205
222
|
end
|
206
223
|
else
|
@@ -222,18 +239,19 @@ module NTable
|
|
222
239
|
end
|
223
240
|
|
224
241
|
|
225
|
-
def _populate_nested_values(table_, path_, obj_) # :nodoc:
|
242
|
+
def _populate_nested_values(table_, path_, axis_data_, obj_) # :nodoc:
|
226
243
|
if path_.size == table_.dim
|
227
244
|
table_.set!(*path_, obj_)
|
228
245
|
else
|
229
246
|
case obj_
|
230
247
|
when ::Hash
|
248
|
+
h_ = axis_data_[path_.size]
|
231
249
|
obj_.each do |k_, v_|
|
232
|
-
_populate_nested_values(table_, path_ + [k_], v_)
|
250
|
+
_populate_nested_values(table_, path_ + [h_[k_]], axis_data_, v_)
|
233
251
|
end
|
234
252
|
when ::Array
|
235
253
|
obj_.each_with_index do |v_, i_|
|
236
|
-
_populate_nested_values(table_, path_ + [i_], v_) unless v_.nil?
|
254
|
+
_populate_nested_values(table_, path_ + [i_], axis_data_, v_) unless v_.nil?
|
237
255
|
end
|
238
256
|
end
|
239
257
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# NTable index wrapper
|
4
|
+
#
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# Copyright 2012 Daniel Azuma
|
7
|
+
#
|
8
|
+
# All rights reserved.
|
9
|
+
#
|
10
|
+
# Redistribution and use in source and binary forms, with or without
|
11
|
+
# modification, are permitted provided that the following conditions are met:
|
12
|
+
#
|
13
|
+
# * Redistributions of source code must retain the above copyright notice,
|
14
|
+
# this list of conditions and the following disclaimer.
|
15
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
16
|
+
# this list of conditions and the following disclaimer in the documentation
|
17
|
+
# and/or other materials provided with the distribution.
|
18
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
19
|
+
# contributors to this software, may be used to endorse or promote products
|
20
|
+
# derived from this software without specific prior written permission.
|
21
|
+
#
|
22
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
25
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
26
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
27
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
28
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
29
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
30
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
31
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
32
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
# -----------------------------------------------------------------------------
|
34
|
+
;
|
35
|
+
|
36
|
+
|
37
|
+
module NTable
|
38
|
+
|
39
|
+
|
40
|
+
# Use one of these in a coordinate to force the coordinate to be
|
41
|
+
# treated as an index rather than a label.
|
42
|
+
|
43
|
+
class IndexWrapper
|
44
|
+
|
45
|
+
# Create an IndexWrapper with the given integer index
|
46
|
+
|
47
|
+
def initialize(val_)
|
48
|
+
@value = val_.to_i
|
49
|
+
end
|
50
|
+
|
51
|
+
def eql?(rhs_)
|
52
|
+
rhs_.is_a?(IndexWrapper) && @value == @rhs_.value
|
53
|
+
end
|
54
|
+
alias_method :==, :eql?
|
55
|
+
|
56
|
+
def hash
|
57
|
+
@value.hash
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_reader :value
|
61
|
+
alias_method :to_i, :value
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
# Convenience method for creating an IndexWrapper
|
67
|
+
|
68
|
+
def self.index(val_)
|
69
|
+
IndexWrapper.new(val_)
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
end
|
data/lib/ntable/structure.rb
CHANGED
@@ -132,6 +132,18 @@ module NTable
|
|
132
132
|
@axis_index -= 1
|
133
133
|
end
|
134
134
|
|
135
|
+
|
136
|
+
def _compute_offset(v_)
|
137
|
+
if v_.is_a?(::NTable::IndexWrapper)
|
138
|
+
index_ = v_.to_i
|
139
|
+
index_ = nil if index_ < 0 || index_ >= @axis_object.size
|
140
|
+
else
|
141
|
+
index_ = @axis_object.index(v_)
|
142
|
+
index_ = v_ if !index_ && v_.is_a?(::Integer) && v_ >= 0 && v_ < @axis_object.size
|
143
|
+
end
|
144
|
+
index_ ? @step * index_ : nil
|
145
|
+
end
|
146
|
+
|
135
147
|
end
|
136
148
|
|
137
149
|
|
@@ -551,9 +563,9 @@ module NTable
|
|
551
563
|
offset_ = 0
|
552
564
|
arg_.each do |k_, v_|
|
553
565
|
if (ainfo_ = axis(k_))
|
554
|
-
|
555
|
-
return nil unless
|
556
|
-
offset_ +=
|
566
|
+
delta_ = ainfo_._compute_offset(v_)
|
567
|
+
return nil unless delta_
|
568
|
+
offset_ += delta_
|
557
569
|
else
|
558
570
|
return nil
|
559
571
|
end
|
@@ -563,9 +575,9 @@ module NTable
|
|
563
575
|
offset_ = 0
|
564
576
|
arg_.each_with_index do |v_, i_|
|
565
577
|
if (ainfo_ = @indexes[i_])
|
566
|
-
|
567
|
-
return nil unless
|
568
|
-
offset_ +=
|
578
|
+
delta_ = ainfo_._compute_offset(v_)
|
579
|
+
return nil unless delta_
|
580
|
+
offset_ += delta_
|
569
581
|
else
|
570
582
|
return nil
|
571
583
|
end
|
data/lib/ntable/table.rb
CHANGED
@@ -189,9 +189,9 @@ module NTable
|
|
189
189
|
|
190
190
|
|
191
191
|
# Returns the value in the cell at the given coordinates, which
|
192
|
-
#
|
192
|
+
# may be given as labels or as 0-based row indexes.
|
193
193
|
# You may specify the cell as an array of coordinates, or as a
|
194
|
-
# hash mapping axis name to coordinate.
|
194
|
+
# hash mapping axis name or axis index to coordinate.
|
195
195
|
#
|
196
196
|
# For example, for a typical database result set with an axis called
|
197
197
|
# "row" of numerically identified rows, and an axis called "col" with
|
@@ -200,6 +200,23 @@ module NTable
|
|
200
200
|
# get(3, 'name')
|
201
201
|
# get([3, 'name'])
|
202
202
|
# get(:row => 3, :col => 'name')
|
203
|
+
# get(0 => 3, 1 => 'name')
|
204
|
+
#
|
205
|
+
# Alternately, you can provide row numbers (0-based) instead. If, for
|
206
|
+
# example, "name" is the second column (corresponding to index 1),
|
207
|
+
# then the following queries are also equivalent:
|
208
|
+
#
|
209
|
+
# get(3, 1)
|
210
|
+
# get(:row => 3, :col => 1)
|
211
|
+
#
|
212
|
+
# For axes whose labels are integers (for example, a numerically
|
213
|
+
# identified axis such as IndexedAxis), it is ambiguous whether a
|
214
|
+
# value is intended as a label or an index. In this case, NTable
|
215
|
+
# defalts to assuming the value is a label. If you want to force a
|
216
|
+
# value to be treated as a 0-based row index, wrap it in a call to
|
217
|
+
# NTable.index(), as follows:
|
218
|
+
#
|
219
|
+
# get(NTable.index(3), 1)
|
203
220
|
#
|
204
221
|
# Raises NoSuchCellError if the coordinates do not exist.
|
205
222
|
|
@@ -450,10 +467,10 @@ module NTable
|
|
450
467
|
# Performs a reduce on the entire table and returns the result.
|
451
468
|
# You may use one of the following call sequences:
|
452
469
|
#
|
453
|
-
# [
|
470
|
+
# [reduce_with_position{ |accumulator, value, position| <i>block</i> }]
|
454
471
|
# Reduces using the given block as the reduction function. The
|
455
472
|
# first element in the table is used as the initial accumulator.
|
456
|
-
# [
|
473
|
+
# [reduce_with_position(initial){ |accumulator, value, position| <i>block</i> }]
|
457
474
|
# Reduces using the given block as the reduction function, with
|
458
475
|
# the given initial value for the accumulator.
|
459
476
|
|
data/test/tc_basic_values.rb
CHANGED
@@ -47,7 +47,9 @@ module NTable
|
|
47
47
|
def setup
|
48
48
|
@labeled_axis = LabeledAxis.new([:red, :white, :blue])
|
49
49
|
@indexed_axis = IndexedAxis.new(10)
|
50
|
+
@indexed_axis_1 = IndexedAxis.new(10, 1)
|
50
51
|
@structure = Structure.add(@indexed_axis, :row).add(@labeled_axis, :column)
|
52
|
+
@structure_1 = Structure.add(@indexed_axis_1, :row).add(@labeled_axis, :column)
|
51
53
|
end
|
52
54
|
|
53
55
|
|
@@ -81,6 +83,15 @@ module NTable
|
|
81
83
|
end
|
82
84
|
|
83
85
|
|
86
|
+
def test_load_and_get_indexes
|
87
|
+
table_ = Table.new(@structure_1, :load => (0..29).to_a)
|
88
|
+
assert_equal(14, table_.get(5, 2))
|
89
|
+
assert_equal(14, table_.get(0 => 5, 1 => 2))
|
90
|
+
assert_equal(17, table_.get(::NTable.index(5), 2))
|
91
|
+
assert_equal(17, table_.get(0 => ::NTable.index(5), 1 => 2))
|
92
|
+
end
|
93
|
+
|
94
|
+
|
84
95
|
def test_set_from_array
|
85
96
|
table_ = Table.new(@structure)
|
86
97
|
table_.set!(0, :red, "foo")
|
@@ -101,6 +112,16 @@ module NTable
|
|
101
112
|
end
|
102
113
|
|
103
114
|
|
115
|
+
def test_set_indexes
|
116
|
+
table_ = Table.new(@structure_1)
|
117
|
+
table_.set!(1, 1, "foo")
|
118
|
+
table_[1 => 2, 0 => ::NTable.index(5)] = "bar"
|
119
|
+
assert_equal("foo", table_.get(::NTable.index(0), :white))
|
120
|
+
assert_equal("bar", table_[6, :blue])
|
121
|
+
assert_nil(table_.get(5, :blue))
|
122
|
+
end
|
123
|
+
|
124
|
+
|
104
125
|
def test_load_no_axes
|
105
126
|
t1_ = Table.new(Structure.new, :load => [1])
|
106
127
|
assert_equal(1, t1_.get)
|
data/test/tc_nested_object.rb
CHANGED
@@ -199,6 +199,22 @@ module NTable
|
|
199
199
|
end
|
200
200
|
|
201
201
|
|
202
|
+
def test_from_level_1_labeled_with_objectify_conversion
|
203
|
+
obj_ = {'one' => 1, 'two' => 2}
|
204
|
+
t1_ = Table.from_nested_object(obj_,
|
205
|
+
[{:sort => true, :objectify => ::Proc.new{ |a_| a_.to_sym }}])
|
206
|
+
assert_equal(Table.new(Structure.add(@object_axis_2), :load => [1,2]), t1_)
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
def test_from_level_1_labeled_with_stringify_conversion
|
211
|
+
obj_ = {:one1 => 1, :two22 => 2}
|
212
|
+
t1_ = Table.from_nested_object(obj_,
|
213
|
+
[{:sort => true, :stringify => ::Proc.new{ |a_| a_.to_s.gsub(/\d/, '') }}])
|
214
|
+
assert_equal(Table.new(Structure.add(@labeled_axis_2), :load => [1,2]), t1_)
|
215
|
+
end
|
216
|
+
|
217
|
+
|
202
218
|
end
|
203
219
|
|
204
220
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ntable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -28,6 +28,7 @@ files:
|
|
28
28
|
- lib/ntable/axis.rb
|
29
29
|
- lib/ntable/construction.rb
|
30
30
|
- lib/ntable/errors.rb
|
31
|
+
- lib/ntable/index_wrapper.rb
|
31
32
|
- lib/ntable/structure.rb
|
32
33
|
- lib/ntable/table.rb
|
33
34
|
- lib/ntable.rb
|