Pass a property name as a parameter name

This may not even be possible, but here goes. I am working on a snmp project and have a yaml config file which contains this:

# /home/vagrant/.snob/snobrc.yml
---
dummy:
  user: username
  auth_pass: auth passphrase
  priv_pass: priv passphrase
  auth: MD5/SHA
  crypto: AES/DES

‘dummy’ in this case is a test host name. I currently retrieve the contents via:

  class Config
    include YAML::Serializable

    property dummy : Hash(String, String)

    def self.load
      File.exists?(PATH) ? Config.from_yaml File.read(PATH) : raise FileNotFoundError.new(PATH)
    rescue ex
      raise InvalidFileFormatError.new(ex.message)
    end
  end

config = Config.load

I would like to pass that name, ‘dummy’, into the class as the property name so I can access other hostnames. Something like:

config = Config.new(newhost).load

Is this even possible? I have tried all sorts of combinations and it seems as though my naive approach is showing. Any thoughts are greatly appreciated.

Thanks

what happens if you do like:

def self.load(name : String) : self
  File.exists?(PATH) ? Config.from_yaml(File.read(PATH), root: name) : raise FileNotFoundError.new(PATH)
rescue ex
  raise InvalidFileFormatError.new(ex.message)
end

EDIT: Nevermind, apparently only .from_json has a root property.
EDIT2: This would also only work if the Config type defined each property and not just a general Hash

Is it feasible to wrap it in a NamedTuple and then drill down into that key?

require "yaml"

pp NamedTuple(dummy: Hash(String, String)).from_yaml(<<-YAML)[:dummy]
---
dummy:
  user: username
  auth_pass: auth passphrase
  priv_pass: priv passphrase
  auth: MD5/SHA
  crypto: AES/DES
YAML

@Blacksmoke16 , as per your edit2, that is what I’m running into. Each host as a property.
Using YAML::Any:

  def fetch_credentials(config_file : String, hostname : String)
    creds = YAML.parse(File.read(config_file))[hostname]
    {user: creds["user"].to_s, auth_pass: creds["auth_pass"].to_s,
     priv_pass: creds["priv_pass"].to_s, auth: creds["auth"].to_s,
     crypto: creds["crypto"].to_s}
  end

This is getting me by for now but, seems a little clumsy.

After thinking about it more I think you could change things up to make your Config class more like a Registry of Host configurations. Could make a singleton instance of it, and expose a method to allow getting the configuration for a specific host. E.g. something like:

require "yaml"

DATA = <<-YAML
---
dummy:
  user: username
  auth_pass: auth passphrase
  priv_pass: priv passphrase
  auth: MD5/SHA
  crypto: AES/DES
YAML

class Registry
  record Host, user : String, auth_pass : String, priv_pass : String, auth : String, crypto : String do
    include YAML::Serializable
  end

  private class_getter instance : self { new }

  def self.get(name : String) : Host
    self.instance.configurations[name]
  end

  protected getter configurations : Hash(String, Host)

  private def initialize
    @configurations = Hash(String, Host).from_yaml DATA
  end
end

pp Registry.get "dummy"
3 Likes

Thank you so much for this solution. Lots to unpack here for me.