dry-effects

v0.5
  1. Introduction
  2. Effects
    1. Cache
    2. Current Time
    3. Deferred execution
    4. Environment
    5. Interrupt
    6. Parallel execution
    7. Reader
    8. Resolve (Dependency Injection)
    9. State
    10. Timeout

TOC

  1. Cache longevity
  2. Using in tests

Cache

Cache provides two interfaces for caching. Set up a handler:

require 'dry/effects'

class CacheMiddleware
  # Providing scope is required
  # All cache values will be scoped with this key
  include Dry::Effects::Handler.Cache(:blog)

  def initialize(app)
    @app = app
  end

  def call(env)
    with_cache { @app.env }
  end
end

Using prepend:

require 'dry/effects'

class ShowUsers
  include Dry::Effects.Resolve(:user_repo)
  # It will cache .find_user calls
  # Users with the same id won't be searched twice
  # Effectively (no pun intended),
  # it's `memoize` scoped with the call in CacheMiddleware
  prepend Dry::Effects.Cache(blog: :find_user)

  def call(user_ids)
    users = user_ids.map { find_user(id) }
    # ...
  end

  def find_user(id)
    user_repo.find(id)
  end
end

Or using include:

require 'dry/effects'

class ShowUsers
  include Dry::Effects.Resolve(:user_repo)
  # When included, adds #cache method
  include Dry::Effects.Cache(:blog)

  def call(user_ids)
    users = user_ids.map { cache(:user, id) { user_repo.find(id) } }
    # ...
  end
end

Cache longevity

The default cache handler doesn't (yet) support long-lived storage. Cache values are discarded once with_cache returns.

Using in tests

It's usually OK to have a global handler for cache effects:

require 'dry/effects'

with_cache = Object.new.extend(Dry::Effects::Handler.Cache(:my_app, as: :call))

RSpec.configure do |config|
  config.around(:each) { with_cache.(&ex) }
end