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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1bc0f90c2517b809ed9929ffcdf2fbc1e538974bc30320a3b603d93582f5200
4
- data.tar.gz: 70247c7e8fa7b48ac0192400016351c323f5abcd9ee1095653cc58d6edc524e4
3
+ metadata.gz: 6841b3921358ce7eefdbfbdba3a62eafd74857223d9df86038f9cc8087bbb947
4
+ data.tar.gz: bf05398ce78ea49683fbb7adb0b9989c6d6df86864a9bdf2373b156b14d8d5e7
5
5
  SHA512:
6
- metadata.gz: b7162863da3b04b989dd6206234094b160b0f32d36fee58f948608b85a3cd1c2dc09691c6e2c2c74d598942a0c15e44760f6b498a7bddbb1cc4bb2366b2996ac
7
- data.tar.gz: 5dd204de47dc6979753a0b7113765093222f5fab870bacd4034aada2f93288af6e872781f357704951b75d1e17ea9c6aefc8a625530ca2e6f253f695c5456fc2
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
@@ -1,6 +1,6 @@
1
1
  # Namo/VERSION.rb
2
2
  # Namo::VERSION
3
3
 
4
- module Namo
5
- VERSION = '0.1.0'
4
+ class Namo
5
+ VERSION = '0.2.0'
6
6
  end
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
- data = selections.any? ? select_rows(selections) : @data
39
- if names.any?
40
- data = data.map do |row_data|
41
- row = Row.new(row_data, @formulae)
42
- names.each_with_object({}){|name, hash| hash[name] = row[name]}
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
- end
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.1.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.8
89
+ rubygems_version: 4.0.10
90
90
  specification_version: 4
91
91
  summary: Named dimensional data for Ruby.
92
92
  test_files: []