-
Notifications
You must be signed in to change notification settings - Fork 375
/
options.rb
128 lines (105 loc) · 3.87 KB
/
options.rb
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
require_relative 'option_set'
require_relative 'option_definition'
require_relative 'option_definition_set'
module Datadog
module Core
module Configuration
# Behavior for a configuration object that has options
# @public_api
module Options
def self.included(base)
base.extend(ClassMethods)
base.include(InstanceMethods)
end
# Class behavior for a configuration object with options
# @public_api
module ClassMethods
def options
# Allows for class inheritance of option definitions
@options ||= superclass <= Options ? superclass.options.dup : OptionDefinitionSet.new
end
protected
def option(name, meta = {}, &block)
settings_name = defined?(@settings_name) && @settings_name
option_name = settings_name ? "#{settings_name}.#{name}" : name
builder = OptionDefinition::Builder.new(option_name, meta, &block)
options[name] = builder.to_definition.tap do
# Resolve and define helper functions
helpers = default_helpers(name)
# Prevent unnecessary creation of an identical copy of helpers if there's nothing to merge
helpers = helpers.merge(builder.helpers) unless builder.helpers.empty?
define_helpers(helpers)
end
end
private
def default_helpers(name)
option_name = name.to_sym
{
option_name.to_sym => proc do
get_option(option_name)
end,
"#{option_name}=".to_sym => proc do |value|
set_option(option_name, value)
end
}
end
def define_helpers(helpers)
helpers.each do |name, block|
next unless block.is_a?(Proc)
define_method(name, &block)
end
end
end
# Instance behavior for a configuration object with options
# @public_api
module InstanceMethods
def options
@options ||= OptionSet.new
end
def set_option(name, value, precedence: Configuration::Option::Precedence::PROGRAMMATIC)
resolve_option(name).set(value, precedence: precedence)
end
def unset_option(name, precedence: Configuration::Option::Precedence::PROGRAMMATIC)
resolve_option(name).unset(precedence)
end
def get_option(name)
resolve_option(name).get
end
def reset_option(name)
assert_valid_option!(name)
options[name].reset if options.key?(name)
end
def option_defined?(name)
self.class.options.key?(name)
end
# Is this option's value the default fallback value?
def using_default?(name)
get_option(name) # Resolve value check if environment variable overwrote the default
options[name].default_precedence?
end
def options_hash
self.class.options.merge(options).each_with_object({}) do |(key, _), hash|
hash[key] = get_option(key)
end
end
def reset_options!
options.values.each(&:reset)
end
private
# Ensure option DSL is loaded
def resolve_option(name)
option = options[name]
return option if option
assert_valid_option!(name)
definition = self.class.options[name]
options[name] = definition.build(self)
end
def assert_valid_option!(name)
raise(InvalidOptionError, "#{self.class.name} doesn't define the option: #{name}") unless option_defined?(name)
end
end
InvalidOptionError = Class.new(StandardError)
end
end
end
end