0

I am trying to use anyway_config for the first time in a plain Ruby program with RSpec tests. The docs do not give as much guidance as I would like. The end of this posting shows the pressing issue that I need to solve, plus a related bonus question that would be so helpful to me.

My config class is GitTree::GTConfig.

require "anyway"
require "anyway/testing"

# See https://github.com/palkan/anyway_config?tab=readme-ov-file#usage
module GitTree
  # Enables loading config from `treeconfig.yml` and `treeconfig.local.yml` files.
  # By default, Anyway! looks for yml files in
  # - `./config/treeconfig.yml`
  # - `./.treeconfig.yml`
  # - `~/.config/treeconfig.yml`
  # - `~/.treeconfig.yml`
  class GTConfig < Anyway::Config
    config_name :treeconfig
    Anyway::Settings.default_config_path = "config/treeconfig.yml"

    # All environment variables will be prefixed with `GIT_TREE_`
    env_prefix :git_tree

    # Add required attributes with default values
    attr_config git_timeout:   300,
                verbosity:     ::Logging::NORMAL,
                default_roots: %w[sites sitesUbuntu work]

    # See https://github.com/palkan/anyway_config?tab=readme-ov-file#required-options
    required :git_timeout,
             :verbosity,
             :default_roots

    # See https://github.com/palkan/anyway_config?tab=readme-ov-file#multi-env-configuration
    Anyway::Settings.future.use :unwrap_known_environments

    # See https://github.com/palkan/anyway_config?tab=readme-ov-file#source-tracing
    # Anyway::Settings.enable_source_tracing

    # On_load validators must not accept any arguments
    on_load :validate_environment
    on_load :log_environment

    private

    # Raise RuntimeError if a configuration error
    def validate_environment
      raise "The Anyway::Settings environment is not set" unless Anyway::Settings.current_environment
    end

    def log_environment
      $stdout.puts "Current environment: #{Anyway::Settings.current_environment}" # if Anyway::Settings.verbosity >= ::Logging::VERBOSE
    end
  end
end

config/treeconfig.yml:

test:
  git_timeout: 7
  verbosity: NORMAL
  default_roots:

development:
  git_timeout: 7
  verbosity: NORMAL
  default_roots:

production:
  git_timeout: 300
  verbosity: NORMAL
  default_roots: [sites, sitesUbuntu, work]

This is my RSpec code:

require "spec_helper"
require "anyway/testing"

describe GitTree::GTConfig, type: :config do
  include Anyway::Testing::Helpers

  let(:config) { described_class.new }

  # Reset to default config before each example
  around do |ex|
    with_config(default_roots: %w[a b]) do
      x = ex.run
      puts "x is a #{x.class.name}"
    end
  end

  context "when the environment is not set" do
    it "raises an error" do
      Anyway::Settings.current_environment = nil
      expect { config }.to raise_error(RuntimeError, /Anyway::Settings environment/)
    end
  end

  context "when the environment is set" do
    before do
      Anyway::Settings.current_environment = "test"
    end

    after do
      Anyway::Settings.current_environment = nil
    end

    it "does not raise an error" do
      expect { config }.not_to raise_error
    end

    context "with yaml configuration" do
      it "loads configuration from a YAML file" do
        with_config(default_roots: %w[c d]) do
          expect(config.default_roots).to eq(%w[c d])
        end
      end

      it "loads configuration from a YAML file with a specific location" do
        with_config_path("spec/fixtures/treeconfig.yml") do
          expect(config.default_roots).to eq(%w[e f])
        end
      end
    end

    context "with environment variables" do
      it "loads configuration from environment variables" do
        with_env("GIT_TREE_DEFAULT_ROOTS" => "g h") do
          expect(config.default_roots).to eq(%w[g h])
        end
      end
    end

    context "with source tracing" do
      it "traces the source of the configuration" do
        with_config(default_roots: %w[c d]) do
          expect(config.to_source_trace["default_roots"]).to eq(default: %w[a b], test: { "default_roots" => %w[c d] })
        end
      end
    end
  end
end

The tests all have similar complaints:

NoMethodError:
       undefined method 'with_config' for #<RSpec::ExampleGroups::GitTreeGTConfig::WhenTheEnvironmentIsNotSet:0x000078d34db7aa90>
     # ./spec/git_tree/gt_config_spec.rb:11:in 'block (2 levels) in <top (required)>'
     # ./binstub/rspec:16:in 'Kernel#load'
     # ./binstub/rspec:16:in '<main>'

Furthermore, my program has integer constants defined for verbosity; NORMAL has value 1. How can the text values ("NORMAL") specified in treeconfig.yml be converted to integers when read?

3
  • with_config does not appear to be a method anywhere in the code base. Did you possibly mean with_env? Additionally include Anyway::Testing::Helpers is not needed as require "anyway/testing" will handle this inclusion for you. Commented Oct 6 at 18:38
  • I used copy/paste, there is no mistake: with_config is mentioned. How can I troubleshoot this? The erb idea is cool! Commented Oct 6 at 20:08
  • Ah... Gemini snuck that hallucination past me. Gemini created the above for me. Can you suggest a better suite of tests in an answer? Commented Oct 6 at 20:18

1 Answer 1

2

with_config is not a method defined by anyway_config or its test helpers. As you noted in your comment this is a hallucination provided by the LLM you chose to use.

Ignoring that fact, most of your spec is simply testing that anyway_config actually works, an exercise the library itself has already gone through. Specs

Instead your tests should focus on your implementation.

For instance:

require "spec_helper"
require "anyway/testing"

describe GitTree::GTConfig, type: :config do
  # include Anyway::Testing::Helpers # this is not necessary 
  # See: https://github.com/palkan/anyway_config/blob/master/lib/anyway/testing.rb

  before do
    Anyway::Settings.current_environment = "test"
  end
  let(:config) { described_class.new }

  context "when the environment is not set" do
    it "raises an error" do
      Anyway::Settings.current_environment = nil
      expect { config }.to raise_error(RuntimeError, /Anyway::Settings environment/)
    end
  end

  context "when the environment is set" do
    it "does not raise an error" do
      expect { config }.not_to raise_error
    end
  end

  context "has attributes" do 
    it "#git_timeout" do 
      expect(config).to respond_to(:git_timeout) 
    end 
    it "#verbosity" do 
      expect(config).to respond_to(:verbosity) 
    end
    it "#default_roots" do 
      expect(config).to respond_to(:default_roots) 
    end
    context "with defaults" do 
      it "#git_timeout" do 
        expect(config.git_timeout).to eq(300)
      end 
      it "#verbosity" do 
        expect(config.verbosity).to eq(::Logging::NORMAL)
      end
      it "#default_roots" do 
        expect(config.default_roots).to eq(%w[sites sitesUbuntu work])  
      end
    end 
  end 
  # etc. 
end

Also to answer your second question "How can the text values ("NORMAL") specified in treeconfig.yml be converted to integers when read?"

As stated in the Docs YAML parsing with ERB is supported (provided that ERB is loaded).

This means you simply need to include require 'erb' in the entry point to your application and then you can change your config/treeconfig.yml to :

test:
  git_timeout: 7
  verbosity: <%= ::Logging::NORMAL %>
  default_roots:

development:
  git_timeout: 7
  verbosity: <%= ::Logging::NORMAL %>
  default_roots:

production:
  git_timeout: 300
  verbosity: <%= ::Logging::NORMAL %>
  default_roots: 
    - sites
    - sitesUbuntu
    - work
Sign up to request clarification or add additional context in comments.

2 Comments

Finished in 0.01414 seconds (files took 0.67382 seconds to load) 8 examples, 0 failures
So helpful! Many thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.