[dry-monads] Pass more than one parameter into bind method

Ok I’m not sure what happened with my last topic so I created a new one.

The question is - something has changed lately that I cannot pass more params than the first one defined in a call when using bind method in monads? Take a look.

require 'dry-monads'
require 'dry/monads/all'

module Test
  class MonadsClass
    include Dry::Monads

    def initialize(signees)
      @signees = signees
    end

    def call
      Success(signees)
        .bind(method(:fetch_template))
        .bind(method(:envelope_from_template))
    end

    attr_reader :signees

    private

    def fetch_template(signees)
      key = "template_#{signees.size}".to_sym
      template_id = Rails.application.credentials.some_api.fetch(key)

      Success(template_id: template_id, key: key)
    end

    def envelope_from_template(template_id:, key:)
      response = some_api.copy_from_template(template_id, key)

      response.failure? ? Failure(response.failure) : Success(response.value!)
    end
  end
end

Which gives me a strange error of:

     Failure/Error:
           def envelope_from_template(template_id:, key:)
             response = namirial_api.copy_from_template(template_id)

             response.failure? ? Failure(response.failure) : Success(response.value!)
           end

     ArgumentError:
       wrong number of arguments (given 1, expected 0; required keywords: template_id, key)

Am I missed something?

You’d need to splat the arguments to #envelope_from_template. Here’s a simplified version of your problem space using Ruby 3.1.3:

#! /usr/bin/env ruby
# frozen_string_literal: true

# Save as `snippet`, then `chmod 755 snippet`, and run as `./snippet`.

require "bundler/inline"

gemfile true do
  source "https://rubygems.org"

  gem "amazing_print"
  gem "debug"
  gem "dry-monads"
end

class Demo
  include Dry::Monads[:result]

  def initialize extractor: -> id:, key: { puts "ID: #{id}, KEY: #{key}" }
    @extractor = extractor
  end

  def call(payload) = Success(payload).bind { |data| extractor.call(**data) }

  private

  attr_reader :extractor
end

Demo.new.call id: 1, key: :label

The above will output:

ID: 1, KEY: label

However, if you don’t splat the hash by modifying the above code to use extractor.call data, then you’ll get the same error as in your code example:

wrong number of arguments (given 1, expected 0; required keywords: id, key) (ArgumentError)

.bind doesn’t pass arguments as keywords. I prefer do notation to using .bind