Skip to content

Commit

Permalink
Merge pull request #489 from PuerkitoBio/amikai-itereach-pr
Browse files Browse the repository at this point in the history
Support EachIter based on Go's 1.23 iterator.
  • Loading branch information
mna authored Sep 6, 2024
2 parents 957a864 + 291e2cf commit 9551ee5
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.21.x, 1.22.x]
go-version: [1.23.x]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}

Expand Down
42 changes: 42 additions & 0 deletions bench_iteration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,48 @@ func BenchmarkEach(b *testing.B) {
}
}

func BenchmarkEachIter(b *testing.B) {
var tmp, n int

b.StopTimer()
sel := DocW().Find("td")
b.StartTimer()
for i := 0; i < b.N; i++ {
for range sel.EachIter() {
tmp++
}
if n == 0 {
n = tmp
}
}
if n != 59 {
b.Fatalf("want 59, got %d", n)
}
}

func BenchmarkEachIterWithBreak(b *testing.B) {
var tmp, n int

b.StopTimer()
sel := DocW().Find("td")
b.StartTimer()
for i := 0; i < b.N; i++ {
tmp = 0
for range sel.EachIter() {
tmp++
if tmp >= 10 {
break
}
}
if n == 0 {
n = tmp
}
}
if n != 10 {
b.Fatalf("want 10, got %d", n)
}
}

func BenchmarkMap(b *testing.B) {
var tmp, n int

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ require (
golang.org/x/net v0.29.0
)

go 1.18
go 1.23
14 changes: 14 additions & 0 deletions iteration.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package goquery

import "iter"

// Each iterates over a Selection object, executing a function for each
// matched element. It returns the current Selection object. The function
// f is called for each element in the selection with the index of the
Expand All @@ -12,6 +14,18 @@ func (s *Selection) Each(f func(int, *Selection)) *Selection {
return s
}

// EachIter returns an iterator that yields the Selection object in order.
// The implementation is similar to Each, but it returns an iterator instead.
func (s *Selection) EachIter() iter.Seq2[int, *Selection] {
return func(yield func(int, *Selection) bool) {
for i, n := range s.Nodes {
if !yield(i, newSingleSelection(n, s.document)) {
return
}
}
}
}

// EachWithBreak iterates over a Selection object, executing a function for each
// matched element. It is identical to Each except that it is possible to break
// out of the loop by returning false in the callback function. It returns the
Expand Down
36 changes: 36 additions & 0 deletions iteration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,39 @@ func TestGenericMap(t *testing.T) {
t.Errorf("Expected Map array result to have a length of 3, found %v.", len(vals))
}
}

func TestEachIter(t *testing.T) {
var cnt int

sel := Doc().Find(".hero-unit .row-fluid")

for i, s := range sel.EachIter() {
cnt++
t.Logf("At index %v, node %v", i, s.Nodes[0].Data)
}

sel = sel.Find("a")

if cnt != 4 {
t.Errorf("Expected Each() to call function 4 times, got %v times.", cnt)
}
assertLength(t, sel.Nodes, 6)
}

func TestEachIterWithBreak(t *testing.T) {
var cnt int

sel := Doc().Find(".hero-unit .row-fluid")
for i, s := range sel.EachIter() {
cnt++
t.Logf("At index %v, node %v", i, s.Nodes[0].Data)
break
}

sel = sel.Find("a")

if cnt != 1 {
t.Errorf("Expected Each() to call function 1 time, got %v times.", cnt)
}
assertLength(t, sel.Nodes, 6)
}

0 comments on commit 9551ee5

Please sign in to comment.