Вы путаете передачу возвращаемого значения в метод / функцию и вызов метода для возвращаемого значения. Способ сделать то, что вы описали, таков:
lambda {|arr| "#{arr.slice(0, arr.length - 1).join(", ")} and #{arr.last}"}.call(tasks.collect(&:title))
Если вы хотите сделать это так, как пытались, самое близкое совпадение - instance_eval
, что позволяет запустить блок в контексте объекта. Так что будет:
tasks.collect(&:title).instance_eval {"#{slice(0, length - 1).join(", ")} and #{last}"}
Однако я бы не стал делать ни один из них, поскольку он длиннее и менее читаем, чем альтернатива.