File: config.rb

package info (click to toggle)
ruby-moneta 1.6.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,776 kB
  • sloc: ruby: 13,201; sh: 178; makefile: 7
file content (101 lines) | stat: -rw-r--r-- 2,820 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
require 'set'

module Moneta
  # Some docs here
  module Config
    # @api private
    module ClassMethods
      def config(name, coerce: nil, default: nil, required: false, &block)
        raise ArgumentError, 'name must be a symbol' unless Symbol === name

        defaults = config_defaults

        raise ArgumentError, "#{name} is already a config option" if defaults.key?(name)
        raise ArgumentError, "coerce must respond to :to_proc" if coerce && !coerce.respond_to?(:to_proc)

        defaults.merge!(name => default.freeze).freeze
        instance_variable_set :@config_defaults, defaults

        instance_variable_set :@config_coercions, config_coercions.merge!(name => coerce.to_proc) if coerce
        instance_variable_set :@config_required_keys, config_required_keys.add(name).freeze if required
        instance_variable_set :@config_blocks, config_blocks.merge!(name => block) if block
      end

      def config_variable(name)
        if instance_variable_defined?(name)
          instance_variable_get(name).dup
        elsif superclass.respond_to?(:config_variable)
          superclass.config_variable(name)
        end
      end

      def config_defaults
        config_variable(:@config_defaults) || {}
      end

      def config_required_keys
        config_variable(:@config_required_keys) || Set.new
      end

      def config_coercions
        config_variable(:@config_coercions) || {}
      end

      def config_blocks
        config_variable(:@config_blocks) || {}
      end

      def config_struct
        unless @config_struct
          keys = config_defaults.keys
          @config_struct = Struct.new(*keys) unless keys.empty?
        end

        @config_struct
      end
    end

    def config
      raise "Not configured" unless defined?(@config)
      @config
    end

    def self.included(base)
      base.extend(ClassMethods)
    end

    protected

    def configure(**options)
      raise 'Already configured' if defined?(@config)

      self.class.config_required_keys.each do |key|
        raise ArgumentError, "#{key} is required" unless options.key? key
      end

      defaults = self.class.config_defaults

      overrides, remainder = options
        .partition { |key,| defaults.key? key }
        .map { |pairs| pairs.to_h }

      self.class.config_coercions.each do |key, coerce|
        overrides[key] = coerce.call(overrides[key]) if overrides.key?(key)
      end

      overridden = defaults.merge!(overrides)

      config_blocks = self.class.config_blocks
      values = overridden.map do |key, value|
        if config_block = config_blocks[key]
          instance_exec(**overridden, &config_block)
        else
          value
        end
      end

      @config = self.class.config_struct&.new(*values).freeze
      remainder
    end
  end
end