From 588a6a0c2a6dbbab9029b1c19d8e6413d8df2727 Mon Sep 17 00:00:00 2001 From: James Harris Date: Fri, 6 Dec 2019 11:45:24 +1000 Subject: [PATCH 1/4] Add accept methods to handler sets. --- handlerset.go | 38 +++++++++++++++++++- handlerset_test.go | 90 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 1 deletion(-) diff --git a/handlerset.go b/handlerset.go index 2ea9069b..34c90bfe 100644 --- a/handlerset.go +++ b/handlerset.go @@ -1,6 +1,10 @@ package configkit -import "github.com/dogmatiq/configkit/message" +import ( + "context" + + "github.com/dogmatiq/configkit/message" +) // HandlerSet is a collection of handlers. type HandlerSet map[Identity]Handler @@ -111,6 +115,22 @@ func (s HandlerSet) Filter(fn func(Handler) bool) HandlerSet { return subset } +// AcceptVisitor visits each handler in the set. +// +// It returns the error returned by the first handler to return a non-nil error. +// It returns nil if all handlers accept the visitor without failure. +// +// The order in which handlers are visited is not guaranteed. +func (s HandlerSet) AcceptVisitor(ctx context.Context, v Visitor) error { + for _, h := range s { + if err := h.AcceptVisitor(ctx, v); err != nil { + return err + } + } + + return nil +} + // RichHandlerSet is a collection of rich handlers. type RichHandlerSet map[Identity]RichHandler @@ -245,3 +265,19 @@ func (s RichHandlerSet) Filter(fn func(RichHandler) bool) RichHandlerSet { return subset } + +// AcceptRichVisitor visits each handler in the set. +// +// It returns the error returned by the first handler to return a non-nil error. +// It returns nil if all handlers accept the visitor without failure. +// +// The order in which handlers are visited is not guaranteed. +func (s RichHandlerSet) AcceptRichVisitor(ctx context.Context, v RichVisitor) error { + for _, h := range s { + if err := h.AcceptRichVisitor(ctx, v); err != nil { + return err + } + } + + return nil +} diff --git a/handlerset_test.go b/handlerset_test.go index cef87e34..c7f51032 100644 --- a/handlerset_test.go +++ b/handlerset_test.go @@ -1,6 +1,10 @@ package configkit_test import ( + "context" + "errors" + + "github.com/dogmatiq/configkit" . "github.com/dogmatiq/configkit" cfixtures "github.com/dogmatiq/configkit/fixtures" "github.com/dogmatiq/dogma" @@ -208,6 +212,49 @@ var _ = Describe("type HandlerSet", func() { Expect(set.Has(projection)).To(BeTrue()) }) }) + + Describe("func AcceptVisitor()", func() { + BeforeEach(func() { + set.Add(aggregate) + set.Add(projection) + }) + + It("visits each handler in the set", func() { + var visited []Handler + + err := set.AcceptVisitor( + context.Background(), + &cfixtures.Visitor{ + VisitAggregateFunc: func(_ context.Context, cfg configkit.Aggregate) error { + Expect(cfg).To(BeIdenticalTo(aggregate)) + visited = append(visited, cfg) + return nil + }, + VisitProjectionFunc: func(_ context.Context, cfg configkit.Projection) error { + Expect(cfg).To(BeIdenticalTo(projection)) + visited = append(visited, cfg) + return nil + }, + }, + ) + + Expect(err).ShouldNot(HaveOccurred()) + Expect(visited).To(ConsistOf(aggregate, projection)) + }) + + It("returns an error if one of the handlers fails", func() { + err := set.AcceptVisitor( + context.Background(), + &cfixtures.Visitor{ + VisitProjectionFunc: func(_ context.Context, cfg configkit.Projection) error { + return errors.New("") + }, + }, + ) + + Expect(err).To(MatchError("")) + }) + }) }) var _ = Describe("type RichHandlerSet", func() { @@ -409,4 +456,47 @@ var _ = Describe("type RichHandlerSet", func() { Expect(set.Has(projection)).To(BeTrue()) }) }) + + Describe("func AcceptRichVisitor()", func() { + BeforeEach(func() { + set.Add(aggregate) + set.Add(projection) + }) + + It("visits each handler in the set", func() { + var visited []RichHandler + + err := set.AcceptRichVisitor( + context.Background(), + &cfixtures.RichVisitor{ + VisitRichAggregateFunc: func(_ context.Context, cfg configkit.RichAggregate) error { + Expect(cfg).To(BeIdenticalTo(aggregate)) + visited = append(visited, cfg) + return nil + }, + VisitRichProjectionFunc: func(_ context.Context, cfg configkit.RichProjection) error { + Expect(cfg).To(BeIdenticalTo(projection)) + visited = append(visited, cfg) + return nil + }, + }, + ) + + Expect(err).ShouldNot(HaveOccurred()) + Expect(visited).To(ConsistOf(aggregate, projection)) + }) + + It("returns an error if one of the handlers fails", func() { + err := set.AcceptRichVisitor( + context.Background(), + &cfixtures.RichVisitor{ + VisitRichProjectionFunc: func(_ context.Context, cfg configkit.RichProjection) error { + return errors.New("") + }, + }, + ) + + Expect(err).To(MatchError("")) + }) + }) }) From c8fcfd6ea56fa04395d4ddbbc41d86b77fdcf53b Mon Sep 17 00:00:00 2001 From: James Harris Date: Fri, 6 Dec 2019 11:51:41 +1000 Subject: [PATCH 2/4] Use `Handler[Rich]Set.Accept[Rich]Visitor()` in visitor fixtures. --- fixtures/visitor.go | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/fixtures/visitor.go b/fixtures/visitor.go index 5397509a..e58aad6d 100644 --- a/fixtures/visitor.go +++ b/fixtures/visitor.go @@ -25,13 +25,7 @@ func (v *Visitor) VisitApplication(ctx context.Context, cfg configkit.Applicatio return v.VisitApplicationFunc(ctx, cfg) } - for _, h := range cfg.Handlers() { - if err := h.AcceptVisitor(ctx, v); err != nil { - return err - } - } - - return nil + return cfg.Handlers().AcceptVisitor(ctx, v) } // VisitAggregate calls v.VisitAggregateFunc(ctx, cfg) if it is non-nil. @@ -89,13 +83,7 @@ func (v *RichVisitor) VisitRichApplication(ctx context.Context, cfg configkit.Ri return v.VisitRichApplicationFunc(ctx, cfg) } - for _, h := range cfg.RichHandlers() { - if err := h.AcceptRichVisitor(ctx, v); err != nil { - return err - } - } - - return nil + return cfg.RichHandlers().AcceptRichVisitor(ctx, v) } // VisitRichAggregate calls v.VisitAggregateFunc(ctx, cfg) if it is non-nil. From 0deca6c600299647578773d00816dc090ac322b5 Mon Sep 17 00:00:00 2001 From: James Harris Date: Fri, 6 Dec 2019 12:06:42 +1000 Subject: [PATCH 3/4] Remove duplicate import of `configkit`. --- handlerset_test.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/handlerset_test.go b/handlerset_test.go index c7f51032..1b0b7397 100644 --- a/handlerset_test.go +++ b/handlerset_test.go @@ -4,7 +4,6 @@ import ( "context" "errors" - "github.com/dogmatiq/configkit" . "github.com/dogmatiq/configkit" cfixtures "github.com/dogmatiq/configkit/fixtures" "github.com/dogmatiq/dogma" @@ -225,12 +224,12 @@ var _ = Describe("type HandlerSet", func() { err := set.AcceptVisitor( context.Background(), &cfixtures.Visitor{ - VisitAggregateFunc: func(_ context.Context, cfg configkit.Aggregate) error { + VisitAggregateFunc: func(_ context.Context, cfg Aggregate) error { Expect(cfg).To(BeIdenticalTo(aggregate)) visited = append(visited, cfg) return nil }, - VisitProjectionFunc: func(_ context.Context, cfg configkit.Projection) error { + VisitProjectionFunc: func(_ context.Context, cfg Projection) error { Expect(cfg).To(BeIdenticalTo(projection)) visited = append(visited, cfg) return nil @@ -246,7 +245,7 @@ var _ = Describe("type HandlerSet", func() { err := set.AcceptVisitor( context.Background(), &cfixtures.Visitor{ - VisitProjectionFunc: func(_ context.Context, cfg configkit.Projection) error { + VisitProjectionFunc: func(_ context.Context, cfg Projection) error { return errors.New("") }, }, @@ -469,12 +468,12 @@ var _ = Describe("type RichHandlerSet", func() { err := set.AcceptRichVisitor( context.Background(), &cfixtures.RichVisitor{ - VisitRichAggregateFunc: func(_ context.Context, cfg configkit.RichAggregate) error { + VisitRichAggregateFunc: func(_ context.Context, cfg RichAggregate) error { Expect(cfg).To(BeIdenticalTo(aggregate)) visited = append(visited, cfg) return nil }, - VisitRichProjectionFunc: func(_ context.Context, cfg configkit.RichProjection) error { + VisitRichProjectionFunc: func(_ context.Context, cfg RichProjection) error { Expect(cfg).To(BeIdenticalTo(projection)) visited = append(visited, cfg) return nil @@ -490,7 +489,7 @@ var _ = Describe("type RichHandlerSet", func() { err := set.AcceptRichVisitor( context.Background(), &cfixtures.RichVisitor{ - VisitRichProjectionFunc: func(_ context.Context, cfg configkit.RichProjection) error { + VisitRichProjectionFunc: func(_ context.Context, cfg RichProjection) error { return errors.New("") }, }, From 10fbdf19bc001ec4878ca342b577ee396c3092c8 Mon Sep 17 00:00:00 2001 From: James Harris Date: Fri, 6 Dec 2019 12:12:53 +1000 Subject: [PATCH 4/4] Add handler-set visitation methods to the changelog. --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c65d3bc0..b94c140e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ The format is based on [Keep a Changelog], and this project adheres to [Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ [Semantic Versioning]: https://semver.org/spec/v2.0.0.html +## [Unreleased] + +### Added + +- Add `HandlerSet.AcceptVisitor()` and `RichHandlerSet.AcceptRichVisitor()` + ## [0.1.0] - 2019-12-02 - Initial release