Class: ActsAsCalculator::FunctionRegistry

Inherits:
Object
  • Object
show all
Defined in:
lib/acts_as_calculator/function_registry.rb

Defined Under Namespace

Classes: Definition

Constant Summary collapse

BRACKET =
lambda { |amount, tiers|
  FindTier.(tiers:, amount:).value
}
PROGRESSIVE_BRACKET =
lambda { |amount, tiers|
  total = CastDecimal.(amount)

  tiers.map { |tier| Tier.build(tier) }.sum(BigDecimal(0)) do |tier|
    floor = CastDecimal.(tier.from || 0)
    ceiling = tier.to.nil? ? total : [total, CastDecimal.(tier.to)].min
    band = ceiling - floor

    band.positive? ? band * CastDecimal.(tier.value) : BigDecimal(0)
  end
}
ROUND_CURRENCY =
lambda { |amount, precision = 2|
  CastDecimal.(amount).round(Integer(precision), :half_up)
}
PRORATE =
lambda { |amount, part, whole|
  divisor = CastDecimal.(whole)
  raise EvaluationError, "cannot prorate over a whole of zero" if divisor.zero?

  CastDecimal.(amount) * CastDecimal.(part) / divisor
}
BUILTINS =
{
  bracket: BRACKET,
  progressive_bracket: PROGRESSIVE_BRACKET,
  round_currency: ROUND_CURRENCY,
  prorate: PRORATE
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeFunctionRegistry

Returns a new instance of FunctionRegistry.



47
48
49
50
# File 'lib/acts_as_calculator/function_registry.rb', line 47

def initialize
  @definitions = {}
  BUILTINS.each { |name, implementation| register(name:, implementation:) }
end

Class Method Details

.defaultObject



43
44
45
# File 'lib/acts_as_calculator/function_registry.rb', line 43

def self.default
  @default ||= new
end

Instance Method Details

#install(calculator) ⇒ Object



70
71
72
73
# File 'lib/acts_as_calculator/function_registry.rb', line 70

def install(calculator)
  to_a.each { |it| calculator.add_function(it.name, it.type, it.implementation) }
  calculator
end

#register(name:, implementation:, type: :numeric) ⇒ Object

Raises:

  • (ArgumentError)


52
53
54
55
56
57
58
59
60
# File 'lib/acts_as_calculator/function_registry.rb', line 52

def register(name:, implementation:, type: :numeric)
  # Dentaku derives a function's arity from its implementation's #parameters, and a
  # non-lambda proc reports every parameter as optional, so arity checking silently
  # stops working for anything registered as a bare block or proc.
  raise ArgumentError, "implementation for #{name.inspect} must be a lambda" unless implementation.lambda?

  definitions[key_for(name)] = Definition.new(name: key_for(name), type:, implementation:)
  self
end

#registered?(name) ⇒ Boolean

Returns:

  • (Boolean)


62
63
64
# File 'lib/acts_as_calculator/function_registry.rb', line 62

def registered?(name)
  definitions.key?(key_for(name))
end

#to_aObject



66
67
68
# File 'lib/acts_as_calculator/function_registry.rb', line 66

def to_a
  definitions.values
end