familia 2.0.0.pre15 → 2.0.0.pre16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/code-quality.yml +138 -0
- data/.github/workflows/code-smellage.yml +145 -0
- data/.github/workflows/docs.yml +31 -8
- data/.gitignore +1 -1
- data/.pre-commit-config.yaml +7 -1
- data/.reek.yml +98 -0
- data/.rubocop.yml +48 -10
- data/.talismanrc +9 -0
- data/.yardopts +18 -13
- data/CHANGELOG.rst +64 -4
- data/CLAUDE.md +1 -1
- data/Gemfile +6 -5
- data/Gemfile.lock +99 -23
- data/LICENSE.txt +1 -1
- data/README.md +285 -85
- data/changelog.d/README.md +2 -2
- data/docs/archive/FAMILIA_RELATIONSHIPS.md +22 -22
- data/docs/archive/FAMILIA_TECHNICAL.md +41 -41
- data/docs/archive/FAMILIA_UPDATE.md +3 -3
- data/docs/archive/README.md +3 -2
- data/docs/{guides/API-Reference.md → archive/api-reference.md} +87 -101
- data/docs/conf.py +29 -0
- data/docs/guides/{Field-System-Guide.md → core-field-system.md} +9 -9
- data/docs/guides/feature-encrypted-fields.md +785 -0
- data/docs/guides/{Expiration-Feature-Guide.md → feature-expiration.md} +11 -2
- data/docs/guides/feature-external-identifiers.md +637 -0
- data/docs/guides/feature-object-identifiers.md +435 -0
- data/docs/guides/{Quantization-Feature-Guide.md → feature-quantization.md} +94 -29
- data/docs/guides/feature-relationships-methods.md +684 -0
- data/docs/guides/feature-relationships.md +200 -0
- data/docs/guides/{Features-System-Developer-Guide.md → feature-system-devs.md} +4 -4
- data/docs/guides/{Feature-System-Guide.md → feature-system.md} +5 -5
- data/docs/guides/{Transient-Fields-Guide.md → feature-transient-fields.md} +2 -2
- data/docs/guides/{Implementation-Guide.md → implementation.md} +3 -3
- data/docs/guides/index.md +176 -0
- data/docs/guides/{Security-Model.md → security-model.md} +1 -1
- data/docs/migrating/v2.0.0-pre.md +1 -1
- data/docs/migrating/v2.0.0-pre11.md +2 -2
- data/docs/migrating/v2.0.0-pre12.md +2 -2
- data/docs/migrating/v2.0.0-pre5.md +33 -12
- data/docs/migrating/v2.0.0-pre6.md +2 -2
- data/docs/migrating/v2.0.0-pre7.md +8 -8
- data/docs/overview.md +623 -19
- data/docs/reference/api-technical.md +1365 -0
- data/examples/autoloader/mega_customer/features/deprecated_fields.rb +7 -0
- data/examples/autoloader/mega_customer/safe_dump_fields.rb +1 -1
- data/examples/autoloader/mega_customer.rb +3 -1
- data/examples/encrypted_fields.rb +378 -0
- data/examples/json_usage_patterns.rb +144 -0
- data/examples/relationships.rb +13 -13
- data/examples/safe_dump.rb +6 -6
- data/examples/single_connection_transaction_confusions.rb +379 -0
- data/lib/familia/base.rb +49 -10
- data/lib/familia/connection/handlers.rb +223 -0
- data/lib/familia/connection/individual_command_proxy.rb +64 -0
- data/lib/familia/connection/middleware.rb +75 -0
- data/lib/familia/connection/operation_core.rb +93 -0
- data/lib/familia/connection/operations.rb +277 -0
- data/lib/familia/connection/pipeline_core.rb +87 -0
- data/lib/familia/connection/transaction_core.rb +100 -0
- data/lib/familia/connection.rb +60 -186
- data/lib/familia/data_type/commands.rb +53 -51
- data/lib/familia/data_type/serialization.rb +108 -107
- data/lib/familia/data_type/types/counter.rb +1 -1
- data/lib/familia/data_type/types/hashkey.rb +13 -10
- data/lib/familia/data_type/types/{list.rb → listkey.rb} +13 -5
- data/lib/familia/data_type/types/lock.rb +3 -2
- data/lib/familia/data_type/types/sorted_set.rb +26 -15
- data/lib/familia/data_type/types/{string.rb → stringkey.rb} +7 -5
- data/lib/familia/data_type/types/unsorted_set.rb +20 -27
- data/lib/familia/data_type.rb +75 -47
- data/lib/familia/distinguisher.rb +85 -0
- data/lib/familia/encryption/encrypted_data.rb +15 -24
- data/lib/familia/encryption/manager.rb +6 -4
- data/lib/familia/encryption/providers/aes_gcm_provider.rb +1 -1
- data/lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb +7 -9
- data/lib/familia/encryption/providers/xchacha20_poly1305_provider.rb +4 -5
- data/lib/familia/encryption/request_cache.rb +7 -7
- data/lib/familia/encryption.rb +2 -3
- data/lib/familia/errors.rb +9 -3
- data/lib/familia/features/autoloader.rb +30 -12
- data/lib/familia/features/encrypted_fields/concealed_string.rb +3 -4
- data/lib/familia/features/encrypted_fields/encrypted_field_type.rb +13 -14
- data/lib/familia/features/encrypted_fields.rb +66 -64
- data/lib/familia/features/expiration/extensions.rb +1 -1
- data/lib/familia/features/expiration.rb +31 -26
- data/lib/familia/features/external_identifier.rb +9 -12
- data/lib/familia/features/object_identifier.rb +56 -19
- data/lib/familia/features/quantization.rb +16 -21
- data/lib/familia/features/relationships/README.md +97 -0
- data/lib/familia/features/relationships/collection_operations.rb +104 -0
- data/lib/familia/features/relationships/indexing/multi_index_generators.rb +202 -0
- data/lib/familia/features/relationships/indexing/unique_index_generators.rb +301 -0
- data/lib/familia/features/relationships/indexing.rb +176 -256
- data/lib/familia/features/relationships/indexing_relationship.rb +35 -0
- data/lib/familia/features/relationships/participation/participant_methods.rb +160 -0
- data/lib/familia/features/relationships/participation/target_methods.rb +225 -0
- data/lib/familia/features/relationships/participation.rb +656 -0
- data/lib/familia/features/relationships/participation_relationship.rb +31 -0
- data/lib/familia/features/relationships/score_encoding.rb +20 -20
- data/lib/familia/features/relationships.rb +65 -266
- data/lib/familia/features/safe_dump.rb +127 -130
- data/lib/familia/features/transient_fields/redacted_string.rb +6 -6
- data/lib/familia/features/transient_fields/transient_field_type.rb +5 -5
- data/lib/familia/features/transient_fields.rb +3 -5
- data/lib/familia/features.rb +4 -13
- data/lib/familia/field_type.rb +24 -4
- data/lib/familia/horreum/core/connection.rb +229 -26
- data/lib/familia/horreum/core/database_commands.rb +27 -17
- data/lib/familia/horreum/core/serialization.rb +40 -20
- data/lib/familia/horreum/core/utils.rb +2 -1
- data/lib/familia/horreum/shared/settings.rb +2 -1
- data/lib/familia/horreum/subclass/definition.rb +33 -45
- data/lib/familia/horreum/subclass/management.rb +72 -24
- data/lib/familia/horreum/subclass/related_fields_management.rb +82 -21
- data/lib/familia/horreum.rb +196 -114
- data/lib/familia/json_serializer.rb +0 -1
- data/lib/familia/logging.rb +11 -114
- data/lib/familia/refinements/dear_json.rb +122 -0
- data/lib/familia/refinements/logger_trace.rb +20 -17
- data/lib/familia/refinements/stylize_words.rb +65 -0
- data/lib/familia/refinements/time_literals.rb +60 -52
- data/lib/familia/refinements.rb +2 -1
- data/lib/familia/secure_identifier.rb +60 -28
- data/lib/familia/settings.rb +83 -7
- data/lib/familia/utils.rb +5 -87
- data/lib/familia/verifiable_identifier.rb +4 -4
- data/lib/familia/version.rb +1 -1
- data/lib/familia.rb +72 -14
- data/lib/middleware/database_middleware.rb +56 -14
- data/lib/{familia/multi_result.rb → multi_result.rb} +23 -16
- data/try/configuration/scenarios_try.rb +1 -1
- data/try/connection/fiber_context_preservation_try.rb +250 -0
- data/try/connection/handler_constraints_try.rb +59 -0
- data/try/connection/operation_mode_guards_try.rb +208 -0
- data/try/connection/pipeline_fallback_integration_try.rb +128 -0
- data/try/connection/responsibility_chain_tracking_try.rb +72 -0
- data/try/connection/transaction_fallback_integration_try.rb +288 -0
- data/try/connection/transaction_mode_permissive_try.rb +153 -0
- data/try/connection/transaction_mode_strict_try.rb +98 -0
- data/try/connection/transaction_mode_warn_try.rb +131 -0
- data/try/connection/transaction_modes_try.rb +249 -0
- data/try/core/autoloader_try.rb +120 -2
- data/try/core/connection_try.rb +7 -7
- data/try/core/conventional_inheritance_try.rb +130 -0
- data/try/core/create_method_try.rb +15 -23
- data/try/core/database_consistency_try.rb +10 -10
- data/try/core/errors_try.rb +8 -11
- data/try/core/familia_extended_try.rb +2 -2
- data/try/core/familia_members_methods_try.rb +76 -0
- data/try/core/isolated_dbclient_try.rb +165 -0
- data/try/core/middleware_try.rb +16 -16
- data/try/core/persistence_operations_try.rb +4 -4
- data/try/core/pools_try.rb +42 -26
- data/try/core/secure_identifier_try.rb +28 -24
- data/try/core/time_utils_try.rb +10 -10
- data/try/core/tools_try.rb +1 -1
- data/try/core/utils_try.rb +2 -2
- data/try/data_types/boolean_try.rb +4 -4
- data/try/data_types/datatype_base_try.rb +0 -2
- data/try/data_types/list_try.rb +10 -10
- data/try/data_types/sorted_set_try.rb +5 -5
- data/try/data_types/string_try.rb +12 -12
- data/try/data_types/unsortedset_try.rb +33 -0
- data/try/debugging/cache_behavior_tracer.rb +7 -7
- data/try/debugging/debug_aad_process.rb +1 -1
- data/try/debugging/debug_concealed_internal.rb +1 -1
- data/try/debugging/debug_cross_context.rb +1 -1
- data/try/debugging/debug_fresh_cross_context.rb +1 -1
- data/try/debugging/encryption_method_tracer.rb +10 -10
- data/try/edge_cases/hash_symbolization_try.rb +1 -1
- data/try/edge_cases/ttl_side_effects_try.rb +1 -1
- data/try/encryption/config_persistence_try.rb +2 -2
- data/try/encryption/encryption_core_try.rb +19 -19
- data/try/encryption/instance_variable_scope_try.rb +1 -1
- data/try/encryption/module_loading_try.rb +2 -2
- data/try/encryption/providers/aes_gcm_provider_try.rb +1 -1
- data/try/encryption/providers/xchacha20_poly1305_provider_try.rb +1 -1
- data/try/encryption/secure_memory_handling_try.rb +1 -1
- data/try/features/encrypted_fields/concealed_string_core_try.rb +11 -7
- data/try/features/encrypted_fields/encrypted_fields_core_try.rb +1 -1
- data/try/features/encrypted_fields/encrypted_fields_integration_try.rb +3 -3
- data/try/features/encrypted_fields/encrypted_fields_no_cache_security_try.rb +10 -10
- data/try/features/encrypted_fields/encrypted_fields_security_try.rb +14 -14
- data/try/features/encrypted_fields/error_conditions_try.rb +7 -7
- data/try/features/encrypted_fields/fresh_key_try.rb +1 -1
- data/try/features/encrypted_fields/nonce_uniqueness_try.rb +1 -1
- data/try/features/encrypted_fields/secure_by_default_behavior_try.rb +7 -7
- data/try/features/encrypted_fields/universal_serialization_safety_try.rb +13 -20
- data/try/features/external_identifier/external_identifier_try.rb +1 -1
- data/try/features/feature_dependencies_try.rb +3 -3
- data/try/features/object_identifier/object_identifier_integration_try.rb +28 -34
- data/try/features/object_identifier/object_identifier_try.rb +10 -0
- data/try/features/quantization/quantization_try.rb +1 -1
- data/try/features/relationships/indexing_commands_verification_try.rb +136 -0
- data/try/features/relationships/indexing_try.rb +433 -0
- data/try/features/relationships/participation_commands_verification_spec.rb +102 -0
- data/try/features/relationships/participation_commands_verification_try.rb +105 -0
- data/try/features/relationships/participation_performance_improvements_try.rb +124 -0
- data/try/features/relationships/participation_reverse_index_try.rb +196 -0
- data/try/features/relationships/relationships_api_changes_try.rb +72 -71
- data/try/features/relationships/relationships_edge_cases_try.rb +15 -18
- data/try/features/relationships/relationships_performance_minimal_try.rb +2 -2
- data/try/features/relationships/relationships_performance_simple_try.rb +8 -8
- data/try/features/relationships/relationships_performance_try.rb +20 -20
- data/try/features/relationships/relationships_try.rb +27 -38
- data/try/features/safe_dump/safe_dump_advanced_try.rb +2 -2
- data/try/features/transient_fields/refresh_reset_try.rb +1 -1
- data/try/features/transient_fields/simple_refresh_test.rb +1 -1
- data/try/helpers/test_cleanup.rb +86 -0
- data/try/helpers/test_helpers.rb +3 -3
- data/try/horreum/base_try.rb +3 -2
- data/try/horreum/commands_try.rb +1 -1
- data/try/horreum/destroy_related_fields_cleanup_try.rb +330 -0
- data/try/horreum/initialization_try.rb +11 -7
- data/try/horreum/relations_try.rb +21 -13
- data/try/horreum/serialization_try.rb +12 -11
- data/try/integration/cross_component_try.rb +3 -3
- data/try/memory/memory_basic_test.rb +1 -1
- data/try/memory/memory_docker_ruby_dump.sh +1 -1
- data/try/models/customer_safe_dump_try.rb +1 -1
- data/try/models/customer_try.rb +8 -10
- data/try/models/datatype_base_try.rb +3 -3
- data/try/models/familia_object_try.rb +9 -8
- data/try/performance/benchmarks_try.rb +2 -2
- data/try/prototypes/atomic_saves_v1_context_proxy.rb +2 -2
- data/try/prototypes/atomic_saves_v3_connection_pool.rb +3 -3
- data/try/prototypes/atomic_saves_v4.rb +1 -1
- data/try/prototypes/lib/atomic_saves_v2_connection_switching_helpers.rb +4 -4
- data/try/prototypes/lib/atomic_saves_v3_connection_pool_helpers.rb +4 -4
- data/try/prototypes/pooling/lib/atomic_saves_v3_connection_pool_helpers.rb +4 -4
- data/try/prototypes/pooling/lib/connection_pool_metrics.rb +5 -5
- data/try/prototypes/pooling/lib/connection_pool_stress_test.rb +26 -26
- data/try/prototypes/pooling/lib/connection_pool_threading_models.rb +7 -7
- data/try/prototypes/pooling/lib/visualize_stress_results.rb +1 -1
- data/try/prototypes/pooling/pool_siege.rb +11 -11
- data/try/prototypes/pooling/run_stress_tests.rb +7 -7
- data/try/refinements/dear_json_array_methods_try.rb +53 -0
- data/try/refinements/dear_json_hash_methods_try.rb +54 -0
- data/try/refinements/logger_trace_methods_try.rb +44 -0
- data/try/refinements/time_literals_numeric_methods_try.rb +141 -0
- data/try/refinements/time_literals_string_methods_try.rb +80 -0
- metadata +75 -43
- data/.rubocop_todo.yml +0 -208
- data/docs/connection_pooling.md +0 -192
- data/docs/guides/Connection-Pooling-Guide.md +0 -437
- data/docs/guides/Encrypted-Fields-Overview.md +0 -101
- data/docs/guides/Feature-System-Autoloading.md +0 -198
- data/docs/guides/Home.md +0 -116
- data/docs/guides/Relationships-Guide.md +0 -737
- data/docs/guides/relationships-methods.md +0 -266
- data/docs/reference/auditing_database_commands.rb +0 -228
- data/examples/permissions.rb +0 -240
- data/lib/familia/features/relationships/cascading.rb +0 -437
- data/lib/familia/features/relationships/membership.rb +0 -497
- data/lib/familia/features/relationships/permission_management.rb +0 -264
- data/lib/familia/features/relationships/querying.rb +0 -615
- data/lib/familia/features/relationships/redis_operations.rb +0 -274
- data/lib/familia/features/relationships/tracking.rb +0 -418
- data/lib/familia/refinements/snake_case.rb +0 -40
- data/lib/familia/validation/command_recorder.rb +0 -336
- data/lib/familia/validation/expectations.rb +0 -519
- data/lib/familia/validation/validation_helpers.rb +0 -443
- data/lib/familia/validation/validator.rb +0 -412
- data/lib/familia/validation.rb +0 -140
- data/try/data_types/set_try.rb +0 -33
- data/try/features/relationships/categorical_permissions_try.rb +0 -515
- data/try/features/safe_dump/module_based_extensions_try.rb +0 -100
- data/try/features/safe_dump/safe_dump_autoloading_try.rb +0 -107
- data/try/validation/atomic_operations_try.rb.disabled +0 -320
- data/try/validation/command_validation_try.rb.disabled +0 -207
- data/try/validation/performance_validation_try.rb.disabled +0 -324
- data/try/validation/real_world_scenarios_try.rb.disabled +0 -390
@@ -1,198 +0,0 @@
|
|
1
|
-
# Feature System Autoloading
|
2
|
-
|
3
|
-
## Overview
|
4
|
-
|
5
|
-
Familia's feature system includes an autoloading mechanism that automatically discovers and loads feature-specific extension files when features are included in your classes. This allows you to keep your main model files clean while organizing feature-specific configurations in separate files.
|
6
|
-
|
7
|
-
## The Problem It Solves
|
8
|
-
|
9
|
-
When you include a feature like `safe_dump` in a Familia class:
|
10
|
-
|
11
|
-
```ruby
|
12
|
-
class User < Familia::Horreum
|
13
|
-
feature :safe_dump # This line should trigger autoloading
|
14
|
-
end
|
15
|
-
```
|
16
|
-
|
17
|
-
You want to be able to define the safe dump configuration in a separate file:
|
18
|
-
|
19
|
-
```ruby
|
20
|
-
# user/safe_dump_extensions.rb
|
21
|
-
class User
|
22
|
-
safe_dump_fields :name, :email # Don't dump :password
|
23
|
-
end
|
24
|
-
```
|
25
|
-
|
26
|
-
But there's a **timing problem**: when should this extension file be loaded?
|
27
|
-
|
28
|
-
## Why Standard `included` Hook Doesn't Work
|
29
|
-
|
30
|
-
The original approach tried to use the standard `included` hook:
|
31
|
-
|
32
|
-
```ruby
|
33
|
-
module SafeDump
|
34
|
-
def self.included(base)
|
35
|
-
# Try to autoload here - BUT THIS IS TOO EARLY!
|
36
|
-
autoload_files_for(base)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
```
|
40
|
-
|
41
|
-
**Problem**: This happens **during** the feature inclusion process, before the feature is fully set up. The class isn't in a stable state yet.
|
42
|
-
|
43
|
-
## The Solution: Post-Inclusion Hook
|
44
|
-
|
45
|
-
The `post_inclusion_autoload` system works in **two phases**:
|
46
|
-
|
47
|
-
### Feature System Hook
|
48
|
-
|
49
|
-
In `lib/familia/features.rb`, after including the feature module:
|
50
|
-
|
51
|
-
```ruby
|
52
|
-
def feature(feature_name, **options)
|
53
|
-
# ... setup code ...
|
54
|
-
|
55
|
-
include feature_class # Include the feature module
|
56
|
-
|
57
|
-
# NOW call the post-inclusion hook
|
58
|
-
if feature_class.respond_to?(:post_inclusion_autoload)
|
59
|
-
feature_class.post_inclusion_autoload(self, feature_name, options)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
```
|
63
|
-
|
64
|
-
3. **Loads any matching files** found in those locations
|
65
|
-
|
66
|
-
## Why This Timing Matters
|
67
|
-
|
68
|
-
```ruby
|
69
|
-
class User < Familia::Horreum
|
70
|
-
feature :safe_dump # ← Timing is critical here
|
71
|
-
end
|
72
|
-
```
|
73
|
-
|
74
|
-
**What happens in order:**
|
75
|
-
|
76
|
-
1. `feature :safe_dump` is called
|
77
|
-
2. Feature system includes `Familia::Features::SafeDump` module
|
78
|
-
3. **Feature is now fully included and stable**
|
79
|
-
4. `post_inclusion_autoload` is called
|
80
|
-
5. Extension files are discovered and loaded
|
81
|
-
6. `safe_dump_fields :name, :email` executes in the extension file
|
82
|
-
|
83
|
-
## File Naming Conventions
|
84
|
-
|
85
|
-
The autoloading system looks for files matching these patterns (in order of precedence):
|
86
|
-
|
87
|
-
1. `{model_directory}/{model_name}/{feature_name}_*.rb`
|
88
|
-
2. `{model_directory}/{model_name}/features/{feature_name}_*.rb`
|
89
|
-
3. `{model_directory}/features/{feature_name}_*.rb`
|
90
|
-
|
91
|
-
### Examples
|
92
|
-
|
93
|
-
For a `User` class defined in `app/models/user.rb` with `feature :safe_dump`:
|
94
|
-
|
95
|
-
```
|
96
|
-
app/models/user/safe_dump_extensions.rb # ← Most specific
|
97
|
-
app/models/user/safe_dump_config.rb # ← Also matches pattern
|
98
|
-
app/models/user/features/safe_dump_*.rb # ← Feature subdirectory
|
99
|
-
app/models/features/safe_dump_*.rb # ← Shared feature configs
|
100
|
-
```
|
101
|
-
|
102
|
-
## Complete Example
|
103
|
-
|
104
|
-
### Main Model File
|
105
|
-
|
106
|
-
```ruby
|
107
|
-
# app/models/user.rb
|
108
|
-
class User < Familia::Horreum
|
109
|
-
field :name
|
110
|
-
field :email
|
111
|
-
field :password
|
112
|
-
field :created_at
|
113
|
-
|
114
|
-
feature :safe_dump # ← Triggers autoloading
|
115
|
-
feature :expiration
|
116
|
-
end
|
117
|
-
```
|
118
|
-
|
119
|
-
### Safe Dump Extensions
|
120
|
-
|
121
|
-
```ruby
|
122
|
-
# app/models/user/safe_dump_extensions.rb
|
123
|
-
class User
|
124
|
-
# Configure which fields are safe to dump in API responses
|
125
|
-
safe_dump_fields :name, :email, :created_at
|
126
|
-
# Note: :password is intentionally excluded for security
|
127
|
-
|
128
|
-
def safe_dump_display_name
|
129
|
-
"#{name} (#{email})"
|
130
|
-
end
|
131
|
-
end
|
132
|
-
```
|
133
|
-
|
134
|
-
### Expiration Extensions
|
135
|
-
|
136
|
-
```ruby
|
137
|
-
# app/models/user/expiration_config.rb
|
138
|
-
class User
|
139
|
-
# Set default TTL for user objects
|
140
|
-
expires_in 30.days
|
141
|
-
|
142
|
-
# Custom expiration logic
|
143
|
-
def should_expire?
|
144
|
-
!active? && last_login_at < 90.days.ago
|
145
|
-
end
|
146
|
-
end
|
147
|
-
```
|
148
|
-
|
149
|
-
### Result
|
150
|
-
|
151
|
-
After loading, the `User` class has:
|
152
|
-
- `User.safe_dump_field_names` returns `[:name, :email, :created_at]`
|
153
|
-
- `User.ttl` returns the configured expiration
|
154
|
-
- All extension methods are available on instances
|
155
|
-
|
156
|
-
## Key Benefits
|
157
|
-
|
158
|
-
1. **Separation of Concerns**: Main model file focuses on core definition, extension files handle feature-specific configuration
|
159
|
-
|
160
|
-
2. **Convention Over Configuration**: No manual requires, just follow naming conventions
|
161
|
-
|
162
|
-
3. **Safe Timing**: Extension files load after the feature is fully set up
|
163
|
-
|
164
|
-
4. **Thread Safe**: No shared state between classes
|
165
|
-
|
166
|
-
5. **Discoverable**: Clear file organization makes extensions easy to find
|
167
|
-
|
168
|
-
## Why It's Better Than Alternatives
|
169
|
-
|
170
|
-
- **Manual requires**: Error-prone, verbose, easy to forget
|
171
|
-
- **Configuration blocks**: Clutters the main model file
|
172
|
-
- **Included hook**: Wrong timing, class not stable yet
|
173
|
-
- **Class_eval strings**: Complex, hard to debug and maintain
|
174
|
-
|
175
|
-
The `post_inclusion_autoload` system provides a clean, automatic, and safe way to extend feature behavior without polluting the main class definitions.
|
176
|
-
|
177
|
-
## Implementation Details
|
178
|
-
|
179
|
-
### Autoloader
|
180
|
-
|
181
|
-
Looks for features files in models/features.rb, models/features/, models/model_name/features.rb, models/model_name/features/
|
182
|
-
|
183
|
-
|
184
|
-
### Anonymous Class Handling
|
185
|
-
|
186
|
-
The system gracefully handles edge cases:
|
187
|
-
|
188
|
-
- **Anonymous classes**: Classes without names (e.g., `Class.new`) are skipped
|
189
|
-
- **Eval contexts**: Classes defined in `eval` or irb are skipped
|
190
|
-
- **Missing files**: No errors if extension files don't exist
|
191
|
-
|
192
|
-
### Error Handling
|
193
|
-
|
194
|
-
- Missing extension files are silently ignored
|
195
|
-
- Syntax errors in extension files propagate normally
|
196
|
-
- `NameError` during constant resolution is caught and logged
|
197
|
-
|
198
|
-
This robust error handling ensures the autoloading system never breaks your application, even with unusual class definitions or missing files.
|
data/docs/guides/Home.md
DELETED
@@ -1,116 +0,0 @@
|
|
1
|
-
# Familia v2.0 Documentation
|
2
|
-
|
3
|
-
Welcome to the comprehensive documentation for Familia v2.0. This wiki covers all major features including security, connection management, architecture, and object relationships.
|
4
|
-
|
5
|
-
## 📚 Documentation Structure
|
6
|
-
|
7
|
-
### 🔐 Security & Data Protection
|
8
|
-
|
9
|
-
1. **[Encrypted Fields Overview](Encrypted-Fields-Overview.md)** - Persistent encrypted storage with modular providers
|
10
|
-
2. **[Transient Fields Guide](Transient-Fields-Guide.md)** - Non-persistent secure data handling with RedactedString
|
11
|
-
3. **[Security Model](Security-Model.md)** - Cryptographic design and Ruby memory limitations
|
12
|
-
|
13
|
-
### 🏗️ Architecture & System Design
|
14
|
-
|
15
|
-
4. **[Feature System Guide](Feature-System-Guide.md)** - Modular architecture with dependencies and conflict resolution _(new!)_
|
16
|
-
5. **[Connection Pooling Guide](Connection-Pooling-Guide.md)** - Provider pattern for efficient Redis/Valkey pooling _(new!)_
|
17
|
-
6. **[Relationships Guide](Relationships-Guide.md)** - Object relationships and membership system _(new!)_
|
18
|
-
|
19
|
-
### 🛠️ Implementation & Usage
|
20
|
-
|
21
|
-
7. **[Implementation Guide](Implementation-Guide.md)** - Configuration, providers, and advanced usage
|
22
|
-
8. **[API Reference](API-Reference.md)** - Complete class and method documentation
|
23
|
-
|
24
|
-
### 🚀 Operations (As Needed)
|
25
|
-
|
26
|
-
9. **[Migrating Guide](Migrating-Guide.md)** - Upgrading existing fields _(coming soon)_
|
27
|
-
10. **[Key Management](Key-Management.md)** - Rotation and best practices _(coming soon)_
|
28
|
-
|
29
|
-
## 🚀 Quick Start Examples
|
30
|
-
|
31
|
-
### Encrypted Fields (Persistent)
|
32
|
-
```ruby
|
33
|
-
class User < Familia::Horreum
|
34
|
-
feature :encrypted_fields
|
35
|
-
encrypted_field :secret_recipe
|
36
|
-
end
|
37
|
-
|
38
|
-
# Configure encryption
|
39
|
-
Familia.configure do |config|
|
40
|
-
config.encryption_keys = { v1: ENV['FAMILIA_ENCRYPTION_KEY'] }
|
41
|
-
config.current_key_version = :v1
|
42
|
-
end
|
43
|
-
|
44
|
-
user = User.new(secret_recipe: "donna's cookies")
|
45
|
-
user.save
|
46
|
-
user.secret_recipe # => "donna's cookies" (automatically decrypted)
|
47
|
-
```
|
48
|
-
|
49
|
-
### Feature System (Modular)
|
50
|
-
```ruby
|
51
|
-
class Customer < Familia::Horreum
|
52
|
-
feature :safe_dump # API-safe serialization
|
53
|
-
feature :expiration # TTL support
|
54
|
-
feature :encrypted_fields # Secure storage
|
55
|
-
|
56
|
-
field :name, :email
|
57
|
-
encrypted_field :api_key
|
58
|
-
default_expiration 24.hours
|
59
|
-
safe_dump_fields :name, :email
|
60
|
-
end
|
61
|
-
```
|
62
|
-
|
63
|
-
### Connection Pooling (Performance)
|
64
|
-
```ruby
|
65
|
-
# Configure connection provider for multi-database pooling
|
66
|
-
Familia.connection_provider = lambda do |uri|
|
67
|
-
parsed = URI.parse(uri)
|
68
|
-
pool_key = "#{parsed.host}:#{parsed.port}/#{parsed.db || 0}"
|
69
|
-
|
70
|
-
@pools[pool_key] ||= ConnectionPool.new(size: 10) do
|
71
|
-
Redis.new(host: parsed.host, port: parsed.port, db: parsed.db || 0)
|
72
|
-
end
|
73
|
-
|
74
|
-
@pools[pool_key].with { |conn| conn }
|
75
|
-
end
|
76
|
-
```
|
77
|
-
|
78
|
-
### Object Relationships
|
79
|
-
```ruby
|
80
|
-
class Customer < Familia::Horreum
|
81
|
-
feature :relationships
|
82
|
-
identifier_field :custid
|
83
|
-
field :custid, :name, :email
|
84
|
-
|
85
|
-
# Customer collections
|
86
|
-
set :domains
|
87
|
-
end
|
88
|
-
|
89
|
-
class Domain < Familia::Horreum
|
90
|
-
feature :relationships
|
91
|
-
identifier_field :domain_id
|
92
|
-
field :domain_id, :name, :dns_zone
|
93
|
-
|
94
|
-
# Declare membership in customer collections
|
95
|
-
member_of Customer, :domains, type: :set
|
96
|
-
end
|
97
|
-
|
98
|
-
# Create objects and establish relationships
|
99
|
-
customer = Customer.new(custid: "cust123", name: "Acme Corp")
|
100
|
-
domain = Domain.new(domain_id: "dom456", name: "acme.com")
|
101
|
-
|
102
|
-
# Establish bidirectional relationship
|
103
|
-
domain.add_to_customer_domains(customer.custid)
|
104
|
-
customer.domains.add(domain.identifier)
|
105
|
-
|
106
|
-
# Query relationships
|
107
|
-
domain.in_customer_domains?(customer.custid) # => true
|
108
|
-
customer.domains.member?(domain.identifier) # => true
|
109
|
-
```
|
110
|
-
|
111
|
-
|
112
|
-
## Related Resources
|
113
|
-
|
114
|
-
- [Familia README](https://github.com/delano/familia) - Main project documentation
|
115
|
-
- [Issue #57](https://github.com/delano/familia/issues/57) - Original feature proposal
|
116
|
-
- [Issue #58](https://github.com/delano/familia/issues/58) - Wiki documentation tracking
|