familia 2.0.0.pre12 → 2.0.0.pre13

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +2 -3
  3. data/CHANGELOG.rst +507 -0
  4. data/CLAUDE.md +1 -1
  5. data/Gemfile +1 -6
  6. data/Gemfile.lock +13 -7
  7. data/changelog.d/README.md +5 -5
  8. data/{setup.cfg → changelog.d/scriv.ini} +1 -1
  9. data/docs/guides/Feature-System-Autoloading.md +228 -0
  10. data/docs/guides/time-utilities.md +221 -0
  11. data/docs/migrating/v2.0.0-pre11.md +14 -16
  12. data/docs/migrating/v2.0.0-pre13.md +329 -0
  13. data/examples/autoloader/mega_customer/safe_dump_fields.rb +6 -0
  14. data/examples/autoloader/mega_customer.rb +17 -0
  15. data/familia.gemspec +1 -0
  16. data/lib/familia/autoloader.rb +53 -0
  17. data/lib/familia/base.rb +5 -0
  18. data/lib/familia/data_type.rb +4 -0
  19. data/lib/familia/encryption/encrypted_data.rb +4 -4
  20. data/lib/familia/encryption/manager.rb +6 -4
  21. data/lib/familia/encryption.rb +1 -1
  22. data/lib/familia/errors.rb +3 -0
  23. data/lib/familia/features/autoloadable.rb +113 -0
  24. data/lib/familia/features/encrypted_fields/concealed_string.rb +4 -2
  25. data/lib/familia/features/expiration.rb +4 -0
  26. data/lib/familia/features/quantization.rb +5 -0
  27. data/lib/familia/features/safe_dump.rb +7 -0
  28. data/lib/familia/features.rb +20 -16
  29. data/lib/familia/field_type.rb +2 -0
  30. data/lib/familia/horreum/core/serialization.rb +3 -3
  31. data/lib/familia/horreum/subclass/definition.rb +3 -4
  32. data/lib/familia/horreum.rb +2 -0
  33. data/lib/familia/json_serializer.rb +70 -0
  34. data/lib/familia/logging.rb +12 -10
  35. data/lib/familia/refinements/logger_trace.rb +57 -0
  36. data/lib/familia/refinements/snake_case.rb +40 -0
  37. data/lib/familia/refinements/time_utils.rb +248 -0
  38. data/lib/familia/refinements.rb +3 -49
  39. data/lib/familia/utils.rb +2 -0
  40. data/lib/familia/validation/{test_helpers.rb → validation_helpers.rb} +2 -2
  41. data/lib/familia/validation.rb +1 -1
  42. data/lib/familia/version.rb +1 -1
  43. data/lib/familia.rb +15 -3
  44. data/try/core/autoloader_try.rb +112 -0
  45. data/try/core/extensions_try.rb +38 -21
  46. data/try/core/familia_extended_try.rb +4 -3
  47. data/try/core/time_utils_try.rb +130 -0
  48. data/try/data_types/datatype_base_try.rb +3 -2
  49. data/try/features/autoloadable/autoloadable_try.rb +61 -0
  50. data/try/features/encrypted_fields/concealed_string_core_try.rb +8 -3
  51. data/try/features/encrypted_fields/secure_by_default_behavior_try.rb +59 -17
  52. data/try/features/encrypted_fields/universal_serialization_safety_try.rb +36 -12
  53. data/try/features/feature_improvements_try.rb +2 -1
  54. data/try/features/real_feature_integration_try.rb +1 -1
  55. data/try/features/safe_dump/safe_dump_autoloading_try.rb +111 -0
  56. data/try/helpers/test_helpers.rb +24 -0
  57. data/try/integration/cross_component_try.rb +3 -1
  58. metadata +33 -6
  59. data/CHANGELOG.md +0 -247
  60. data/lib/familia/core_ext.rb +0 -135
  61. data/lib/familia/features/autoloader.rb +0 -57
data/CHANGELOG.md DELETED
@@ -1,247 +0,0 @@
1
- # CHANGELOG.md
2
-
3
- All notable changes to Familia are documented here.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- <!--scriv-insert-here-->
9
-
10
- <a id='changelog-2.0.0.pre12'></a>
11
- ## 2.0.0.pre12 — 2025-09-04
12
-
13
- ### Added
14
-
15
- - Added the `Familia::VerifiableIdentifier` module to create and verify identifiers with an embedded HMAC signature. This allows an application to stateless-ly confirm that an identifier was generated by itself, preventing forged IDs from malicious sources.
16
-
17
- - **Scoped VerifiableIdentifier**: Added `scope` parameter to `generate_verifiable_id()` and `verified_identifier?()` methods, enabling cryptographically isolated identifier namespaces for multi-tenant, multi-domain, or multi-environment applications while maintaining full backward compatibility with existing code.
18
-
19
- ### Changed
20
-
21
- - ObjectIdentifier feature now tracks which generator (uuid_v7, uuid_v4, hex, or custom) was used for each objid to provide provenance information for security-sensitive operations.
22
- - Updated external identifier derivation to normalize objid format based on the known generator type, eliminating format ambiguity between UUID and hex formats.
23
-
24
- - Refactored identifier generation methods for clarity and consistency. Method `generate_objid` is now `generate_object_identifier`, and `generate_external_identifier` is now `derive_external_identifier` to reflect its deterministic nature.
25
-
26
- ### Removed
27
-
28
- - Removed the `generate_extid` class method, which was less secure than the instance-level derivation logic.
29
-
30
- ### Security
31
-
32
- - Hardened external identifier derivation with provenance validation. ExternalIdentifier now validates that objid values come from the ObjectIdentifier feature before deriving external identifiers, preventing derivation from potentially malicious or unvalidated objid values while maintaining deterministic behavior for legitimate use cases.
33
-
34
- - Improved the security of external identifiers (`extid`) by using the internal object identifier (`objid`) as a seed for a new random value, rather than deriving the `extid` directly. This prevents potential information leakage from the internal `objid`.
35
-
36
- ### Documentation
37
-
38
- - Added detailed YARD documentation for `VerifiableIdentifier`, explaining how to securely generate and manage the required `VERIFIABLE_ID_HMAC_SECRET` key.
39
-
40
- ### AI Assistance
41
-
42
- - Security analysis of external identifier derivation and hardened design approach was discussed and developed with AI assistance, including provenance tracking, validation logic, format normalization, and comprehensive test updates.
43
-
44
- - Implementation of scoped verifiable identifiers was developed with AI assistance to ensure cryptographic security properties and comprehensive test coverage.
45
-
46
- <a id='changelog-2.0.0.pre11'></a>
47
- ## 2.0.0.pre11 - 2025-09-03
48
-
49
- ### Added
50
-
51
- - **Enhanced Feature System**: Introduced a hierarchical feature system with ancestry chain traversal for model-specific feature registration. This enables better organization, standardized naming, and automatic loading of project-specific features via the new `Familia::Features::Autoloader` module.
52
- - **Improved SafeDump DSL**: Replaced the internal `@safe_dump_fields` implementation with a cleaner, more robust DSL using `safe_dump_field` and `safe_dump_fields` methods.
53
- - Added `generate_short_id` and `shorten_securely` utility methods for creating short, secure identifiers, adapted from `OT::Utils::SecureNumbers`.
54
- - For a detailed guide on migrating to the new feature system, see `docs/migration/v2.0.0-pre11.md`.
55
-
56
- ### Changed
57
-
58
- - External identifier now raises an `ExternalIdentifierError` if the model does not have an objid field. Previously: returned nil. In practice this should never happen, since the external_identifier feature declares its dependency on object_identifier.
59
- - Moved lib/familia/encryption_request_cache.rb to lib/familia/encryption/request_cache.rb for consistency.
60
- - **Simplified ObjectIdentifier Feature Implementation**: Consolidated the ObjectIdentifier feature from two files (~190 lines) to a single file (~140 lines) by moving the ObjectIdentifierFieldType class inline. This reduces complexity while maintaining all existing functionality including lazy generation, data integrity preservation, and multiple generator strategies.
61
- - **Renamed Identifier Features to Singular Form**: Renamed `object_identifier` → `object_identifier` and `external_identifier` → `external_identifier` for more accurate naming. Added full-length aliases (`object_identifier`/`external_identifier`) alongside the short forms (`objid`/`extid`) for clarity when needed.
62
- - **Simplified ExternalIdentifier Feature Implementation**: Consolidated the ExternalIdentifier feature from two files (~240 lines) to a single file (~120 lines) by moving the ExternalIdentifierFieldType class inline, following the same pattern as ObjectIdentifier.
63
-
64
- ### Fixed
65
-
66
- - Fixed external identifier generation returning all zeros for UUID-based objids. The `shorten_to_external_id` method now correctly handles both 256-bit secure identifiers and 128-bit UUIDs by detecting input length and applying appropriate bit truncation only when needed.
67
-
68
- ### Security
69
-
70
- - Improved input validation in `shorten_to_external_id` method by replacing insecure character count checking with proper bit length calculation and explicit validation. Invalid inputs now raise clear error messages instead of being silently processed incorrectly.
71
-
72
- <a id='changelog-2.0.0-pre10'></a>
73
- ## 2.0.0-pre10 - 2025-09-02
74
-
75
- ### Added
76
-
77
- - The `Familia::Horreum` initializer now supports creating an object directly from its identifier by passing a single argument (e.g., `Customer.new(customer_id)`). This provides a more convenient and intuitive way to instantiate objects from lookups.
78
-
79
- - Automatic indexing and class-level tracking on `save()` operations, eliminating the need for manual index updates.
80
- - Enhanced collection syntax supports the Ruby-idiomatic `<<` operator for more natural relationship management.
81
-
82
- ### Changed
83
-
84
- - The `member_of` relationship is now bidirectional. A single call to `member.add_to_owner_collection(owner)` is sufficient to establish the relationship, removing the need for a second, redundant call on the owner object. This fixes bugs where members could be added to collections twice.
85
-
86
- - **BREAKING**: Refactored Familia Relationships API to remove "global" terminology and simplify method generation. (Closes #86)
87
- - Split `generate_indexing_instance_methods` into focused `generate_direct_index_methods` and `generate_relationship_index_methods` for better separation between direct class-level and relationship-based indexing.
88
- - Simplified method generation by removing complex global vs parent conditionals.
89
- - All indexes are now stored at the class level for consistency.
90
-
91
- ### Fixed
92
-
93
- - Fixed a bug in the `class_indexed_by` feature where finder methods (e.g., `find_by_email`) would fail to correctly instantiate objects from the index, returning partially-formed objects.
94
-
95
- - Refactored connection handling to properly cache and reuse Redis connections. This eliminates repetitive "Overriding existing connection" warnings and improves performance.
96
-
97
- - Method generation now works consistently for both `class_indexed_by` and `indexed_by` with a `parent:`.
98
- - Resolved metadata storage issues for dynamically created classes.
99
- - Improved error handling for nil class names in tracking relationships.
100
-
101
- ### Documentation
102
-
103
- - Updated the `examples/relationships_basic.rb` script to reflect the improved, bidirectional `member_of` API and to ensure a clean database state for each run.
104
-
105
- ### AI Assistance
106
-
107
- - This refactoring was implemented with Claude Code assistance, including comprehensive test updates and API modernization.
108
-
109
- <a id='changelog-2.0.0-pre9'></a>
110
- ## 2.0.0-pre9 - 2025-09-02
111
-
112
- ### Added
113
-
114
- - Added `class_tracked_in` method for global tracking relationships following Horreum's established `class_` prefix convention
115
- - Added `class_indexed_by` method for global index relationships with consistent API design
116
-
117
- ### Changed
118
-
119
- - **BREAKING**: `tracked_in :global, collection` syntax now raises ArgumentError - use `class_tracked_in collection` instead
120
- - **BREAKING**: `indexed_by field, index, context: :global` syntax replaced with `class_indexed_by field, index`
121
- - **BREAKING**: `indexed_by field, index, context: SomeClass` syntax replaced with `indexed_by field, index, parent: SomeClass`
122
- - Relationships API now provides consistent parameter naming across all relationship types
123
-
124
- ### Documentation
125
-
126
- - Updated Relationships Guide with new API syntax and migration examples
127
- - Updated relationships method documentation with new method signatures
128
- - Updated basic relationships example to demonstrate new API patterns
129
- - Added tryouts test coverage in try/features/relationships/relationships_api_changes_try.rb
130
-
131
-
132
- <a id='changelog-2.0.0-pre8'></a>
133
- ## 2.0.0-pre8 - 2025-09-01
134
-
135
- ### Added
136
-
137
- - Implemented Scriv-based changelog system for sustainable documentation
138
- - Added fragment-based workflow for tracking changes
139
- - Created structured changelog templates and configuration
140
-
141
- ### Documentation
142
-
143
- - Set up Scriv configuration and directory structure
144
- - Created README for changelog fragment workflow
145
-
146
- <!-- scriv-end-here -->
147
-
148
- <a id='changelog-2.0.0-pre7'></a>
149
- ## 2.0.0-pre7 - 2025-08-31
150
-
151
- ### Added
152
-
153
- - Comprehensive relationships system with three relationship types:
154
- - `tracked_in` - Multi-presence tracking with score encoding
155
- - `indexed_by` - O(1) hash-based lookups
156
- - `member_of` - Bidirectional membership with collision-free naming
157
- - Categorical permission system with bit-encoded permissions
158
- - Time-based permission scoring for temporal access control
159
- - Permission tier hierarchies with inheritance patterns
160
- - Scalable permission management for large object collections
161
- - Score-based sorting with custom scoring functions
162
- - Permission-aware queries filtering by access levels
163
- - Relationship validation framework ensuring data integrity
164
-
165
- ### Changed
166
-
167
- - Performance optimizations for large-scale relationship operations
168
-
169
- ### Security
170
-
171
- - GitHub Actions security hardening with matrix optimization
172
-
173
-
174
- <a id='changelog-2.0.0-pre6'></a>
175
- ## 2.0.0-pre6 - 2025-08-15
176
-
177
- ### Added
178
-
179
- - New `save_if_not_exists` method for conditional persistence
180
- - Atomic persistence operations with transaction support
181
- - Enhanced error handling for persistence failures
182
- - Improved data consistency guarantees
183
-
184
- ### Changed
185
-
186
- - Connection provider pattern for flexible pooling strategies
187
- - Multi-database support with intelligent pool management
188
- - Thread-safe connection handling for concurrent applications
189
- - Configurable pool sizing and timeout management
190
- - Modular class structure with cleaner separation of concerns
191
- - Enhanced feature system with dependency management
192
- - Improved inheritance patterns for better code organization
193
- - Streamlined base class functionality
194
-
195
- ### Fixed
196
-
197
- - Critical security fixes in Ruby workflow vulnerabilities
198
- - Systematic dependency resolution via multi-constraint optimization
199
-
200
-
201
- <a id='changelog-2.0.0-pre5'></a>
202
- ## 2.0.0-pre5 - 2025-08-05
203
-
204
- ### Added
205
-
206
- - Field-level encryption with transparent access patterns
207
- - Multiple encryption providers:
208
- - XChaCha20-Poly1305 (preferred, requires rbnacl)
209
- - AES-256-GCM (fallback, OpenSSL-based)
210
- - Field-specific key derivation for cryptographic domain separation
211
- - Configurable key versioning supporting key rotation
212
- - Non-persistent field storage for sensitive runtime data
213
- - RedactedString wrapper preventing accidental logging/serialization
214
- - Memory-safe handling of sensitive data in Ruby objects
215
- - API-safe serialization excluding transient fields
216
-
217
- ### Security
218
-
219
- - Encryption field security hardening with additional validation
220
- - Enhanced memory protection for sensitive data handling
221
- - Improved key management patterns and best practices
222
- - Security test suite expansion with comprehensive coverage
223
-
224
-
225
- <a id='changelog-2.0.0-pre'></a>
226
- ## 2.0.0-pre - 2025-07-25
227
-
228
- ### Added
229
-
230
- - Complete API redesign for clarity and modern Ruby conventions
231
- - Valkey compatibility alongside traditional Redis support
232
- - Ruby 3.4+ modernization with fiber and thread safety improvements
233
- - Connection pooling foundation with provider pattern architecture
234
-
235
- ### Changed
236
-
237
- - `Familia::Base` replaced by `Familia::Horreum` as the primary base class
238
- - Connection configuration moved from simple string to block-based setup
239
- - Feature activation changed from `include` to `feature` declarations
240
- - Method naming updated for consistency (`delete` → `destroy`, `exists` → `exists?`, `dump` → `serialize`)
241
-
242
- ### Documentation
243
-
244
- - YARD documentation workflow with automated GitHub Pages deployment
245
- - Comprehensive migrating guide for v1.x to v2.0.0-pre transition
246
-
247
- <!-- scriv-end-here -->
@@ -1,135 +0,0 @@
1
- # lib/familia/core_ext.rb
2
-
3
- # Extends the String class with time-related functionality
4
- #
5
- # This implementaton assumes Time::Units and Numeric mixins are available.
6
- #
7
- class String
8
- # Converts a string representation of time to seconds
9
- #
10
- # @example
11
- # "60m".in_seconds #=> 3600.0
12
- #
13
- # @return [Float, nil] The time in seconds, or nil if the string is invalid
14
- def in_seconds
15
- q, u = scan(/([\d.]+)([smhyd])?/).flatten
16
- q &&= q.to_f and u ||= 's'
17
- q&.in_seconds(u)
18
- end
19
- end
20
-
21
- # Extends the Time class with additional time unit functionality
22
- class Time
23
- # Provides methods for working with various time units
24
- module Units
25
- # rubocop:disable Style/SingleLineMethods, Layout/ExtraSpacing
26
-
27
- PER_MICROSECOND = 0.000001
28
- PER_MILLISECOND = 0.001
29
- PER_MINUTE = 60.0
30
- PER_HOUR = 3600.0
31
- PER_DAY = 86_400.0
32
-
33
- # Conversion methods
34
- #
35
- # From other time units -> seconds
36
- #
37
- def microseconds() seconds * PER_MICROSECOND end
38
- def milliseconds() seconds * PER_MILLISECOND end
39
- def seconds() self end
40
- def minutes() seconds * PER_MINUTE end
41
- def hours() seconds * PER_HOUR end
42
- def days() seconds * PER_DAY end
43
- def weeks() seconds * PER_DAY * 7 end
44
- def years() seconds * PER_DAY * 365 end
45
-
46
- # From seconds -> other time units
47
- #
48
- def in_years() seconds / PER_DAY / 365 end
49
- def in_weeks() seconds / PER_DAY / 7 end
50
- def in_days() seconds / PER_DAY end
51
- def in_hours() seconds / PER_HOUR end
52
- def in_minutes() seconds / PER_MINUTE end
53
- def in_milliseconds() seconds / PER_MILLISECOND end
54
- def in_microseconds() seconds / PER_MICROSECOND end
55
-
56
- #
57
- # Converts seconds to a Time object
58
- #
59
- # @return [Time] A Time object representing the seconds
60
- def in_time
61
- Time.at(self).utc
62
- end
63
-
64
- # Converts seconds to the specified time unit
65
- #
66
- # @param u [String, Symbol] The unit to convert to (e.g., 'y', 'w', 'd', 'h', 'm', 'ms', 'us')
67
- # @return [Float] The converted time value
68
- def in_seconds(u = nil)
69
- case u.to_s
70
- when /\A(y)|(years?)\z/
71
- years
72
- when /\A(w)|(weeks?)\z/
73
- weeks
74
- when /\A(d)|(days?)\z/
75
- days
76
- when /\A(h)|(hours?)\z/
77
- hours
78
- when /\A(m)|(minutes?)\z/
79
- minutes
80
- when /\A(ms)|(milliseconds?)\z/
81
- milliseconds
82
- when /\A(us)|(microseconds?)|(μs)\z/
83
- microseconds
84
- else
85
- self
86
- end
87
- end
88
-
89
- # Starring Jennifer Garner, Victor Garber, and Carl Lumbly
90
- alias ms milliseconds
91
- alias μs microseconds
92
- alias second seconds
93
- alias minute minutes
94
- alias hour hours
95
- alias day days
96
- alias week weeks
97
- alias year years
98
-
99
- # rubocop:enable Style/SingleLineMethods, Layout/ExtraSpacing
100
- end
101
- end
102
-
103
- # Extends the Numeric class with time unit and byte conversion functionality
104
- class Numeric
105
- include Time::Units
106
-
107
- # Converts the number to milliseconds
108
- #
109
- # @return [Float] The number in milliseconds
110
- def to_ms
111
- (self * 1000.to_f)
112
- end
113
-
114
- # Converts the number to a human-readable byte representation using binary units
115
- #
116
- # @return [String] A string representing the number in bytes, KiB, MiB, GiB, or TiB
117
- #
118
- # @example
119
- # 1024.to_bytes #=> "1.00 KiB"
120
- # 2_097_152.to_bytes #=> "2.00 MiB"
121
- # 3_221_225_472.to_bytes #=> "3.00 GiB"
122
- #
123
- def to_bytes
124
- units = %w[B KiB MiB GiB TiB]
125
- size = abs.to_f
126
- unit = 0
127
-
128
- while size >= 1024 && unit < units.length - 1
129
- size /= 1024
130
- unit += 1
131
- end
132
-
133
- format('%3.2f %s', size, units[unit])
134
- end
135
- end
@@ -1,57 +0,0 @@
1
- # lib/familia/features/autoloader.rb
2
-
3
- module Familia
4
- module Features
5
- # Autoloader is a mixin that automatically loads feature files from a 'features'
6
- # subdirectory when included. This provides a standardized way to organize and
7
- # auto-load project-specific features.
8
- #
9
- # When included in a module, it automatically:
10
- # 1. Determines the directory containing the module file
11
- # 2. Looks for a 'features' subdirectory in that location
12
- # 3. Loads all *.rb files from that features directory
13
- #
14
- # Example usage:
15
- #
16
- # # apps/api/v2/models/customer/features.rb
17
- # module V2
18
- # class Customer < Familia::Horreum
19
- # module Features
20
- # include Familia::Features::Autoloader
21
- # # Automatically loads all files from customer/features/
22
- # end
23
- # end
24
- # end
25
- #
26
- # This would automatically load:
27
- # - apps/api/v2/models/customer/features/deprecated_fields.rb
28
- # - apps/api/v2/models/customer/features/legacy_support.rb
29
- # - etc.
30
- #
31
- module Autoloader
32
- def self.included(_base)
33
- # Get the file path of the module that's including us.
34
- # `caller_locations(1, 1).first` gives us the location where `include` was called.
35
- # This is a robust way to find the file path, especially for anonymous modules.
36
- calling_location = caller_locations(1, 1)&.first
37
- return unless calling_location
38
-
39
- including_file = calling_location.path
40
-
41
- # Find the features directory relative to the including file
42
- features_dir = File.join(File.dirname(including_file), 'features')
43
-
44
- Familia.ld "[DEBUG] Autoloader: Looking for features in #{features_dir}"
45
-
46
- if Dir.exist?(features_dir)
47
- Dir.glob(File.join(features_dir, '*.rb')).each do |feature_file|
48
- Familia.ld "[DEBUG] Autoloader: Loading feature #{feature_file}"
49
- require feature_file
50
- end
51
- else
52
- Familia.ld "[DEBUG] Autoloader: No features directory found at #{features_dir}"
53
- end
54
- end
55
- end
56
- end
57
- end