AlbertGazizov/opatch

View on GitHub
README.md

Summary

Maintainability
Test Coverage
# OPatch [![Build Status](https://travis-ci.org/AlbertGazizov/opatch.png)](https://travis-ci.org/AlbertGazizov/opatch) [![Code Climate](https://codeclimate.com/github/AlbertGazizov/opatch.png)](https://codeclimate.com/github/AlbertGazizov/opatch)



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:
```ruby
  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:
```ruby
  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:
```ruby
  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:
```ruby
  => #<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:
```ruby
  person = Person.new(name: "John Smith")
  => #<Person:0x007f8bc40239e0 @name="John Smith", @address=nil>
```
```ruby
  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
```
```ruby
  => #<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:
```ruby
  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](https://twitter.com/deeper4k)