Нам нужны твои мозги

Хотите расти как разработчик и найти крутую работу? Не протирайте штаны — займитесь Open Source проектами. Так легче всего попасть в лучшие команды разработчиков и положить себе в резюме настоящий проект, вместо нелепых «примеров кода». Но найти подходящий проект для участия сложно. Начинаются лень и отговорки, а за ними — отсутствие профессионального роста, критики по-настоящему крутых программистов, уныние и застой.

На Cult of Martians мы собираем интересные задачи для современных веб-программистов. Можно выбрать подходящую по сложности, продолжительности и специализации. Задачи не выдуманы «из воздуха» — каждая решает насущную проблему, и решить ее можно через создание нового Open Source проекта или улучшение существующего. Решайте задачи, прокачивайтесь, присылайте решение на оценку. Лучших могут пригласить к себе на работу компании, программистам которых понравится ваше решение.

Бэк: Clowne: инструмент для клонирования моделей

Для продвинутых, задача на неделю

Необходимо написать инструмент для клонирования моделей (например, Active Record) с гибкими настройками. Существующие гемы (deep_clonable и amoeba), к сожалению, неудобны при работе со сложной бизнес-логикой и завязаны на ActiveRecord.

Польза: попрактиковаться в написании расширяемого DSL на Ruby и написать инструмент, которым будет активно пользоваться сообщество.

Что должен уметь Clowne?

  • Конфигурация логики клонирования на уровне модели через DSL c поддержкой наследования
class PostCloner < Clowne::Cloner
  # клонировать все ассоциированные объекты
  include_all

  # клонировать указанную ассоциацию
  include_association :comments

  # указать scope для ассоциации
  include_association :comments, -> { where('created_at > ?', 1.year.ago) }
  # или именнованный scope
  include_association :comments, :this_year

  # исключить ассоциацию (если она была добавлена через include_all или в родительском конфиге)
  exclude_association :likes

  # обнулить поля
  nullify :external_id, :modified_at, :modified_by

  # пользовательский блок, вызываемый в конце клонирования
  finalize do |source, record|
     # ...
  end
end

Для клонирования объекта вызываем:

cloned_post = PostCloner.call(post)
  • Поддержка контекста
# Дополнительно указываем контекст и произвольные параметры
cloned_post = PostCloner.call(post, for: :another_user, user_id: 123)

class PostCloner < Clowne::Cloner
  ...
  # в конфигурации описываем именнованный контекст
  context :another_user do
    nullify :user_id

    # в модификаторах ассоциаций имеем доступ к доп. параметрам
    include_association :likes, -> (params) { where.not(user_id: params[:user_id]) }

    # и в finalize
    finalize do |source, record, params|
      record.user_id = params[:user_id]
    end
  end
end

# Только произвольные параметры
cloned_post = PostCloner.call(post, user_id: 123)
  • Вложенные объекты клонируются с использованием собственных конфигов (но можно указать другой), доп. параметры передаются сверху вниз
# По умолчанию для модели Comment
class CommentCloner < Clowne::Cloner
  ...
end

class SimpleCommentCloner < Clowne::Cloner
  ...
end

class PostCloner < Clowne::Cloner
  include_associations :comments, clone_with: SimpleCommentCloner
end
  • Если для модели не существует конфига, то клонируем только атрибуты, без ассоциаций

  • Механизм клонирования должен подразумевать интеграцию с разными фреймворками (не только Active Record), то есть должен быть внутренний API для написания адаптеров для произвольных фреймворков

  • По умолчанию должна быть только поддержка ActiveRecord:

class Post < ActiveRecord::Base
  # Явно указать класс клонера
  clone_with ArticleCloner
end

post.clone(params) == ArticleCloner.call(post, params)

Инструкции по выполнению

  1. Форкнуть проект clowne на GitHub.
  2. Реализовать необходимый функционал.
  3. Сделать Pull Request.