client-data-adapter

Build Status Gem Version Coverage Status

Table of Contents

Introduction

For unify data formats to transfer to clients.

Install

gem install client-data-adapter

or in Gemfile

gem 'client-data-adapter'

Usage

define_adapter

Include library to model and use define_adapter to define the adapter.

# book.rb

include ClientDataAdapter

define_adapter do

  # define your adapter here.
  # ... 

end

adapter

adapter method define the main adapter, should return a Hash.

# ...

define_adapter do

  adapter do
    {
      id: id,
      title: title,
    }
  end

end

In elsewhere

# ...

@book = Book.new(id: 1, title: 'My Book')
@book.adapter # => { id: 1, title: 'My Book' } 

with

And you probably need some complex calculation or related some other class, they maybe need some cost and is unnecessary to load everywhere.

So we need use them on-demand.

# ...

define_adapter do

  adapter do
    {
      id: id,
      title: title,
    }
  end

  with :my_complex_calc do
    'something complex'
  end

end

Then

# ...

@book = Book.new(id: 1, title: 'My Book')
@book.adapter(:my_complex_calc) 
# => { id: 1, title: 'My Book', my_complex_calc: 'something complex' }

Merge Methods

And you can merge any instance method of original class to the adapter result, such as

# book.rb

def full_title
  "<#{title}>"
end

Then you can use adapter like this

# ... 

@book.adapter(:full_title)
# => { id: 1, title: 'My Book', full_title: '<My Book>' }

It will set the method name as the key, and returns as the value.

But notice that if method name is repeated, will trigger the one inside the adapter.

Pass Arguments

Sometimes we need pass some arguments to deal different case, you can write like this

@book.adapter(foo: [:bar, :baz])

Arguments with Hash will consider the key as the method name, and values as arguments.

To work with the method like this

def foo(*args)
  args.join(',')
end

or this

with :foo do |*args|
  args.join(',')
end

The result will be

@book.adapter(foo: [:bar, :baz]) 
# => { id: 1, title: 'My Book', foo: 'bar,baz' }

Use Return

You can use return in adapter block to flow control.

# ...

with :id do
  return 'i have no id' unless id 
  id
end

It is works.

Read Methods Inside

If you define something inside the adapter, you can't read it directly.

# book.rb

define_adapter do
  # ...

  with :my_method do
    'invoke me please!'
  end

end
@book.my_method # => ERROR! No Method

Since that adapter differentiate the namespace with the original class to make naming more flexible.

It create a wrapper for the adapter named AdapterWrapper, and exposed by the instance method adapter_wrapper.

@book.adapter_wrapper.class # => Book::AdapterWrapper

And you can read the adapter internal method via it.

@book.adapter_wrapper.my_method # => works

hmm... but i'm not very recommend you to use it by this way, if you need some method works alone, maybe you should define it in the original class.

This method is a syntactic sugar of with, seems like

with :my_link do |*args|
  my_link.adapter(*args)
end

is equal with

link_one :my_link

It usual used in one-to-one relationship like belongs_to in rails.

For example

# book.rb

belongs_to :book_shelf 

define_adapter do
  link_one :book_shelf

  # ...
end

# book_shelf.rb

define_adapter do

  adapter do
    {
      id: id,
      desc: desc,
    }
  end

end

Then

@book.adapter(:book_shelf)
# => { id: 1, title: 'My Book', book_shelf: @book.book_shelf.adapter }

Of course you can pass some arguments, and if you have several links, can also used in nested.

# ...

@book.adapter(book_shelf: [:foo, library: :bar])
# => { ..., book_shelf: { ..., foo: ..., library: { ..., bar: ... } } }

And can define many links once.

# ...

link_one :my_link1, :my_link2

Okay, this method is similar with link_one but multiple.

If use with to implement likes

with :my_links do |*args|
  my_links.map { |link| link.adapter(*args) } 
end

Usual used in one-to-many relationship, such as has_many in rails.

For example

# book.rb

has_many :categories 

define_adapter do
  link_many :categories

  # ...
end

@book.adapter(:categories)
# => { id: 1, title: 'My Book', categories: @book.categories.map(&:adapter) }

Support multiple arguments and other usage, detail above.