Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
xronos-i-am committed Dec 12, 2024
1 parent dffb3c7 commit 77115d5
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 60 deletions.
25 changes: 4 additions & 21 deletions lib/active_dry_deps/container.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,13 @@ module ActiveDryDeps
class Container < Hash

def resolve(container_key)
unless key?(container_key)
self[container_key] = Entry.new(value: Object.const_get(container_key))
end

self[container_key]&.value
value = self[container_key]
value.is_a?(Proc) ? value.call : value
end

def register(container_key, &block)
self[container_key.to_s] = Entry.new(proc: block)
def register(container_key, value = nil)
self[container_key.to_s] = block_given? ? yield : value
end

Entry =
Struct.new(:input) do
def initialize(input = {})
super
@value = input[:value] if input.key?(:value)
end

def value
return @value if defined? @value

@value = input.fetch(:proc).call
end
end

end
end
53 changes: 24 additions & 29 deletions lib/active_dry_deps/dependency.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,59 +3,53 @@
module ActiveDryDeps
class Dependency

LOWER = /[[:lower:]]/

attr_reader :receiver_method_name, :resolve_key, :const_name, :method_name
attr_reader :receiver_method_name, :container_key, :const_name, :method_name

def initialize(resolver, receiver_method_alias: nil)
if LOWER.match?(resolver[0])
receiver_method_by_key(resolver, receiver_method_alias: receiver_method_alias)
else
receiver_method_by_const_name(resolver, receiver_method_alias: receiver_method_alias)
end
parse_resolver(resolver, receiver_method_alias: receiver_method_alias)
end

if Rails.env.test?
def receiver_method_string
Kernel.sprintf(
METHOD_TEMPLATES.fetch(container: true, method_call: !@method_name.nil?),
receiver_method_name: @receiver_method_name,
container_key_or_const_name: @const_name || @resolve_key,
container_key_or_const_name: @const_name || @container_key,
method_name: @method_name,
)
end
else
def receiver_method_string
Kernel.sprintf(
METHOD_TEMPLATES.fetch(container: !@resolve_key.nil?, method_call: !@method_name.nil?),
METHOD_TEMPLATES.fetch(container: !@container_key.nil?, method_call: !@method_name.nil?),
receiver_method_name: @receiver_method_name,
container_key_or_const_name: @const_name || @resolve_key,
container_key_or_const_name: @const_name || @container_key,
method_name: @method_name,
)
end
end

VALID_CONST_NAME = /^[[:upper:]][[[:alnum:]]:_]*$/
VALID_METHOD_NAME = /^[[[:alnum:]]_]+$/
LOWER = /[[:lower:]]/
METHODS_AS_KLASS = %w[perform_later call].freeze

private def receiver_method_by_key(resolver, receiver_method_alias: nil)
receiver_method_name = receiver_method_alias || resolver

unless VALID_METHOD_NAME.match?(receiver_method_name.to_s)
raise DependencyNameInvalid, "name +#{receiver_method_name}+ is not a valid Ruby identifier"
end

@receiver_method_name = receiver_method_name.to_sym
@resolve_key = resolver
end
private def parse_resolver(resolver, receiver_method_alias:)
container_key_or_const_name, method_name = resolver.to_s.split('.', 2)

VALID_CONST_NAME = /^[[:upper:]][[[:alnum:]]:_]*$/
METHODS_AS_KLASS = %w[perform_later call].freeze
container_key, const_name =
if LOWER.match?(container_key_or_const_name[0])
[container_key_or_const_name, nil]
else
[nil, container_key_or_const_name]
end

private def receiver_method_by_const_name(resolver, receiver_method_alias: nil)
const_name, method_name = resolver.to_s.split('.', 2)
if container_key && !VALID_METHOD_NAME.match?(container_key)
raise DependencyNameInvalid, "name +#{container_key}+ is not a valid Ruby identifier"
end

unless VALID_CONST_NAME.match?(const_name)
raise DependencyNameInvalid, "+#{resolver}+ must contains valid constant name"
if const_name && !VALID_CONST_NAME.match?(const_name)
raise DependencyNameInvalid, "+#{const_name}+ must contains valid constant name"
end

if method_name && !VALID_METHOD_NAME.match?(method_name)
Expand All @@ -78,6 +72,7 @@ def receiver_method_string
end

@receiver_method_name = receiver_method_name.to_sym
@container_key = container_key
@const_name = const_name
@method_name = method_name&.to_sym
end
Expand All @@ -89,7 +84,7 @@ def receiver_method_string
# end
def %<receiver_method_name>s(...)
::ActiveDryDeps::Deps::CONTAINER.resolve("%<container_key_or_const_name>s").%<method_name>s(...)
(::ActiveDryDeps::Deps::CONTAINER.resolve("%<container_key_or_const_name>s") || %<container_key_or_const_name>s).%<method_name>s(...)
end
RUBY
{ container: true, method_call: false } => <<~RUBY,
Expand All @@ -98,7 +93,7 @@ def %<receiver_method_name>s(...)
# end
def %<receiver_method_name>s
::ActiveDryDeps::Deps::CONTAINER.resolve("%<container_key_or_const_name>s")
::ActiveDryDeps::Deps::CONTAINER.resolve("%<container_key_or_const_name>s") || %<container_key_or_const_name>s
end
RUBY
{ container: false, method_call: true } => <<~RUBY,
Expand Down
8 changes: 4 additions & 4 deletions lib/active_dry_deps/stub.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ module ActiveDryDeps

module StubDeps

def stub(key, &block)
self::CONTAINER.stub(key, &block)
def stub(key, value)
self::CONTAINER.stub(key, value)
end

def unstub(*keys)
Expand All @@ -20,8 +20,8 @@ def self.extended(container)
const_set(:CONTAINER_ORIG, container.dup)
end

def stub(key, &block)
self[key] = ActiveDryDeps::Container::Entry.new(proc: block)
def stub(key, value)
self[key] = value
end

def unstub(*unstub_keys)
Expand Down
22 changes: 16 additions & 6 deletions spec/active_dry_deps_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

RSpec.describe ActiveDryDeps do
it 'all dependencies works' do
expect(CreateOrder.call).to eq %w[CreateDeparture CreateDeparture job-performed message-ok email-sent-hello]
expect(CreateOrder.call).to eq %w[CreateDeparture CreateDeparture job-performed message-ok email-sent-hello track]
end

it 'stub dependencies with `deps`' do
Expand All @@ -14,8 +14,18 @@
ReserveJob: '3',
message: '4',
mailer: double(call: '5'),
track: '6',
)
expect(service.call).to eq %w[1 2 3 4 5]
expect(service.call).to eq %w[1 2 3 4 5 6]
end

it 'resolves block in runtime' do
service = CreateOrder.new

first_tick = service.tick
second_tick = service.tick

expect(second_tick).not_to eq(first_tick)
end

it 'stub dependency with `deps` not runnable' do
Expand All @@ -33,13 +43,13 @@

describe '#stub' do
def expect_call_orig
expect(CreateOrder.call).to eq %w[CreateDeparture CreateDeparture job-performed message-ok email-sent-hello]
expect(CreateOrder.call).to eq %w[CreateDeparture CreateDeparture job-performed message-ok email-sent-hello track]
end

it 'stubs dependency at the container level' do
Deps.stub('CreateDeparture') { double(call: '1') }
Deps.stub('CreateDeparture', double(call: '1'))

expect(CreateOrder.call).to eq %w[1 1 job-performed message-ok email-sent-hello]
expect(CreateOrder.call).to eq %w[1 1 job-performed message-ok email-sent-hello track]

Deps.unstub

Expand All @@ -48,7 +58,7 @@ def expect_call_orig

it 'raises exception when calls a stub block' do
expect {
Deps.stub('CreateDeparture') { raise StandardError, 'Something went wrong' }
Deps.stub('CreateDeparture', -> { raise StandardError, 'Something went wrong' })
}.not_to raise_error

expect { CreateOrder.call }
Expand Down
3 changes: 3 additions & 0 deletions spec/app/create_order.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ def self.call
'Utils.message',
'SupplierSync::ReserveJob.perform_later',
'mailer',
'tick',
'stats.track',
CreateDepartureCallable: 'CreateDeparture.call',
]

Expand All @@ -21,6 +23,7 @@ def call(is_message: true)
ReserveJob(),
(message('ok') if is_message),
mailer.call('hello'),
track,
]
end

Expand Down
2 changes: 2 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ def call(message)

end

Deps.register(:stats) { Class.new { def self.track = 'track' } }
Deps.register(:tick, -> { rand })
Deps.register(:mailer) { Mailer.new }

Dir['./spec/app/**/*.rb'].each { |f| require f }
Expand Down

0 comments on commit 77115d5

Please sign in to comment.