OPatch Build Status Code Climate

OPatch is ruby objects patcher in declarative way. By providing simple DSL it allows you write complex patch logic with ease

Usage

Let's say you have the folowing plain ruby classes:

  class Person
    attr_accessor :name, :address

    def initialize(name:, address: nil)
      @name = name
      @address = address
    end
  end

  class Address
    attr_accessor :city, :country

    def initialize(city:, country:)
      @city = city
      @country = country
    end
  end

And you have the following instance of the Person class:

  person = Person.new(name: "John Smith", address: Address.new(city: "Kazan", country: "Russia"))

Now you want to update person's name and address fields, let's use OPatch for that. You need to call OPatch with attributes you want to update:

  new_attributes = { name: "Jim White", address: { country: "USA", city: "New York" } }
  OPatch.patch(person, new_attributes) do
    field  :name
    object :address do
      field :country
      field :city
    end
  end

That's all! Now you have the person updated:

  => #<Person:0x007f8bc42487c0 @name="Jim White", @address=#<Address:0x007f8bc4248838 @city="New York", @country="USA">>

Creating nested objects

Opatch allows you to build nested objects if you specify build block. Lets see how it works if we want to build address when it wasn't created initialilly:

  person = Person.new(name: "John Smith")
  => #<Person:0x007f8bc40239e0 @name="John Smith", @address=nil>
  new_attributes = { address: { country: "USA", city: "New York" } }
  OPatch.patch(person, new_attributes) do
    field  :name
    object :address, build: proc { |person, attributes| person.address = Address.new(attributes) }  do
      field :country
      field :city
    end
  end
  => #<Person:0x007f8bc4130590 @name="John Smith", @address=#<Address:0x007f8bc4049a28 @city="New York", @country="USA">>

Deleting nested objects

If you provide nil for the nested object the object will be removed:

  person = Person.new(name: "John Smith", address: Address.new(city: "Kazan", country: "Russia"))

  OPatch.patch(person, name: 'Vasya', address: nil) do
    field  :name
    object :address do
      field :country
      field :city
    end
  end

  => #<Person:0x007f8bc400a850 @name="Vasya", @address=nil>

Author

Albert Gazizov, @deeper4k