lib/pdk/config/namespace.rb in pdk-2.7.1 vs lib/pdk/config/namespace.rb in pdk-3.0.0

- old
+ new

@@ -34,11 +34,11 @@ @persistent_defaults = persistent_defaults @mounts = {} @loaded_from_file = false @read_only = false - instance_eval(&block) if block_given? + instance_eval(&block) if block end # Pre-configure a value in the namespace. # # Allows you to specify validators and a default value for value in the @@ -48,11 +48,11 @@ # @param block [Proc] a block that is evaluated within the new [self]. # # @return [nil] def setting(key, &block) @settings[key.to_s] ||= default_setting_class.new(key.to_s, self) - @settings[key.to_s].instance_eval(&block) if block_given? + @settings[key.to_s].instance_eval(&block) if block end # Mount a provided [self] (or subclass) into the namespace. # # @param key [String,Symbol] the name of the namespace to be mounted. @@ -64,13 +64,14 @@ # subclass thereof. # # @return [self] the mounted namespace. def mount(key, obj, &block) raise ArgumentError, 'Only PDK::Config::Namespace objects can be mounted into a namespace' unless obj.is_a?(PDK::Config::Namespace) + obj.parent = self obj.name = key.to_s - obj.instance_eval(&block) if block_given? + obj.instance_eval(&block) if block @mounts[key.to_s] = obj end # Create and mount a new child namespace. # @@ -96,13 +97,15 @@ # Check if it's a mount first... return @mounts[key.to_s] unless @mounts[key.to_s].nil? # Check if it's a setting, otherwise nil return nil if settings[key.to_s].nil? return settings[key.to_s].value unless settings[key.to_s].value.nil? + # Duplicate arrays and hashes so that they are isolated from changes being made default_value = PDK::Util.deep_duplicate(settings[key.to_s].default) return default_value if default_value.nil? || !@persistent_defaults + # Persist the default value settings[key.to_s].value = default_value save_data default_value end @@ -123,10 +126,11 @@ def fetch(key, default_value) # Check if it's a mount first... return @mounts[key.to_s] unless @mounts[key.to_s].nil? # Check if it's a setting, otherwise default_value return default_value if settings[key.to_s].nil? + # Check if has a value, otherwise default_value settings[key.to_s].value.nil? ? default_value : settings[key.to_s].value end # After the value has been set in memory, the value will then be @@ -137,10 +141,11 @@ # # @return [nil] def []=(key, value) # You can't set the value of a mount raise ArgumentError, 'Namespace mounts can not be set a value' unless @mounts[key.to_s].nil? + set_volatile_value(key, value) # Persist the change save_data end @@ -155,29 +160,29 @@ # should be persisted to disk. def to_h new_hash = {} settings.each_pair { |k, v| new_hash[k] = v.value } @mounts.each_pair { |k, mount_point| new_hash[k] = mount_point.to_h if mount_point.include_in_parent? } - new_hash.delete_if { |_, v| v.nil? } + new_hash.delete_if { |_k, v| v.nil? } # rubocop :disable Style/CollectionCompact new_hash end # Resolves all filtered settings, including child namespaces, fully namespaced and filling in default values. # # @param filter [String] Only resolve setting names which match the filter. See #be_resolved? for matching rules # @return [Hash{String => Object}] All resolved settings for example {'user.module_defaults.author' => 'johndoe'} def resolve(filter = nil) resolved = {} # Resolve the settings - settings.values.each do |setting| + settings.each_value do |setting| setting_name = setting.qualified_name if be_resolved?(setting_name, filter) resolved[setting_name] = setting.value.nil? ? setting.default : setting.value end end # Resolve the mounts - @mounts.values.each { |mount| resolved.merge!(mount.resolve(filter)) } + @mounts.each_value { |mount| resolved.merge!(mount.resolve(filter)) } resolved end # @return [Boolean] true if the namespace has a parent, otherwise false. def child_namespace? @@ -237,11 +242,12 @@ # @param filter [String] The filter used to test on the name. # @return [Boolean] Whether the name passes the filter. def be_resolved?(name, filter = nil) return true if filter.nil? # If we're not filtering, this value should always be resolved return true if name == filter # If it's exactly the same name then it should be resolved - name.start_with?(filter + '.') # If name is a subkey of the filter then it should be resolved + + name.start_with?("#{filter}.") # If name is a subkey of the filter then it should be resolved end # @abstract Subclass and override {#parse_file} to implement parsing logic # for a particular config file format. # @@ -271,10 +277,11 @@ # writing to disk. def create_missing_setting(key, initial_value = nil) # Need to use `@settings` and `@mounts` here to stop recursive calls return unless @mounts[key.to_s].nil? return unless @settings[key.to_s].nil? + @settings[key.to_s] = default_setting_class.new(key.to_s, self, initial_value) end # Set the value of the named key. # @@ -284,10 +291,11 @@ # @param key [String,Symbol] the name of the configuration value. # @param value [Object] the value of the configuration value. def set_volatile_value(key, value) # Need to use `settings` here to force the backing file to be loaded return create_missing_setting(key, value) if settings[key.to_s].nil? + # Need to use `@settings` here to stop recursive calls from []= @settings[key.to_s].value = value end # Helper method to read files. @@ -303,13 +311,11 @@ PDK::Util::Filesystem.read_file(filename) rescue Errno::ENOENT => e raise PDK::Config::LoadError, e.message rescue Errno::EACCES - raise PDK::Config::LoadError, 'Unable to open %{file} for reading' % { - file: filename, - } + raise PDK::Config::LoadError, format('Unable to open %{file} for reading', file: filename) end # Persist the contents of the namespace to disk. # # Directories will be automatically created and the contents of the @@ -326,23 +332,23 @@ PDK::Util::Filesystem.mkdir_p(File.dirname(file)) PDK::Util::Filesystem.write_file(file, serialize_data(to_h)) rescue Errno::EACCES - raise PDK::Config::LoadError, 'Unable to open %{file} for writing' % { - file: file, - } + raise PDK::Config::LoadError, format('Unable to open %{file} for writing', file: file) rescue SystemCallError => e raise PDK::Config::LoadError, e.message end # Memoised accessor for the loaded data. # # @return [Hash<String => PDK::Config::Setting>] the contents of the namespace. def settings return @settings if @loaded_from_file + @loaded_from_file = true return @settings if file.nil? + parse_file(file) do |key, parsed_setting| # Create a settings chain if a setting already exists parsed_setting.previous_setting = @settings[key] unless @settings[key].nil? @settings[key] = parsed_setting end