synthra 0.1.0
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 +7 -0
- data/.rspec +4 -0
- data/.rubocop.yml +40 -0
- data/.yardopts +18 -0
- data/ACCESS_DOCS.md +116 -0
- data/ADVANCED_FEATURES_SUMMARY.md +245 -0
- data/CHANGELOG.md +498 -0
- data/CODE_OF_CONDUCT.md +122 -0
- data/CONTRIBUTING.md +307 -0
- data/DOCUMENTATION.md +204 -0
- data/DOCUMENTATION_GUIDE.md +194 -0
- data/LICENSE +22 -0
- data/README.md +1458 -0
- data/Rakefile +128 -0
- data/benchmark/README.md +591 -0
- data/benchmark/batch_generation.rb +63 -0
- data/benchmark/engine_comparison.rb +295 -0
- data/benchmark/single_record.rb +108 -0
- data/benchmark/streaming.rb +74 -0
- data/docs/ACTIVERECORD_INFERENCE.md +524 -0
- data/docs/API_SERVER.md +278 -0
- data/docs/CONFIG_FILE.md +315 -0
- data/docs/DATA_CONTRACTS.md +312 -0
- data/docs/ENHANCED_REPL.md +304 -0
- data/docs/FACTORY_BOT.md +271 -0
- data/docs/GITHUB_ACTION.md +420 -0
- data/docs/GRAPHQL_EXPORT.md +303 -0
- data/docs/GRAPHQL_FEDERATION.md +651 -0
- data/docs/HOW_TO_GENERATE_DOCS.md +252 -0
- data/docs/LSP.md +189 -0
- data/docs/MIGRATION_GENERATOR.md +547 -0
- data/docs/MOCK_SERVER.md +280 -0
- data/docs/NATIVE_ENGINE.md +298 -0
- data/docs/OPENAPI_EXPORT.md +252 -0
- data/docs/PERFORMANCE_MODE.md +228 -0
- data/docs/PERSONAS.md +547 -0
- data/docs/PROPERTY_TESTING.md +284 -0
- data/docs/PROTOBUF_EXPORT.md +276 -0
- data/docs/QUALITY_METRICS.md +555 -0
- data/docs/QUICK_REFERENCE.md +88 -0
- data/docs/RAILS_ENGINE.md +404 -0
- data/docs/RAILS_INTEGRATION.md +454 -0
- data/docs/README.md +175 -0
- data/docs/REPL_QUICK_REFERENCE.md +149 -0
- data/docs/RUST_INTEGRATION_GUIDE.md +1376 -0
- data/docs/SCENARIOS.md +576 -0
- data/docs/SECURITY_TESTING.md +318 -0
- data/docs/SNAPSHOT_TESTING.md +308 -0
- data/docs/STRING_TEXT_TYPES_REFERENCE.md +512 -0
- data/docs/TERRAFORM_EXPORT.md +447 -0
- data/docs/TIME_TRAVEL.md +507 -0
- data/docs/USAGE_GUIDE.md +980 -0
- data/docs/WEBHOOK_SIMULATOR.md +579 -0
- data/docs/advanced_features.md +183 -0
- data/docs/api_reference.md +153 -0
- data/docs/behaviors.md +138 -0
- data/docs/best_practices.md +191 -0
- data/docs/dsl_reference.md +172 -0
- data/docs/examples.md +162 -0
- data/docs/generation_modes.md +125 -0
- data/docs/getting_started.md +92 -0
- data/docs/index.html +177 -0
- data/docs/strategic/CLOUD_REGISTRY_ARCHITECTURE.md +268 -0
- data/docs/strategic/SIMD_OPTIMIZATION_STRATEGY.md +153 -0
- data/docs/troubleshooting.md +215 -0
- data/docs/type_reference.md +224 -0
- data/examples/hostile_mode_demo.rb +64 -0
- data/exe/synthra +6 -0
- data/ext/synthra_native/Cargo.lock +972 -0
- data/ext/synthra_native/Cargo.toml +46 -0
- data/ext/synthra_native/extconf.rb +41 -0
- data/ext/synthra_native/src/generator.rs +397 -0
- data/ext/synthra_native/src/lib.rs +229 -0
- data/ext/synthra_native/src/types.rs +1485 -0
- data/lib/generators/synthra/install_generator.rb +86 -0
- data/lib/generators/synthra/templates/api_response.dsl +15 -0
- data/lib/generators/synthra/templates/fake_data.rake +116 -0
- data/lib/generators/synthra/templates/synthra.yml +31 -0
- data/lib/generators/synthra/templates/synthra_support.rb +19 -0
- data/lib/generators/synthra/templates/user.dsl +11 -0
- data/lib/synthra/activerecord_inference.rb +394 -0
- data/lib/synthra/api.rb +381 -0
- data/lib/synthra/api_server.rb +718 -0
- data/lib/synthra/behaviors/applicator.rb +165 -0
- data/lib/synthra/behaviors/base.rb +155 -0
- data/lib/synthra/behaviors/close_connection.rb +60 -0
- data/lib/synthra/behaviors/deprecated.rb +100 -0
- data/lib/synthra/behaviors/failure.rb +69 -0
- data/lib/synthra/behaviors/latency.rb +103 -0
- data/lib/synthra/behaviors/partial_data.rb +83 -0
- data/lib/synthra/behaviors/randomize_order.rb +74 -0
- data/lib/synthra/behaviors/registry.rb +238 -0
- data/lib/synthra/behaviors/simulate_error.rb +79 -0
- data/lib/synthra/cli/commands/base.rb +105 -0
- data/lib/synthra/cli/commands/diff.rb +227 -0
- data/lib/synthra/cli/commands/docs.rb +67 -0
- data/lib/synthra/cli/commands/export.rb +150 -0
- data/lib/synthra/cli/commands/generate.rb +72 -0
- data/lib/synthra/cli/commands/import.rb +80 -0
- data/lib/synthra/cli/commands/lint.rb +53 -0
- data/lib/synthra/cli/commands/live.rb +57 -0
- data/lib/synthra/cli/commands/seed.rb +99 -0
- data/lib/synthra/cli/commands/validate.rb +28 -0
- data/lib/synthra/cli.rb +2471 -0
- data/lib/synthra/config_file.rb +129 -0
- data/lib/synthra/configuration.rb +281 -0
- data/lib/synthra/contracts_registry.rb +408 -0
- data/lib/synthra/database_seeder.rb +268 -0
- data/lib/synthra/deterministic_ids.rb +218 -0
- data/lib/synthra/documentation_generator.rb +414 -0
- data/lib/synthra/engine.rb +251 -0
- data/lib/synthra/errors.rb +1169 -0
- data/lib/synthra/export/base.rb +85 -0
- data/lib/synthra/export/csv.rb +101 -0
- data/lib/synthra/export/graphql.rb +266 -0
- data/lib/synthra/export/graphql_federation.rb +377 -0
- data/lib/synthra/export/graphviz.rb +258 -0
- data/lib/synthra/export/javascript.rb +327 -0
- data/lib/synthra/export/json_data.rb +61 -0
- data/lib/synthra/export/json_schema.rb +290 -0
- data/lib/synthra/export/openapi.rb +514 -0
- data/lib/synthra/export/protobuf.rb +483 -0
- data/lib/synthra/export/python.rb +560 -0
- data/lib/synthra/export/sql.rb +381 -0
- data/lib/synthra/export/sql_insert.rb +152 -0
- data/lib/synthra/export/terraform.rb +501 -0
- data/lib/synthra/export/type_mapping.rb +389 -0
- data/lib/synthra/export/typescript.rb +300 -0
- data/lib/synthra/export/xml_data.rb +104 -0
- data/lib/synthra/export/yaml_data.rb +56 -0
- data/lib/synthra/export.rb +404 -0
- data/lib/synthra/factory_bot_integration.rb +157 -0
- data/lib/synthra/field.rb +440 -0
- data/lib/synthra/functions/registry.rb +104 -0
- data/lib/synthra/generator/context.rb +372 -0
- data/lib/synthra/generator/engine.rb +336 -0
- data/lib/synthra/generator/faker_adapter.rb +425 -0
- data/lib/synthra/generator/modes.rb +444 -0
- data/lib/synthra/generator/resolver.rb +256 -0
- data/lib/synthra/generator/rng.rb +273 -0
- data/lib/synthra/generator/streamer.rb +63 -0
- data/lib/synthra/generator/uniqueness.rb +118 -0
- data/lib/synthra/initializer.rb +97 -0
- data/lib/synthra/limits.rb +279 -0
- data/lib/synthra/live_preview.rb +518 -0
- data/lib/synthra/loader_config.rb +78 -0
- data/lib/synthra/lsp/server.rb +689 -0
- data/lib/synthra/migration_generator.rb +301 -0
- data/lib/synthra/mixin.rb +174 -0
- data/lib/synthra/mock_server.rb +458 -0
- data/lib/synthra/native_engine.rb +304 -0
- data/lib/synthra/openapi_importer.rb +228 -0
- data/lib/synthra/output/json_formatter.rb +40 -0
- data/lib/synthra/output/ndjson_formatter.rb +55 -0
- data/lib/synthra/parser/ast.rb +1287 -0
- data/lib/synthra/parser/lexer.rb +1152 -0
- data/lib/synthra/parser/parser.rb +1664 -0
- data/lib/synthra/parser/tokens.rb +461 -0
- data/lib/synthra/performance_mode.rb +364 -0
- data/lib/synthra/personas.rb +397 -0
- data/lib/synthra/property_testing.rb +172 -0
- data/lib/synthra/quality_metrics.rb +405 -0
- data/lib/synthra/rails_test_helper.rb +248 -0
- data/lib/synthra/registry.rb +533 -0
- data/lib/synthra/relationships.rb +193 -0
- data/lib/synthra/repl/enhanced_repl.rb +607 -0
- data/lib/synthra/repl/formatter.rb +191 -0
- data/lib/synthra/scenarios.rb +423 -0
- data/lib/synthra/schema.rb +605 -0
- data/lib/synthra/schema_inheritance.rb +104 -0
- data/lib/synthra/schema_versioning.rb +212 -0
- data/lib/synthra/snapshot_testing.rb +199 -0
- data/lib/synthra/time_travel.rb +338 -0
- data/lib/synthra/type_definitions.rb +274 -0
- data/lib/synthra/types/address_location/addresses.rb +125 -0
- data/lib/synthra/types/address_location/airports.rb +200 -0
- data/lib/synthra/types/address_location/banks_hospitals.rb +207 -0
- data/lib/synthra/types/address_location/locations.rb +406 -0
- data/lib/synthra/types/base.rb +48 -0
- data/lib/synthra/types/commerce_products/commerce.rb +119 -0
- data/lib/synthra/types/commerce_products/companies.rb +71 -0
- data/lib/synthra/types/commerce_products/construction.rb +126 -0
- data/lib/synthra/types/commerce_products/products.rb +205 -0
- data/lib/synthra/types/core/collections.rb +513 -0
- data/lib/synthra/types/core/defaults.rb +76 -0
- data/lib/synthra/types/core/enums.rb +102 -0
- data/lib/synthra/types/core/identifiers.rb +445 -0
- data/lib/synthra/types/core/primitives.rb +586 -0
- data/lib/synthra/types/core/references.rb +466 -0
- data/lib/synthra/types/core/sequences.rb +304 -0
- data/lib/synthra/types/crypto/crypto.rb +162 -0
- data/lib/synthra/types/date_time/dates.rb +387 -0
- data/lib/synthra/types/finance_banking/banking.rb +424 -0
- data/lib/synthra/types/finance_banking/credit_cards.rb +24 -0
- data/lib/synthra/types/finance_banking/identifiers.rb +93 -0
- data/lib/synthra/types/formula.rb +184 -0
- data/lib/synthra/types/health_medical/medical.rb +150 -0
- data/lib/synthra/types/hostile_payloads.rb +122 -0
- data/lib/synthra/types/json_array.rb +51 -0
- data/lib/synthra/types/media_entertainment/media.rb +62 -0
- data/lib/synthra/types/naughty_string.rb +30 -0
- data/lib/synthra/types/personal_names/chinese.rb +41 -0
- data/lib/synthra/types/personal_names/identifiers.rb +187 -0
- data/lib/synthra/types/personal_names/names.rb +246 -0
- data/lib/synthra/types/personal_names/national_id.rb +89 -0
- data/lib/synthra/types/personal_names/titles_suffixes.rb +41 -0
- data/lib/synthra/types/regex.rb +248 -0
- data/lib/synthra/types/registry.rb +182 -0
- data/lib/synthra/types/repeating_element.rb +50 -0
- data/lib/synthra/types/scenario.rb +29 -0
- data/lib/synthra/types/technology_internet/apps.rb +67 -0
- data/lib/synthra/types/technology_internet/communication.rb +162 -0
- data/lib/synthra/types/technology_internet/devices.rb +80 -0
- data/lib/synthra/types/technology_internet/formats.rb +139 -0
- data/lib/synthra/types/technology_internet/networking.rb +143 -0
- data/lib/synthra/types/template.rb +92 -0
- data/lib/synthra/types/text_content/business.rb +128 -0
- data/lib/synthra/types/text_content/colors.rb +70 -0
- data/lib/synthra/types/text_content/misc.rb +237 -0
- data/lib/synthra/types/text_content/security.rb +130 -0
- data/lib/synthra/types/text_content/text_generation.rb +532 -0
- data/lib/synthra/types/travel/travel.rb +150 -0
- data/lib/synthra/utils/string_distance.rb +133 -0
- data/lib/synthra/validator/dsl_validator.rb +339 -0
- data/lib/synthra/validator/path_validator.rb +615 -0
- data/lib/synthra/version.rb +35 -0
- data/lib/synthra/webhook_simulator.rb +341 -0
- data/lib/synthra.rb +259 -0
- data/schemas/address.dsl +16 -0
- data/schemas/api_response.dsl +8 -0
- data/schemas/error_payload.dsl +9 -0
- data/schemas/order.dsl +10 -0
- data/schemas/order_item.dsl +8 -0
- data/schemas/payment.dsl +11 -0
- data/schemas/social_post.dsl +13 -0
- data/schemas/user.dsl +10 -0
- data/scripts/batch_fix_all.rb +96 -0
- data/scripts/delete_old_files.rb +32 -0
- data/scripts/fix_all_grouped_files.rb +137 -0
- data/scripts/fix_all_indentation.rb +48 -0
- data/scripts/fix_all_syntax.rb +124 -0
- data/scripts/fix_grouped_files.rb +184 -0
- data/scripts/fix_syntax_errors.rb +108 -0
- data/scripts/group_domain_types.rb +112 -0
- data/scripts/group_domain_types_fixed.rb +150 -0
- data/scripts/merge_domains_to_one_file.rb +68 -0
- data/scripts/move_existing_types.rb +130 -0
- data/scripts/split_grouped_types.rb +142 -0
- data/tech_docs/README.md +134 -0
- data/tech_docs/advanced/streaming.md +405 -0
- data/tech_docs/advanced/thread_safety.md +253 -0
- data/tech_docs/api/overview.md +485 -0
- data/tech_docs/appendices/type_chart.md +193 -0
- data/tech_docs/basic_concepts.md +383 -0
- data/tech_docs/behaviors/overview.md +346 -0
- data/tech_docs/dsl/complex_types.md +790 -0
- data/tech_docs/dsl/core_types.md +464 -0
- data/tech_docs/dsl/datetime_types.md +325 -0
- data/tech_docs/dsl/field_modifiers.md +414 -0
- data/tech_docs/dsl/grammar.md +431 -0
- data/tech_docs/dsl/schema_definition.md +399 -0
- data/tech_docs/export/README.md +276 -0
- data/tech_docs/installation.md +273 -0
- data/tech_docs/integration/ci_cd.md +707 -0
- data/tech_docs/integration/ci_cd_guide.md +579 -0
- data/tech_docs/integration/factory_bot.md +485 -0
- data/tech_docs/integration/rails.md +630 -0
- data/tech_docs/integration/rspec.md +449 -0
- data/tech_docs/modes/overview.md +350 -0
- data/tech_docs/performance/NATIVE_RUST_EXTENSION.md +1270 -0
- data/tech_docs/performance/OPTIMIZATION_GUIDE.md +901 -0
- data/tech_docs/quick_start.md +256 -0
- data/tech_docs/templates/README.md +805 -0
- data/tech_docs/tutorials/advanced.md +371 -0
- data/tech_docs/tutorials/getting_started.md +189 -0
- data/tech_docs/tutorials/intermediate.md +231 -0
- data/tech_docs/tutorials/template_gallery.md +569 -0
- data/tech_example/01_basic_usage.rb +238 -0
- data/tech_example/02_types_demo.rb +336 -0
- data/tech_example/04_cli_usage.md +429 -0
- data/tech_example/05_database_seeding.rb +283 -0
- data/tech_example/07_rspec_integration.rb +359 -0
- data/tech_example/10_custom_types.rb +387 -0
- data/tech_example/12_behaviors.rb +372 -0
- data/tech_example/13_twitter_dm_example.rb +120 -0
- data/tech_example/14_exact_json_structure.rb +253 -0
- data/tech_example/16_lsp_server.rb +56 -0
- data/tech_example/17_property_testing.rb +92 -0
- data/tech_example/18_enhanced_repl.rb +120 -0
- data/tech_example/19_security_fuzzing.rb +145 -0
- data/tech_example/NEW_FEATURES.md +169 -0
- data/tech_example/README.md +118 -0
- data/tech_example/schemas/api_response.dsl +123 -0
- data/tech_example/schemas/ecommerce.dsl +121 -0
- data/tech_example/schemas/twitter_dm.dsl +109 -0
- data/tech_example/schemas/user.dsl +36 -0
- data/vscode-extension/README.md +246 -0
- data/vscode-extension/language-configuration.json +31 -0
- data/vscode-extension/package.json +55 -0
- data/vscode-extension/snippets/fakedatadsl.json +198 -0
- data/vscode-extension/syntaxes/fakedatadsl.tmLanguage.json +128 -0
- metadata +478 -0
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
# Data Quality Metrics
|
|
2
|
+
|
|
3
|
+
FakeDataDSL's Quality Metrics feature analyzes your generated data for **realism, uniqueness, distribution, and completeness**. Get actionable insights into how realistic and diverse your test data is.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
# Generate data with quality report
|
|
9
|
+
result = FakeDataDSL.generate_with_quality("User", count: 1000)
|
|
10
|
+
|
|
11
|
+
# Access the data
|
|
12
|
+
result.data # => Array of 1000 user records
|
|
13
|
+
|
|
14
|
+
# Access the quality report
|
|
15
|
+
result.quality_report
|
|
16
|
+
# => {
|
|
17
|
+
# uniqueness: { id: 100%, email: 100%, name: 85% },
|
|
18
|
+
# distribution: { role: { admin: 5%, user: 95% } },
|
|
19
|
+
# completeness: 98.5%,
|
|
20
|
+
# realism_score: 94
|
|
21
|
+
# }
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Basic Usage
|
|
25
|
+
|
|
26
|
+
### Generate with Quality Analysis
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
result = FakeDataDSL::QualityMetrics.generate_with_quality("Order",
|
|
30
|
+
count: 500,
|
|
31
|
+
seed: 42
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
puts result.quality_report.summary
|
|
35
|
+
# Uniqueness: 98.2%
|
|
36
|
+
# Completeness: 96.5%
|
|
37
|
+
# Distribution: balanced
|
|
38
|
+
# Realism: 92/100
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Analyze Existing Data
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
# Analyze data you've already generated
|
|
45
|
+
data = FakeDataDSL.generate_many("Product", 1000)
|
|
46
|
+
report = FakeDataDSL::QualityMetrics.analyze(data, schema: "Product")
|
|
47
|
+
|
|
48
|
+
report.issues # => Array of quality issues
|
|
49
|
+
report.suggestions # => How to improve data quality
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Quality Metrics
|
|
53
|
+
|
|
54
|
+
### Uniqueness
|
|
55
|
+
|
|
56
|
+
Measures how unique values are across records:
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
report.uniqueness
|
|
60
|
+
# => {
|
|
61
|
+
# id: 100.0, # 100% unique (good for IDs)
|
|
62
|
+
# email: 100.0, # 100% unique (as expected)
|
|
63
|
+
# name: 85.3, # 85% unique (some duplicates)
|
|
64
|
+
# country: 12.5, # 12.5% unique (expected for enums)
|
|
65
|
+
# status: 3.3 # 3.3% unique (only 3 possible values)
|
|
66
|
+
# }
|
|
67
|
+
|
|
68
|
+
# Check specific field
|
|
69
|
+
report.uniqueness_for(:email) # => 100.0
|
|
70
|
+
|
|
71
|
+
# Fields that should be unique
|
|
72
|
+
report.uniqueness_violations
|
|
73
|
+
# => [:name] # name has @unique annotation but has duplicates
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Distribution
|
|
77
|
+
|
|
78
|
+
Analyzes value distribution for enum-like fields:
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
report.distribution
|
|
82
|
+
# => {
|
|
83
|
+
# role: {
|
|
84
|
+
# "user" => 0.85, # 85% are regular users
|
|
85
|
+
# "admin" => 0.10, # 10% are admins
|
|
86
|
+
# "moderator" => 0.05 # 5% are moderators
|
|
87
|
+
# },
|
|
88
|
+
# status: {
|
|
89
|
+
# "active" => 0.70,
|
|
90
|
+
# "pending" => 0.20,
|
|
91
|
+
# "suspended" => 0.10
|
|
92
|
+
# }
|
|
93
|
+
# }
|
|
94
|
+
|
|
95
|
+
# Check if distribution matches expected
|
|
96
|
+
report.distribution_balanced?(:role) # => true/false
|
|
97
|
+
|
|
98
|
+
# Get distribution statistics
|
|
99
|
+
report.distribution_stats(:role)
|
|
100
|
+
# => {
|
|
101
|
+
# entropy: 0.85, # Information entropy (higher = more diverse)
|
|
102
|
+
# chi_squared: 2.34, # Chi-squared statistic
|
|
103
|
+
# is_uniform: false, # Whether uniformly distributed
|
|
104
|
+
# dominant_value: "user" # Most common value
|
|
105
|
+
# }
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Completeness
|
|
109
|
+
|
|
110
|
+
Measures how many optional fields are populated:
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
report.completeness
|
|
114
|
+
# => 98.5 # 98.5% of optional fields have values
|
|
115
|
+
|
|
116
|
+
report.completeness_by_field
|
|
117
|
+
# => {
|
|
118
|
+
# bio: 95.0, # 95% of records have bio
|
|
119
|
+
# avatar_url: 88.2, # 88.2% have avatar
|
|
120
|
+
# phone: 72.0, # 72% have phone
|
|
121
|
+
# middle_name: 45.5 # 45.5% have middle name
|
|
122
|
+
# }
|
|
123
|
+
|
|
124
|
+
# Fields with low completeness
|
|
125
|
+
report.sparse_fields(threshold: 50)
|
|
126
|
+
# => [:middle_name] # Less than 50% populated
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Realism Score
|
|
130
|
+
|
|
131
|
+
Overall assessment of how realistic the data looks:
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
report.realism_score # => 94 (out of 100)
|
|
135
|
+
|
|
136
|
+
report.realism_breakdown
|
|
137
|
+
# => {
|
|
138
|
+
# email_format: 100, # Emails look real
|
|
139
|
+
# name_format: 95, # Names are realistic
|
|
140
|
+
# phone_format: 90, # Phones follow patterns
|
|
141
|
+
# date_consistency: 98, # Dates are logically consistent
|
|
142
|
+
# numeric_ranges: 85, # Numbers in expected ranges
|
|
143
|
+
# text_quality: 92 # Text is coherent
|
|
144
|
+
# }
|
|
145
|
+
|
|
146
|
+
# Specific realism checks
|
|
147
|
+
report.realism_issues
|
|
148
|
+
# => [
|
|
149
|
+
# { field: :age, issue: "5% of values are negative" },
|
|
150
|
+
# { field: :price, issue: "Values exceed expected range" }
|
|
151
|
+
# ]
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Quality Thresholds
|
|
155
|
+
|
|
156
|
+
### Define Quality Standards
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
FakeDataDSL::QualityMetrics.configure do |config|
|
|
160
|
+
config.thresholds = {
|
|
161
|
+
uniqueness: {
|
|
162
|
+
id: 100, # Must be 100% unique
|
|
163
|
+
email: 100, # Must be 100% unique
|
|
164
|
+
name: 80 # At least 80% unique
|
|
165
|
+
},
|
|
166
|
+
completeness: {
|
|
167
|
+
minimum: 90, # At least 90% of optional fields filled
|
|
168
|
+
required: 100 # Required fields must always be present
|
|
169
|
+
},
|
|
170
|
+
realism: {
|
|
171
|
+
minimum: 85 # Minimum realism score
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
end
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Validate Against Thresholds
|
|
178
|
+
|
|
179
|
+
```ruby
|
|
180
|
+
result = FakeDataDSL.generate_with_quality("User", count: 1000)
|
|
181
|
+
|
|
182
|
+
if result.quality_report.meets_thresholds?
|
|
183
|
+
puts "Data quality is acceptable"
|
|
184
|
+
else
|
|
185
|
+
puts "Quality issues:"
|
|
186
|
+
result.quality_report.threshold_violations.each do |violation|
|
|
187
|
+
puts " - #{violation[:field]}: #{violation[:message]}"
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### CI Integration
|
|
193
|
+
|
|
194
|
+
```ruby
|
|
195
|
+
# In your test suite
|
|
196
|
+
RSpec.describe "Data Quality" do
|
|
197
|
+
it "generates high-quality user data" do
|
|
198
|
+
result = FakeDataDSL.generate_with_quality("User", count: 1000)
|
|
199
|
+
|
|
200
|
+
expect(result.quality_report.realism_score).to be >= 90
|
|
201
|
+
expect(result.quality_report.uniqueness[:email]).to eq(100)
|
|
202
|
+
expect(result.quality_report.completeness).to be >= 95
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Detailed Analysis
|
|
208
|
+
|
|
209
|
+
### Field-Level Analysis
|
|
210
|
+
|
|
211
|
+
```ruby
|
|
212
|
+
report = FakeDataDSL::QualityMetrics.analyze(data, schema: "User")
|
|
213
|
+
|
|
214
|
+
# Analyze specific field
|
|
215
|
+
field_report = report.field_analysis(:email)
|
|
216
|
+
# => {
|
|
217
|
+
# type: "email",
|
|
218
|
+
# total_values: 1000,
|
|
219
|
+
# unique_values: 1000,
|
|
220
|
+
# uniqueness: 100.0,
|
|
221
|
+
# null_count: 0,
|
|
222
|
+
# format_valid: 1000,
|
|
223
|
+
# format_invalid: 0,
|
|
224
|
+
# sample_values: ["john@example.com", "jane@test.org", ...],
|
|
225
|
+
# patterns: {
|
|
226
|
+
# "gmail.com" => 230,
|
|
227
|
+
# "yahoo.com" => 180,
|
|
228
|
+
# "example.com" => 590
|
|
229
|
+
# }
|
|
230
|
+
# }
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Correlation Analysis
|
|
234
|
+
|
|
235
|
+
```ruby
|
|
236
|
+
# Find correlations between fields
|
|
237
|
+
report.correlations
|
|
238
|
+
# => {
|
|
239
|
+
# [:age, :retirement_status] => 0.95, # Strong correlation
|
|
240
|
+
# [:country, :phone_prefix] => 0.88, # Expected correlation
|
|
241
|
+
# [:name, :email] => 0.02 # No correlation (good)
|
|
242
|
+
# }
|
|
243
|
+
|
|
244
|
+
# Check for unexpected correlations
|
|
245
|
+
report.suspicious_correlations
|
|
246
|
+
# => [
|
|
247
|
+
# { fields: [:id, :created_at], correlation: 0.99,
|
|
248
|
+
# message: "ID and created_at are highly correlated - may indicate sequential generation" }
|
|
249
|
+
# ]
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Outlier Detection
|
|
253
|
+
|
|
254
|
+
```ruby
|
|
255
|
+
# Find outliers in numeric fields
|
|
256
|
+
report.outliers
|
|
257
|
+
# => {
|
|
258
|
+
# age: {
|
|
259
|
+
# outliers: [150, -5, 999],
|
|
260
|
+
# outlier_percentage: 0.3,
|
|
261
|
+
# expected_range: 0..120
|
|
262
|
+
# },
|
|
263
|
+
# price: {
|
|
264
|
+
# outliers: [0.001, 999999.99],
|
|
265
|
+
# outlier_percentage: 0.1,
|
|
266
|
+
# expected_range: 0.01..10000
|
|
267
|
+
# }
|
|
268
|
+
# }
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Quality Reports
|
|
272
|
+
|
|
273
|
+
### Summary Report
|
|
274
|
+
|
|
275
|
+
```ruby
|
|
276
|
+
report = FakeDataDSL.generate_with_quality("User", count: 1000).quality_report
|
|
277
|
+
|
|
278
|
+
puts report.summary
|
|
279
|
+
# ═══════════════════════════════════════════════
|
|
280
|
+
# Data Quality Report: User (1000 records)
|
|
281
|
+
# ═══════════════════════════════════════════════
|
|
282
|
+
#
|
|
283
|
+
# Overall Score: 94/100 ✓
|
|
284
|
+
#
|
|
285
|
+
# Uniqueness: 98.2% ✓
|
|
286
|
+
# - id: 100% ✓
|
|
287
|
+
# - email: 100% ✓
|
|
288
|
+
# - name: 85.3% ⚠ (expected: 80%)
|
|
289
|
+
#
|
|
290
|
+
# Completeness: 96.5% ✓
|
|
291
|
+
# - bio: 95.0%
|
|
292
|
+
# - avatar: 88.2%
|
|
293
|
+
#
|
|
294
|
+
# Distribution: Balanced ✓
|
|
295
|
+
# - role: { user: 85%, admin: 10%, mod: 5% }
|
|
296
|
+
#
|
|
297
|
+
# Realism: 92/100 ✓
|
|
298
|
+
# - 2 minor issues detected
|
|
299
|
+
# ═══════════════════════════════════════════════
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### JSON Report
|
|
303
|
+
|
|
304
|
+
```ruby
|
|
305
|
+
report.to_json
|
|
306
|
+
# => {
|
|
307
|
+
# "schema": "User",
|
|
308
|
+
# "record_count": 1000,
|
|
309
|
+
# "generated_at": "2026-01-24T10:30:00Z",
|
|
310
|
+
# "overall_score": 94,
|
|
311
|
+
# "metrics": {
|
|
312
|
+
# "uniqueness": { ... },
|
|
313
|
+
# "completeness": { ... },
|
|
314
|
+
# "distribution": { ... },
|
|
315
|
+
# "realism": { ... }
|
|
316
|
+
# },
|
|
317
|
+
# "issues": [ ... ],
|
|
318
|
+
# "suggestions": [ ... ]
|
|
319
|
+
# }
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### HTML Report
|
|
323
|
+
|
|
324
|
+
```ruby
|
|
325
|
+
# Generate visual HTML report
|
|
326
|
+
report.to_html("quality_report.html")
|
|
327
|
+
|
|
328
|
+
# Or get HTML string
|
|
329
|
+
html = report.to_html_string
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Export for Monitoring
|
|
333
|
+
|
|
334
|
+
```ruby
|
|
335
|
+
# Export metrics for monitoring systems
|
|
336
|
+
report.to_prometheus
|
|
337
|
+
# => [
|
|
338
|
+
# 'fake_data_quality_uniqueness{schema="User",field="email"} 100.0',
|
|
339
|
+
# 'fake_data_quality_completeness{schema="User"} 96.5',
|
|
340
|
+
# ...
|
|
341
|
+
# ]
|
|
342
|
+
|
|
343
|
+
report.to_datadog
|
|
344
|
+
# => { metrics: [...], tags: [...] }
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## Quality Improvement Suggestions
|
|
348
|
+
|
|
349
|
+
```ruby
|
|
350
|
+
report.suggestions
|
|
351
|
+
# => [
|
|
352
|
+
# {
|
|
353
|
+
# field: :name,
|
|
354
|
+
# issue: "Low uniqueness (85%)",
|
|
355
|
+
# suggestion: "Consider using more diverse name patterns or adding middle names",
|
|
356
|
+
# priority: :medium
|
|
357
|
+
# },
|
|
358
|
+
# {
|
|
359
|
+
# field: :phone,
|
|
360
|
+
# issue: "28% null values",
|
|
361
|
+
# suggestion: "Increase phone generation probability or make required",
|
|
362
|
+
# priority: :low
|
|
363
|
+
# }
|
|
364
|
+
# ]
|
|
365
|
+
|
|
366
|
+
# Auto-apply suggestions
|
|
367
|
+
improved_schema = FakeDataDSL::QualityMetrics.improve_schema(
|
|
368
|
+
FakeDataDSL.schema("User"),
|
|
369
|
+
based_on: report
|
|
370
|
+
)
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
## Comparison Reports
|
|
374
|
+
|
|
375
|
+
### Compare Generations
|
|
376
|
+
|
|
377
|
+
```ruby
|
|
378
|
+
# Compare quality across different generations
|
|
379
|
+
report1 = FakeDataDSL.generate_with_quality("User", count: 1000, seed: 1)
|
|
380
|
+
report2 = FakeDataDSL.generate_with_quality("User", count: 1000, seed: 2)
|
|
381
|
+
|
|
382
|
+
comparison = FakeDataDSL::QualityMetrics.compare(
|
|
383
|
+
report1.quality_report,
|
|
384
|
+
report2.quality_report
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
comparison.differences
|
|
388
|
+
# => {
|
|
389
|
+
# uniqueness: { name: [-2.3, "seed 1 had higher name uniqueness"] },
|
|
390
|
+
# realism: [+3, "seed 2 produced more realistic data"]
|
|
391
|
+
# }
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Compare Against Baseline
|
|
395
|
+
|
|
396
|
+
```ruby
|
|
397
|
+
# Save a baseline
|
|
398
|
+
baseline = FakeDataDSL.generate_with_quality("User", count: 1000)
|
|
399
|
+
baseline.quality_report.save_as_baseline("user_baseline")
|
|
400
|
+
|
|
401
|
+
# Later, compare against baseline
|
|
402
|
+
current = FakeDataDSL.generate_with_quality("User", count: 1000)
|
|
403
|
+
diff = current.quality_report.compare_to_baseline("user_baseline")
|
|
404
|
+
|
|
405
|
+
diff.regressions
|
|
406
|
+
# => [{ metric: :uniqueness, field: :email, change: -5.0 }]
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
## API Reference
|
|
410
|
+
|
|
411
|
+
### QualityMetrics.generate_with_quality
|
|
412
|
+
|
|
413
|
+
```ruby
|
|
414
|
+
FakeDataDSL::QualityMetrics.generate_with_quality(schema_name, options = {})
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
**Parameters:**
|
|
418
|
+
- `schema_name` - Name of the schema
|
|
419
|
+
- `options[:count]` - Number of records (default: 100)
|
|
420
|
+
- `options[:seed]` - Random seed
|
|
421
|
+
- `options[:mode]` - Generation mode
|
|
422
|
+
- `options[:analyze_fields]` - Specific fields to analyze (default: all)
|
|
423
|
+
|
|
424
|
+
**Returns:** `QualityResult` with `data` and `quality_report`
|
|
425
|
+
|
|
426
|
+
### QualityMetrics.analyze
|
|
427
|
+
|
|
428
|
+
```ruby
|
|
429
|
+
FakeDataDSL::QualityMetrics.analyze(data, options = {})
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
**Parameters:**
|
|
433
|
+
- `data` - Array of records to analyze
|
|
434
|
+
- `options[:schema]` - Schema name for context
|
|
435
|
+
- `options[:thresholds]` - Quality thresholds to validate against
|
|
436
|
+
|
|
437
|
+
**Returns:** `QualityReport`
|
|
438
|
+
|
|
439
|
+
### QualityReport Methods
|
|
440
|
+
|
|
441
|
+
```ruby
|
|
442
|
+
report.uniqueness # Hash of field => uniqueness percentage
|
|
443
|
+
report.completeness # Overall completeness percentage
|
|
444
|
+
report.distribution # Distribution analysis for enum fields
|
|
445
|
+
report.realism_score # Overall realism score (0-100)
|
|
446
|
+
report.issues # Array of detected issues
|
|
447
|
+
report.suggestions # Array of improvement suggestions
|
|
448
|
+
report.meets_thresholds? # Boolean - passes all thresholds?
|
|
449
|
+
report.summary # Human-readable summary string
|
|
450
|
+
report.to_json # JSON representation
|
|
451
|
+
report.to_html(path) # Generate HTML report file
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
## Configuration
|
|
455
|
+
|
|
456
|
+
```ruby
|
|
457
|
+
FakeDataDSL::QualityMetrics.configure do |config|
|
|
458
|
+
# Default thresholds
|
|
459
|
+
config.default_thresholds = {
|
|
460
|
+
uniqueness: { default: 80, id: 100, email: 100 },
|
|
461
|
+
completeness: { minimum: 90 },
|
|
462
|
+
realism: { minimum: 85 }
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
# Analysis options
|
|
466
|
+
config.analyze_distributions = true
|
|
467
|
+
config.detect_outliers = true
|
|
468
|
+
config.correlation_threshold = 0.8
|
|
469
|
+
|
|
470
|
+
# Sampling for large datasets
|
|
471
|
+
config.max_sample_size = 10000
|
|
472
|
+
config.sample_strategy = :random # :random, :stratified
|
|
473
|
+
|
|
474
|
+
# Report options
|
|
475
|
+
config.include_sample_values = true
|
|
476
|
+
config.max_sample_values = 5
|
|
477
|
+
end
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
## Best Practices
|
|
481
|
+
|
|
482
|
+
### 1. Set Appropriate Thresholds
|
|
483
|
+
|
|
484
|
+
```ruby
|
|
485
|
+
# Strict for critical fields
|
|
486
|
+
config.thresholds[:uniqueness][:id] = 100
|
|
487
|
+
config.thresholds[:uniqueness][:email] = 100
|
|
488
|
+
|
|
489
|
+
# Relaxed for non-unique fields
|
|
490
|
+
config.thresholds[:uniqueness][:name] = 70
|
|
491
|
+
config.thresholds[:uniqueness][:city] = 10
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### 2. Monitor Quality Over Time
|
|
495
|
+
|
|
496
|
+
```ruby
|
|
497
|
+
# Track quality metrics in CI
|
|
498
|
+
after(:suite) do
|
|
499
|
+
report = aggregate_quality_reports
|
|
500
|
+
QualityMetricsDashboard.record(report)
|
|
501
|
+
end
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
### 3. Use Quality Gates
|
|
505
|
+
|
|
506
|
+
```ruby
|
|
507
|
+
# Fail CI if quality drops
|
|
508
|
+
RSpec.configure do |config|
|
|
509
|
+
config.after(:suite) do
|
|
510
|
+
report = FakeDataDSL::QualityMetrics.session_report
|
|
511
|
+
if report.realism_score < 85
|
|
512
|
+
raise "Data quality below threshold: #{report.realism_score}"
|
|
513
|
+
end
|
|
514
|
+
end
|
|
515
|
+
end
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
## Troubleshooting
|
|
519
|
+
|
|
520
|
+
### Low Uniqueness
|
|
521
|
+
|
|
522
|
+
```ruby
|
|
523
|
+
# Issue: email uniqueness is only 95%
|
|
524
|
+
# Solution: Increase domain variety
|
|
525
|
+
override "User", email: -> { Faker::Internet.email(domain: random_domain) }
|
|
526
|
+
|
|
527
|
+
# Or use @unique annotation
|
|
528
|
+
# User:
|
|
529
|
+
# email: email @unique
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### Poor Distribution
|
|
533
|
+
|
|
534
|
+
```ruby
|
|
535
|
+
# Issue: role distribution is skewed (99% user, 1% admin)
|
|
536
|
+
# Solution: Use weighted enum
|
|
537
|
+
# role: enum(user:70%, admin:20%, moderator:10%)
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### Low Realism
|
|
541
|
+
|
|
542
|
+
```ruby
|
|
543
|
+
# Issue: phone numbers don't look realistic
|
|
544
|
+
# Solution: Use locale-specific formats
|
|
545
|
+
FakeDataDSL.configure do |c|
|
|
546
|
+
c.locale = :en_US # US phone format
|
|
547
|
+
end
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
## See Also
|
|
551
|
+
|
|
552
|
+
- [Generation Modes](generation_modes.md)
|
|
553
|
+
- [Behaviors](behaviors.md)
|
|
554
|
+
- [Testing Best Practices](best_practices.md)
|
|
555
|
+
- [Snapshot Testing](SNAPSHOT_TESTING.md)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Quick Reference
|
|
2
|
+
|
|
3
|
+
Quick reference card for FakeDataDSL.
|
|
4
|
+
|
|
5
|
+
## Basic Syntax
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
SchemaName:
|
|
9
|
+
field_name: type
|
|
10
|
+
field_name: type(args)
|
|
11
|
+
field_name: type? # Nullable
|
|
12
|
+
field_name: type optional # Optional
|
|
13
|
+
field_name: type unique # Unique
|
|
14
|
+
field_name: type if condition # Conditional
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Common Types
|
|
18
|
+
|
|
19
|
+
| Type | Example | Description |
|
|
20
|
+
|------|---------|-------------|
|
|
21
|
+
| `uuid` | `id: uuid` | UUID identifier |
|
|
22
|
+
| `name` | `name: name` | Person name |
|
|
23
|
+
| `email` | `email: email` | Email address |
|
|
24
|
+
| `number` | `age: number(18..65)` | Number in range |
|
|
25
|
+
| `boolean` | `active: boolean` | True/false |
|
|
26
|
+
| `text` | `bio: text(100..500)` | Text with length |
|
|
27
|
+
| `date` | `birth_date: date` | Calendar date |
|
|
28
|
+
| `array` | `tags: array(text, 3..10)` | Array of values |
|
|
29
|
+
| `enum` | `status: enum(active, inactive)` | Enumeration |
|
|
30
|
+
|
|
31
|
+
## Behaviors
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
@latency 100ms # Add delay
|
|
35
|
+
@failure 5% # Failure probability
|
|
36
|
+
@partial_data 20% # Omit fields sometimes
|
|
37
|
+
@randomize_order # Randomize field order
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Generation Modes
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
schema.generate(mode: :random) # Default: realistic data
|
|
44
|
+
schema.generate(mode: :edge) # Edge cases
|
|
45
|
+
schema.generate(mode: :invalid) # Invalid data
|
|
46
|
+
schema.generate(mode: :mixed) # Mix of all
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Code Examples
|
|
50
|
+
|
|
51
|
+
### Basic Usage
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
require 'fake_data_dsl'
|
|
55
|
+
|
|
56
|
+
registry = FakeDataDSL::Registry.new
|
|
57
|
+
registry.load_file('schema.dsl')
|
|
58
|
+
schema = registry.schema('User')
|
|
59
|
+
record = schema.generate
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Multiple Records
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
records = schema.generate_many(10)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Streaming
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
schema.generate_many_stream(1000).each do |record|
|
|
72
|
+
process(record)
|
|
73
|
+
end
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Deterministic
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
FakeDataDSL.configure { |c| c.seed = 12345 }
|
|
80
|
+
record = schema.generate # Same data every time
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## See Also
|
|
84
|
+
|
|
85
|
+
- [Getting Started](getting_started.md) - Full guide
|
|
86
|
+
- [DSL Reference](dsl_reference.md) - Complete syntax
|
|
87
|
+
- [Type Reference](type_reference.md) - All types
|
|
88
|
+
|