Migrating Guide: v2.0.0-pre11
This version introduces significant improvements to Familia's feature system, making it easier to organize and use features across complex projects.
Enhanced Feature System
Model-Specific Feature Registration
Previously, all features were registered globally. Now you can register features specific to individual model classes, allowing for better organization and namespace management.
Before
# Global feature registration only
module MyProjectFeature
# Feature implementation
end
Familia::Base.add_feature MyProjectFeature, :my_project_feature
class Customer < Familia::Horreum
feature :my_project_feature
end
class Session < Familia::Horreum
feature :my_project_feature # Same global feature
end
After
# Model-specific feature registration
module CustomerSpecificFeature
# Feature implementation
end
# Register feature only for Customer and its subclasses
Customer.add_feature CustomerSpecificFeature, :customer_specific
class Customer < Familia::Horreum
feature :customer_specific # Available via Customer's registry
end
class PremiumCustomer < Customer
feature :customer_specific # Inherited via ancestry chain
end
class Session < Familia::Horreum
# feature :customer_specific # Not available - would raise error
end
Benefits:
- Features can have the same name across different model hierarchies
- Standardized naming:
deprecated_fields.rbinstead ofcustomer_deprecated_fields.rb - Natural inheritance through Ruby's class hierarchy
SafeDump DSL Improvements
The new DSL replaces the brittle @safe_dump_fields class instance variable pattern with clean, explicit methods.
Before
class Customer < Familia::Horreum
feature :safe_dump
# Brittle - hard to move to feature modules, confusing syntax
@safe_dump_fields = [
:custid,
:email,
{ active: ->(obj) { obj.active? } },
{ display_name: ->(obj) { "#{obj.name} (#{obj.custid})" } }
]
end
After
class Customer < Familia::Horreum
feature :safe_dump
# Clean DSL - easy to understand and organize
safe_dump_field :custid
safe_dump_field :email
safe_dump_field :active, ->(obj) { obj.active? }
safe_dump_field :display_name, ->(obj) { "#{obj.name} (#{obj.custid})" }
# Or define multiple fields at once
safe_dump_fields :created, :updated, { status: ->(obj) { obj.role } }
end
New methods available:
safe_dump_field(name, callable = nil)- Define a single fieldsafe_dump_fields(*fields)- Define multiple fields or get field namessafe_dump_field_names- Get array of field namessafe_dump_field_map- Get the internal callable map
Backward Compatibility:
set_safe_dump_fields(*fields)- Legacy setter method (still works)- The old
@safe_dump_fieldspattern is no longer supported
Auto-loading Features
Before: Manual Loading
# customer/features.rb
# Manual feature loading (copied from Familia)
features_dir = File.join(__dir__, 'features')
if Dir.exist?(features_dir)
Dir.glob(File.join(features_dir, '*.rb')).each do |feature_file|
require_relative feature_file
end
end
class Customer < Familia::Horreum
# Features now available for use
feature :deprecated_fields
end
After: Automatic Loading
# customer/features.rb
class Customer < Familia::Horreum
module Features
include Familia::Features::Autoloader
# Automatically discovers and loads all *.rb files from customer/features/
end
end
class Customer < Familia::Horreum
# Features automatically loaded and available
feature :deprecated_fields
end
Directory structure this enables:
models/
├── customer/
│ ├── features/
│ │ ├── deprecated_fields.rb # Standardized names!
│ │ ├── legacy_support.rb
│ │ └── stripe_integration.rb
│ └── features.rb # Include Autoloader here
├── session/
│ ├── features/
│ │ ├── deprecated_fields.rb # Same name, different implementation
│ │ └── expiration_hooks.rb
│ └── features.rb
└── customer.rb
Field Definitions in Feature Modules
Feature modules can now define fields directly in their ClassMethods modules. When a class extends the module, the field definitions execute in the extending class's context.
Example
# features/common_fields.rb
module CommonFields
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
# These field calls execute in the extending class's context
field :created
field :updated
field :version
def touch_updated
self.updated = Familia.now.to_i
end
end
Familia::Base.add_feature self, :common_fields
end
# Usage
class Customer < Familia::Horreum
feature :common_fields
# Now has :created, :updated, :version fields and touch_updated class method
end
Migration Steps
1. Update SafeDump Usage
Replace all @safe_dump_fields definitions with the new DSL:
# Find and replace pattern:
# Old: @safe_dump_fields = [:field1, :field2, { field3: ->(obj) { ... } }]
# New: safe_dump_fields :field1, :field2, { field3: ->(obj) { ... } }
# Or use individual field definitions for better readability:
safe_dump_field :field1
safe_dump_field :field2
safe_dump_field :field3, ->(obj) { ... }
2. UnsortedSet Up Auto-loading (Optional)
If you have project-specific features, set up auto-loading:
# Create: models/[model_name]/features.rb
module YourProject
class ModelName < Familia::Horreum
module Features
include Familia::Features::Autoloader
end
end
end
# Require this file before your model definitions
require_relative 'model_name/features'
3. Organize Features by Model (Optional)
Consider reorganizing shared feature names by model:
# Before: features/customer_deprecated_fields.rb
# After: models/customer/features/deprecated_fields.rb
# This allows multiple models to have their own deprecated_fields.rb
4. Test Your Changes
Run your test suite to ensure all SafeDump functionality works correctly:
# Verify SafeDump DSL works
model = YourModel.new(field1: 'value')
result = model.safe_dump
puts result.keys # Should include your defined fields
Breaking Changes
@safe_dump_fieldsno longer supported - Must migrate to DSL methods- SafeDump field order - Fields are now returned in definition order via Hash keys (Ruby 1.9+ behavior)
New Capabilities Unlocked
- Standardized feature names across different models
- Cleaner SafeDump definitions that can be easily moved to feature modules
- Automatic feature discovery for better project organization
- Model-specific feature registries for better namespace management
- Field definitions in feature modules for shared functionality