ntable 0.1.3 → 0.1.4
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/axis.rb +28 -4
- data/lib/ntable/construction.rb +12 -3
- data/lib/ntable/index_wrapper.rb +11 -0
- data/lib/ntable/structure.rb +43 -5
- data/lib/ntable/table.rb +8 -1
- data/test/tc_nested_object.rb +12 -2
- data/test/tc_structure.rb +16 -0
- metadata +3 -3
data/History.rdoc
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
=== 0.1.4 / 2012-09-24
|
2
|
+
|
3
|
+
* NTable::Structure and NTable::AxisInfo are now Enumerable, letting you iterate over the axes and labels, respectively.
|
4
|
+
* You can now postprocess the labels generated by NTable.from_nested_object. Useful for filling in labels missing in the data.
|
5
|
+
|
1
6
|
=== 0.1.3 / 2012-09-10
|
2
7
|
|
3
8
|
* Creating a table from a nested object, using a label conversion procedure, tended to fail with NoSuchCellError. Fixed and added test cases.
|
data/Version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.4
|
data/lib/ntable/axis.rb
CHANGED
@@ -131,40 +131,45 @@ module NTable
|
|
131
131
|
end
|
132
132
|
|
133
133
|
|
134
|
+
# See EmptyAxis#eql?
|
134
135
|
def eql?(obj_)
|
135
136
|
obj_.is_a?(LabeledAxis) && @a.eql?(obj_.instance_variable_get(:@a))
|
136
137
|
end
|
138
|
+
alias_method :==, :eql?
|
137
139
|
|
138
|
-
|
139
|
-
obj_.is_a?(LabeledAxis) && @a == obj_.instance_variable_get(:@a)
|
140
|
-
end
|
141
|
-
|
140
|
+
# See EmptyAxis#hash
|
142
141
|
def hash
|
143
142
|
@a.hash
|
144
143
|
end
|
145
144
|
|
145
|
+
# See EmptyAxis#inspect
|
146
146
|
def inspect
|
147
147
|
"#<#{self.class}:0x#{object_id.to_s(16)} #{@a.inspect}>"
|
148
148
|
end
|
149
149
|
alias_method :to_s, :inspect
|
150
150
|
|
151
151
|
|
152
|
+
# See EmptyAxis#size
|
152
153
|
attr_reader :size
|
153
154
|
|
154
155
|
|
156
|
+
# See EmptyAxis#index
|
155
157
|
def index(label_)
|
156
158
|
@h[label_.to_s]
|
157
159
|
end
|
158
160
|
|
161
|
+
# See EmptyAxis#label
|
159
162
|
def label(index_)
|
160
163
|
@a[index_]
|
161
164
|
end
|
162
165
|
|
163
166
|
|
167
|
+
# See EmptyAxis#to_json_object
|
164
168
|
def to_json_object(json_obj_)
|
165
169
|
json_obj_['labels'] = @a
|
166
170
|
end
|
167
171
|
|
172
|
+
# See EmptyAxis#from_json_object
|
168
173
|
def from_json_object(json_obj_)
|
169
174
|
initialize(json_obj_['labels'] || [])
|
170
175
|
end
|
@@ -188,39 +193,49 @@ module NTable
|
|
188
193
|
end
|
189
194
|
|
190
195
|
|
196
|
+
# See EmptyAxis#eql?
|
191
197
|
def eql?(obj_)
|
192
198
|
obj_.is_a?(IndexedAxis) && obj_.size.eql?(@size) && obj_.start.eql?(@start)
|
193
199
|
end
|
194
200
|
alias_method :==, :eql?
|
195
201
|
|
202
|
+
# See EmptyAxis#hash
|
196
203
|
def hash
|
197
204
|
@size.hash ^ @start.hash
|
198
205
|
end
|
199
206
|
|
207
|
+
# See EmptyAxis#inspect
|
200
208
|
def inspect
|
201
209
|
"#<#{self.class}:0x#{object_id.to_s(16)} size=#{@size} start=#{@start}>"
|
202
210
|
end
|
203
211
|
alias_method :to_s, :inspect
|
204
212
|
|
205
213
|
|
214
|
+
# See EmptyAxis#size
|
206
215
|
attr_reader :size
|
216
|
+
|
217
|
+
# Retrieve the number of the first row
|
207
218
|
attr_reader :start
|
208
219
|
|
209
220
|
|
221
|
+
# See EmptyAxis#index
|
210
222
|
def index(label_)
|
211
223
|
label_ >= @start && label_ < @size + @start ? label_ - @start : nil
|
212
224
|
end
|
213
225
|
|
226
|
+
# See EmptyAxis#label
|
214
227
|
def label(index_)
|
215
228
|
index_ >= 0 && index_ < @size ? index_ + @start : nil
|
216
229
|
end
|
217
230
|
|
218
231
|
|
232
|
+
# See EmptyAxis#to_json_object
|
219
233
|
def to_json_object(json_obj_)
|
220
234
|
json_obj_['size'] = @size
|
221
235
|
json_obj_['start'] = @start unless @start == 0
|
222
236
|
end
|
223
237
|
|
238
|
+
# See EmptyAxis#from_json_object
|
224
239
|
def from_json_object(json_obj_)
|
225
240
|
initialize(json_obj_['size'], json_obj_['start'].to_i)
|
226
241
|
end
|
@@ -245,40 +260,49 @@ module NTable
|
|
245
260
|
end
|
246
261
|
|
247
262
|
|
263
|
+
# See EmptyAxis#eql?
|
248
264
|
def eql?(obj_)
|
249
265
|
obj_.is_a?(ObjectAxis) && @a.eql?(obj_.instance_variable_get(:@a))
|
250
266
|
end
|
251
267
|
|
268
|
+
# See EmptyAxis#==
|
252
269
|
def ==(obj_)
|
253
270
|
obj_.is_a?(ObjectAxis) && @a == obj_.instance_variable_get(:@a)
|
254
271
|
end
|
255
272
|
|
273
|
+
# See EmptyAxis#hash
|
256
274
|
def hash
|
257
275
|
@a.hash
|
258
276
|
end
|
259
277
|
|
278
|
+
# See EmptyAxis#inspect
|
260
279
|
def inspect
|
261
280
|
"#<#{self.class}:0x#{object_id.to_s(16)} #{@a.inspect}>"
|
262
281
|
end
|
263
282
|
alias_method :to_s, :inspect
|
264
283
|
|
265
284
|
|
285
|
+
# See EmptyAxis#size
|
266
286
|
attr_reader :size
|
267
287
|
|
268
288
|
|
289
|
+
# See EmptyAxis#index
|
269
290
|
def index(label_)
|
270
291
|
@h[label_]
|
271
292
|
end
|
272
293
|
|
294
|
+
# See EmptyAxis#label
|
273
295
|
def label(index_)
|
274
296
|
@a[index_]
|
275
297
|
end
|
276
298
|
|
277
299
|
|
300
|
+
# See EmptyAxis#to_json_object
|
278
301
|
def to_json_object(json_obj_)
|
279
302
|
raise "Unable to JSON serialize an ObjectAxis"
|
280
303
|
end
|
281
304
|
|
305
|
+
# See EmptyAxis#from_json_object
|
282
306
|
def from_json_object(json_obj_)
|
283
307
|
raise "Unable to JSON serialize an ObjectAxis"
|
284
308
|
end
|
data/lib/ntable/construction.rb
CHANGED
@@ -41,9 +41,9 @@ require 'json'
|
|
41
41
|
module NTable
|
42
42
|
|
43
43
|
|
44
|
-
@numeric_sort =
|
45
|
-
@integer_sort =
|
46
|
-
@string_sort =
|
44
|
+
@numeric_sort = ->(a_, b_){ a_.to_f <=> b_.to_f }
|
45
|
+
@integer_sort = ->(a_, b_){ a_.to_i <=> b_.to_i }
|
46
|
+
@string_sort = ->(a_, b_){ a_.to_s <=> b_.to_s }
|
47
47
|
|
48
48
|
|
49
49
|
class << self
|
@@ -119,6 +119,13 @@ module NTable
|
|
119
119
|
# proc is provided, the resulting axis will be a LabeledAxis.
|
120
120
|
# You can also pass true instead of a Proc; this will create an
|
121
121
|
# LabeledAxis and make the conversion a simple to_s.
|
122
|
+
# [<tt>:postprocess</tt>]
|
123
|
+
# An optional Proc that postprocesses the final labels array.
|
124
|
+
# It should take an array of labels and return a modified array
|
125
|
+
# (which can be the original array modified in place). Called
|
126
|
+
# after any sort has been completed.
|
127
|
+
# You can use this, for example, to "fill in" labels that were
|
128
|
+
# not present in the original data.
|
122
129
|
#
|
123
130
|
# The third argument is an optional hash of miscellaneous options.
|
124
131
|
# The following keys are recognized:
|
@@ -188,6 +195,8 @@ module NTable
|
|
188
195
|
end
|
189
196
|
labels_.sort!(&func_)
|
190
197
|
end
|
198
|
+
postprocess_ = field_[:postprocess]
|
199
|
+
labels_ = postprocess_.call(labels_) if postprocess_.respond_to?(:call)
|
191
200
|
axis_ = klass_.new(labels_)
|
192
201
|
when ::Array
|
193
202
|
axis_ = IndexedAxis.new(ai_[1].to_i - ai_[0].to_i, ai_[0].to_i)
|
data/lib/ntable/index_wrapper.rb
CHANGED
@@ -42,24 +42,35 @@ module NTable
|
|
42
42
|
|
43
43
|
class IndexWrapper
|
44
44
|
|
45
|
+
|
45
46
|
# Create an IndexWrapper with the given integer index
|
46
47
|
|
47
48
|
def initialize(val_)
|
48
49
|
@value = val_.to_i
|
49
50
|
end
|
50
51
|
|
52
|
+
|
53
|
+
# Standard equality checker
|
54
|
+
|
51
55
|
def eql?(rhs_)
|
52
56
|
rhs_.is_a?(IndexWrapper) && @value == @rhs_.value
|
53
57
|
end
|
54
58
|
alias_method :==, :eql?
|
55
59
|
|
60
|
+
|
61
|
+
# Standard hash value
|
62
|
+
|
56
63
|
def hash
|
57
64
|
@value.hash
|
58
65
|
end
|
59
66
|
|
67
|
+
|
68
|
+
# Retrieve the actual index
|
69
|
+
|
60
70
|
attr_reader :value
|
61
71
|
alias_method :to_i, :value
|
62
72
|
|
73
|
+
|
63
74
|
end
|
64
75
|
|
65
76
|
|
data/lib/ntable/structure.rb
CHANGED
@@ -104,6 +104,7 @@ module NTable
|
|
104
104
|
def label(index_)
|
105
105
|
@axis_object.label(index_)
|
106
106
|
end
|
107
|
+
alias_method :[], :label
|
107
108
|
|
108
109
|
|
109
110
|
# Return the number of rows along this axis.
|
@@ -114,10 +115,27 @@ module NTable
|
|
114
115
|
end
|
115
116
|
|
116
117
|
|
117
|
-
|
118
|
+
# Iterate over the labels, in order.
|
119
|
+
|
120
|
+
def each
|
121
|
+
if block_given?
|
122
|
+
@axis_object.size.times do |i_|
|
123
|
+
yield @axis_object.label(i_)
|
124
|
+
end
|
125
|
+
else
|
126
|
+
to_enum
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
include ::Enumerable
|
131
|
+
|
132
|
+
|
133
|
+
# Standard equality check
|
134
|
+
|
135
|
+
def eql?(obj_)
|
118
136
|
obj_.is_a?(AxisInfo) && @axis_object.eql?(obj_.axis_object) && @axis_name.eql?(obj_.axis_name)
|
119
137
|
end
|
120
|
-
alias_method :==, :eql?
|
138
|
+
alias_method :==, :eql?
|
121
139
|
|
122
140
|
|
123
141
|
def _set_axis(axis_) # :nodoc:
|
@@ -133,7 +151,7 @@ module NTable
|
|
133
151
|
end
|
134
152
|
|
135
153
|
|
136
|
-
def _compute_offset(v_)
|
154
|
+
def _compute_offset(v_) # :nodoc:
|
137
155
|
if v_.is_a?(::NTable::IndexWrapper)
|
138
156
|
index_ = v_.to_i
|
139
157
|
index_ = nil if index_ < 0 || index_ >= @axis_object.size
|
@@ -160,11 +178,21 @@ module NTable
|
|
160
178
|
end
|
161
179
|
|
162
180
|
|
181
|
+
# Standard equality check
|
182
|
+
|
163
183
|
def eql?(obj_)
|
164
184
|
obj_.is_a?(Position) && obj_.structure.eql?(@structure) && obj_._offset.eql?(self._offset)
|
165
185
|
end
|
166
186
|
alias_method :==, :eql?
|
167
187
|
|
188
|
+
|
189
|
+
# Standard hash value
|
190
|
+
|
191
|
+
def hash
|
192
|
+
@structure.hash + @vector.hash
|
193
|
+
end
|
194
|
+
|
195
|
+
|
168
196
|
attr_reader :structure # :nodoc:
|
169
197
|
|
170
198
|
|
@@ -398,11 +426,21 @@ module NTable
|
|
398
426
|
@names[axis_.to_s]
|
399
427
|
end
|
400
428
|
end
|
429
|
+
alias_method :[], :axis
|
430
|
+
|
431
|
+
|
432
|
+
# Iterate over the axes in order, yielding AxisInfo objects.
|
433
|
+
|
434
|
+
def each(&block_)
|
435
|
+
@indexes.each(&block_)
|
436
|
+
end
|
437
|
+
|
438
|
+
include ::Enumerable
|
401
439
|
|
402
440
|
|
403
441
|
# Lock this structure, preventing further modification. Generally,
|
404
|
-
# this is done automatically when a structure is used by a table
|
405
|
-
#
|
442
|
+
# this is done automatically when a structure is used by a table;
|
443
|
+
# you normally do not need to call it yourself.
|
406
444
|
|
407
445
|
def lock!
|
408
446
|
unless @locked
|
data/lib/ntable/table.rb
CHANGED
@@ -128,6 +128,13 @@ module NTable
|
|
128
128
|
end
|
129
129
|
|
130
130
|
|
131
|
+
# Standard hash value
|
132
|
+
|
133
|
+
def hash
|
134
|
+
@structure.hash + @vals.hash + @offset.hash + @parent.hash
|
135
|
+
end
|
136
|
+
|
137
|
+
|
131
138
|
# The Structure of this table
|
132
139
|
attr_reader :structure
|
133
140
|
|
@@ -643,7 +650,7 @@ module NTable
|
|
643
650
|
end
|
644
651
|
|
645
652
|
|
646
|
-
def _offset_for_args(args_)
|
653
|
+
def _offset_for_args(args_) # :nodoc:
|
647
654
|
if args_.size == 1
|
648
655
|
first_ = args_.first
|
649
656
|
args_ = first_ if first_.is_a?(::Hash) || first_.is_a?(::Array)
|
data/test/tc_nested_object.rb
CHANGED
@@ -47,6 +47,7 @@ module NTable
|
|
47
47
|
def setup
|
48
48
|
@labeled_axis_2 = LabeledAxis.new([:one, :two])
|
49
49
|
@object_axis_2 = ObjectAxis.new([:one, :two])
|
50
|
+
@object_axis_3 = ObjectAxis.new([:one, :two, :three])
|
50
51
|
@labeled_axis_3 = LabeledAxis.new([:blue, :red, :white])
|
51
52
|
@indexed_axis_2 = IndexedAxis.new(2)
|
52
53
|
@indexed_axis_10 = IndexedAxis.new(10, 1)
|
@@ -202,7 +203,7 @@ module NTable
|
|
202
203
|
def test_from_level_1_labeled_with_objectify_conversion
|
203
204
|
obj_ = {'one' => 1, 'two' => 2}
|
204
205
|
t1_ = Table.from_nested_object(obj_,
|
205
|
-
[{:sort => true, :objectify =>
|
206
|
+
[{:sort => true, :objectify => ->(a_){ a_.to_sym }}])
|
206
207
|
assert_equal(Table.new(Structure.add(@object_axis_2), :load => [1,2]), t1_)
|
207
208
|
end
|
208
209
|
|
@@ -210,11 +211,20 @@ module NTable
|
|
210
211
|
def test_from_level_1_labeled_with_stringify_conversion
|
211
212
|
obj_ = {:one1 => 1, :two22 => 2}
|
212
213
|
t1_ = Table.from_nested_object(obj_,
|
213
|
-
[{:sort => true, :stringify =>
|
214
|
+
[{:sort => true, :stringify => ->(a_){ a_.to_s.gsub(/\d/, '') }}])
|
214
215
|
assert_equal(Table.new(Structure.add(@labeled_axis_2), :load => [1,2]), t1_)
|
215
216
|
end
|
216
217
|
|
217
218
|
|
219
|
+
def test_from_level_1_labeled_with_objectify_and_postprocess
|
220
|
+
obj_ = {:one => 1, :two => 2}
|
221
|
+
t1_ = Table.from_nested_object(obj_,
|
222
|
+
[{:sort => true, :objectify => true, :postprocess => ->(labels_){ labels_ << :three }}],
|
223
|
+
:fill => 0)
|
224
|
+
assert_equal(Table.new(Structure.add(@object_axis_3), :load => [1,2,0]), t1_)
|
225
|
+
end
|
226
|
+
|
227
|
+
|
218
228
|
end
|
219
229
|
|
220
230
|
end
|
data/test/tc_structure.rb
CHANGED
@@ -74,6 +74,13 @@ module NTable
|
|
74
74
|
end
|
75
75
|
|
76
76
|
|
77
|
+
def test_axis_info_enumerable
|
78
|
+
s_ = Structure.new
|
79
|
+
s_.add(@indexed1, :first)
|
80
|
+
assert_equal(45, s_.axis(0).inject(:+))
|
81
|
+
end
|
82
|
+
|
83
|
+
|
77
84
|
def test_add_multi_axis
|
78
85
|
s_ = Structure.new
|
79
86
|
s_.add(@labeled1, :first)
|
@@ -92,6 +99,15 @@ module NTable
|
|
92
99
|
end
|
93
100
|
|
94
101
|
|
102
|
+
def test_structure_enumerable
|
103
|
+
s_ = Structure.new
|
104
|
+
s_.add(@labeled1, :first)
|
105
|
+
s_.add(@indexed1, :second)
|
106
|
+
s_.add(@indexed1)
|
107
|
+
assert_equal([LabeledAxis, IndexedAxis, IndexedAxis], s_.map{ |ai_| ai_.axis_object.class })
|
108
|
+
end
|
109
|
+
|
110
|
+
|
95
111
|
def test_remove_axis
|
96
112
|
s_ = Structure.new
|
97
113
|
s_.add(@labeled1, :first)
|
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.4
|
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: 2012-09-
|
12
|
+
date: 2012-09-24 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: NTable provides a convenient data structure for storing n-dimensional
|
15
15
|
tabular data. It works with zero-dimensional scalar values, arrays, tables, and
|
@@ -64,7 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
64
|
version: 1.3.1
|
65
65
|
requirements: []
|
66
66
|
rubyforge_project: virtuoso
|
67
|
-
rubygems_version: 1.8.
|
67
|
+
rubygems_version: 1.8.24
|
68
68
|
signing_key:
|
69
69
|
specification_version: 3
|
70
70
|
summary: NTable is an n-dimensional table data structure for Ruby.
|