### Integrating Middleware in config.ru Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/resolve.html.md Provides an example of how to use the custom 'ProviderMiddleware' within a Rack application's configuration file (config.ru) to inject dependencies globally. ```ruby # ...some bootstrapping code ... use ProviderMiddleware, user_repo: UserRepo.new run Application.new ``` -------------------------------- ### Cache Handler Configuration for Testing Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/cache.html.md Provides an example of setting up a global cache handler for use in tests, typically integrated with testing frameworks like RSpec. This allows tests to leverage caching effects without needing complex setup for each test case. ```ruby 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 ``` -------------------------------- ### Basic Resolve Injection Example Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/resolve.html.md Demonstrates the fundamental usage of Dry::Effects.Resolve to inject a dependency named 'user_repo' into a class. The injected dependency is then used within the 'call' method to interact with a repository. ```ruby require 'dry/effects' class CreateUser include Dry::Effects.Resolve(:user_repo) def call(values) name = values.values_at(:first_name, :last_name).join(' ') user_repo.create(**values.merge(name: name)) end end ``` -------------------------------- ### Setup Cache Handler with Scope Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/cache.html.md Demonstrates setting up a cache handler using `Dry::Effects::Handler.Cache` with a required scope. This handler can be integrated into middleware to manage cached values scoped to a specific key, ensuring data isolation. ```ruby 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 ``` -------------------------------- ### Example Output from dry-effects Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/index.html.md Illustrates the output format and potential data structure changes when using algebraic effects with dry-effects, showing a transformation from a tuple of strings to a more complex nested structure. ```ruby # => [2, ["1. Hello Alice", "2. Hello Alice!"]] ``` -------------------------------- ### Effect Composition: Handling Combined Effects Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/index.html.md Illustrates how to handle multiple effects (State and Cmp) by nesting their respective handlers. This example shows the flexibility in ordering effect handlers and the resulting output when effects are combined. ```ruby class Context include Dry::Effects::Handler.Cmp(:excitement, as: :test_excitement) include Dry::Effects::Handler.State(:greetings_given) def initialize @greeting = GreetUser.new end def call(name) test_excitement do with_greetings_given(0) do @greeting.(name) end end end end Context.new.('Alice') # => [[1, "1. Hello Alice"], [1, "1. Hello Alice!"]] ``` ```ruby class Context # ... def call(name) with_greetings_given(0) do test_excitement do @greeting.(name) end end end end Context.new.('Alice') ``` -------------------------------- ### State Effect: Counter Middleware Example Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/index.html.md Demonstrates how to use the State effect provider in a middleware to manage shared state. It shows how to include the handler, wrap application calls, and access the state within the handled block. ```ruby require 'dry/effects' class CounterMiddleware # This adds a `counter` effect provider. It will handle (eliminate) effects include Dry::Effects::Handler.State(:counter) def initialize(app) @app = app end def call(env) # Calling `with_counter` makes the value available anywhere in `@app.call` counter, response = with_counter(0) do @app.(env) end # Once processing is complete, the result value # will be stored in `counter` response end end ``` -------------------------------- ### Effect Composition: State and Cmp Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/index.html.md Demonstrates the composability of algebraic effects by combining State and Cmp effects within a single class. This example shows how multiple effects can be introduced and handled simultaneously. ```ruby require 'dry/effects' class GreetUser include Dry::Effects.Cmp(:excitement) include Dry::Effects.State(:greetings_given) def call(name) self.greetings_given += 1 if excitement? "#{greetings_given}. Hello #{name}!" else "#{greetings_given}. Hello #{name}" end end end ``` -------------------------------- ### Testing Environment with RSpec Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/env.html.md Provides an example of how to use `with_env` within an RSpec `around` hook to mock environment values for testing. This avoids modifying global `ENV` variables. ```ruby RSpec.describe SendRequest do include Dry::Effects::Handler.Env subject(:send_request) { described_class.new } let(:endpoint) { "fake server" } around { with_env('THIRD_PARTY' => endpoint, &ex) } it 'sends a request to a fake server' do send_request.(...) end end ``` -------------------------------- ### Define NullExecutor for skipping deferred tasks in Ruby Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/defer.html.md Provides an example of creating a `NullExecutor` by extending `Concurrent::ExecutorService` and defining a no-op `post` method. This mock executor can be used to skip deferred tasks, typically in testing environments. ```ruby require 'concurrent/executor/executor_service' NullExecutor = Object.new.extend(Concurrent::ExecutorService).tap do |null| def null.post end end ``` -------------------------------- ### Cmp Effect: Feature Comparison Middleware Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/index.html.md Explains the Cmp (comparative) effect provider, used for comparing code execution results. This example shows a middleware that runs the application twice, once with and once without a specific feature, to detect differences. ```ruby require 'dry/effects' class TestNewFeatureMiddleware # `as:` renames handler method include Dry::Effects::Handler.Cmp(:feature, as: :test_feature) def initialize(app) @app = app end def call(env) without_feature, with_feature = test_feature do @app.(env) end if with_feature != without_feature # something is different! end without_feature end end ``` -------------------------------- ### Reader Effect in Application Class Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/reader.html.md Shows a practical example of using the Reader effect within an application class ('GreetUser') to access context-specific data like 'locale'. It highlights how the effect is included and accessed via the `locale` attribute. ```ruby class GreetUser include Dry::Effects.Reader(:locale) def call(user) case locale when :en then "Hello #{user.name}" when :de then "Hallo #{user.name}" when :ru then "Привет, #{user.name}" when :it then "Ciao #{user.name}" end end end ``` -------------------------------- ### CurrentTime Middleware Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/current_time.html.md Example of a middleware that uses the CurrentTime effect to fix the time internally for the duration of a request. It wraps the application call with `with_current_time`. ```ruby require 'dry/effects' class CurrentTimeMiddleware include Dry::Effects::Handler.CurrentTime def initialize(app) @app = app end def call(env) # It will use Time.now internally once and set it fixed with_current_time do @app.(env) end end end ``` -------------------------------- ### RSpec Configuration for Current Time Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/current_time.html.md Configures RSpec to include the CurrentTime effect handlers and wraps all examples with `with_current_time`. This allows tests to easily control or mock the current time. ```ruby require 'dry/effects' RSpec.configure do |config| config.include Dry::Effects::Handler.CurrentTime config.include Dry::Effects.CurrentTime config.around { |ex| with_current_time(&ex) } end ``` -------------------------------- ### Overriding Dependencies in Test Environment (Rack::Test) Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/resolve.html.md Provides an example using Rack::Test and Dry::Effects::Handler.Provider to override a specific dependency ('repos.user_repo') within a test case, assuming the application middleware was configured with 'overridable: true'. ```ruby require 'dry/effects' require 'rack/test' RSpec.describe do include Rack::Test::Methods include Dry::Effects::Handler.Provider let(:app) do # building an assembled rack app end describe 'POST /users' do let(:user_repo) { double(:user_repo) } it 'creates a user' do expect(user_repo).to receive(:create).with( first_name: 'John', last_name: 'Doe' ).and_return(1) # Overriding one dependency # It will only work if `overridable: true` is passed # in the middleware provide('repos.user_repo' => user_repo) do post( '/users', JSON.dump(first_name: 'John', last_name: 'Doe'), 'CONTENT_TYPE' => 'application/json' ) end end end end ``` -------------------------------- ### Testing Middleware with State Effect in Ruby Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/state.html.md Provides an example of using the State effect within an RSpec test to manage the 'env' variable for middleware testing. It sets the 'env' state within the middleware's execution and asserts its content. ```ruby RSpec.describe AddingSomeMiddleware do include Dry::Effects::Handler.State(:env) include Dry::Effects.State(:env) let(:app) do lambda do |env| self.env = env [200, {}, ["ok"]] end end subject(:middleware) { described_class.new(app) } it 'adds SOME_KEY to env' do captured_env, _ = middleware.({}) expect(captured_env).to have_key('SOME_KEY') end end ``` -------------------------------- ### Testing Reader Effect with RSpec Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/reader.html.md Provides an example of how to test components that rely on the Reader effect, specifically by setting up the 'locale' context using `with_locale` within RSpec tests. It demonstrates asserting behavior based on different locale values. ```ruby RSpec.describe GreetUser do include Dry::Effects::Handler.Reader(:locale) subject(:greet) { described_class.new } let(:user) { double(:user, name: 'John') } it 'uses the current locale to greet the user' do examples = { en: 'Hello John', de: 'Hallo John', ru: 'Привет, John', it: 'Ciao John' } examples.each do |locale, expected_greeting| with_locale(locale) do expect(greet.(user)).to eql(expected_greeting) end end end end ``` -------------------------------- ### Execute deferred blocks on handler exit with later in Ruby Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/defer.html.md Shows how `later` captures a block that is executed when the `with_defer` context exits. This contrasts with `defer`, which runs immediately on a thread pool. The example highlights that `later` blocks typically run outside of transactions, preventing anomalies. ```ruby with_defer { @app.(env) } ``` -------------------------------- ### Providing Environment Configuration Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/env.html.md Demonstrates creating a middleware to handle the `Env` effect, setting the environment based on `ENV['RACK_ENV']`. This middleware wraps the application call within the `with_env` context. ```ruby require 'dry/effects' class EnvironmentMiddleware include Dry::Effects::Handler.Env(environment: ENV['RACK_ENV']) def initialize(app) @app = app end def call(env) with_env { @app.(env) } end end ``` -------------------------------- ### Compatibility with Dry-Container and Dry-System Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/resolve.html.md Explains and demonstrates how the Resolve effect is compatible with 'dry-container' and 'dry-system' by accepting objects that respond to '.key?' and '.[]' for dependency provision. ```ruby def call(env) # Assuming App is a subclass of Dry::System::Container provide(App) { @app.(env) } end ``` -------------------------------- ### Sidekiq Integration with Environment Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/env.html.md Demonstrates integrating the `Env` handler as middleware in Sidekiq. This allows background jobs to access environment configurations managed by the `Env` effect. ```ruby require 'dry/effects' class SidekiqEnvMiddleware include Dry::Effects::Handler.Env def call(_worker, _job, _queue, &block) with_env(&block) end end Sidekiq.configure_server do |config| config.server_middleware do |chain| chain.add SidekiqEnvMiddleware end end ``` -------------------------------- ### Injecting Multiple Keys with Aliases Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/resolve.html.md Shows how to inject multiple dependencies and use aliases for them. This allows specifying both the injected name and the key used for resolution from the container or provider. ```ruby require 'dry/effects' class CreateUser include Dry::Effects.Resolve( # Injected as .schema # but resolved with 'operations.create_user.schema' 'operations.create_user.schema', # Injected as .repo # but resolved with 'repos.user_repo' repo: 'repos.user_repo' ) def call(values) result = schema.(values) if result.success? user = repo.create(result.to_h) [:ok, user] else [:err, result] end end end ``` -------------------------------- ### Testing with Resolve Dependencies Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/resolve.html.md Shows how to test a class that uses Dry::Effects.Resolve. It utilizes RSpec and Dry::Effects::Handler.Resolve to provide a mock 'user_repo' dependency using the 'provide' method within a test context. ```ruby RSpec.describe CreateUser do # adds #provide include Dry::Effects::Handler.Resolve subject(:create_user) { described_class.new } let(:user_repo) { double(:user_repo) } it 'creates a user' do expect(user_repo).to receive(:create).with( first_name: 'John', last_name: 'Doe', name: 'John Doe' ) provide(user_repo: user_repo) { create_user.(first_name: 'John', last_name: 'Doe') } end end ``` -------------------------------- ### Using Environment with Custom Accessor Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/env.html.md Illustrates how to map an environment key to a custom method name using `Dry::Effects.Env(env: :environment)`. This allows for more flexible naming of environment accessors. ```ruby class CreateUser include Dry::Effects.Env(env: :environment) def call(...) # log unless env.eql?('test') end end ``` -------------------------------- ### Using Environment with Default Accessor Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/env.html.md Shows how to include `Dry::Effects.Env(:environment)` in a class to automatically create an accessor for the 'environment' key within the `Env` effect context. ```ruby class CreateUser include Dry::Effects.Env(:environment) def call(...) # log unless environemnt.eql?('test') end end ``` -------------------------------- ### Middleware for Providing Dependencies Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/resolve.html.md Illustrates creating a middleware class that integrates Dry::Effects.Resolve. The middleware wraps the application's call with provided dependencies, making them available to downstream components. ```ruby class ProviderMiddleware include Dry::Effects::Handler.Resolve def initialize(app, dependencies) @app = app @dependencies = dependencies end def call(env) provide(@dependencies) { @app.(env) } end end ``` -------------------------------- ### Discrete Time Shifts Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/current_time.html.md Demonstrates using `step` and `initial` arguments with `with_fixed_time` to create a time provider that advances by a fixed interval on each access. This is useful for simulating discrete time progression. ```ruby with_fixed_time(step: 0.1) do current_time # => ... 18:00:00.000 current_time # => ... 18:00:00.100 current_time # => ... 18:00:00.200 end initial = Time.new(1970) with_fixed_time(initial: initial, step: 60) do current_time # => 1970-01-01 00:00:00 +0000 current_time # => 1970-01-01 00:01:00 +0000 current_time # => 1970-01-01 00:02:00 +0000 end ``` -------------------------------- ### Parallel Execution with `par` and `join` Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/parallel.html.md Demonstrates how to use `par` to create parallel execution units and `join` to combine their results, running multiple requests concurrently. This pattern is useful for executing multiple operations in parallel and aggregating their outcomes. ```ruby class MakeRequests include Dry::Effects.Resolve(:make_request) def call(urls) # Run every request in parallel and combine their results urls.map { |url| par { make_request.(url) } }.then { |pars| join(pars) } end end ``` -------------------------------- ### Configure Defer handler with immediate executor in Ruby Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/defer.html.md Shows how to configure the `Dry::Effects::Handler.Defer` to use a specific executor, such as `:immediate`, which runs deferred tasks on the same thread. This is achieved by passing the `executor` option to the handler. ```ruby class HandleDefer include Dry::Effects::Handler.Defer(executor: :immediate) def initialize(app) @app = app end def call(env) # defer tasks in @app will be run on the same thread with_defer { @app.(env) } end end ``` -------------------------------- ### Cache Specific Method Calls with `prepend` Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/cache.html.md Shows how to cache specific method calls, like `find_user`, by prepending `Dry::Effects.Cache` to a class. This effectively memoizes method results within the scope of the cache handler, preventing redundant computations for identical inputs. ```ruby 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 ``` -------------------------------- ### Mixing Multiple State Identifiers in Ruby Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/state.html.md Explains how to use multiple State effects with different identifiers within the same class. It demonstrates mixing `:sum` and `:product` states and shows how the order of applying handlers can affect the return structure. ```ruby require 'dry/effects' class Program include Dry::Effects.State(:sum) include Dry::Effects.State(:product) def call 1.upto(10) do |i| self.sum += i self.product *= i end :done end end program = Program.new extend Dry::Effects::Handler.State(:sum) extend Dry::Effects::Handler.State(:product) with_sum(0) { with_product(1) { program.call } } # => [55, [3628800, :done]] with_product(1) { with_sum(0) { program.call } } # => [3628800, [55, :done]] ``` -------------------------------- ### Environment Fallback to ENV Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/env.html.md Explains how the `Env` handler can automatically search for keys in the global `ENV` hash as a fallback mechanism if a key is not explicitly provided. ```ruby class SendRequest include Dry::Effects.Env(endpoint: 'THIRD_PARTY') def call(...) # some code using `endpoint` end end ``` -------------------------------- ### Basic State Handling with Handler in Ruby Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/state.html.md Shows how to define a handler class that manages a state variable named 'counter'. It initializes the state to 0 and yields control, allowing the block to modify the state. The handler then returns the final state and the block's result. ```ruby require 'dry/effects' class CountCalls include Dry::Effects::Handler.State(:counter) def call counter, result = with_counter(0) do yield end puts "Counter: #{counter}" result end end ``` -------------------------------- ### Configuring Reader with RSpec around(:each) Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/reader.html.md Illustrates how to configure RSpec to automatically provide a default 'locale' context for all tests within a suite using an `around(:each)` hook and a provider object. ```ruby require 'dry/effects' # Build a provider object with .call interface locale_provider = Object.new.extend(Dry::Effects::Handler.Reader(:locale, as: :call)) RSpec.configure do |config| config.around(:each) do |ex| locale_provider.(:en, &ex) end end ``` -------------------------------- ### Explicit Caching with `#cache` method via `include` Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/cache.html.md Illustrates using `include Dry::Effects.Cache` to add a `#cache` method to a class. This method allows for explicit caching of code blocks, identified by a cache key and an optional identifier, providing fine-grained control over caching behavior. ```ruby 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 ``` -------------------------------- ### Handling Timeouts with Dry::Effects::Handler Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/timeout.html.md Shows how to use `Dry::Effects::Handler.Timeout` to wrap an application call with a specific timeout duration (e.g., 10.0 seconds). It also includes error handling for common network timeout exceptions like `Net::OpenTimeout`. ```ruby class WithTimeout include Dry::Effects::Handler.Timeout(:http) def initialize(app) @app = app end def call(env) with_timeout(10.0) { @app.(env) } rescue Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout [504, {}, ["Gateway Timeout"]] end end ``` -------------------------------- ### Ruby Interrupt Effect: Basic Usage Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/interrupt.html.md Demonstrates the fundamental usage of the Interrupt effect in Ruby. It shows how to define an effect that can be interrupted and a handler that catches these interruptions, similar to raise/rescue patterns. ```ruby require 'dry/effects' class RunDivision include Dry::Effects::Handler.Interrupt(:division_by_zero, as: :catch_zero_division) def call error, answer = catch_zero_division do yield end if error :error else answer end end end class Divide include Dry::Effects.Interrupt(:division_by_zero) def call(dividend, divisor) if divisor.zero? division_by_zero else dividend / divisor end end end run = RunDivision.new divide = Divide.new app = -> a, b { run.() { divide.(a, b) } } app.(10, 2) # => 5 app.(1, 0) # => :error ``` -------------------------------- ### Handling Undefined State in Ruby Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/state.html.md Demonstrates the behavior when a State effect's initial value is not provided. Reading the state before it's assigned raises `Dry::Effects::Errors::UndefinedStateError`. Assigning a value before reading resolves the issue. ```ruby extend Dry::Effects::Handler.State(:user) extend Dry::Effects.State(:user) with_user { user } # => Dry::Effects::Errors::UndefinedStateError (+user+ is not defined, you need to assign it first by using a writer, passing initial value to the handler, or providing a fallback value) with_user do self.user = 'John' "Hello, #{user}" end # => ["John", "Hello, John"] ``` -------------------------------- ### State Effect: Introducing State in a Class Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/index.html.md Illustrates how to introduce a State effect within a class, making the state accessible via an accessor. This requires an effect handler to be present in the call stack. ```ruby require 'dry/effects' class CreatePost # Adds counter accessor (by introducing state effects) include Dry::Effects.State(:counter) def call(values) # Value is passed from middleware self.counter += 1 # ... end end ``` -------------------------------- ### Overriding Dependencies in Test Environment (Middleware) Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/resolve.html.md Demonstrates how to enable dependency overriding in a middleware by passing 'overridable: true' to the 'provide' method. This is crucial for testing scenarios where specific dependencies need to be replaced. ```ruby require 'dry/effects' class ProviderMiddleware include Dry::Effects::Handler.Resolve def initialize(app) @app = app end def call(env) provide(Application, overridable: overridable?) { @app.(env) } end def overridable? ENV['RACK_ENV'].eql?('test') end end ``` -------------------------------- ### Use NullExecutor in middleware for testing in Ruby Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/defer.html.md Demonstrates integrating a `NullExecutor` into a `Defer` handler middleware. The `executor` method conditionally returns `NullExecutor` when the environment is `:test`, effectively skipping deferred tasks during tests. ```ruby class HandleDefer include Dry::Effects::Handler.Defer include Dry::Effects::Handler.Env(:environment) def initialize(app) @app = app end def call(env) with_defer(executor: executor) { @app.(env) } end def executor environment.equal?(:test) ? NullExecutor : :io end end ``` -------------------------------- ### State Effect: Testing with a Handler Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/index.html.md Shows how to test a class that introduces a State effect by providing a `with_counter` handler in the test environment. This allows isolated testing of the component's logic. ```ruby require 'dry/effects' require 'posting_app/create_post' RSpec.describe CreatePost do include Dry::Effects::Handler::State(:counter) subject(:create_post) { described_class.new } it 'updates the counter' do counter, post = with_counter(0) { create_post.(post_values) } expect(counter).to be(1) end end ``` -------------------------------- ### Default Value for State/Reader Effect in Ruby Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/state.html.md Shows how to provide a default value for a State effect when no initial value is given, using a block. This is particularly useful when the state might not be set, preventing errors and providing a fallback. ```ruby extend Dry::Effects::Handler.State(:artist) extend Dry::Effects.State(:artist) with_artist { artist { 'Unknown Artist' } } # => "Unknown Artist" ``` -------------------------------- ### Use defer for concurrent execution in Ruby Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/defer.html.md Demonstrates using `defer` to run a block of code on a thread pool, returning a `Promise`. This is useful for asynchronous operations like sending invitations after user creation. Note that some effects like `Interrupt` are not supported within `defer` blocks due to thread limitations. ```ruby class CreateUser include Dry::Effects.Resolve(:user_repo, :send_invitation) include Dry::Effects.Defer def call(values) user = user_repo.create(values) defer { send_invitation.(user) } user end end ``` -------------------------------- ### Using Reader in Middleware Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/reader.html.md Demonstrates how to integrate the Reader effect within a middleware component to pass a 'locale' value down the stack. It shows the inclusion of the handler and the `with_locale` context manager. ```ruby require 'dry/effects' class SetLocaleMiddleware include Dry::Effects::Handler.Reader(:locale) def initialize(app) @app = app end def call(env) with_locale(detect_locale(env)) do @app.(env) end end def detect_locale(env) # arbitrary detection logic end end ``` -------------------------------- ### Mixing Reader Handlers Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/reader.html.md Demonstrates how to use multiple Reader effects with distinct identifiers within the same execution context. It shows that handlers with different identifiers do not interfere with each other. ```ruby require 'dry/effects' extend Dry::Effects::Handler.Reader(:locale) extend Dry::Effects::Handler.Reader(:context) extend Dry::Effects.Reader(:locale) extend Dry::Effects.Reader(:context) with_locale(:en) { with_context(:background) { [locale, context] } } # => [:en, :background] # Order doesn't matter: with_context(:background) { with_locale(:en) { [locale, context] } } # => [:en, :background] ``` -------------------------------- ### State Handler Interface in Ruby Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/state.html.md Illustrates the interface of a State handler, specifically the `with_state` method. It shows how the handler returns both the accumulated state and the result of the yielded block, providing access to the final state value. ```ruby include Dry::Effects::Handler.State(:state) def run(&block) accumulated_state, result = with_state(initial_state) do block.call end # result holds the return value of block.call # accumulated_state refers to the last written value # or initial_value if the state wasn't changed end ``` -------------------------------- ### Using State Effect in Ruby Class Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/state.html.md Demonstrates how a class can include the State effect to directly read and write a state variable named 'counter'. The `self.counter += 1` syntax is used to mutate the state within the class's methods. ```ruby require 'dry/effects' class HeavyLifting include Dry::Effects.State(:counter) def call self.counter += 1 # ... do heavy work ... end end ``` -------------------------------- ### Use later for post-handler execution in Ruby Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/defer.html.md Explains the `later` method, which captures a block to be executed upon handler exit, unlike `defer` which returns a `Promise`. This is useful for ensuring operations happen after a transaction or context has completed, avoiding race conditions. ```ruby later { send_invitation.(user) } ``` -------------------------------- ### Pass executor directly to with_defer in Ruby Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/defer.html.md Illustrates how to pass an executor, like `:fast` for short operations, directly to the `with_defer` method. This allows for dynamic control over where deferred tasks are executed on a per-call basis. ```ruby def call(env) with_defer(executor: :fast) { @app.(env) } end ``` -------------------------------- ### Nesting Reader Handlers Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/reader.html.md Explains the behavior of nested Reader handlers, demonstrating that the most recently applied handler in the stack takes precedence when accessing the shared context value. ```ruby require 'dry/effects' extend Dry::Effects::Handler.Reader(:locale) extend Dry::Effects.Reader(:locale) with_locale(:en) { with_locale(:de) { locale } } # => :de ``` -------------------------------- ### State Effect: Missing Handler Error Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/index.html.md Demonstrates the error raised when a State effect is introduced but no corresponding handler is found in the execution stack. This highlights the requirement for effect handlers. ```ruby CreatePost.new.({}) # => Dry::Effects::Errors::MissingStateError (Value of +counter+ is not set, you need to provide value with an effect handler) ``` -------------------------------- ### Overriding Environment Values Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/env.html.md Explains how to override environment values provided by nested handlers by passing `overridable: true`. This is particularly useful for testing scenarios where specific values need to be injected. ```ruby class Application include Dry::Effects.Env(:foo) def call puts foo end end class ProvidingContext include Dry::Effects::Handler.Env def call with_env({ foo: 100 }, overridable: true) { yield } end end class OverridingContext include Dry::Effects::Handler.Env def call with_env(foo: 200) { yield } end end overriding = OverridingContext.new providing = ProvidingContext.new app = Application.new overriding.() { providing.() { app.() } } # prints 200, coming from overriding context ``` -------------------------------- ### Using Timeout Effect in a Request Class Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/timeout.html.md Demonstrates how to include the `Dry::Effects.Timeout` module in a class to access the `timeout` method for setting HTTP request timeouts. The `timeout` method provides an ever-decreasing number of seconds until it reaches 0. ```ruby class MakeRequest include Dry::Effects.Timeout(:http) def call(url) HTTParty.get(url, timeout: timeout) end end ``` -------------------------------- ### Testing with Fixed Current Time Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/current_time.html.md Demonstrates how to use `with_current_time` with a proc to provide a fixed time value in tests. This ensures predictable behavior for time-dependent logic. ```ruby it 'uses current time as a start' do subscription = create_subscription(...) expect(subscription.start_at).to eql(current_time) end it 'closes a subscription with current time' do future = current_time + 86_400 closed_subscription = with_current_time(proc { future }) { close_subscription(subscription) } expect(closed_subscription.closed_at).to eql(future) end ``` -------------------------------- ### Current Time Rounding Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/current_time.html.md Shows how to configure time rounding for the `current_time` effect. Rounding can be set statically when including the handler or dynamically when calling the effect. ```ruby class CreateSubscription include Dry::Effects.CurrentTime(round: 3) def call(...) # value will be rounded to milliseconds current_time # value will be rounded to microseconds current_time(round: 6) end end ``` -------------------------------- ### Ruby Interrupt Effect: Composition Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/interrupt.html.md Shows how to compose multiple Interrupt effects with different identifiers in Ruby. This allows for handling distinct interruption types within nested blocks, ensuring proper isolation. ```ruby class Catcher include Dry::Effects::Handler(:div_error, as: :catch_div) include Dry::Effects::Handler(:sqrt_error, as: :catch_sqrt) def call _, div_result = catch_div do _, sqrt_result = catch_sqrt do yield end sqrt_result end div_result end end ``` -------------------------------- ### Cmp Effect: Conditional Rendering Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/index.html.md Shows how to introduce a Cmp effect within a class to conditionally execute logic based on whether the effect is active. This is useful for feature flagging or A/B testing. ```ruby require 'dry/effects' class PostView include Dry::Effects.Cmp(:feature) def call if feature? # do render with feature else # do render without feature end end end ``` -------------------------------- ### Ruby Interrupt Effect: Handling Payloads Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/interrupt.html.md Illustrates how to send a payload along with an Interrupt effect in Ruby. The `halt` keyword is used to interrupt execution and pass a value, which is then captured by the handler. ```ruby class Callee include Dry::Effects.Interrupt(:halt) def call halt :foo end end class Caller include Dry::Effects::Handler.Interrupt(:halt, as: :catch_halt) def call _, result = catch_halt do yield :bar end result end end caller = Caller.new callee = Callee.new caller.() { callee.() } # => :foo caller.() { } # => :bar ``` -------------------------------- ### Custom Time Generator Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/current_time.html.md Illustrates using a custom callable object (like a proc) as a generator for the time effect. This allows for more complex time generation logic, such as incrementing time. ```ruby frozen = Time.now with_fixed_time(proc { frozen }) do # ... end start = Time.now with_fixed_time(proc { start += 0.1 }) do # ... end ``` -------------------------------- ### Service Using Current Time Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/current_time.html.md A service class that resolves a repository dependency and uses the `current_time` effect to set a timestamp during record creation. This makes the time dependency explicit. ```ruby require 'dry/effects' class CreateSubscription include Dry::Effects.Resolve(:subscription_repo) include Dry::Effects.CurrentTime def call(values) subscription_repo.create( values.merge(start_at: current_time) ) end end ``` -------------------------------- ### Timeout Effect API Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/timeout.html.md The `Dry::Effects.Timeout` module provides two core methods for managing time limits. The `timeout` method returns a decreasing time value, while `timed_out?` checks if the time limit has been reached. ```APIDOC Dry::Effects.Timeout Provides methods for managing time limits. Methods: timeout Description: Returns an ever-decreasing number of seconds until this number reaches 0. Returns: A numeric value representing remaining time. timed_out? Description: Checks if no time is left. Returns: Boolean indicating if the timeout has occurred. ``` -------------------------------- ### Disabling Time Fixing Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/current_time.html.md Explains how to disable the default time-fixing behavior of `with_current_time` by passing `fixed: false` to the handler builder. This is generally not recommended for consistency between test and production. ```ruby include Dry::Effects::Handler.CurrentTime(fixed: false) ``` -------------------------------- ### Overriding Time Handlers in Tests Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/current_time.html.md Shows how to make a CurrentTime handler overridable using `overridable: true`. This is commonly used in tests to inject a specific time value, overriding any outer handler. ```ruby require 'dry/effects' class CurrentTimeMiddleware include Dry::Effects::Handler.CurrentTime def initialize(app) @app = app end def call(env) with_current_time(overridable: ENV['RACK_ENV'].eql?('test')) do @app.(env) end end end # Using global time frozen_time = Time.now RSpec.configure do |config| config.include Dry::Effects::Handler.CurrentTime config.include(Module.new { define_method(:current_time) { frozen_time } }) config.around { |ex| with_current_time(proc { frozen_time }, &ex) } end ``` -------------------------------- ### State Eliminates Reader Effect in Ruby Source: https://github.com/dry-rb/dry-effects/blob/main/docsite/source/effects/state.html.md Illustrates how a State effect with the same identifier can override or eliminate a Reader effect. When `with_counter` is used, the `counter` reader inside the block accesses the state managed by the handler, not a separate reader effect. ```ruby require 'dry/effects' extend Dry::Effects::Handler.State(:counter) extend Dry::Effects.Reader(:counter) with_counter(100) { "Counter value is #{counter}" } # => [100, "Counter values is 100"] ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.