class ServiceOperation::Context

Context for an Operation

Constants

CALLER_NAME_REGEXP

Public Class Methods

build(context = {}) click to toggle source

Class Methods

# File lib/service_operation/context.rb, line 14
def self.build(context = {})
  self === context ? context : new(context) # rubocop:disable Style/CaseEquality
end

Public Instance Methods

as_json(*args) click to toggle source

Fixes stack loop issue with OpenStruct @requires ActiveModel::Serializers

# File lib/service_operation/context.rb, line 24
def as_json(*args)
  to_h.as_json(*args)
end
coerce_if(*klasses) { |self| ... } click to toggle source

Use in the Operation class to create eager loading objects:

@example

 def Operation#record
   context.coerce_if(Integer, String) { |name| Model.find_by_param(name) }
 end

Operation.call(record: 'something').record == <Model name='something'>
# File lib/service_operation/context.rb, line 43
def coerce_if(*klasses)
  field = klasses.shift if klasses.first.is_a?(Symbol)
  field ||= caller(1..1).first[CALLER_NAME_REGEXP, 2] # method name fetch was called from
  self[field] = yield(self[field]) if klasses.any? { |k| self[field].is_a?(k) }
  self[field]
end
fail!(context = {}) click to toggle source
# File lib/service_operation/context.rb, line 28
def fail!(context = {})
  context.each { |k, v| send("#{k}=", v) }
  @failure = true

  raise Failure, self
end
failure?() click to toggle source
# File lib/service_operation/context.rb, line 106
def failure?
  @failure || false
end
fetch(*args) { || ... } click to toggle source

@example

fetch(:field, 'value')

@example

fetch(:field) { 'value' }

@example will infer field name from enclosing method name

def enclosing_method
  context.fetch { 'value' }
end

@example

def enclosing_method
  context.fetch 'value'
end
# File lib/service_operation/context.rb, line 62
def fetch(*args)
  if !block_given? && args.length == 1 # context.fetch 'value'
    new_value = args.first
  else
    field, new_value = args
  end

  field ||= caller(1..1).first[CALLER_NAME_REGEXP, 2] # method name fetch was called from

  # field is already set
  value = send(field)
  return value if value

  # context.fetch { block }
  if block_given?
    begin
      value ||= yield
    rescue StandardError => e
      # apply if this context to the field, if this is first instance of this error being raised
      self[field] = e.context if e.respond_to?(:context) &&
                                 e.context.is_a?(self.class) &&
                                 e.context != self &&
                                 e.context.not_yet_raised

      raise e
    end
  end

  value ||= new_value

  self[field] = value

  value
end
not_yet_raised() click to toggle source

@return [true, false] first call returns false, after that true.

# File lib/service_operation/context.rb, line 98
def not_yet_raised
  if @already_raised
    false
  else
    @already_raised = true
  end
end
success?() click to toggle source
# File lib/service_operation/context.rb, line 110
def success?
  !failure?
end
to_h(*args) click to toggle source
Calls superclass method
# File lib/service_operation/context.rb, line 114
def to_h(*args)
  if args.any?
    super().slice(*args)
  else
    super()
  end
end