namo 0.1.0 → 0.2.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 +4 -4
- data/CHANGELOG +13 -0
- data/README.md +29 -0
- data/lib/Namo/VERSION.rb +2 -2
- data/lib/namo.rb +31 -19
- data/test/namo_test.rb +58 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6841b3921358ce7eefdbfbdba3a62eafd74857223d9df86038f9cc8087bbb947
|
|
4
|
+
data.tar.gz: bf05398ce78ea49683fbb7adb0b9989c6d6df86864a9bdf2373b156b14d8d5e7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2887c9dee76341b5e4ee75d50a1416475bd8c579d52117f67dcab81c9fe7c8cb1c50c08be7295db74aaf1f2d8727aa678b95d231d4c2e1d82a25b1ca050de61e
|
|
7
|
+
data.tar.gz: d5c5a35ac078d60dcd1baf43e73b5be1aa1bf02ed27a65071fd146223402a812a8b9ff9b88e6be5e4e62b5b47966460df613994d79215405439cde96c1a63278
|
data/CHANGELOG
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
CHANGELOG
|
|
2
2
|
_________
|
|
3
3
|
|
|
4
|
+
20260414
|
|
5
|
+
0.2.0: Include Enumerable.
|
|
6
|
+
|
|
7
|
+
1. ~ Namo: include Enumerable
|
|
8
|
+
2. + Namo#each: Yield Row objects wrapping each data row with formulae. Returns an Enumerator when no block is given.
|
|
9
|
+
3. ~ Namo#[]: Refactor to use Enumerable#select and Row#match? instead of select_rows.
|
|
10
|
+
4. - Namo#select_rows: Replaced by Row#match?.
|
|
11
|
+
5. + Namo::Row#match?: Selection logic moved from Namo to Row.
|
|
12
|
+
6. + Namo::Row#to_h: Return the underlying row hash.
|
|
13
|
+
7. ~ namo_test.rb: Add tests for #each and Enumerable methods (map, reduce, min_by, flat_map).
|
|
14
|
+
8. ~ README.md: + Enumerable section
|
|
15
|
+
9. ~ Namo::VERSION: /0.1.0/0.2.0/; /module/class/ to match Namo's definition.
|
|
16
|
+
|
|
4
17
|
20260328
|
|
5
18
|
0.1.0: Add formulae via []=. Formulae are procs which receive a Row object, compose via named references, and carry through selection.
|
|
6
19
|
|
data/README.md
CHANGED
|
@@ -156,6 +156,35 @@ sales[product: 'Widget'][:revenue, :quarter]
|
|
|
156
156
|
|
|
157
157
|
Formulae carry through selection — a filtered Namo instance remembers its formulae.
|
|
158
158
|
|
|
159
|
+
### Enumerable
|
|
160
|
+
|
|
161
|
+
Namo includes `Enumerable`, so `each`, `reduce`, `map`, `select`, `min_by`, and all the rest work out of the box. Rows are yielded as `Row` objects, so formulae are accessible during enumeration:
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
sales.reduce(0){|sum, row| sum + row[:quantity]}
|
|
165
|
+
# => 350
|
|
166
|
+
|
|
167
|
+
sales[product: 'Widget'].reduce(0){|sum, row| sum + row[:quantity]}
|
|
168
|
+
# => 250
|
|
169
|
+
|
|
170
|
+
sales[:revenue] = proc{|row| row[:price] * row[:quantity]}
|
|
171
|
+
|
|
172
|
+
sales.reduce(0){|sum, row| sum + row[:revenue]}
|
|
173
|
+
# => 5000.0
|
|
174
|
+
|
|
175
|
+
sales[product: 'Widget'].reduce(0){|sum, row| sum + row[:revenue]}
|
|
176
|
+
# => 2500.0
|
|
177
|
+
|
|
178
|
+
sales.map{|row| row[:product]}
|
|
179
|
+
# => ['Widget', 'Widget', 'Gadget', 'Gadget']
|
|
180
|
+
|
|
181
|
+
sales.min_by{|row| row[:price]}[:product]
|
|
182
|
+
# => 'Widget'
|
|
183
|
+
|
|
184
|
+
sales.flat_map{|row| [row[:price]]}
|
|
185
|
+
# => [10.0, 10.0, 25.0, 25.0]
|
|
186
|
+
```
|
|
187
|
+
|
|
159
188
|
### Extracting data
|
|
160
189
|
|
|
161
190
|
`to_a` returns an array of hashes:
|
data/lib/Namo/VERSION.rb
CHANGED
data/lib/namo.rb
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
# Namo
|
|
3
3
|
|
|
4
4
|
class Namo
|
|
5
|
+
include Enumerable
|
|
6
|
+
|
|
5
7
|
class Row
|
|
6
8
|
def [](name)
|
|
7
9
|
if @formulae.key?(name)
|
|
@@ -11,6 +13,21 @@ class Namo
|
|
|
11
13
|
end
|
|
12
14
|
end
|
|
13
15
|
|
|
16
|
+
def match?(selections)
|
|
17
|
+
selections.all? do |dimension, coordinate|
|
|
18
|
+
case coordinate
|
|
19
|
+
when Array, Range
|
|
20
|
+
coordinate.include?(self[dimension])
|
|
21
|
+
else
|
|
22
|
+
self[dimension] == coordinate
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_h
|
|
28
|
+
@row
|
|
29
|
+
end
|
|
30
|
+
|
|
14
31
|
private
|
|
15
32
|
|
|
16
33
|
def initialize(row, formulae)
|
|
@@ -35,13 +52,16 @@ class Namo
|
|
|
35
52
|
end
|
|
36
53
|
|
|
37
54
|
def [](*names, **selections)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
55
|
+
rows = selections.any? ? select{|row| row.match?(selections)} : entries
|
|
56
|
+
data = (
|
|
57
|
+
if names.any?
|
|
58
|
+
rows.map do |row|
|
|
59
|
+
names.each_with_object({}){|name, hash| hash[name] = row[name]}
|
|
60
|
+
end
|
|
61
|
+
else
|
|
62
|
+
rows.map(&:to_h)
|
|
43
63
|
end
|
|
44
|
-
|
|
64
|
+
)
|
|
45
65
|
self.class.new(data, formulae: @formulae.dup)
|
|
46
66
|
end
|
|
47
67
|
|
|
@@ -49,6 +69,11 @@ class Namo
|
|
|
49
69
|
@formulae[name] = proc
|
|
50
70
|
end
|
|
51
71
|
|
|
72
|
+
def each(&block)
|
|
73
|
+
return enum_for(:each) unless block_given?
|
|
74
|
+
@data.each{|row_data| block.call(Row.new(row_data, @formulae))}
|
|
75
|
+
end
|
|
76
|
+
|
|
52
77
|
def to_a
|
|
53
78
|
@data.map do |row|
|
|
54
79
|
row.keys.each_with_object({}) do |key, hash|
|
|
@@ -63,17 +88,4 @@ class Namo
|
|
|
63
88
|
@data = data
|
|
64
89
|
@formulae = formulae
|
|
65
90
|
end
|
|
66
|
-
|
|
67
|
-
def select_rows(selections)
|
|
68
|
-
@data.select do |row|
|
|
69
|
-
selections.all? do |dimension, coordinate|
|
|
70
|
-
case coordinate
|
|
71
|
-
when Array, Range
|
|
72
|
-
coordinate.include?(row[dimension])
|
|
73
|
-
else
|
|
74
|
-
row[dimension] == coordinate
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
91
|
end
|
data/test/namo_test.rb
CHANGED
|
@@ -146,6 +146,64 @@ describe Namo do
|
|
|
146
146
|
end
|
|
147
147
|
end
|
|
148
148
|
|
|
149
|
+
describe "#each" do
|
|
150
|
+
it "yields Row objects" do
|
|
151
|
+
rows = []
|
|
152
|
+
sales.each{|row| rows << row}
|
|
153
|
+
_(rows.first).must_be_kind_of Namo::Row
|
|
154
|
+
_(rows.length).must_equal 4
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it "yields rows with access to data" do
|
|
158
|
+
products = sales.map{|row| row[:product]}
|
|
159
|
+
_(products).must_equal ['Widget', 'Widget', 'Gadget', 'Gadget']
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it "yields rows with access to formulae" do
|
|
163
|
+
sales[:revenue] = proc{|r| r[:price] * r[:quantity]}
|
|
164
|
+
revenues = sales.map{|row| row[:revenue]}
|
|
165
|
+
_(revenues).must_equal [1000.0, 1500.0, 1000.0, 1500.0]
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
it "returns an enumerator without a block" do
|
|
169
|
+
_(sales.each).must_be_kind_of Enumerator
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
describe "Enumerable" do
|
|
174
|
+
it "supports reduce" do
|
|
175
|
+
total_quantity = sales.reduce(0){|sum, row| sum + row[:quantity]}
|
|
176
|
+
_(total_quantity).must_equal 350
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it "supports reduce with selection" do
|
|
180
|
+
widget_quantity = sales[product: 'Widget'].reduce(0){|sum, row| sum + row[:quantity]}
|
|
181
|
+
_(widget_quantity).must_equal 250
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it "supports reduce with formulae" do
|
|
185
|
+
sales[:revenue] = proc{|r| r[:price] * r[:quantity]}
|
|
186
|
+
total_revenue = sales.reduce(0){|sum, row| sum + row[:revenue]}
|
|
187
|
+
_(total_revenue).must_equal 5000.0
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it "supports reduce with selection and formulae" do
|
|
191
|
+
sales[:revenue] = proc{|r| r[:price] * r[:quantity]}
|
|
192
|
+
widget_revenue = sales[product: 'Widget'].reduce(0){|sum, row| sum + row[:revenue]}
|
|
193
|
+
_(widget_revenue).must_equal 2500.0
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it "supports min_by" do
|
|
197
|
+
cheapest = sales.min_by{|row| row[:price]}
|
|
198
|
+
_(cheapest[:product]).must_equal 'Widget'
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it "supports flat_map" do
|
|
202
|
+
prices = sales.flat_map{|row| [row[:price]]}
|
|
203
|
+
_(prices).must_equal [10.0, 10.0, 25.0, 25.0]
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
149
207
|
describe "#to_a" do
|
|
150
208
|
it "returns the data as an array of hashes" do
|
|
151
209
|
_(sales.to_a).must_equal sample_data
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: namo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- thoran
|
|
@@ -86,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
86
86
|
- !ruby/object:Gem::Version
|
|
87
87
|
version: '0'
|
|
88
88
|
requirements: []
|
|
89
|
-
rubygems_version: 4.0.
|
|
89
|
+
rubygems_version: 4.0.10
|
|
90
90
|
specification_version: 4
|
|
91
91
|
summary: Named dimensional data for Ruby.
|
|
92
92
|
test_files: []
|