Skip to content

Commit

Permalink
Add support for dependent options
Browse files Browse the repository at this point in the history
  • Loading branch information
p-lambert committed Oct 17, 2017
1 parent d105bd4 commit 20e4ee9
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 4 deletions.
15 changes: 13 additions & 2 deletions lib/ddtrace/configurable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,16 @@ def reset_options!
end
end

def sorted_options
Configuration::Resolver.new(__dependency_graph).call
end

private

def option(name, meta = {})
def option(name, meta = {}, &block)
name = name.to_sym
meta[:setter] ||= IDENTITY
meta[:setter] ||= (block || IDENTITY)
meta[:depends_on] ||= []
__options[name] = meta
end

Expand All @@ -65,6 +70,12 @@ def __pretty_name

to_s
end

def __dependency_graph
__options.each_with_object({}) do |(name, meta), graph|
graph[name] = meta[:depends_on]
end
end
end
end
end
5 changes: 3 additions & 2 deletions lib/ddtrace/configuration.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require_relative 'configuration/proxy'
require_relative 'configuration/resolver'

module Datadog
# Configuration provides a unique access point for configurations
Expand All @@ -17,8 +18,8 @@ def [](integration_name)
def use(integration_name, options = {})
integration = fetch_integration(integration_name)

options.each_with_object(Proxy.new(integration)) do |(name, value), proxy|
proxy[name] = value
integration.sorted_options.each do |name|
integration.set_option(name, options[name]) if options.key?(name)
end

integration.patch if integration.respond_to?(:patch)
Expand Down
23 changes: 23 additions & 0 deletions lib/ddtrace/configuration/resolver.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require 'tsort'

module Datadog
class Configuration
class Resolver
include TSort

def initialize(dependency_graph = {})
@dependency_graph = dependency_graph
end

def tsort_each_node(&blk)
@dependency_graph.each_key(&blk)
end

def tsort_each_child(node, &blk)
@dependency_graph.fetch(node).each(&blk)
end

alias call tsort
end
end
end
19 changes: 19 additions & 0 deletions test/configurable_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ def test_custom_setter
assert_equal('LOUD', @module.get_option(:shout))
end

def test_custom_setter_block
@module.class_eval do
option(:shout) { |value| value.upcase }
end

@module.set_option(:shout, 'loud')
assert_equal('LOUD', @module.get_option(:shout))
end

def test_invalid_option
assert_raises(InvalidOptionError) do
@module.set_option(:bad_option, 'foo')
Expand Down Expand Up @@ -85,5 +94,15 @@ def test_false_options
@module.set_option(:boolean, false)
refute(@module.get_option(:boolean))
end

def test_dependency_solving
@module.class_eval do
option :foo, depends_on: [:bar]
option :bar, depends_on: [:baz]
option :baz
end

assert_equal([:baz, :bar, :foo], @module.sorted_options)
end
end
end
22 changes: 22 additions & 0 deletions test/configuration/resolver_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
require 'ddtrace/configuration'

module Datadog
class Configuration
class ResolverTest < Minitest::Test
def test_dependency_solving
graph = { 1 => [2], 2 => [3, 4], 3 => [], 4 => [3], 5 => [1] }
tsort = Resolver.new(graph).call

assert_equal([3, 4, 2, 1, 5], tsort)
end

def test_cyclic_dependecy
graph = { 1 => [2], 2 => [1] }

assert_raises(TSort::Cyclic) do
Resolver.new(graph).call
end
end
end
end
end
17 changes: 17 additions & 0 deletions test/configuration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def setup
def test_use_method
contrib = Minitest::Mock.new
contrib.expect(:patch, true)
contrib.expect(:sorted_options, [])

@registry.add(:example, contrib)
@configuration.use(:example)
Expand Down Expand Up @@ -71,5 +72,21 @@ def test_hash_coercion
@registry.add(:example, integration)
assert_equal({ option1: :foo, option2: :bar }, @configuration[:example].to_h)
end

def test_dependency_solving
integration = Module.new do
include Contrib::Base
option :multiply_by, depends_on: [:number] do |value|
get_option(:number) * value
end

option :number
end

@registry.add(:example, integration)
@configuration.use(:example, multiply_by: 5, number: 5)
assert_equal(5, @configuration[:example][:number])
assert_equal(25, @configuration[:example][:multiply_by])
end
end
end

0 comments on commit 20e4ee9

Please sign in to comment.