Skip to content

Commit

Permalink
Added: Options, Patchable, Registerable, Configurable to Datadog::Con…
Browse files Browse the repository at this point in the history
…trib.
  • Loading branch information
delner committed Jun 11, 2018
1 parent 37bec75 commit afe57f3
Show file tree
Hide file tree
Showing 14 changed files with 344 additions and 98 deletions.
3 changes: 2 additions & 1 deletion lib/ddtrace/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ def use(integration_name, options = {}, &block)

if integration.class <= Datadog::Contrib::Integration
configuration_name = options[:describes] || :default
integration.configure(configuration_name, options, &block)
filtered_options = options.reject { |k, _v| k == :describes }
integration.configure(configuration_name, filtered_options, &block)
else
settings = Proxy.new(integration)
integration.sorted_options.each do |name|
Expand Down
7 changes: 4 additions & 3 deletions lib/ddtrace/contrib/base.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
require 'ddtrace/registry'
require 'ddtrace/configurable'
require 'ddtrace/patcher'
require 'ddtrace/registry/registerable'

module Datadog
module Contrib
# Base provides features that are shared across all integrations
module Base
def self.included(base)
base.send(:include, Registry::Registerable)
base.send(:include, Configurable)
base.send(:include, Patcher)
base.send(:include, Datadog::Configurable)
base.send(:include, Datadog::Patcher)
end
end
end
Expand Down
55 changes: 55 additions & 0 deletions lib/ddtrace/contrib/configurable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
require 'ddtrace/contrib/configuration/resolver'
require 'ddtrace/contrib/configuration/settings'

module Datadog
module Contrib
# Defines configurable behavior for integrations
module Configurable
def self.included(base)
base.send(:include, InstanceMethods)
end

# Configurable instance behavior for integrations
module InstanceMethods
def default_configuration
Configuration::Settings.new
end

def reset_configuration!
@configurations = nil
@resolver = nil
end

def configuration(name = :default)
name = :default if name.nil?
name = resolver.resolve(name)
return nil unless configurations.key?(name)
configurations[name]
end

def configurations
@configurations ||= Hash.new { default_configuration }.tap do |configs|
configs[:default] = default_configuration
end
end

def configure(name = :default, options = {}, &block)
name = resolver.resolve(name)

configurations[name].tap do |settings|
settings.configure(options, &block)
configurations[name] = settings
end
end

protected

attr_writer :resolver

def resolver
@resolver ||= Configuration::Resolver.new
end
end
end
end
end
33 changes: 33 additions & 0 deletions lib/ddtrace/contrib/configuration/option.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module Datadog
module Contrib
module Configuration
# Represents an instance of an integration configuration option
class Option
attr_reader \
:definition

def initialize(definition, context)
@definition = definition
@context = context
@value = nil
@is_set = false
end

def set(value)
@value = @context.instance_exec(value, &definition.setter).tap do
@is_set = true
end
end

def get
return definition.default_value unless @is_set
@value
end

def reset
set(definition.default_value)
end
end
end
end
end
29 changes: 29 additions & 0 deletions lib/ddtrace/contrib/configuration/option_definition.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module Datadog
module Contrib
module Configuration
# Represents a definition for an integration configuration option
class OptionDefinition
IDENTITY = ->(x) { x }

attr_reader \
:default,
:depends_on,
:lazy,
:name,
:setter

def initialize(name, meta = {}, &block)
@default = meta[:default]
@depends_on = meta[:depends_on] || []
@lazy = meta[:lazy] || false
@name = name.to_sym
@setter = meta[:setter] || block || IDENTITY
end

def default_value
lazy ? @default.call : @default
end
end
end
end
end
20 changes: 20 additions & 0 deletions lib/ddtrace/contrib/configuration/option_definition_set.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require 'ddtrace/configuration/resolver'

module Datadog
module Contrib
module Configuration
# Represents a set of configuration option definitions for an integration
class OptionDefinitionSet < Hash
def dependency_order
Datadog::Configuration::Resolver.new(dependency_graph).call
end

def dependency_graph
each_with_object({}) do |(name, option), graph|
graph[name] = option.depends_on
end
end
end
end
end
end
8 changes: 8 additions & 0 deletions lib/ddtrace/contrib/configuration/option_set.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module Datadog
module Contrib
module Configuration
class OptionSet < Hash
end
end
end
end
95 changes: 95 additions & 0 deletions lib/ddtrace/contrib/configuration/options.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
require 'ddtrace/contrib/configuration/option'
require 'ddtrace/contrib/configuration/option_set'
require 'ddtrace/contrib/configuration/option_definition'
require 'ddtrace/contrib/configuration/option_definition_set'

module Datadog
module Contrib
module Configuration
# Behavior for a configuration object that has options
module Options
def self.included(base)
base.send(:extend, ClassMethods)
base.send(:include, InstanceMethods)
end

# Class behavior for a configuration object with options
module ClassMethods
def options
@options ||= begin
# Allows for class inheritance of option definitions
superclass <= Options ? superclass.options.dup : OptionDefinitionSet.new
end
end

protected

def option(name, meta = {}, &block)
options[name] = OptionDefinition.new(name, meta, &block).tap do
define_option_accessors(name)
end
end

private

def define_option_accessors(name)
option_name = name

define_method(option_name) do
get_option(option_name)
end

define_method("#{option_name}=") do |value|
set_option(option_name, value)
end
end
end

# Instance behavior for a configuration object with options
module InstanceMethods
def options
@options ||= OptionSet.new
end

def set_option(name, value)
add_option(name) unless options.key?(name)
options[name].set(value)
end

def get_option(name)
add_option(name) unless options.key?(name)
options[name].get
end

def to_h
options.each_with_object({}) do |(key, _), hash|
hash[key] = get_option(key)
end
end

def reset_options!
options.values.each(&:reset)
end

private

def add_option(name)
assert_valid_option!(name)
definition = self.class.options[name]
Option.new(definition, self).tap do |option|
options[name] = option
end
end

def assert_valid_option!(name)
unless self.class.options.key?(name)
raise(InvalidOptionError, "#{self.class.name} doesn't define the option: #{name}")
end
end
end

InvalidOptionError = Class.new(StandardError)
end
end
end
end
12 changes: 12 additions & 0 deletions lib/ddtrace/contrib/configuration/resolver.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module Datadog
module Contrib
module Configuration
# Resolves a value to a configuration key
class Resolver
def resolve(name)
name
end
end
end
end
end
37 changes: 14 additions & 23 deletions lib/ddtrace/contrib/configuration/settings.rb
Original file line number Diff line number Diff line change
@@ -1,42 +1,33 @@
require 'ddtrace/contrib/configuration/options'

module Datadog
module Contrib
module Configuration
# Common settings for all integrations
class Settings
attr_reader \
:service_name,
:tracer
include Options

attr_writer \
:service_name,
:tracer
option :service_name
option :tracer, default: Datadog.tracer

def initialize(options = {})
configure(default_options.merge(options))
end

def reset_options!
configure(default_options)
configure(options)
end

def configure(options = {})
options.each { |k, v| self[k] = v }
yield(self) if block_given?
end
self.class.options.dependency_order.each do |name|
self[name] = options.fetch(name, self[name])
end

def [](param)
send(param)
yield(self) if block_given?
end

def []=(param, value)
send("#{param}=", value)
def [](name)
respond_to?(name) ? send(name) : get_option(name)
end

def default_options
{
service_name: nil,
tracer: Datadog.tracer
}
def []=(name, value)
respond_to?("#{name}=") ? send("#{name}=", value) : set_option(name, value)
end
end
end
Expand Down
Loading

0 comments on commit afe57f3

Please sign in to comment.