0.0
No release in over 3 years
Easily provide block-scoped context values in your Ruby code.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies
 Project Readme

use_context

Unit Tests

What is this thing?

use_context is a tool for providing block-level context to Ruby programs in a thread-safe and fiber-safe way. Internally it leverages fiber-local storage. It can be used to provide data, etc to parts of your program that might be difficult or inconvenient to reach with eg. normal argument passing.

use_context was inspired by this use-case, and originally proposed as an addition to ViewComponent: ViewComponent/view_component#2327

Usage

There are four ways to use this gem. As some folks are understandably uncomfortable using monkeypatches - especially ones applied to core classes and modules - you are free to choose the one that fits your preferences.

As a monkeypatch

Add the following to your program or application somewhere:

require "use_context/ext/kernel"

This will add two methods to Kernel so they are available everywhere: provide_context, and use_context. Contexts consist of a name and a hash of key/value pairs.

def speak
  use_context(:welcome) do |context|
    puts context[:salutation]
  end
end

provide_context(:welcome, { salutation: "Hello, world!" }) do
  speak  # prints "Hello, world!"
end

Values are available in the current context only for the duration of the block passed to provide_context, and reset after the block returns.

As a refinement

Add the following to your program or application somewhere:

require "use_context/ext/kernel_refinement"

The refinement can be enabled at the class, module, or file level, and adds the same two methods to Kernel. Refinements work differently than monkeypatching in that their changes are not globally applied and are only visible within the scope they are enabled in.

# Makes provide_context and use_context available on Kernel, but only within this file
using UseContext::KernelRefinement

provide_context(:welcome, { salutation: "Hello, world!" }) do
  ...
end

As a mixin

If you'd rather opt-in to use_context's methods on a per-class or per-module basis, you can include the ContextMethods mixin:

require "use_context"

class MyClass
  include UseContext::ContextMethods

  def speak
    use_context(:welcome) do |context|
      puts context[:salutation]
    end
  end
end

UseContext.provide_context(:welcome, { salutation: "Hello, world!" }) do
  MyClass.new.speak  # prints "Hello, world!"
end

No magic

If you'd rather avoid modifying Kernel altogether, use_context can also be used via the UseContext constant.

Add the following to your program or application somewhere:

require "use_context"

Then simply call UseContext.provide_context and UseContext.use_context:

UseContext.provide_context(:welcome, { salutation: "Hello, world!" }) do
  UseContext.use_context(:welcome) do |context|
    puts context[:salutation]  # prints "Hello, world!"
  end
end

Overriding context

If a key already exists in the current context, it will be overridden, but only for the duration of the block:

provide_context(:welcome, { salutation: "Hello, world!" }) do
  provide_context(:welcome, { salutation: "Hola, mundo!" }) do
    speak  # prints "Hola, mundo!"
  end

  speak  # prints "Hello, world!"
end

Extracting individual keys

The use_context method allows extracting individual keys from the current context. All arguments after the context name are treated as keys to extract. The extracted values are passed to the block in the order they are specified:

provide_context(:welcome, { salutation: "Hello", recipient: "world" }) do
  use_context(:welcome, :salutation, :recipient) do |salutation, recipient|
    puts "#{salutation}, #{recipient}!"  # prints "Hello, world!"
  end
end

Running Tests

bundle exec rake should do the trick.

License

Licensed under the MIT license. See LICENSE for details.

Authors