Class: Statefully::State Abstract

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Enumerable
Defined in:
lib/statefully/state.rb

Overview

This class is abstract.

State is an immutable collection of fields with some convenience methods.

Direct Known Subclasses

Failure, Finished, None, Success

Defined Under Namespace

Classes: Failure, Finished, None, Success

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object (private)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Dynamically pass unknown messages to the underlying state storage

State fields become accessible through readers, like in an OpenStruct. A single state field can be questioned for existence by having its name followed by a question mark - eg. bacon?. A single state field can be force-accessed by having its name followed by an exclamation mark - eg. bacon!.

This method reeks of :reek:TooManyStatements.

Examples:

state = Statefully::State.create(bacon: 'tasty')

state.bacon
=> "tasty"

state.bacon?
=> true

state.bacon!
=> "tasty"

state.cabbage
NoMethodError: undefined method `cabbage' for #<Statefully::State::Success bacon="tasty">
        [STACK TRACE]

state.cabbage?
=> false

state.cabbage!
Statefully::Errors::StateMissing: field 'cabbage' missing from state
        [STACK TRACE]

Parameters:

  • name (Symbol|String)
  • args (Array<Object>)
  • block (Proc)

Returns:

  • (Object)

Raises:



273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/statefully/state.rb', line 273

def method_missing(name, *args, &block)
  sym_name = name.to_sym
  return fetch(sym_name) if key?(sym_name)
  str_name = name.to_s
  modifier = str_name[-1]
  return super unless %w[? !].include?(modifier)
  base = str_name[0...-1].to_sym
  known = key?(base)
  return known if modifier == '?'
  return fetch(base) if known
  raise Errors::StateMissing, base
end

Instance Attribute Details

#previousState (readonly)

Return the previous Statefully::State

Examples:

Statefully::State.create.previous
=> #<Statefully::State::None>

Statefully::State.create.succeed.previous
=> #<Statefully::State::Success>

Returns:



23
24
25
# File 'lib/statefully/state.rb', line 23

def previous
  @previous
end

Class Method Details

.create(**values) ⇒ State::Success

Create an instance of Statefully::State object

This is meant as the only valid way of creating Statefully::State objects.

Examples:

Statefully::State.create(key: 'val')
=> #<Statefully::State::Success key="val">

Parameters:

  • values (Hash<Symbol, Object>)

    keyword arguments

Returns:



69
70
71
72
# File 'lib/statefully/state.rb', line 69

def self.create(**values)
  base = { correlation_id: SecureRandom.uuid }
  Success.send(:new, base.merge(values), previous: None.instance).freeze
end

Instance Method Details

#ancestryArray<State>

Return all States that came before

Examples:

state = Statefully::State.create
=> [#<Statefully::State::None>]

Returns:



81
82
83
# File 'lib/statefully/state.rb', line 81

def ancestry
  [previous] + previous.ancestry
end

#diffDiff

Return a Diff between current and previous Statefully::State

Examples:

Statefully::State.create.succeed(key: 'val').diff
=> #<Statefully::Diff::Changed added={key: "val"}>

Returns:



92
93
94
# File 'lib/statefully/state.rb', line 92

def diff
  Diff.create(current: self, previous: previous)
end

#eachEnumerator

Examples:

Statefully::State.create(key: 'val').each { |key, val| puts("#{key} => #{val}") }
key => val

Returns:

  • (Enumerator)

See Also:



56
# File 'lib/statefully/state.rb', line 56

def_delegators :@_members, :each, :fetch, :key?, :keys

#failed?Boolean

Check if the current Statefully::State is failed

Examples:

state = Statefully::State.create
state.failed?
=> false

state.fail(RuntimeError.new('Boom!')).failed?
=> true

Returns:

  • (Boolean)


133
134
135
# File 'lib/statefully/state.rb', line 133

def failed?
  !successful?
end

#fetchObject

Examples:

Statefully::State.create(key: 'val').fetch(:key)
=> 'val'

Returns:

  • (Object)

See Also:



56
# File 'lib/statefully/state.rb', line 56

def_delegators :@_members, :each, :fetch, :key?, :keys

#finished?Boolean

Check if the current Statefully::State is finished

Examples:

state = Statefully::State.create
state.finished?
=> false

state.finish.finished?
=> true

Returns:

  • (Boolean)


148
149
150
# File 'lib/statefully/state.rb', line 148

def finished?
  false
end

#historyArray<Diff>

Return all historical changes to this Statefully::State

Examples:

Statefully::State.create.succeed(key: 'val').history
=> [#<Statefully::Diff::Changed added={key: "val"}>, #<Statefully::Diff::Created>]

Returns:



103
104
105
# File 'lib/statefully/state.rb', line 103

def history
  ([diff] + previous.history).freeze
end

#inspectString

Show the current Statefully::State in a human-readable form

Examples:

Statefully::State.create(key: 'val')
=> #<Statefully::State::Success key="val">

Returns:

  • (String)


194
195
196
# File 'lib/statefully/state.rb', line 194

def inspect
  _inspect_details({})
end

#key?Boolean

Examples:

state = Statefully::State.create(key: 'val')
state.key?(:key)
=> true
state.key?(:other)
=> false

Returns:

  • (Boolean)

See Also:



56
# File 'lib/statefully/state.rb', line 56

def_delegators :@_members, :each, :fetch, :key?, :keys

#keysArray<Symbol>

Examples:

Statefully::State.create(key: 'val').keys
=> [:key]

Returns:

  • (Array<Symbol>)

See Also:



56
# File 'lib/statefully/state.rb', line 56

def_delegators :@_members, :each, :fetch, :key?, :keys

#none?Boolean

Check if the current Statefully::State is none (a null-object of Statefully::State)

Examples:

state = Statefully::State.create
state.none?
=> false

state.previous.none?
=> true

Returns:

  • (Boolean)


163
164
165
# File 'lib/statefully/state.rb', line 163

def none?
  false
end

#resolveState

Resolve the current Statefully::State

Resolving will return the current Statefully::State if successful, but raise an error wrapped in a Failure. This is a convenience method inspired by monadic composition from functional languages.

Examples:

Statefully::State.create(key: 'val').resolve
=> #<Statefully::State::Success key="val">

Statefully::State.create.fail(RuntimeError.new('Boom!')).resolve
RuntimeError: Boom!
        [STACK TRACE]

Returns:

Raises:

  • (StandardError)

    if the receiver is #failed?



183
184
185
# File 'lib/statefully/state.rb', line 183

def resolve
  self
end

#successful?Boolean

Check if the current Statefully::State is successful

Examples:

state = Statefully::State.create
state.successful?
=> true

state.fail(RuntimeError.new('Boom!')).successful?
=> false

Returns:

  • (Boolean)


118
119
120
# File 'lib/statefully/state.rb', line 118

def successful?
  true
end