đĻ Sparrow Entity
English | įŽäŊ䏿 | æĨæŦčĒ
đ Table of Contents
- đ Introduction
- ⨠Features
- đĻ Installation
- đģ Usage Guide
- đ 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_infoto 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( = {})
last = [:last] || :given
separator = [: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.