# class Gem::ConfigFile

`Gem::ConfigFile` RubyGems options and gem command options from gemrc.

gemrc is a `YAML` file that uses strings to match gem command arguments and symbols to match RubyGems options.

`Gem` command arguments use a `String` key that matches the command name and allow you to specify default arguments:

    install: --no-rdoc --no-ri
    update: --no-rdoc --no-ri

You can use `gem:` to set default arguments for all commands.

RubyGems options use symbol keys. Valid options are:

`:backtrace`

  See `backtrace`

`:sources`

  Sets `Gem::sources`

`:verbose`

  See `verbose`

`:concurrent_downloads`

  See `concurrent_downloads`

gemrc files may exist in various locations and are read and merged in the following order:

- system wide (/etc/gemrc)

- per user (~/.gemrc)

- per environment (gemrc files listed in the GEMRC environment variable)

### Constants

DEFAULT_BACKTRACE
DEFAULT_BULK_THRESHOLD
DEFAULT_CERT_EXPIRATION_LENGTH_DAYS
DEFAULT_CONCURRENT_DOWNLOADS
DEFAULT_INSTALL_EXTENSION_IN_LIB

  TODO: Use false as default value for this option in RubyGems 4.0

DEFAULT_IPV4_FALLBACK_ENABLED
DEFAULT_UPDATE_SOURCES
DEFAULT_VERBOSITY
OPERATING_SYSTEM_DEFAULTS

  For Ruby packagers to set configuration defaults. `Set` in rubygems/defaults/operating_system.rb

PLATFORM_DEFAULTS

  For Ruby implementers to set configuration defaults. `Set` in rubygems/defaults/#{RUBY_ENGINE}.rb

SYSTEM_WIDE_CONFIG_FILE

### Attributes

args [R]

List of arguments supplied to the config file object.

backtrace [W]

True if we print backtraces on errors.

bulk_threshold [RW]

Bulk threshold value. If the number of missing gems are above this threshold value, then a bulk download technique is used. (deprecated)

cert_expiration_length_days [RW]

Expiration length to sign a certificate

concurrent_downloads [RW]

Number of gem downloads that should be performed concurrently.

disable_default_gem_server [RW]

True if we want to force specification of gem server when pushing a gem

hash [R]
home [RW]

Where to install gems (deprecated)

install_extension_in_lib [RW]

Install extensions into lib as well as into the extension directory.

ipv4_fallback_enabled [RW]

## Experimental ==¶ ↑

Fallback to IPv4 when IPv6 is not reachable or slow (default: false)

path [RW]

Where to look for gems (deprecated)

sources [RW]

sources to look for gems

ssl_ca_cert [RW]

Path name of directory or file of openssl CA certificate, used for remote https connection

ssl_client_cert [R]

Path name of directory or file of openssl client certificate, used for remote https connection with client authentication

ssl_verify_mode [R]

openssl verify mode value, used for remote https connection

update_sources [RW]

True if we want to update the SourceInfoCache every time, false otherwise

verbose [RW]

Verbose level of output:

- false – No output

- true – Normal output

- :loud – Extra output

### Public Class Methods

deep_transform_config_keys! (config)
Source

    # File lib/rubygems/config_file.rb, line 563
    def self.deep_transform_config_keys!(config)
      config.transform_keys! do |k|
        if k.match?(/\A:(.*)\Z/)
          k[1..-1].to_sym
        elsif k.include?("__") || k.match?(%r{/\Z})
          if k.is_a?(Symbol)
            k.to_s.gsub(/__/,".").gsub(%r{/\Z}, "").to_sym
          else
            k.dup.gsub(/__/,".").gsub(%r{/\Z}, "")
          end
        else
          k
        end
      end

      config.transform_values! do |v|
        if v.is_a?(String)
          if v.match?(/\A:(.*)\Z/)
            v[1..-1].to_sym
          elsif v.match?(/\A[+-]?\d+\Z/)
            v.to_i
          elsif v.match?(/\Atrue|false\Z/)
            v == "true"
          elsif v.empty?
            nil
          else
            v
          end
        elsif v.empty?
          nil
        elsif v.is_a?(Hash)
          deep_transform_config_keys!(v)
        else
          v
        end
      end

      config
    end

dump_with_rubygems_yaml (content)
Source

    # File lib/rubygems/config_file.rb, line 545
    def self.dump_with_rubygems_yaml(content)
      content.transform_keys! do |k|
        k.is_a?(Symbol) ? ":#{k}" : k
      end

      require_relative "yaml_serializer"
      Gem::YAMLSerializer.dump(content)
    end

load_with_rubygems_config_hash (yaml)
Source

    # File lib/rubygems/config_file.rb, line 554
    def self.load_with_rubygems_config_hash(yaml)
      require_relative "yaml_serializer"

      content = Gem::YAMLSerializer.load(yaml)
      deep_transform_config_keys!(content)
    end

new (args)
Source

    # File lib/rubygems/config_file.rb, line 184
    def initialize(args)
      set_config_file_name(args)

      @backtrace = DEFAULT_BACKTRACE
      @bulk_threshold = DEFAULT_BULK_THRESHOLD
      @verbose = DEFAULT_VERBOSITY
      @update_sources = DEFAULT_UPDATE_SOURCES
      @concurrent_downloads = DEFAULT_CONCURRENT_DOWNLOADS
      @cert_expiration_length_days = DEFAULT_CERT_EXPIRATION_LENGTH_DAYS
      @install_extension_in_lib = DEFAULT_INSTALL_EXTENSION_IN_LIB
      @ipv4_fallback_enabled = ENV["IPV4_FALLBACK_ENABLED"] == "true" || DEFAULT_IPV4_FALLBACK_ENABLED

      operating_system_config = Marshal.load Marshal.dump(OPERATING_SYSTEM_DEFAULTS)
      platform_config = Marshal.load Marshal.dump(PLATFORM_DEFAULTS)
      system_config = load_file SYSTEM_WIDE_CONFIG_FILE
      user_config = load_file config_file_name

      environment_config = (ENV["GEMRC"] || "").
        split(File::PATH_SEPARATOR).inject({}) do |result, file|
          result.merge load_file file
        end

      @hash = operating_system_config.merge platform_config
      unless args.index "--norc"
        @hash = @hash.merge system_config
        @hash = @hash.merge user_config
        @hash = @hash.merge environment_config
      end

      @hash.transform_keys! do |k|
        # gemhome and gempath are not working with symbol keys
        if %w[backtrace bulk_threshold verbose update_sources cert_expiration_length_days
              install_extension_in_lib ipv4_fallback_enabled sources disable_default_gem_server
              ssl_verify_mode ssl_ca_cert ssl_client_cert].include?(k)
          k.to_sym
        else
          k
        end
      end

      # HACK: these override command-line args, which is bad
      @backtrace                   = @hash[:backtrace]                   if @hash.key? :backtrace
      @bulk_threshold              = @hash[:bulk_threshold]              if @hash.key? :bulk_threshold
      @verbose                     = @hash[:verbose]                     if @hash.key? :verbose
      @update_sources              = @hash[:update_sources]              if @hash.key? :update_sources
      # TODO: We should handle concurrent_downloads same as other options
      @cert_expiration_length_days = @hash[:cert_expiration_length_days] if @hash.key? :cert_expiration_length_days
      @install_extension_in_lib    = @hash[:install_extension_in_lib]    if @hash.key? :install_extension_in_lib
      @ipv4_fallback_enabled       = @hash[:ipv4_fallback_enabled]       if @hash.key? :ipv4_fallback_enabled

      @home                        = @hash[:gemhome]                     if @hash.key? :gemhome
      @path                        = @hash[:gempath]                     if @hash.key? :gempath
      @sources                     = @hash[:sources]                     if @hash.key? :sources
      @disable_default_gem_server  = @hash[:disable_default_gem_server]  if @hash.key? :disable_default_gem_server
      @ssl_verify_mode             = @hash[:ssl_verify_mode]             if @hash.key? :ssl_verify_mode
      @ssl_ca_cert                 = @hash[:ssl_ca_cert]                 if @hash.key? :ssl_ca_cert
      @ssl_client_cert             = @hash[:ssl_client_cert]             if @hash.key? :ssl_client_cert

      @api_keys         = nil
      @rubygems_api_key = nil

      handle_arguments args
    end

Create the config file object. `args` is the list of arguments from the command line.

The following command line options are handled early here rather than later at the time most command options are processed.

`--config-file`, `--config-file==NAME`

  Obviously these need to be handled by the `ConfigFile` object to ensure we get the right config file.

`--backtrace`

  Backtrace needs to be turned on early so that errors before normal option parsing can be properly handled.

`--debug`

  Enable Ruby level debug messages. Handled early for the same reason as –backtrace.

### Public Instance Methods

[] (key)
Source

    # File lib/rubygems/config_file.rb, line 524
    def [](key)
      @hash[key] || @hash[key.to_s]
    end

Return the configuration information for `key`.

[]= (key, value)
Source

    # File lib/rubygems/config_file.rb, line 529
    def []=(key, value)
      @hash[key] = value
    end

`Set` configuration option `key` to `value`.

api_keys ()
Source

    # File lib/rubygems/config_file.rb, line 251
    def api_keys
      load_api_keys unless @api_keys

      @api_keys
    end

`Hash` of RubyGems.org and alternate API keys

backtrace ()
Source

    # File lib/rubygems/config_file.rb, line 388
    def backtrace
      @backtrace || $DEBUG
    end

True if the backtrace option has been specified, or debug is on.

check_credentials_permissions ()
Source

    # File lib/rubygems/config_file.rb, line 261
      def check_credentials_permissions
        return if Gem.win_platform? # windows doesn't write 0600 as 0600
        return unless File.exist? credentials_path

        existing_permissions = File.stat(credentials_path).mode & 0o777

        return if existing_permissions == 0o600

        alert_error <<-ERROR
    Your gem push credentials file located at:

    \t#{credentials_path}

    has file permissions of 0#{existing_permissions.to_s 8} but 0600 is required.

    To fix this error run:

    \tchmod 0600 #{credentials_path}

    You should reset your credentials at:

    \thttps://rubygems.org/profile/edit

    if you believe they were disclosed to a third party.
        ERROR

        terminate_interaction 1
      end

Checks the permissions of the credentials file. If they are not 0600 an error message is displayed and RubyGems aborts.

config_file_name ()
Source

    # File lib/rubygems/config_file.rb, line 407
    def config_file_name
      @config_file_name || Gem.config_file
    end

The name of the configuration file.

credentials_path ()
Source

    # File lib/rubygems/config_file.rb, line 293
    def credentials_path
      credentials = File.join Gem.user_home, ".gem", "credentials"
      if File.exist? credentials
        credentials
      else
        File.join Gem.data_home, "gem", "credentials"
      end
    end

Location of RubyGems.org credentials

each () { |:update_sources, update_sources| ... }
Source

    # File lib/rubygems/config_file.rb, line 431
    def each(&block)
      hash = @hash.dup
      hash.delete :update_sources
      hash.delete :verbose
      hash.delete :backtrace
      hash.delete :bulk_threshold

      yield :update_sources, @update_sources
      yield :verbose, @verbose
      yield :backtrace, @backtrace
      yield :bulk_threshold, @bulk_threshold

      yield "config_file_name", @config_file_name if @config_file_name

      hash.each(&block)
    end

Delegates to @hash

handle_arguments (arg_list)
Source

    # File lib/rubygems/config_file.rb, line 449
    def handle_arguments(arg_list)
      @args = []

      arg_list.each do |arg|
        case arg
        when /^--(backtrace|traceback)$/ then
          @backtrace = true
        when /^--debug$/ then
          $DEBUG = true

          warn "NOTE:  Debugging mode prints all exceptions even when rescued"
        else
          @args << arg
        end
      end
    end

Handle the command arguments.

last_update_check ()
Source

    # File lib/rubygems/config_file.rb, line 417
    def last_update_check
      if File.readable?(state_file_name)
        File.read(state_file_name).to_i
      else
        0
      end
    end

Reads time of last update check from state file

last_update_check= (timestamp)
Source

    # File lib/rubygems/config_file.rb, line 426
    def last_update_check=(timestamp)
      File.write(state_file_name, timestamp.to_s) if state_file_writable?
    end

Writes time of last update check to state file

load_api_keys ()
Source

    # File lib/rubygems/config_file.rb, line 302
    def load_api_keys
      check_credentials_permissions

      @api_keys = if File.exist? credentials_path
        load_file(credentials_path)
      else
        @hash
      end

      if @api_keys.key? :rubygems_api_key
        @rubygems_api_key    = @api_keys[:rubygems_api_key]
        @api_keys[:rubygems] = @api_keys.delete :rubygems_api_key unless
          @api_keys.key? :rubygems
      end
    end

load_file (filename)
Source

    # File lib/rubygems/config_file.rb, line 365
    def load_file(filename)
      yaml_errors = [ArgumentError]

      return {} unless filename && !filename.empty? && File.exist?(filename)

      begin
        config = self.class.load_with_rubygems_config_hash(File.read(filename))
        if config.keys.any? {|k| k.to_s.gsub(%r{https?:\/\/}, "").include?(": ") }
          warn "Failed to load #{filename} because it doesn't contain valid YAML hash"
          return {}
        else
          return config
        end
      rescue *yaml_errors => e
        warn "Failed to load #{filename}, #{e}"
      rescue Errno::EACCES
        warn "Failed to load #{filename} due to permissions problem."
      end

      {}
    end

really_verbose ()
Source

    # File lib/rubygems/config_file.rb, line 467
    def really_verbose
      case verbose
      when true, false, nil then
        false
      else
        true
      end
    end

Really verbose mode gives you extra output.

rubygems_api_key ()
Source

    # File lib/rubygems/config_file.rb, line 321
    def rubygems_api_key
      load_api_keys unless @rubygems_api_key

      @rubygems_api_key
    end

Returns the RubyGems.org API key

rubygems_api_key= (api_key)
Source

    # File lib/rubygems/config_file.rb, line 330
    def rubygems_api_key=(api_key)
      set_api_key :rubygems_api_key, api_key

      @rubygems_api_key = api_key
    end

Sets the RubyGems.org API key to `api_key`

set_api_key (host, api_key)
Source

    # File lib/rubygems/config_file.rb, line 339
    def set_api_key(host, api_key)
      check_credentials_permissions

      config = load_file(credentials_path).merge(host => api_key)

      dirname = File.dirname credentials_path
      require "fileutils"
      FileUtils.mkdir_p(dirname)

      permissions = 0o600 & (~File.umask)
      File.open(credentials_path, "w", permissions) do |f|
        f.write self.class.dump_with_rubygems_yaml(config)
      end

      load_api_keys # reload
    end

`Set` a specific host’s API key to `api_key`

state_file_name ()
Source

    # File lib/rubygems/config_file.rb, line 412
    def state_file_name
      Gem.state_file
    end

The name of the state file.

state_file_writable? ()
Source

    # File lib/rubygems/config_file.rb, line 393
    def state_file_writable?
      if File.exist?(state_file_name)
        File.writable?(state_file_name)
      else
        require "fileutils"
        FileUtils.mkdir_p File.dirname(state_file_name)
        File.open(state_file_name, "w") {}
        true
      end
    rescue Errno::EACCES
      false
    end

Check state file is writable. Creates empty file if not present to ensure we can write to it.

unset_api_key! ()
Source

    # File lib/rubygems/config_file.rb, line 359
    def unset_api_key!
      return false unless File.exist?(credentials_path)

      File.delete(credentials_path)
    end

Remove the +~/.gem/credentials+ file to clear all the current sessions.

write ()
Source

    # File lib/rubygems/config_file.rb, line 514
    def write
      require "fileutils"
      FileUtils.mkdir_p File.dirname(config_file_name)

      File.open config_file_name, "w" do |io|
        io.write to_yaml
      end
    end

Writes out this config file, replacing its source.

### Private Instance Methods

set_config_file_name (args)
Source

    # File lib/rubygems/config_file.rb, line 603
    def set_config_file_name(args)
      @config_file_name = ENV["GEMRC"]
      need_config_file_name = false

      args.each do |arg|
        if need_config_file_name
          @config_file_name = arg
          need_config_file_name = false
        elsif arg =~ /^--config-file=(.*)/
          @config_file_name = $1
        elsif /^--config-file$/.match?(arg)
          need_config_file_name = true
        end
      end
    end