0.0
Low commit activity in last 3 years
Provide an easy approach to build entity object for data that can not be reflected to database tables.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

>= 0
>= 0
>= 0
>= 0

Runtime

 Project Readme

đŸĻ Sparrow Entity

English | įŽ€äŊ“中文 | æ—ĨæœŦčĒž

Gem Version License: MIT

📖 Table of Contents

  • 🌟 Introduction
  • ✨ Features
  • đŸ“Ļ Installation
  • đŸ’ģ Usage Guide
    • 1. Basic Entity Definition
    • 2. Automatic Type Casting
    • 3. Boolean Fields
    • 4. Default Values
    • 5. ActiveModel Integrations (Validations & Callbacks)
    • 6. Serialization
  • 🚀 Rails Integration & Generator
  • 📝 License

🌟 Introduction

Sparrow Entity is a lightweight Ruby gem designed to provide ORM-like entity modeling for non-database-backed data.

In modern architectures, especially microservices, applications often consume vast amounts of data from external APIs, message queues, or gRPC services rather than local databases. In these scenarios, ActiveRecord::Base cannot be used since there is no underlying database table. Sparrow perfectly fills this gap by allowing you to define structured, strongly-typed Entity objects (Plain Old Ruby Objects on steroids) with all the familiar ActiveModel conveniences.

✨ Features

  • 🛠 ORM-like Experience: Define attributes and types just like you would in ActiveRecord.
  • 🗂 Automatic Type Casting: Automatically converts assigned values to defined types (e.g., String, Integer, Date, Sparrow::Boolean).
  • âš™ī¸ Default Values: Set default fallback values for attributes when initialization is blank or invalid.
  • 🛤 ActiveModel Integration: Supports callbacks, validations, dirty tracking, and translations out of the box.
  • 🚀 Rails Generator: Instantly generate entity classes using the built-in Rails generator CLI.
  • đŸ“Ļ Serialization: Built-in support for activemodel_object_info to easily serialize entities into Hashes/JSON.

đŸ“Ļ Installation

Add this line to your application's Gemfile:

gem 'sparrow-entity', require: 'sparrow'

Then execute:

$ bundle install

Or install it globally via:

$ gem install sparrow-entity

đŸ’ģ Usage Guide

1. Basic Entity Definition

To create your own entity, simply inherit from Sparrow::Base. You can define fields with their expected Ruby types.

require 'sparrow' # Not required in Rails

#
# Represents a User entity fetched from an external User Service
#
# [Changelog]
# - 1.0.0: Initial release
#
class UserEntity < Sparrow::Base
  field :id, Integer
  field :family_name, String
  field :given_name, String
  field :birthday, Date
  field :nationality, String

  #
  # Format and return the full name of the user
  #
  # @since 1.0.0
  # @param [Hash] options formatting options
  # @option options [Symbol] :last whether to place family name last or first
  # @option options [String] :separator string used to join names
  # @return [String] the formatted full name
  #
  def full_name(options = {})
    last = options[:last] || :given
    separator = options[:separator] || ' '
    
    val = [family_name, given_name]
    val.reverse! if last == :family
    val.join(separator)
  end
end

user = UserEntity.new(id: 1, family_name: 'Doe', given_name: 'John')
puts user.full_name(last: :family) # => "John Doe"

2. Automatic Type Casting

Sparrow will attempt to coerce assigned values into the defined types automatically.

user = UserEntity.new
user.id = "42"          # Assigned as a String
user.birthday = "2023-10-01" # Assigned as a String

puts user.id.class       # => Integer (42)
puts user.birthday.class # => Date (<Date: 2023-10-01 ...>)

3. Boolean Fields

For boolean logic, Sparrow provides Sparrow::Boolean. It handles truthy and falsey values gracefully based on .present? checks or explicit boolean equivalents.

class SettingsEntity < Sparrow::Base
  field :notifications_enabled, Sparrow::Boolean
end

settings = SettingsEntity.new
puts settings.notifications_enabled.inspect # => nil

settings.notifications_enabled = 'yes'
puts settings.notifications_enabled         # => true

settings.notifications_enabled = ''
puts settings.notifications_enabled         # => false

4. Default Values

You can provide a default: option. If the assigned value is empty or invalid, it will fallback to this default value.

class TaskEntity < Sparrow::Base
  field :status, String, default: 'pending'
  field :retry_count, Integer, default: 0
end

task = TaskEntity.new
puts task.status      # => "pending"
puts task.retry_count # => 0

task.status = 'in_progress'
puts task.status      # => "in_progress"

5. ActiveModel Integrations (Validations & Callbacks)

Because Sparrow includes ActiveModel modules, you can use validations and callbacks (before_validation, after_initialize, etc.) out of the box.

class OrderEntity < Sparrow::Base
  field :order_no, String
  field :amount, Float
  field :state, String, default: 'created'

  validates :order_no, presence: true
  validates :amount, numericality: { greater_than: 0 }

  before_validation :generate_order_no, if: -> { order_no.blank? }

  private

  #
  # Generate a random order number if not present
  #
  # @since 1.0.0
  # @return [String] the generated order number
  #
  def generate_order_no
    self.order_no = "ORD-#{Time.now.to_i}"
  end
end

order = OrderEntity.new(amount: 150.50)
order.valid? # => true
puts order.order_no # => "ORD-1698765432"

6. Serialization

Sparrow leverages activemodel_object_info (v0.4.2+) to easily dump entities into Hashes or JSON formats, offering powerful contextual formatting, whitelisting/blacklisting, and custom lambdas.

class ProductEntity < Sparrow::Base
  field :sku, String
  field :price, Float
  field :stock, Integer, default: 0

  # Define default output configuration
  INSTANCE_INFO = {
    only: [:sku, :price],
    attributes: [
      :sku,
      { name: :price, type: :abstract, filter: ->(v) { "$#{format('%.2f', v)}" } }
    ]
  }.freeze

  # Define contextual output configuration
  INSTANCE_INFO_DETAIL = {
    only: [:sku, :price, :stock]
  }.freeze
end

product = ProductEntity.new(sku: 'MAC-M2-001', price: 1299.9)

# Standard attributes hash
puts product.attributes 
# => { sku: "MAC-M2-001", price: 1299.9, stock: 0 }

# 1. Uses default INSTANCE_INFO constant
puts product.instance_info
# => { sku: "MAC-M2-001", price: "$1299.90" }

# 2. Contextual output: Pass `context` to use INSTANCE_INFO_DETAIL
puts product.instance_info(context: :detail)
# => { sku: "MAC-M2-001", price: 1299.9, stock: 0 }

# 3. Override at runtime
puts product.instance_info(only: [:sku])
# => { sku: "MAC-M2-001" }

# 4. Exclude specific fields (except)
puts product.instance_info(context: :detail, except: [:price])
# => { sku: "MAC-M2-001", stock: 0 }

🚀 Rails Integration & Generator

If you are using Ruby on Rails, sparrow-entity files will be automatically required.

You can use the built-in generator to quickly scaffold entity classes:

$ rails g sparrow:entity Post::Reply

This will generate app/entities/post/reply.rb:

module Post
  class Reply < Sparrow::Base
  end
end

📝 License

The gem is available as open source under the terms of the MIT License.