Skip to content

Commit

Permalink
Merge pull request #37 from B-CDD/feat/bcdd-context
Browse files Browse the repository at this point in the history
Transform BCDD::Result::Context into BCDD::Context
  • Loading branch information
serradura authored Mar 16, 2024
2 parents b1b334b + c35c1f9 commit 50cb1b9
Show file tree
Hide file tree
Showing 122 changed files with 623 additions and 642 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@

### Changed

- Transform `BCDD::Result::Context` into `BCDD::Context`. But a constant alias was added to keep the old name. You can use `BCDD::Result::Context` or `BCDD::Context` to access the same class.

- **(BREAKING)** Replace trasitions metadata `:ids_tree`, and `:ids_matrix` with `:ids` property. This property is a hash with the following keys:
- `:tree`, a graph/tree representation of the transitions ids.
- `:level_parent`, a hash with the level (depth) of each transition and its parent id.
Expand Down
152 changes: 78 additions & 74 deletions README.md

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions examples/multiple_listeners/config/initializers/bcdd.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
BCDD::Result.config.then do |config|
config.addon.enable!(:continue)

config.constant_alias.enable!('BCDD::Context')

config.pattern_matching.disable!(:nil_as_valid_value_checking)

# config.feature.disable!(:expectations) if Rails.env.production?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def input(&block)
end

def inherited(subclass)
subclass.include ::BCDD::Result::Context.mixin(config: { addon: { continue: true } })
subclass.include ::BCDD::Context.mixin(config: { addon: { continue: true } })
end

def call(arg)
Expand Down
2 changes: 0 additions & 2 deletions examples/service_objects/config/initializers/bcdd.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
BCDD::Result.config.then do |config|
config.addon.enable!(:continue)

config.constant_alias.enable!('BCDD::Context')

config.pattern_matching.disable!(:nil_as_valid_value_checking)

# config.feature.disable!(:expectations) if Rails.env.production?
Expand Down
2 changes: 0 additions & 2 deletions examples/single_listener/config/initializers/bcdd.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
BCDD::Result.config.then do |config|
config.addon.enable!(:continue)

config.constant_alias.enable!('BCDD::Context')

config.pattern_matching.disable!(:nil_as_valid_value_checking)

# config.feature.disable!(:expectations) if Rails.env.production?
Expand Down
91 changes: 91 additions & 0 deletions lib/bcdd/context.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# frozen_string_literal: true

class BCDD::Context < BCDD::Result
require_relative 'context/failure'
require_relative 'context/success'
require_relative 'context/mixin'
require_relative 'context/expectations'
require_relative 'context/callable_and_then'

EXPECTED_OUTCOME = 'BCDD::Context::Success or BCDD::Context::Failure'

def self.Success(type, **value)
Success.new(type: type, value: value)
end

def self.Failure(type, **value)
Failure.new(type: type, value: value)
end

def initialize(type:, value:, source: nil, expectations: nil, terminal: nil)
value.is_a?(::Hash) or raise ::ArgumentError, 'value must be a Hash'

@acc = {}

super
end

def and_then(method_name = nil, **injected_value, &block)
super(method_name, injected_value, &block)
end

def and_then!(source, **injected_value)
_call = injected_value.delete(:_call)

acc.merge!(injected_value)

super(source, injected_value, _call: _call)
end

protected

attr_reader :acc

private

SourceMethodArity = ->(method) do
return 0 if method.arity.zero?

parameters = method.parameters.map(&:first)

return 1 if !parameters.empty? && parameters.all?(/\Akey/)

-1
end

def call_and_then_source_method!(method, injected_value)
acc.merge!(value.merge(injected_value))

case SourceMethodArity[method]
when 0 then source.send(method.name)
when 1 then source.send(method.name, **acc)
else raise Error::InvalidSourceMethodArity.build(source: source, method: method, max_arity: 1)
end
end

def call_and_then_block!(block)
acc.merge!(value)

block.call(acc)
end

def call_and_then_callable!(source, value:, injected_value:, method_name:)
acc.merge!(value.merge(injected_value))

CallableAndThen::Caller.call(source, value: acc, injected_value: injected_value, method_name: method_name)
end

def ensure_result_object(result, origin:)
raise_unexpected_outcome_error(result, origin) unless result.is_a?(BCDD::Context)

return result.tap { _1.acc.merge!(acc) } if result.source.equal?(source)

raise Error::InvalidResultSource.build(given_result: result, expected_source: source)
end

def raise_unexpected_outcome_error(result, origin)
raise Error::UnexpectedOutcome.build(outcome: result, origin: origin, expected: EXPECTED_OUTCOME)
end

private_constant :SourceMethodArity
end
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# frozen_string_literal: true

class BCDD::Result
module BCDD
module Context::CallableAndThen
class Caller < CallableAndThen::Caller
class Caller < Result::CallableAndThen::Caller
module KeyArgs
def self.parameters?(source)
parameters = source.parameters.map(&:first)
Expand All @@ -11,7 +11,7 @@ def self.parameters?(source)
end

def self.invalid_arity(source, method)
CallableAndThen::Error::InvalidArity.build(source: source, method: method, arity: 'only keyword args')
Result::CallableAndThen::Error::InvalidArity.build(source: source, method: method, arity: 'only keyword args')
end
end

Expand All @@ -30,7 +30,8 @@ def self.call_method!(source, method, value, _injected_value)
def self.ensure_result_object(source, value, result)
return result.tap { result.send(:acc).then { _1.merge!(value.merge(_1)) } } if result.is_a?(Context)

raise Error::UnexpectedOutcome.build(outcome: result, origin: source, expected: Context::EXPECTED_OUTCOME)
raise Result::Error::UnexpectedOutcome.build(outcome: result, origin: source,
expected: Context::EXPECTED_OUTCOME)
end

private_class_method :call_proc!, :call_method!
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

class BCDD::Result::Context
class BCDD::Context
class Expectations < BCDD::Result::Expectations
require_relative 'expectations/mixin'

Expand All @@ -9,7 +9,7 @@ def self.mixin_module
end

def self.result_factory_without_expectations
::BCDD::Result::Context
::BCDD::Context
end

private_class_method :mixin!, :mixin_module, :result_factory_without_expectations
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

class BCDD::Result::Context
class BCDD::Context
module Expectations::Mixin
Factory = BCDD::Result::Expectations::Mixin::Factory

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

class BCDD::Result::Context::Failure < BCDD::Result::Context
class BCDD::Context::Failure < BCDD::Context
include BCDD::Result::Failure::Methods

def and_expose(_type, _keys, **_options)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

class BCDD::Result::Context
class BCDD::Context
module Mixin
Factory = BCDD::Result::Mixin::Factory

Expand Down Expand Up @@ -50,7 +50,7 @@ def self.mixin_module
end

def self.result_factory
::BCDD::Result::Context
::BCDD::Context
end

private_class_method :mixin_module, :result_factory
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# frozen_string_literal: true

class BCDD::Result
class Context::Error < BCDD::Result::Error
class BCDD::Context
class Error < BCDD::Result::Error
InvalidExposure = ::Class.new(self)
end

class Context::Success < Context
class Success < self
include ::BCDD::Result::Success::Methods

FetchValues = ->(acc_values, keys) do
Expand All @@ -15,7 +15,7 @@ class Context::Success < Context
rescue ::KeyError => e
message = "#{e.message}. Available to expose: #{acc_values.keys.map(&:inspect).join(', ')}"

raise Context::Error::InvalidExposure, message
raise Error::InvalidExposure, message
end

def and_expose(type, keys, terminal: true)
Expand Down
2 changes: 1 addition & 1 deletion lib/bcdd/result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
require_relative 'result/mixin'
require_relative 'result/contract'
require_relative 'result/expectations'
require_relative 'result/context'
require_relative 'result/config'
require_relative 'result/context'

class BCDD::Result
attr_accessor :unknown, :transitions
Expand Down
4 changes: 2 additions & 2 deletions lib/bcdd/result/config/switchers/addons.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ class Config
module Addons
AFFECTS = %w[
BCDD::Result.mixin
BCDD::Result::Context.mixin
BCDD::Context.mixin
BCDD::Result::Expectations.mixin
BCDD::Result::Context::Expectations.mixin
BCDD::Context::Expectations.mixin
].freeze

OPTIONS = {
Expand Down
4 changes: 1 addition & 3 deletions lib/bcdd/result/config/switchers/constant_aliases.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ class BCDD::Result
class Config
module ConstantAliases
MAPPING = {
'Result' => { target: ::Object, name: :Result, value: ::BCDD::Result },
'Context' => { target: ::Object, name: :Context, value: ::BCDD::Result::Context },
'BCDD::Context' => { target: ::BCDD, name: :Context, value: ::BCDD::Result::Context }
'Result' => { target: ::Object, name: :Result, value: ::BCDD::Result }
}.transform_values!(&:freeze).freeze

OPTIONS = MAPPING.to_h do |option_name, mapping|
Expand Down
6 changes: 3 additions & 3 deletions lib/bcdd/result/config/switchers/features.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ module Features
OPTIONS = {
expectations: {
default: true,
affects: %w[BCDD::Result::Expectations BCDD::Result::Context::Expectations]
affects: %w[BCDD::Result::Expectations BCDD::Context::Expectations]
},
transitions: {
default: true,
affects: %w[BCDD::Result BCDD::Result::Context BCDD::Result::Expectations BCDD::Result::Context::Expectations]
affects: %w[BCDD::Result BCDD::Context BCDD::Result::Expectations BCDD::Context::Expectations]
},
and_then!: {
default: false,
affects: %w[BCDD::Result BCDD::Result::Context BCDD::Result::Expectations BCDD::Result::Context::Expectations]
affects: %w[BCDD::Result BCDD::Context BCDD::Result::Expectations BCDD::Context::Expectations]
}
}.transform_values!(&:freeze).freeze

Expand Down
2 changes: 1 addition & 1 deletion lib/bcdd/result/config/switchers/pattern_matching.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module PatternMatching
OPTIONS = {
nil_as_valid_value_checking: {
default: false,
affects: %w[BCDD::Result::Expectations BCDD::Result::Context::Expectations]
affects: %w[BCDD::Result::Expectations BCDD::Context::Expectations]
}
}.transform_values!(&:freeze).freeze

Expand Down
92 changes: 3 additions & 89 deletions lib/bcdd/result/context.rb
Original file line number Diff line number Diff line change
@@ -1,93 +1,7 @@
# frozen_string_literal: true

class BCDD::Result
class Context < self
require_relative 'context/failure'
require_relative 'context/success'
require_relative 'context/mixin'
require_relative 'context/expectations'
require_relative 'context/callable_and_then'

EXPECTED_OUTCOME = 'BCDD::Result::Context::Success or BCDD::Result::Context::Failure'

def self.Success(type, **value)
Success.new(type: type, value: value)
end

def self.Failure(type, **value)
Failure.new(type: type, value: value)
end

def initialize(type:, value:, source: nil, expectations: nil, terminal: nil)
value.is_a?(::Hash) or raise ::ArgumentError, 'value must be a Hash'

@acc = {}

super
end

def and_then(method_name = nil, **injected_value, &block)
super(method_name, injected_value, &block)
end

def and_then!(source, **injected_value)
_call = injected_value.delete(:_call)

acc.merge!(injected_value)

super(source, injected_value, _call: _call)
end

protected

attr_reader :acc

private

SourceMethodArity = ->(method) do
return 0 if method.arity.zero?
require 'bcdd/context'

parameters = method.parameters.map(&:first)

return 1 if !parameters.empty? && parameters.all?(/\Akey/)

-1
end

def call_and_then_source_method!(method, injected_value)
acc.merge!(value.merge(injected_value))

case SourceMethodArity[method]
when 0 then source.send(method.name)
when 1 then source.send(method.name, **acc)
else raise Error::InvalidSourceMethodArity.build(source: source, method: method, max_arity: 1)
end
end

def call_and_then_block!(block)
acc.merge!(value)

block.call(acc)
end

def call_and_then_callable!(source, value:, injected_value:, method_name:)
acc.merge!(value.merge(injected_value))

CallableAndThen::Caller.call(source, value: acc, injected_value: injected_value, method_name: method_name)
end

def ensure_result_object(result, origin:)
raise_unexpected_outcome_error(result, origin) unless result.is_a?(Context)

return result.tap { _1.acc.merge!(acc) } if result.source.equal?(source)

raise Error::InvalidResultSource.build(given_result: result, expected_source: source)
end

def raise_unexpected_outcome_error(result, origin)
raise Error::UnexpectedOutcome.build(outcome: result, origin: origin, expected: EXPECTED_OUTCOME)
end

private_constant :SourceMethodArity
end
class BCDD::Result
Context = BCDD::Context
end
Loading

0 comments on commit 50cb1b9

Please sign in to comment.