From 629afd96a7c5dcfd80a14454176aa7b1f65ff814 Mon Sep 17 00:00:00 2001 From: amikai Date: Sat, 20 Jul 2024 11:37:24 +0800 Subject: [PATCH 1/7] Bump the version to 1.23 --- .github/workflows/test.yml | 2 +- go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0bbf5b0..c4cedee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: test: strategy: matrix: - go-version: [1.21.x, 1.22.x] + go-version: [1.21.x, 1.22.x, 1.23.0-rc.1] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} diff --git a/go.mod b/go.mod index 2fe9f3c..8fba30d 100644 --- a/go.mod +++ b/go.mod @@ -5,4 +5,4 @@ require ( golang.org/x/net v0.27.0 ) -go 1.18 +go 1.23 From 3f0ba08339354b340dd90a79173f79d386e33060 Mon Sep 17 00:00:00 2001 From: amikai Date: Sat, 20 Jul 2024 11:38:01 +0800 Subject: [PATCH 2/7] Support EachIter based on 1.23 iterator --- bench_iteration_test.go | 42 +++++++++++++++++++++++++++++++++++++++++ iteration.go | 14 ++++++++++++++ iteration_test.go | 36 +++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+) diff --git a/bench_iteration_test.go b/bench_iteration_test.go index 71bfd59..1def1a2 100644 --- a/bench_iteration_test.go +++ b/bench_iteration_test.go @@ -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 diff --git a/iteration.go b/iteration.go index 1c98158..1ca5245 100644 --- a/iteration.go +++ b/iteration.go @@ -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 @@ -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 diff --git a/iteration_test.go b/iteration_test.go index dd6fefa..48cebb2 100644 --- a/iteration_test.go +++ b/iteration_test.go @@ -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) +} From 0f5ed940723e8cbb6630cdc6550c54927a952279 Mon Sep 17 00:00:00 2001 From: Martin Angers Date: Tue, 23 Jul 2024 10:04:34 -0400 Subject: [PATCH 3/7] Update test.yml to use go1.23rc2 --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c4cedee..d279c8c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: test: strategy: matrix: - go-version: [1.21.x, 1.22.x, 1.23.0-rc.1] + go-version: [1.21.x, 1.22.x, 1.23rc2] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} From 466380eec709da6d847c263032ccc3d69d8c796f Mon Sep 17 00:00:00 2001 From: Martin Angers Date: Tue, 23 Jul 2024 10:08:48 -0400 Subject: [PATCH 4/7] Update test.yml (another attempt to use the go1.23 rc version) --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d279c8c..d987a83 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: test: strategy: matrix: - go-version: [1.21.x, 1.22.x, 1.23rc2] + go-version: [1.21.x, 1.22.x, 1.23.0-rc.2] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} From 6802fc555536600b8f0cae60362afe82bc23504b Mon Sep 17 00:00:00 2001 From: amikai Date: Wed, 24 Jul 2024 10:56:30 +0800 Subject: [PATCH 5/7] Re-orangize code for compitable - We don't need to use the iter.Seq2 type; instead, we can use func(yield func(int, *Selection) bool). In fact, the underlying type of iter.Seq2 is func(yield func(int, *Selection) bool), so we don't need to upgrade the go.mod version. - For for-range testing in version 1.23, we can use build tags to compile only for versions above 1.23. --- bench_iteration123_test.go | 48 ++++++++++++++++++++++++++++++++++++++ bench_iteration_test.go | 14 +++++------ go.mod | 2 +- iteration.go | 4 +--- iteration123_test.go | 42 +++++++++++++++++++++++++++++++++ iteration_test.go | 22 ++++++++--------- 6 files changed, 109 insertions(+), 23 deletions(-) create mode 100644 bench_iteration123_test.go create mode 100644 iteration123_test.go diff --git a/bench_iteration123_test.go b/bench_iteration123_test.go new file mode 100644 index 0000000..956b723 --- /dev/null +++ b/bench_iteration123_test.go @@ -0,0 +1,48 @@ +//go:build go1.23 +// +build go1.23 + +package goquery + +import "testing" + +func BenchmarkEachIter123(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 BenchmarkEachIterWithBreak123(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) + } +} diff --git a/bench_iteration_test.go b/bench_iteration_test.go index 1def1a2..1ff9507 100644 --- a/bench_iteration_test.go +++ b/bench_iteration_test.go @@ -32,9 +32,10 @@ func BenchmarkEachIter(b *testing.B) { sel := DocW().Find("td") b.StartTimer() for i := 0; i < b.N; i++ { - for range sel.EachIter() { + sel.EachIter()(func(i int, s *Selection) bool { tmp++ - } + return true + }) if n == 0 { n = tmp } @@ -52,12 +53,11 @@ func BenchmarkEachIterWithBreak(b *testing.B) { b.StartTimer() for i := 0; i < b.N; i++ { tmp = 0 - for range sel.EachIter() { + sel.EachIter()(func(i int, s *Selection) bool { tmp++ - if tmp >= 10 { - break - } - } + return tmp < 10 + }) + if n == 0 { n = tmp } diff --git a/go.mod b/go.mod index 8fba30d..2fe9f3c 100644 --- a/go.mod +++ b/go.mod @@ -5,4 +5,4 @@ require ( golang.org/x/net v0.27.0 ) -go 1.23 +go 1.18 diff --git a/iteration.go b/iteration.go index 1ca5245..882be2d 100644 --- a/iteration.go +++ b/iteration.go @@ -1,7 +1,5 @@ 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 @@ -16,7 +14,7 @@ func (s *Selection) Each(f func(int, *Selection)) *Selection { // 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] { +func (s *Selection) EachIter() func(yield func(int, *Selection) bool) { return func(yield func(int, *Selection) bool) { for i, n := range s.Nodes { if !yield(i, newSingleSelection(n, s.document)) { diff --git a/iteration123_test.go b/iteration123_test.go new file mode 100644 index 0000000..23f4a2f --- /dev/null +++ b/iteration123_test.go @@ -0,0 +1,42 @@ +//go:build go1.23 +// +build go1.23 + +package goquery + +import "testing" + +func TestEachIter123(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 EachIter() to call function 4 times, got %v times.", cnt) + } + assertLength(t, sel.Nodes, 6) +} + +func TestEachIterWithBreak123(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 EachIter() to call function 1 time, got %v times.", cnt) + } + assertLength(t, sel.Nodes, 6) +} diff --git a/iteration_test.go b/iteration_test.go index 48cebb2..b976fce 100644 --- a/iteration_test.go +++ b/iteration_test.go @@ -110,16 +110,15 @@ func TestEachIter(t *testing.T) { var cnt int sel := Doc().Find(".hero-unit .row-fluid") - - for i, s := range sel.EachIter() { + sel.EachIter()(func(i int, n *Selection) bool { cnt++ - t.Logf("At index %v, node %v", i, s.Nodes[0].Data) - } - + t.Logf("At index %v, node %v", i, n.Nodes[0].Data) + return true + }) sel = sel.Find("a") if cnt != 4 { - t.Errorf("Expected Each() to call function 4 times, got %v times.", cnt) + t.Errorf("Expected EachIter() to call function 4 time, got %v times.", cnt) } assertLength(t, sel.Nodes, 6) } @@ -128,16 +127,15 @@ func TestEachIterWithBreak(t *testing.T) { var cnt int sel := Doc().Find(".hero-unit .row-fluid") - for i, s := range sel.EachIter() { + sel.EachIter()(func(i int, n *Selection) bool { cnt++ - t.Logf("At index %v, node %v", i, s.Nodes[0].Data) - break - } - + t.Logf("At index %v, node %v", i, n.Nodes[0].Data) + return false + }) sel = sel.Find("a") if cnt != 1 { - t.Errorf("Expected Each() to call function 1 time, got %v times.", cnt) + t.Errorf("Expected EachIter() to call function 1 time, got %v times.", cnt) } assertLength(t, sel.Nodes, 6) } From eec8e87fed856dc0ebbdc6c19efbb835b3ee627e Mon Sep 17 00:00:00 2001 From: Martin Angers Date: Fri, 6 Sep 2024 10:14:32 -0400 Subject: [PATCH 6/7] Revert "Re-orangize code for compitable" This reverts commit 6802fc555536600b8f0cae60362afe82bc23504b. --- bench_iteration123_test.go | 48 -------------------------------------- bench_iteration_test.go | 14 +++++------ go.mod | 2 +- iteration.go | 4 +++- iteration123_test.go | 42 --------------------------------- iteration_test.go | 22 +++++++++-------- 6 files changed, 23 insertions(+), 109 deletions(-) delete mode 100644 bench_iteration123_test.go delete mode 100644 iteration123_test.go diff --git a/bench_iteration123_test.go b/bench_iteration123_test.go deleted file mode 100644 index 956b723..0000000 --- a/bench_iteration123_test.go +++ /dev/null @@ -1,48 +0,0 @@ -//go:build go1.23 -// +build go1.23 - -package goquery - -import "testing" - -func BenchmarkEachIter123(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 BenchmarkEachIterWithBreak123(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) - } -} diff --git a/bench_iteration_test.go b/bench_iteration_test.go index 1ff9507..1def1a2 100644 --- a/bench_iteration_test.go +++ b/bench_iteration_test.go @@ -32,10 +32,9 @@ func BenchmarkEachIter(b *testing.B) { sel := DocW().Find("td") b.StartTimer() for i := 0; i < b.N; i++ { - sel.EachIter()(func(i int, s *Selection) bool { + for range sel.EachIter() { tmp++ - return true - }) + } if n == 0 { n = tmp } @@ -53,11 +52,12 @@ func BenchmarkEachIterWithBreak(b *testing.B) { b.StartTimer() for i := 0; i < b.N; i++ { tmp = 0 - sel.EachIter()(func(i int, s *Selection) bool { + for range sel.EachIter() { tmp++ - return tmp < 10 - }) - + if tmp >= 10 { + break + } + } if n == 0 { n = tmp } diff --git a/go.mod b/go.mod index 2fe9f3c..8fba30d 100644 --- a/go.mod +++ b/go.mod @@ -5,4 +5,4 @@ require ( golang.org/x/net v0.27.0 ) -go 1.18 +go 1.23 diff --git a/iteration.go b/iteration.go index 882be2d..1ca5245 100644 --- a/iteration.go +++ b/iteration.go @@ -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 @@ -14,7 +16,7 @@ func (s *Selection) Each(f func(int, *Selection)) *Selection { // 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() func(yield func(int, *Selection) bool) { +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)) { diff --git a/iteration123_test.go b/iteration123_test.go deleted file mode 100644 index 23f4a2f..0000000 --- a/iteration123_test.go +++ /dev/null @@ -1,42 +0,0 @@ -//go:build go1.23 -// +build go1.23 - -package goquery - -import "testing" - -func TestEachIter123(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 EachIter() to call function 4 times, got %v times.", cnt) - } - assertLength(t, sel.Nodes, 6) -} - -func TestEachIterWithBreak123(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 EachIter() to call function 1 time, got %v times.", cnt) - } - assertLength(t, sel.Nodes, 6) -} diff --git a/iteration_test.go b/iteration_test.go index b976fce..48cebb2 100644 --- a/iteration_test.go +++ b/iteration_test.go @@ -110,15 +110,16 @@ func TestEachIter(t *testing.T) { var cnt int sel := Doc().Find(".hero-unit .row-fluid") - sel.EachIter()(func(i int, n *Selection) bool { + + for i, s := range sel.EachIter() { cnt++ - t.Logf("At index %v, node %v", i, n.Nodes[0].Data) - return true - }) + t.Logf("At index %v, node %v", i, s.Nodes[0].Data) + } + sel = sel.Find("a") if cnt != 4 { - t.Errorf("Expected EachIter() to call function 4 time, got %v times.", cnt) + t.Errorf("Expected Each() to call function 4 times, got %v times.", cnt) } assertLength(t, sel.Nodes, 6) } @@ -127,15 +128,16 @@ func TestEachIterWithBreak(t *testing.T) { var cnt int sel := Doc().Find(".hero-unit .row-fluid") - sel.EachIter()(func(i int, n *Selection) bool { + for i, s := range sel.EachIter() { cnt++ - t.Logf("At index %v, node %v", i, n.Nodes[0].Data) - return false - }) + t.Logf("At index %v, node %v", i, s.Nodes[0].Data) + break + } + sel = sel.Find("a") if cnt != 1 { - t.Errorf("Expected EachIter() to call function 1 time, got %v times.", cnt) + t.Errorf("Expected Each() to call function 1 time, got %v times.", cnt) } assertLength(t, sel.Nodes, 6) } From 7019296f03391013d526544d8cd6aaa98e4db3ff Mon Sep 17 00:00:00 2001 From: Martin Angers Date: Fri, 6 Sep 2024 10:21:11 -0400 Subject: [PATCH 7/7] Update CI to target go1.23+ --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d987a83..f42f31b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: test: strategy: matrix: - go-version: [1.21.x, 1.22.x, 1.23.0-rc.2] + go-version: [1.23.x] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }}