From 669948ee254b69a9c345abbcfa5056f264a0088d Mon Sep 17 00:00:00 2001 From: Volodymyr Date: Wed, 7 Feb 2024 22:03:02 +0100 Subject: [PATCH] feat: [CN-37] - Merge censor constructors. --- docs/index.md | 8 ++++---- format_test.go | 17 +++++++++++------ options.go | 24 ++++++++++++++++++++++++ processor.go | 47 ++++++++++++++++++++++++++++------------------- processor_test.go | 27 +++++++++++++++++---------- 5 files changed, 84 insertions(+), 39 deletions(-) create mode 100644 options.go diff --git a/docs/index.md b/docs/index.md index ae1fb77..deec3e7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -121,7 +121,7 @@ func main() { } // Create a new instance of censor.Processor with the specified configuration and set it as a global processor. - censor.SetGlobalProcessor(censor.NewWithConfig(cfg)) + censor.NewWithOpts(censor.WithConfig(&cfg)) const msg = `Here are the details of your account: email=user.example.email@ggmail.com, IBAN=UA123456789123456789123456789` @@ -207,7 +207,7 @@ func main() { }, } - p := censor.NewWithConfig(cfg) + p, err := censor.NewWithOpts(censor.WithConfig(&cfg)) } ``` @@ -228,7 +228,7 @@ func main() { pathToConfigFile := "./cfg_example.yml" // Create a new instance of censor.Processor with the configuration file usage. - p, err := censor.NewWithFileConfig(pathToConfigFile) + p, err := censor.NewWithOpts(censor.WithConfigPath(pathToConfigFile)) if err != nil { // Handle error. } @@ -454,7 +454,7 @@ func main() { }, } - p := censor.NewWithConfig(cfg) + p, err := censor.NewWithOpts(censor.WithConfig(&cfg)) slog.Info("Request", "payload", p.Format(v)) // Here is what we'll see in the log: diff --git a/format_test.go b/format_test.go index 945133b..a9150c1 100644 --- a/format_test.go +++ b/format_test.go @@ -54,7 +54,9 @@ func Test_InstanceConfiguration(t *testing.T) { UseJSONTagName: true, }, } - p := NewWithConfig(c) + + p, err := NewWithOpts(WithConfig(&c)) + require.NoError(t, err) type testStruct struct { Name string `censor:"display"` @@ -112,7 +114,8 @@ func Test_GlobalInstanceConfiguration(t *testing.T) { Age int `json:"age" censor:"display"` } - p := NewWithConfig(c) + p, err := NewWithOpts(WithConfig(&c)) + require.NoError(t, err) SetGlobalInstance(p) exp := `censor.testStruct{Name: John, age: 30}` @@ -128,11 +131,12 @@ func Test_GetGlobalInstance(t *testing.T) { func Test_SetGlobalInstance(t *testing.T) { t.Cleanup(func() { SetGlobalInstance(New()) }) - p := NewWithConfig(Config{ + p, err := NewWithOpts(WithConfig(&Config{ Formatter: formatter.Config{ MaskValue: "[censored]", }, - }) + })) + require.NoError(t, err) SetGlobalInstance(p) @@ -148,12 +152,13 @@ func Test_SetGlobalInstance(t *testing.T) { func TestExcludePatterns(t *testing.T) { t.Cleanup(func() { SetGlobalInstance(New()) }) - p := NewWithConfig(Config{ + p, err := NewWithOpts(WithConfig(&Config{ Formatter: formatter.Config{ MaskValue: "[CENSORED]", ExcludePatterns: []string{`\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b`}, }, - }) + })) + require.NoError(t, err) SetGlobalInstance(p) diff --git a/options.go b/options.go new file mode 100644 index 0000000..5e11266 --- /dev/null +++ b/options.go @@ -0,0 +1,24 @@ +package censor + +// OptsConfig is a options configuration for the Processor. +type OptsConfig struct { + config *Config + configPath string +} + +// Option is a function that sets some option on the Processor. +type Option func(*OptsConfig) + +// WithConfig returns an Option that sets the configuration on the Processor. +func WithConfig(c *Config) func(*OptsConfig) { + return func(o *OptsConfig) { + o.config = c + } +} + +// WithConfigPath returns an Option that sets the configuration path on the Processor. +func WithConfigPath(path string) func(*OptsConfig) { + return func(o *OptsConfig) { + o.configPath = path + } +} diff --git a/processor.go b/processor.go index 5901abe..4444844 100644 --- a/processor.go +++ b/processor.go @@ -39,30 +39,39 @@ func New() *Processor { return &p } -// NewWithConfig returns a new instance of Processor with given configuration. -func NewWithConfig(c Config) *Processor { - p := Processor{ - formatter: formatter.New(c.Formatter), - parser: parser.New(c.Parser), - cfg: c, +// NewWithOpts returns a new instance of Processor, options can be passed to it. +// If no options are passed, the default configuration will be used. +func NewWithOpts(opts ...Option) (*Processor, error) { + var optCfg OptsConfig + for _, opt := range opts { + opt(&optCfg) } - if c.General.PrintConfigOnInit { - p.PrintConfig() + cfg := optCfg.config + + if cfg == nil && optCfg.configPath != "" { + c, err := ConfigFromFile(optCfg.configPath) + if err != nil { + return nil, fmt.Errorf("failed to read the configuration: %w", err) + } + + cfg = &c } - return &p -} + if cfg == nil { + c := Default() + cfg = &c + } -// NewWithFileConfig returns a new instance of Processor with configuration from a given file. -// It returns an error if the file cannot be read or unmarshalled. -func NewWithFileConfig(path string) (*Processor, error) { - cfg, err := ConfigFromFile(path) - if err != nil { - return nil, fmt.Errorf("failed to read the configuration: %w", err) + p := Processor{ + formatter: formatter.New(cfg.Formatter), + parser: parser.New(cfg.Parser), + cfg: *cfg, } - return NewWithConfig(cfg), nil + p.PrintConfig() + + return &p, nil } /* @@ -103,8 +112,8 @@ func (p *Processor) Format(val any) string { } // Clone returns a new instance of Processor with the same configuration as the original one. -func (p *Processor) Clone() *Processor { - return NewWithConfig(p.cfg) +func (p *Processor) Clone() (*Processor, error) { + return NewWithOpts(WithConfig(&p.cfg)) } // PrintConfig prints the configuration of the censor Processor. diff --git a/processor_test.go b/processor_test.go index 0f53128..1dffb3a 100644 --- a/processor_test.go +++ b/processor_test.go @@ -698,7 +698,9 @@ func TestNewWithConfig(t *testing.T) { ExcludePatterns: nil, }, } - got := NewWithConfig(cfg) + + got, err := NewWithOpts(WithConfig(&cfg)) + require.NoError(t, err) fConfig := FormatterConfig{ MaskValue: cfg.Formatter.MaskValue, @@ -746,8 +748,9 @@ func TestNewWithFileConfig(t *testing.T) { cfg: cfg, } - p, err := NewWithFileConfig("./testdata/cfg.yml") + p, err := NewWithOpts(WithConfigPath("./testdata/cfg.yml")) require.NoError(t, err) + require.EqualValues(t, want.formatter, p.formatter) require.EqualValues(t, want.parser, p.parser) require.EqualValues(t, want.cfg, p.cfg) @@ -756,9 +759,9 @@ func TestNewWithFileConfig(t *testing.T) { t.Run("empty_file_path", func(t *testing.T) { t.Cleanup(func() { SetGlobalInstance(New()) }) - var want *Processor - p, err := NewWithFileConfig("") - require.Error(t, err) + want := New() + p, err := NewWithOpts(WithConfigPath("")) + require.NoError(t, err) require.Equal(t, want, p) }) @@ -767,7 +770,7 @@ func TestNewWithFileConfig(t *testing.T) { var want *Processor - p, err := NewWithFileConfig("./config/testdata/invalid_cfg.yml") + p, err := NewWithOpts(WithConfigPath("./config/testdata/invalid_cfg.yml")) require.Error(t, err) require.Equal(t, want, p) }) @@ -780,7 +783,7 @@ func TestNewWithFileConfig(t *testing.T) { parser: parser.New(ParserConfig{}), } - p, err := NewWithFileConfig("./testdata/empty.yml") + p, err := NewWithOpts(WithConfigPath("./testdata/empty.yml")) require.NoError(t, err) require.EqualValues(t, want.formatter, p.formatter) require.EqualValues(t, want.parser, p.parser) @@ -820,7 +823,8 @@ func TestProcessor_PrintConfig(t *testing.T) { }, } - p := NewWithConfig(cfg) + p, err := NewWithOpts(WithConfig(&cfg)) + require.NoError(t, err) p.PrintConfig() // Restore stdout. @@ -874,8 +878,11 @@ func TestClone(t *testing.T) { }, } - original := NewWithConfig(cfg) - clone := original.Clone() + original, err := NewWithOpts(WithConfig(&cfg)) + require.NoError(t, err) + + clone, err := original.Clone() + require.NoError(t, err) // Check if the original and clone have the same configuration. require.Equal(t, original.cfg, clone.cfg)