{"id":16215509,"url":"https://github.com/arturictus/easy_serializer","last_synced_at":"2025-03-19T10:30:20.878Z","repository":{"id":62557681,"uuid":"46087716","full_name":"arturictus/easy_serializer","owner":"arturictus","description":"Semantic way to serialize your objects","archived":false,"fork":false,"pushed_at":"2019-02-20T14:01:28.000Z","size":180,"stargazers_count":3,"open_issues_count":8,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-28T17:50:48.059Z","etag":null,"topics":["api","json","json-api","serializer"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arturictus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-11-12T23:38:37.000Z","updated_at":"2019-02-20T14:01:26.000Z","dependencies_parsed_at":"2022-11-03T06:45:38.448Z","dependency_job_id":null,"html_url":"https://github.com/arturictus/easy_serializer","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arturictus%2Feasy_serializer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arturictus%2Feasy_serializer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arturictus%2Feasy_serializer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arturictus%2Feasy_serializer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arturictus","download_url":"https://codeload.github.com/arturictus/easy_serializer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243982177,"owners_count":20378604,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","json","json-api","serializer"],"created_at":"2024-10-10T11:15:11.051Z","updated_at":"2025-03-19T10:30:20.428Z","avatar_url":"https://github.com/arturictus.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# EasySerializer\n\n[![Build Status](https://travis-ci.org/arturictus/easy_serializer.svg?branch=master)](https://travis-ci.org/arturictus/easy_serializer)\n[![Gem Version](https://badge.fury.io/rb/easy_serializer.svg)](https://badge.fury.io/rb/easy_serializer)\n[![Test Coverage](https://codeclimate.com/github/arturictus/easy_serializer/badges/coverage.svg)](https://codeclimate.com/github/arturictus/easy_serializer/coverage)\n[![Code Climate](https://codeclimate.com/github/arturictus/easy_serializer/badges/gpa.svg)](https://codeclimate.com/github/arturictus/easy_serializer)\n[![Issue Count](https://codeclimate.com/github/arturictus/easy_serializer/badges/issue_count.svg)](https://codeclimate.com/github/arturictus/easy_serializer)\n\nSemantic serializer for making easy serializing objects.\nEasySerializer is inspired in [ActiveModel Serializer \u003e 0.10] (https://github.com/rails-api/active_model_serializers/tree/v0.10.0.rc3) it's a\nsimple solution for a day to day work with APIs.\nIt tries to give you a serializer with flexibility, full of features and important capabilities for caching.\n\nFeatures:\n- Nice and simple serialization DSL.\n- Cache helpers to use with your favorite adapter like rails cache.\n\nAdvantages:\n- Separated responsibility from Model class and serialization allowing multiple serializers for the same Model class, very useful for API versioning.\n- In contraposition with active model serializers with EasySerializer you can serialize any object responding to the methods you want to serialize.\n- EasySerializer is an small library with few dependencies.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'easy_serializer'\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install easy_serializer\n\nAdd the configuration file:\n\n**Only if you need caching.**\n\n_If your are in a Rails environment place this file at config/initializers_\n\n```ruby\nEasySerializer.setup do |config|\n  # = perform_caching\n  #\n  # Enable o disable caching.\n  # default: false\n  #\n  # config.perform_caching = true\n\n  # = cache\n  #\n  # Set your caching tool for the serializer\n  # must respond to fetch(obj, opts, \u0026block) like Rails Cache.\n  # default: nil\n  #\n  # config.cache = Rails.cache\nend\n```\n\n## Usage\n\n### Simple example:\n\n```ruby\nuser = OpenStruct.new(name: 'John', surname: 'Doe')\n\nclass UserSerializer \u003c EasySerializer::Base\n  attributes :name, :surname\nend\n\nUserSerializer.call(user)\n# =\u003e\n{\n  name: 'John',\n  surname: 'Doe'\n}\n```\n**Using blocks:**\n\nObject being serialized is pass in the block as a first argument.\n\n```ruby\nclass UserSerializer \u003c EasySerializer::Base\n  attribute(:name) { |user| user.name.capitalize }\n  attribute(:surname) { |user| user.surname.capitalize }\nend\n```\n\n**Using helpers in blocks:**\n\nBlocks are executed in the serializer instance, this way you can build your helpers and use them inside the blocks.\n\n```ruby\nclass BlockExample \u003c EasySerializer::Base\n  attribute :name do |object|\n    upcase object.name\n  end\n\n  def upcase(str)\n    str.upcase\n  end\nend\n```\n**Passing options as a second argument:**\n\n```ruby\nclass OptionsSerializer \u003c EasySerializer::Base\n  attribute :name\n  attribute :from_opts do\n    options[:hello]\n  end\nend\n\nOptionsSerializer.call(OpenStruct.new(name: 'Dave'), hello: \"hello with from options\")\n# =\u003e {:name=\u003e\"Dave\", :from_opts=\u003e\"hello with from options\"}\n```\n\n**Changing keys:**\n\n```ruby\nclass UserSerializer \u003c EasySerializer::Base\n  attribute :name, key: :first_name\n  attribute(:surname, key: :last_name) { |user| user.surname.capitalize }\nend\n```\n\n**Using defaults:**\n\nDefault will only be triggered when value is `nil`\n\n```ruby\nobj = OpenStruct.new(name: 'Jack', boolean: nil, missing: nil)\n\nclass DefaultLiteral \u003c EasySerializer::Base\n  attribute :name\n  attribute :boolean, default: true\n  attribute(:missing, default: 'anything') { |obj| obj.missing }\nend\n\noutput = DefaultLiteral.call(obj)\noutput.fetch(:name) #=\u003e 'Jack'\noutput.fetch(:boolean) #=\u003e true\noutput.fetch(:missing) #=\u003e 'anything'\n```\n\nUsing blocks:\n\n```ruby\nobj = OpenStruct.new(name: 'Jack', boolean: nil, missing: nil)\n\nclass DefaultBlock \u003c EasySerializer::Base\n  attribute :name\n  attribute :boolean, default: proc { |obj| obj.name == 'Jack' }\n  attribute :missing, default: proc { |obj| \"#{obj.name}-missing\" } do |obj|\n    obj.missing\n  end\nend\n\noutput = DefaultBlock.call(obj)\noutput.fetch(:name) #=\u003e 'Jack'\noutput.fetch(:boolean) #=\u003e true\noutput.fetch(:missing) #=\u003e 'Jack-missing'\n```\n\n### Serializing nested objects\n\n```ruby\nuser = OpenStruct.new(\n  name: 'John',\n  surname: 'Doe',\n  address: OpenStruct.new(\n    street: 'Happy street',\n    country: 'Wonderland'\n  )\n)\n\nclass AddressSerializer \u003c EasySerializer::Base\n  attributes :street, :country\nend\n\nclass UserSerializer \u003c EasySerializer::Base\n  attributes :name, :surname\n  attribute :address, serializer: AddressSerializer\nend\n\nUserSerializer.call(user)\n# =\u003e\n{\n  name: 'John',\n  surname: 'Doe',\n  address: {\n    street: 'Happy street',\n    country: 'Wonderland'\n  }\n}\n```\n\n**Removing keys from nested hashes:**\n\n```ruby\nclass UserSerializer \u003c EasySerializer::Base\n  attribute :name, :lastname\n  attribute :address,\n            key: false,\n            serializer: AddressSerializer\nend\nUserSerializer.call(user)\n# =\u003e\n{\n  name: 'John',\n  surname: 'Doe',\n  street: 'Happy street',\n  country: 'Wonderland'\n}\n```\n\n**Serializer option accepts a Block:**\n\nThe block will be executed in the Serializer instance.\n\n```ruby\nclass DynamicSerializer \u003c EasySerializer::Base\n  attribute :thing, serializer: proc { serializer_for_object }\n  attribute :d_name\n\n  def serializer_for_object\n    \"#{object.class.name}Serializer\".classify\n  end\nend\n```\nInside the block is yielded the value of the method\n\n```ruby\nthing = OpenStruct.new(name: 'rigoverto', serializer: 'ThingSerializer')\nobj = OpenStruct.new(d_name: 'a name', thing: thing)\n\nclass DynamicWithContentSerializer \u003c EasySerializer::Base\n  attribute :thing,\n            serializer: proc { |value| to_const value.serializer }\n            # =\u003e block will output ThingSerializer\n  attribute :d_name\n\n  def to_const(str)\n    Class.const_get str.classify\n  end\nend\n\nDynamicWithContentSerializer.call(obj)\n```\n\n### Collection Example:\n\n```ruby\nuser = OpenStruct.new(\n  name: 'John',\n  surname: 'Doe',\n  emails: [\n    OpenStruct.new(address: 'hello@email.com', type: 'work')\n  ]\n)\n\nclass EmailSerializer \u003c EasySerializer::Base\n  attributes :address, :type\nend\n\nclass UserSerializer \u003c EasySerializer::Base\n  attributes :name, :surname\n  collection :emails, serializer: EmailSerializer\nend\n\nUserSerializer.call(user)\n# =\u003e\n{\n  name: 'John',\n  surname: 'Doe',\n  emails: [ { address: 'hello@email.com', type: 'work' } ]\n}\n```\n\n### Cache\n\n**Important** cache will only work if is set in the configuration file.\n\n**Caching the serialized object:**\n\nSerialization will happen only once and the resulting hash will be stored in the cache.\n\n```ruby\nclass UserSerializer \u003c EasySerializer::Base\n  cache true\n  attributes :name, :surname\nend\n```\n\n**Caching attributes:**\n\nAttributes can be cached independently.\n\n```ruby\nclass UserSerializer \u003c EasySerializer::Base\n  attributes :name, :surname\n  attribute :costly_query, cache: true\nend\n```\n\nOf course it works with blocks:\n\n```ruby\nclass UserSerializer \u003c EasySerializer::Base\n  attributes :name, :surname\n  attribute(:costly_query, cache: true) do |user|\n    user.best_friends\n  end\nend\n```\n\nPassing cache key:\n\n```ruby\nclass UserSerializer \u003c EasySerializer::Base\n  attribute(:costly_query, cache: true, cache_key: 'hello') do |user|\n    user.best_friends\n  end\nend\n```\n\nPassing cache key block:\n\n```ruby\nclass UserSerializer \u003c EasySerializer::Base\n  attribute(\n    :costly_query,\n    cache: true,\n    cache_key: proc { |object| [object, 'costly_query'] }\n    ) do |user|\n      user.best_friends\n  end\nend\n```\n\nPassing options to the cache:\n\nAny option passed in the cache method not specified for EasySerializer will be\nforwarded as options to the set Cache as options for the fetch method.\n\nexample:\n\n```ruby\nclass OptionForRootCache \u003c EasySerializer::Base\n  cache true, expires_in: 10.minutes, another_option: true\n  attribute :name\nend\n```\n\nCache fetch will receive:\n\n```ruby\nEasySerializer.cache.fetch(\n  key,# object or defined key\n  expires_in: 10.minutes,\n  another_option: true\n)\n```\n\nUse **cache_options** in attributes\n\n```ruby\nclass OptionForAttributeCache \u003c EasySerializer::Base\n  attribute :name, cache: true, cache_options: { expires_in: 10.minutes }\nend\n```\n\n**Caching Collections:**\n\nCache will try to fetch the cached object in the collection **one by one, the whole collection is not cached**.\n\n```ruby\nclass UserSerializer \u003c EasySerializer::Base\n  attributes :name, :surname\n  collection :address, serializer: AddressSerializer, cache: true\nend\n```\n\n### Complex example using all features\n\n```ruby\nclass PolymorphicSerializer \u003c EasySerializer::Base\n  cache true\n  attribute :segment_type do |object|\n    object.subject.class.name.demodulize\n  end\n  attribute :segment_id do |object|\n    object.id\n  end\n  attributes :initial_date,\n             :end_date\n\n  attribute :subject,\n            key: false,\n            serializer: proc { |serializer| serializer.serializer_for_subject },\n            cache: true\n  collection :elements, serializer: ElementsSerializer, cache: true\n\n  def serializer_for_subject\n    object_name = object.subject_type.demodulize\n    \"#{object_name}Serializer\".constantize\n  end\nend\n```\n\n```ruby\nPolymorphicSerializer.call(Polymorphic.last)\n# =\u003e Hash with the object serialized\n```\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run `rake rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/arturictus/easy_serializer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.\n\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farturictus%2Feasy_serializer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farturictus%2Feasy_serializer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farturictus%2Feasy_serializer/lists"}