$LOAD_PATH.unshift File.expand_path('../lib', __dir__)
require 'familia'
Familia.uri = 'redis://localhost:6379/15'
puts '=== SafeDump Feature Examples ==='
puts
class User < Familia::Horreum
feature :safe_dump
identifier_field :email
field :email
field :first_name
field :last_name
field :password_hash field :ssn field :created_at
safe_dump_field :email
safe_dump_field :first_name
safe_dump_field :last_name
safe_dump_field :created_at
end
puts 'Example 1: Basic SafeDump'
user = User.new(
email: 'alice@example.com',
first_name: 'Alice',
last_name: 'Smith',
password_hash: 'secret123',
ssn: '123-45-6789',
created_at: Time.now.to_i
)
puts "Full object data: #{user.to_h}"
puts "Safe dump: #{user.safe_dump}"
puts 'Notice: password_hash and ssn are excluded'
puts
class Product < Familia::Horreum
feature :safe_dump
identifier_field :sku
field :sku
field :name
field :price_cents field :cost_cents field :inventory_count
field :category
field :created_at
safe_dump_field :sku
safe_dump_field :name
safe_dump_field :category
safe_dump_field :created_at
safe_dump_field :price, ->(product) { "$#{format('%.2f', product.price_cents.to_i / 100.0)}" }
safe_dump_field :in_stock, ->(product) { product.inventory_count.to_i > 0 }
safe_dump_field :display_name, ->(product) { "#{product.name} (#{product.sku})" }
end
puts 'Example 2: SafeDump with computed fields'
product = Product.new(
sku: 'WIDGET-001',
name: 'Super Widget',
price_cents: 1599, cost_cents: 800, inventory_count: 25,
category: 'widgets',
created_at: Time.now.to_i
)
puts "Full object data: #{product.to_h}"
puts "Safe dump: #{product.safe_dump}"
puts 'Notice: price converted to dollars, in_stock computed, cost_cents hidden'
puts
class Order < Familia::Horreum
feature :safe_dump
identifier_field :order_id
field :order_id
field :customer_email
field :status
field :total_cents
field :payment_method
field :credit_card_number field :processing_notes field :created_at
field :shipped_at
safe_dump_field :order_id
safe_dump_field :customer_email
safe_dump_field :status
safe_dump_fields :created_at, :shipped_at
safe_dump_fields(
{ total: ->(order) { "$#{format('%.2f', order.total_cents.to_i / 100.0)}" } },
{ payment_type: ->(order) { order.payment_method&.split('_')&.first&.capitalize } }
)
def customer_obscured_email
email = customer_email.to_s
return email if email.length < 3
local, domain = email.split('@', 2)
return email unless domain
obscured_local = local[0] + ('*' * [local.length - 2, 0].max) + local[-1]
"#{obscured_local}@#{domain}"
end
end
puts 'Example 3: Multiple definition styles'
order = Order.new(
order_id: 'ORD-2024-001',
customer_email: 'customer@example.com',
status: 'shipped',
total_cents: 2499, payment_method: 'credit_card',
credit_card_number: '4111-1111-1111-1111', processing_notes: 'Rush order - expedite shipping',
created_at: Time.now.to_i - 86_400, shipped_at: Time.now.to_i - 3600 )
puts "Full object data: #{order.to_h}"
puts "Safe dump: #{order.safe_dump}"
puts 'Notice: credit card and internal notes excluded, computed fields included'
puts
class Address < Familia::Horreum
feature :safe_dump
identifier_field :id
field :id
field :street
field :city
field :state
field :zip_code
field :country
safe_dump_fields :street, :city, :state, :zip_code, :country
end
class Customer < Familia::Horreum
feature :safe_dump
identifier_field :id
field :id
field :name
field :email
field :phone
field :billing_address_id
field :shipping_address_id
field :account_balance_cents
field :credit_limit_cents field :internal_notes
safe_dump_field :id
safe_dump_field :name
safe_dump_field :email
safe_dump_field :phone
safe_dump_field :billing_address, lambda { |customer|
addr_id = customer.billing_address_id
addr_id ? Address.load(addr_id)&.safe_dump : nil
}
safe_dump_field :shipping_address, lambda { |customer|
addr_id = customer.shipping_address_id
addr_id ? Address.load(addr_id)&.safe_dump : nil
}
safe_dump_field :account_balance, lambda { |customer|
"$#{format('%.2f', customer.account_balance_cents.to_i / 100.0)}"
}
end
puts 'Example 4: SafeDump with nested objects'
billing = Address.new(
id: 'addr_1',
street: '123 Main St',
city: 'Anytown',
state: 'CA',
zip_code: '90210',
country: 'USA'
)
billing.save
shipping = Address.new(
id: 'addr_2',
street: '456 Oak Ave',
city: 'Somewhere',
state: 'NY',
zip_code: '10001',
country: 'USA'
)
shipping.save
customer = Customer.new(
id: 'cust_123',
name: 'Bob Johnson',
email: 'bob@example.com',
phone: '555-1234',
billing_address_id: 'addr_1',
shipping_address_id: 'addr_2',
account_balance_cents: 15_000, credit_limit_cents: 100_000, internal_notes: 'VIP customer - handle with care'
)
puts 'Customer safe dump:'
puts JSON.pretty_generate(customer.safe_dump)
puts 'Notice: Nested addresses included, sensitive credit limit excluded'
puts
puts 'Example 5: SafeDump introspection'
puts "User safe dump field names: #{User.safe_dump_field_names}"
puts "Product safe dump field names: #{Product.safe_dump_field_names}"
puts "Order safe dump field names: #{Order.safe_dump_field_names}"
puts
puts "User safe dump field map keys: #{User.safe_dump_field_map.keys}"
puts "All Product safe dump fields are callable: #{Product.safe_dump_field_map.values.all? do |v|
v.respond_to?(:call)
end}"
puts
puts 'Example 6: Legacy compatibility'
puts "Using legacy safe_dump_fields getter: #{User.safe_dump_fields}"
puts 'Setting fields with set_safe_dump_fields:'
class LegacyModel < Familia::Horreum
feature :safe_dump
identifier_field :id
field :id
field :name
field :value
end
LegacyModel.set_safe_dump_fields(:id, :name)
puts "LegacyModel fields after set_safe_dump_fields: #{LegacyModel.safe_dump_fields}"
puts
puts '=== Cleaning up test data ==='
[User, Product, Order, Address, Customer, LegacyModel].each do |klass|
klass.redis.del(klass.redis.keys("#{klass.name.downcase}:*"))
rescue StandardError => e
puts "Error cleaning #{klass}: #{e.message}"
end
puts 'SafeDump examples completed!'