Skip to content

Instantly share code, notes, and snippets.

View davydovanton's full-sized avatar
:shipit:
Working from home

Anton Davydov davydovanton

:shipit:
Working from home
View GitHub Profile
module Platform
module Types
include Dry::Types.module
include ROM::Types
include ROM::SQL::Types
include ROM::SQL::Types::PG
# ...
Phone = String
require 'hanami/interactor'
require 'dry-matcher'
module Hanami::Interactor
module Matcher
SUCCESS_CASE = Dry::Matcher::Case.new(
match: -> result { result.successful? },
resolve: -> result { result.value }
)
class Service
include Dry::Matcher.for(:call, with: Dry::Matcher::EitherMatcher)
include Dry::Monads::Either::Mixin
def call(payload)
# ...
Right(payload)
end
end
@davydovanton
davydovanton / operations.md
Last active June 25, 2020 09:31
Operations

Пример из pepegramming канала

Задача

Есть экшен в рельсе, который создает инвойс:

def create
  invoice = Invoice.new(params[:invoice])

 if invoice.save
@davydovanton
davydovanton / hanami_events.rb
Created July 31, 2017 19:50
Hanami::Events
require 'hanami/events'
events = Hanami::Events.build(:memory)
events.subscribe('user.created') { |payload| puts "Create user: #{payload}" }
events.subscribe('user.created') { |payload| puts "Send notification to user: #{payload}" }
events.subscribe('user.deleted') { |payload| puts "Delete user: #{payload}" }
events.broadcast('user.created', user_id: 1)
# dry-validation (0.10.7)
# dry-types (0.10.3)
require 'dry/types'
require 'dry/validation'
module Types
include Dry::Types.module
Phone = String.constrained(format: /\A([\d]{10}|)\z/)
end

Пример рефакторинга с использованием транзакций

Опять рассмотрим tasks#create экшен.

В экшене 3 разных логики, которые выполняются последовательно:

  1. валидация данных - необходимый шаг;
  2. сохраниение таска - необходимый шаг, если какая-то ошибка, необходимо возвращать failed значение;
  3. отправка нотификаций - мы не хотим, что бы наша транзакия не выполнялась, если отправка нотификации не выполнится;

Поэтому напишем нашу транзакцию. Так же мы будем использовать Either монаду для возвращения статуса шага транзакции. Right для успешного, Left - не успешного:

@davydovanton
davydovanton / action_interactor.md
Last active August 30, 2018 12:45
Пример рефакторинга с interactor

Пример рефакторинга с interactor

Рассмотрим tasks#create экшен. Из названия понятно, что он сохраняет новые таски. Если посмотреть на код, возникает подсознательное недоверие к коду из-за его количества.

Во первых, видно, что мешается логика экшена (authenticated?) и логика сохранения, валидирования, вызова тасков в сайдкик. А так же, видно лишний метод #task_params который приводит данные с экшена в данные, которые будут скормлены нашей модели.

Для начала, давайте сделаем прсотой интерактор CreateTask:

require 'hanami/interactor'

У нас есть либа, которая заруливает отправку всех нотификаций. Выглядит это следующим образом. Есть глобальный класс, который ты вызываешь с юзером (и его настройками) и с параметрами Notify.new.call(account, title: 'bla bla'). У этого класса есть куча стратегий (text, email, push, etc) которые вызываются все для каждого юзера. Но в каждой стратегии указывается условие, при котором эту стратегию нужно выполнять, т.е.:

class TestStrategy
  # ...

  def allow?(preferences)
    preferences.allow_email
  end
end