Class: SoberSwag::Serializer::Conditional

Inherits:
Base
  • Object
show all
Defined in:
lib/sober_swag/serializer/conditional.rb

Overview

Conditionally serialize one thing or the other thing via deciding on a condition. This works by taking three elements: a "decision" proc, a "left" serializer, and a "right" serializer. The decision proc takes in both the object to be serialized and the options hash, and returns a [:left, val] object, or a [:right, val] object, which then get passed on to the appropriate serializer.

This is a very weird, not-very-Ruby-like abstraction, upon which we can build abstractions that are actually use for users. It lets you build abstractions like "Use this serializer if a type has this class, otherwise use this other one." When composed together, you can make arbitrary decision trees.

This class is heavily inspired by the Decideable typeclass from Haskell.

Defined Under Namespace

Classes: BadChoiceError

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#array, #identifier, #meta, #optional, #serializer, #via_map

Constructor Details

#initialize(chooser, left, right) ⇒ Conditional

Create a new conditional serializer, from a "chooser" proc, a "left" serializer, and a "right" serializer.

Parameters:



28
29
30
31
32
# File 'lib/sober_swag/serializer/conditional.rb', line 28

def initialize(chooser, left, right)
  @chooser = chooser
  @left = left
  @right = right
end

Instance Attribute Details

#chooserProc, Lambda (readonly)

Returns the "chooser" proc.

Returns:

  • (Proc, Lambda)

    the "chooser" proc.



36
37
38
# File 'lib/sober_swag/serializer/conditional.rb', line 36

def chooser
  @chooser
end

#leftSoberSwag::Serializer::Base (readonly)

Returns the serializer to use if the "chooser" proc chooses :right. Also called the "left-side serializer.".

Returns:

  • (SoberSwag::Serializer::Base)

    the serializer to use if the "chooser" proc chooses :right. Also called the "left-side serializer."



41
42
43
# File 'lib/sober_swag/serializer/conditional.rb', line 41

def left
  @left
end

#rightSoberSwag::Serializer::Base (readonly)

Returns the serializer to use if the "chooser" proc chooses :right. Also called the "right-side serializer.".

Returns:

  • (SoberSwag::Serializer::Base)

    the serializer to use if the "chooser" proc chooses :right. Also called the "right-side serializer."



46
47
48
# File 'lib/sober_swag/serializer/conditional.rb', line 46

def right
  @right
end

Instance Method Details

#finalize_lazy_type!Object

Finalize both #left and #right



93
94
95
# File 'lib/sober_swag/serializer/conditional.rb', line 93

def finalize_lazy_type!
  [left, right].each(&:finalize_lazy_type!)
end

#lazy_typeObject



79
80
81
82
83
84
85
# File 'lib/sober_swag/serializer/conditional.rb', line 79

def lazy_type
  if left.lazy_type == right.lazy_type
    left.lazy_type
  else
    left.lazy_type | right.lazy_type
  end
end

#lazy_type?Boolean

Returns:

  • (Boolean)


87
88
89
# File 'lib/sober_swag/serializer/conditional.rb', line 87

def lazy_type?
  left.lazy_type? || right.lazy_type?
end

#serialize(object, options = {}) ⇒ Hash

First, call #chooser with object and options to see what serializer to use, and what to serialize. Then, if it returns [:left, val], use #left to serialize val. Otherwise, if it returns [:right, val], use #right to serialize val. If it returns neither, throw BadChoiceError.

Returns:

  • (Hash)

    a JSON-compatible object

Raises:



56
57
58
59
60
61
62
63
64
65
66
# File 'lib/sober_swag/serializer/conditional.rb', line 56

def serialize(object, options = {})
  tag, val = chooser.call(object, options)
  case tag
  when :left
    left.serialize(val, options)
  when :right
    right.serialize(val, options)
  else
    raise BadChoiceError, "result of chooser proc was not a left or right, but a #{val.class}"
  end
end

#typeObject

Since this could potentially serialize one of two alternatives, the "type" we serialize two is either one alternative or the other.



71
72
73
74
75
76
77
# File 'lib/sober_swag/serializer/conditional.rb', line 71

def type
  if left.type == right.type
    left.type
  else
    left.type | right.type
  end
end