Module: TickTock::Locals

Defined in:
lib/tick_tock/locals.rb

Overview

Locals provides the convenience of Thread-local (or Fiber-local) variables to asynchronous code. By “asynchronous”, we simply mean that a given Proc may end up executing on a different Thread or Fiber from the one in which it was created – or equally – on the same thread, but at a later time!

See Locals.wrap_proc for an example of how this can be used to capture local state and wrap it with a Proc for later use, independent of how that state may change during the intervening period.

Here’s how similar concepts are implemented in the Monix library in Scala.

Class Method Summary collapse

Class Method Details

.[](key) ⇒ Object

Fetches current value of given ‘key` in the local context.

Parameters:

  • key (String, Symbol)

    Key to fetch

Returns:

  • (Object)

    Current value of ‘key` in local context

Raises:

  • (KeyError)

    Raise if key not found



67
68
69
# File 'lib/tick_tock/locals.rb', line 67

def [](key)
  context.fetch(key)
end

.[]=(key, value) ⇒ Object

Updates the current local context to map key to value. Works in a non-mutative way, so that any other references to the old context will be left unchanged.

Parameters:

  • key (String, Symbol)

    Key to set a value for

  • value (Object)

    Value to set for ‘key` in local context

Returns:

  • (Object)

    The value that was set



78
79
80
# File 'lib/tick_tock/locals.rb', line 78

def []=(key, value)
  self.context = context.merge(key => value).freeze
end

.clear!Object

Clears the current local context



91
92
93
# File 'lib/tick_tock/locals.rb', line 91

def clear!
  self.context = DEFAULT_CONTEXT
end

.contextHash{String, Symbol => Object}

Returns The current local context represented as a frozen hash.

Returns:

  • (Hash{String, Symbol => Object})

    The current local context represented as a frozen hash.



97
98
99
100
101
102
103
# File 'lib/tick_tock/locals.rb', line 97

def context
  if Thread.current.key?(FIBER_LOCAL_KEY)
    Thread.current[FIBER_LOCAL_KEY]
  else
    DEFAULT_CONTEXT
  end
end

.key?(key) ⇒ Boolean

Check if the given key is currently set in the local context.

Parameters:

  • key (String, Symbol)

    Key to check for

Returns:

  • (Boolean)

    Is the key currently set?



86
87
88
# File 'lib/tick_tock/locals.rb', line 86

def key?(key)
  context.key?(key)
end

.wrap_proc(&proc_to_wrap) ⇒ Proc

Wraps the current local context into the given proc, so that when it is run it has access to the same local context as when it was wrapped, even if it is run in a different Thread, Fiber, or simply at a later time after the local context was changed.

Examples:

Wrap current local context into a Proc object

# proc which depends on some local variable
a_proc = proc { "proc sees: " + TickTock::Locals[:foo].to_s }

# wraps the current state of the locals into the proc
TickTock::Locals[:foo] = :bar
wrapped_proc = TickTock::Locals.wrap_proc(&a_proc)

# later, the state of the locals change, but the wrapped state does not
TickTock::Locals[:foo] = 42
wrapped_proc.call
#=> "proc sees: bar"

TickTock::Locals[:foo]
#=> 42

Parameters:

  • proc_to_wrap (Proc)

    A proc to wrap with the current local context

Returns:

  • (Proc)

    Wrapped version of the given ‘proc_to_wrap`



48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/tick_tock/locals.rb', line 48

def wrap_proc(&proc_to_wrap)
  wrapped_context = context

  proc do |*args|
    begin
      saved_context = context
      self.context = wrapped_context
      proc_to_wrap.call(*args)
    ensure
      self.context = saved_context
    end
  end
end