From 789df49f5b188d1dfad92d87f86660dcbf67dd76 Mon Sep 17 00:00:00 2001 From: Patrick Spek Date: Sun, 26 Aug 2018 13:06:38 +0200 Subject: Return self on .read --- CHANGELOG.md | 4 + lib/Config.pm6 | 424 ++++++++++++++++++++++++++++----------------------------- t/01-reading.t | 51 ++++--- 3 files changed, 245 insertions(+), 234 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2163e4..863e5e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [UNRELEASED] +### Changed +- `.read` will now return the `Config` object, instead of a `Bool`. + ## [1.3.5] - 2018-03-28 ### Added - `api` key to META6.json diff --git a/lib/Config.pm6 b/lib/Config.pm6 index 4fc3121..78dca0a 100644 --- a/lib/Config.pm6 +++ b/lib/Config.pm6 @@ -2,285 +2,283 @@ use v6.c; -use Hash::Merge; - -use Config::Exception::MissingParserException; use Config::Exception::FileNotFoundException; +use Config::Exception::MissingParserException; use Config::Parser; +use Hash::Merge; -class Config is Associative is export -{ - has Hash $!content = {}; - has Str $!path = ""; - has Str $!parser = ""; - - #| Clear the config. - method clear() - { - $!content = {}; - $!path = ""; - $!parser = ""; - } - - #| Return the entire config hash. - multi method get() - { - return $!content; - } - - #| Fallback method in case the key is Nil. Will always return the default - #| value. - multi method get(Nil $key, Any $default = Nil) - { - $default; - } +unit class Config is Associative; - #| Get a value from the config object. To get a nested - #| key, use a . to descent a level. - multi method get(Str $key, Any $default = Nil) - { - self.get($key.split(".").list, $default); - } +has Hash $!content = {}; +has Str $!path = ""; +has Str $!parser = ""; - #| Get a value from the config object using a list - #| to indicate the nested key to get. - multi method get(List $keyparts, Any $default = Nil) - { - my $index = $!content; +#| Clear the config. +method clear() +{ + $!content = {}; + $!path = ""; + $!parser = ""; +} - for $keyparts.list -> $part { - return $default unless defined($index{$part}); +#| Return the entire config hash. +multi method get() +{ + return $!content; +} - $index = $index{$part}; - } +#| Fallback method in case the key is Nil. Will always return the default +#| value. +multi method get(Nil $key, Any $default = Nil) +{ + $default; +} - $index; - } +#| Get a value from the config object. To get a nested +#| key, use a . to descent a level. +multi method get(Str $key, Any $default = Nil) +{ + self.get($key.split(".").list, $default); +} - #| Get the name of the parser module to use for the - #| given path. - method get-parser(Str $path, Str $parser = "" --> Str) - { - return $parser if $parser ne ""; - return $!parser if $!parser ne ""; +#| Get a value from the config object using a list +#| to indicate the nested key to get. +multi method get(List $keyparts, Any $default = Nil) +{ + my $index = $!content; - my $type = self.get-parser-type($path); + for $keyparts.list -> $part { + return $default unless defined($index{$part}); - "Config::Parser::" ~ $type; + $index = $index{$part}; } - #| Get the type of parser required for the given path. - method get-parser-type(Str $path --> Str) - { - given ($path) { - when .ends-with(".yml") { return "yaml"; }; - } - - my $file = $path; + $index; +} - if (defined($path.index("/"))) { - $file = $path.split("/")[*-1]; - } +#| Get the name of the parser module to use for the +#| given path. +method get-parser(Str $path, Str $parser = "" --> Str) +{ + return $parser if $parser ne ""; + return $!parser if $!parser ne ""; - if (defined($file.index("."))) { - return $file.split(".")[*-1].lc; - } + my $type = self.get-parser-type($path); - return ""; - } + "Config::Parser::" ~ $type; +} - #| Check wether a given key exists. - multi method has(Str $key) { - self.has($key.split(".").list); +#| Get the type of parser required for the given path. +method get-parser-type(Str $path --> Str) +{ + given ($path) { + when .ends-with(".yml") { return "yaml"; }; } - #| Check wether a given key exists using a list to supply - #| the nested key to check. - multi method has(List $keyparts) - { - my $index = $!content; + my $file = $path; - for $keyparts.list -> $part { - return False unless defined($index{$part}); - - $index = $index{$part}; - } + if (defined($path.index("/"))) { + $file = $path.split("/")[*-1]; + } - defined($index); + if (defined($file.index("."))) { + return $file.split(".")[*-1].lc; } - #| Return a sorted list of all available keys in the current Config. - method keys() - { - my @keys; + return ""; +} - for $!content.keys -> $key { - @keys.append: self.extract-keys($key); - } +#| Check wether a given key exists. +multi method has(Str $key) { + self.has($key.split(".").list); +} - @keys.sort; - } +#| Check wether a given key exists using a list to supply +#| the nested key to check. +multi method has(List $keyparts) +{ + my $index = $!content; - #| Reload the configuration. Requires the configuration to - #| have been loaded from a file. - multi method read() - { - if ($!path eq "") { - return False; - } + for $keyparts.list -> $part { + return False unless defined($index{$part}); - return self.read($!path); + $index = $index{$part}; } - #| Load a configuration file from the given path. Optionally - #| set a parser module name to use. If not set, Config will - #| attempt to deduce the parser to use. - multi method read( - Str $path, - Str $parser = "", - Bool :$skip-not-found = False - ) { - Config::Exception::FileNotFoundException.new( - path => $path - ).throw() unless ($path.IO.f || $skip-not-found); - - $!parser = self.get-parser($path, $parser); - - try { - CATCH { - when X::CompUnit::UnsatisfiedDependency { - Config::Exception::MissingParserException.new( - parser => $!parser - ).throw(); - } - } - - require ::($!parser); + defined($index); +} - self.read(::($!parser).read($path)); - } +#| Return a sorted list of all available keys in the current Config. +method keys() +{ + my @keys; - return True; + for $!content.keys -> $key { + @keys.append: self.extract-keys($key); } - #| Read a list of paths. Will fail on the first file that fails to load for - #| whatever reason. If no files could be loaded, the method will return - #| False. - multi method read( - List $paths, - Str $parser = "", - Bool :$skip-not-found = False - ) { - my Bool $read = False; + @keys.sort; +} - for $paths.list -> $path { - next if $skip-not-found && !$path.IO.f; +#| Reload the configuration. Requires the configuration to +#| have been loaded from a file. +multi method read ( + --> Config +) { + die "Configuration was not loaded from a file, cannot reload" if $!path eq ""; - self.read($path, $parser); + self.read($!path); +} - $read = True; +#| Load a configuration file from the given path. Optionally +#| set a parser module name to use. If not set, Config will +#| attempt to deduce the parser to use. +multi method read ( + Str $path, + Str $parser = "", + Bool :$skip-not-found = False, + --> Config +) { + Config::Exception::FileNotFoundException.new( + path => $path + ).throw() unless ($path.IO.f || $skip-not-found); + + $!parser = self.get-parser($path, $parser); + + try { + CATCH { + when X::CompUnit::UnsatisfiedDependency { + Config::Exception::MissingParserException.new( + parser => $!parser + ).throw(); + } } - return $read; + require ::($!parser); + + self.read(::($!parser).read($path)); } - #| Read a plain Hash into the configuration. - multi method read(Hash $hash) - { - $!content = merge-hash($!content, $hash); + self; +} - return True; +#| Read a list of paths. Will fail on the first file that fails to load for +#| whatever reason. +multi method read ( + List $paths, + Str $parser = "", + Bool :$skip-not-found = False, + --> Config +) { + for $paths.list -> $path { + next if $skip-not-found && !$path.IO.f; + + self.read($path, $parser); } - #| Set a single key to a given value; - multi method set(Str $key, Any $value) - { - self.set($key.split(".").list, $value); - } + return self; +} - multi method set(List $keyparts, Any $value) - { - my $index := $!content; +#| Read a plain Hash into the configuration. +multi method read ( + Hash $hash, + --> Config +) { + $!content = merge-hash($!content, $hash); - for $keyparts.list -> $part { - $index{$part} = {} unless defined($index{$part}); + return self; +} - $index := $index{$part}; - } +#| Set a single key to a given value; +multi method set(Str $key, Any $value) +{ + self.set($key.split(".").list, $value); +} - $index = $value; +multi method set(List $keyparts, Any $value) +{ + my $index := $!content; - self; - } + for $keyparts.list -> $part { + $index{$part} = {} unless defined($index{$part}); - multi method unset(Str $key) - { - self.unset($key.split(".").Array); + $index := $index{$part}; } - multi method unset(@parts) - { - my %index := $!content; - my $target = @parts.pop; + $index = $value; - for @parts.list -> $part { - %index{$part} = {} unless defined(%index{$part}); + self; +} - %index := %index{$part}; - } +multi method unset(Str $key) +{ + self.unset($key.split(".").Array); +} + +multi method unset(@parts) +{ + my %index := $!content; + my $target = @parts.pop; - %index{$target}:delete if %index{$target}:exists; + for @parts.list -> $part { + %index{$part} = {} unless defined(%index{$part}); - self; + %index := %index{$part}; } - #| Write the current configuration to the given path. If - #| no parser is given, it tries to use the parser that - #| was used when loading the configuration. - method write(Str $path, Str $parser = "") - { - my $chosen-parser = self.get-parser($path, $parser); + %index{$target}:delete if %index{$target}:exists; - require ::($chosen-parser); - return ::($chosen-parser).write($path, $!content); - } + self; +} - multi method AT-KEY(::?CLASS:D: $key) - { - self.get($key); - } +#| Write the current configuration to the given path. If +#| no parser is given, it tries to use the parser that +#| was used when loading the configuration. +method write(Str $path, Str $parser = "") +{ + my $chosen-parser = self.get-parser($path, $parser); - multi method EXISTS-KEY(::?CLASS:D: $key) - { - self.has($key); - } + require ::($chosen-parser); + return ::($chosen-parser).write($path, $!content); +} - multi method DELETE-KEY(::?CLASS:D: $key) - { - self.unset($key); - } +multi method AT-KEY(::?CLASS:D: $key) +{ + self.get($key); +} - multi method ASSIGN-KEY(::?CLASS:D: $key, $new) - { - self.set($key, $new); - } +multi method EXISTS-KEY(::?CLASS:D: $key) +{ + self.has($key); +} - multi method BIND-KEY(::?CLASS:D: $key, \new) - { - self.set($key, new); - } +multi method DELETE-KEY(::?CLASS:D: $key) +{ + self.unset($key); +} - submethod extract-keys($key) - { - my $value = self.get($key); - return $key if $value !~~ Iterable; +multi method ASSIGN-KEY(::?CLASS:D: $key, $new) +{ + self.set($key, $new); +} - my @keys; +multi method BIND-KEY(::?CLASS:D: $key, \new) +{ + self.set($key, new); +} - for $value.keys -> $nested-key { - @keys.append: self.extract-keys("{$key}.{$nested-key}"); - } +submethod extract-keys($key) +{ + my $value = self.get($key); + return $key if $value !~~ Iterable; + + my @keys; - return @keys; + for $value.keys -> $nested-key { + @keys.append: self.extract-keys("{$key}.{$nested-key}"); } + + return @keys; } + +# vim: ft=perl6 sw=4 ts=4 et diff --git a/t/01-reading.t b/t/01-reading.t index 3a4388e..722d6eb 100644 --- a/t/01-reading.t +++ b/t/01-reading.t @@ -13,37 +13,46 @@ my Str $null-parser = "Config::Parser::NULL"; throws-like { $config.read("t/files/none") }, Config::Exception::FileNotFoundException, "Reading nonexisting file"; throws-like { $config.read("t/files/config", "Config::Parser:NoSuchParserForTest") }, Config::Exception::MissingParserException, "Using non-existing parser"; -is $config.read("t/files/none", $null-parser, skip-not-found => True), True, ".read allows for non-fatal execution with skip-not-found set"; +subtest ".read allows for non-fatal execution with skip-not-found set", { + plan 3; + + my %old = $config.get; + my $result = $config.read("t/files/none", $null-parser, :skip-not-found); -my $hash = { + ok $result, "Result is ok"; + is-deeply $result.get, %old, "Config did not change"; + isa-ok $result, Config, ".read returned a Config"; +} + +my %hash = %( "a" => "a", - "b" => { - "c" => "test" - } -}; + "b" => %( + "c" => "test", + ), +); -$config.read($hash); +$config.read: %hash; -is-deeply $config.get(), $hash, "Correctly sets hash"; +is-deeply $config.get, %hash, "Correctly sets hash"; -$config.read({ - "b" => { - "d" => "another" - } -}); +$config.read: %( + "b" => %( + "d" => "another", + ), +); -is-deeply $config.get(), { +is-deeply $config.get, %( "a" => "a", - "b" => { + "b" => %( "c" => "test", - "d" => "another" - } -}, "Correctly merges new hash into existing config"; + "d" => "another", + ), +), "Correctly merges new hash into existing config"; subtest { plan 3; - is $config.read(("t/files/config", "t/files/config.yaml"), $null-parser, skip-not-found => True), True, "All paths exist"; - is $config.read(("t/files/config", "t/files/none", "t/files/config.yaml"), $null-parser, skip-not-found => True), True, "At least one path exists"; - is $config.read(("t/files/none", "t/files/none.yaml"), $null-parser, skip-not-found => True), False, "No paths exist"; + ok $config.read(("t/files/config", "t/files/config.yaml"), $null-parser, :skip-not-found), "All paths exist"; + ok $config.read(("t/files/config", "t/files/none", "t/files/config.yaml"), $null-parser, :skip-not-found), "At least one path exists"; + ok $config.read(("t/files/none", "t/files/none.yaml"), $null-parser, :skip-not-found), "No paths exist"; }, "Read with a List of paths"; -- cgit v1.1