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,485 @@
|
|
|
1
|
+
# Factory Bot Comparison
|
|
2
|
+
|
|
3
|
+
Comparing FakeDataDSL with Factory Bot and migration guide.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Overview](#overview)
|
|
8
|
+
- [Feature Comparison](#feature-comparison)
|
|
9
|
+
- [Syntax Comparison](#syntax-comparison)
|
|
10
|
+
- [When to Use Each](#when-to-use-each)
|
|
11
|
+
- [Migration Guide](#migration-guide)
|
|
12
|
+
- [Using Together](#using-together)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Overview
|
|
17
|
+
|
|
18
|
+
**Factory Bot** and **FakeDataDSL** serve different purposes:
|
|
19
|
+
|
|
20
|
+
| Tool | Primary Purpose |
|
|
21
|
+
|------|-----------------|
|
|
22
|
+
| **Factory Bot** | Create model instances for testing |
|
|
23
|
+
| **FakeDataDSL** | Generate fake data from schemas |
|
|
24
|
+
|
|
25
|
+
They can complement each other rather than compete.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Feature Comparison
|
|
30
|
+
|
|
31
|
+
| Feature | Factory Bot | FakeDataDSL |
|
|
32
|
+
|---------|-------------|-------------|
|
|
33
|
+
| **Model Integration** | ✅ Deep Rails integration | ⚠️ Data only, not models |
|
|
34
|
+
| **Associations** | ✅ Automatic | ⚠️ Manual with Ref() |
|
|
35
|
+
| **Traits** | ✅ Built-in | ⚠️ Via overrides |
|
|
36
|
+
| **Sequences** | ✅ Built-in | ✅ id_sequence |
|
|
37
|
+
| **Callbacks** | ✅ after_create, etc. | ❌ Not available |
|
|
38
|
+
| **Lazy Evaluation** | ✅ Built-in | ❌ Not available |
|
|
39
|
+
| **DSL File** | ❌ Ruby code | ✅ Separate DSL |
|
|
40
|
+
| **Generation Modes** | ❌ Not available | ✅ random/edge/invalid |
|
|
41
|
+
| **Behaviors** | ❌ Not available | ✅ latency/failure/etc. |
|
|
42
|
+
| **Streaming** | ❌ Not available | ✅ Memory-efficient |
|
|
43
|
+
| **Deterministic** | ⚠️ With Faker.seed | ✅ Built-in seeds |
|
|
44
|
+
| **CLI** | ❌ Not available | ✅ Command line |
|
|
45
|
+
| **Non-Rails** | ⚠️ Possible | ✅ Framework agnostic |
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Syntax Comparison
|
|
50
|
+
|
|
51
|
+
### Defining Data Shape
|
|
52
|
+
|
|
53
|
+
**Factory Bot:**
|
|
54
|
+
```ruby
|
|
55
|
+
# spec/factories/users.rb
|
|
56
|
+
FactoryBot.define do
|
|
57
|
+
factory :user do
|
|
58
|
+
id { SecureRandom.uuid }
|
|
59
|
+
name { Faker::Name.name }
|
|
60
|
+
email { Faker::Internet.email }
|
|
61
|
+
age { rand(18..65) }
|
|
62
|
+
active { [true, false].sample }
|
|
63
|
+
role { %w[user admin moderator].sample }
|
|
64
|
+
created_at { rand(1..365).days.ago }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**FakeDataDSL:**
|
|
70
|
+
```dsl
|
|
71
|
+
# schemas/user.dsl
|
|
72
|
+
User:
|
|
73
|
+
id: uuid
|
|
74
|
+
name: name
|
|
75
|
+
email: email
|
|
76
|
+
age: number(18..65)
|
|
77
|
+
active: boolean
|
|
78
|
+
role: enum(user, admin, moderator)
|
|
79
|
+
created_at: past_date(1y)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Creating Records
|
|
83
|
+
|
|
84
|
+
**Factory Bot:**
|
|
85
|
+
```ruby
|
|
86
|
+
# Build (doesn't save)
|
|
87
|
+
user = build(:user)
|
|
88
|
+
|
|
89
|
+
# Create (saves to DB)
|
|
90
|
+
user = create(:user)
|
|
91
|
+
|
|
92
|
+
# With overrides
|
|
93
|
+
admin = create(:user, role: 'admin')
|
|
94
|
+
|
|
95
|
+
# Multiple
|
|
96
|
+
users = create_list(:user, 10)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**FakeDataDSL:**
|
|
100
|
+
```ruby
|
|
101
|
+
# Generate data hash
|
|
102
|
+
user_data = schema.generate
|
|
103
|
+
|
|
104
|
+
# Create model manually
|
|
105
|
+
user = User.create!(user_data)
|
|
106
|
+
|
|
107
|
+
# With overrides
|
|
108
|
+
admin = User.create!(schema.generate.merge('role' => 'admin'))
|
|
109
|
+
|
|
110
|
+
# Multiple
|
|
111
|
+
users_data = schema.generate_many(10)
|
|
112
|
+
users = User.insert_all!(users_data)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Traits
|
|
116
|
+
|
|
117
|
+
**Factory Bot:**
|
|
118
|
+
```ruby
|
|
119
|
+
factory :user do
|
|
120
|
+
name { Faker::Name.name }
|
|
121
|
+
role { 'user' }
|
|
122
|
+
|
|
123
|
+
trait :admin do
|
|
124
|
+
role { 'admin' }
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
trait :inactive do
|
|
128
|
+
active { false }
|
|
129
|
+
deactivated_at { Time.current }
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Usage
|
|
134
|
+
admin = create(:user, :admin)
|
|
135
|
+
inactive_admin = create(:user, :admin, :inactive)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**FakeDataDSL:**
|
|
139
|
+
```ruby
|
|
140
|
+
# Using helper methods
|
|
141
|
+
def fake_user(*traits, **overrides)
|
|
142
|
+
data = schema.generate
|
|
143
|
+
|
|
144
|
+
traits.each do |trait|
|
|
145
|
+
case trait
|
|
146
|
+
when :admin
|
|
147
|
+
data['role'] = 'admin'
|
|
148
|
+
when :inactive
|
|
149
|
+
data['active'] = false
|
|
150
|
+
data['deactivated_at'] = Time.current.iso8601
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
data.merge(overrides.stringify_keys)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Usage
|
|
158
|
+
admin = User.create!(fake_user(:admin))
|
|
159
|
+
inactive_admin = User.create!(fake_user(:admin, :inactive))
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Associations
|
|
163
|
+
|
|
164
|
+
**Factory Bot:**
|
|
165
|
+
```ruby
|
|
166
|
+
factory :post do
|
|
167
|
+
title { Faker::Lorem.sentence }
|
|
168
|
+
user # Automatically creates associated user
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
factory :comment do
|
|
172
|
+
body { Faker::Lorem.paragraph }
|
|
173
|
+
post
|
|
174
|
+
user
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Usage
|
|
178
|
+
post = create(:post) # Creates user automatically
|
|
179
|
+
post.user # => User instance
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**FakeDataDSL:**
|
|
183
|
+
```ruby
|
|
184
|
+
# Manual association
|
|
185
|
+
user = User.create!(fake(:user))
|
|
186
|
+
post_data = fake(:post).merge('user_id' => user.id)
|
|
187
|
+
post = Post.create!(post_data)
|
|
188
|
+
|
|
189
|
+
# Or use Ref() in DSL (references previously generated)
|
|
190
|
+
# post.dsl
|
|
191
|
+
# Post:
|
|
192
|
+
# user_id: Ref(User.id)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Sequences
|
|
196
|
+
|
|
197
|
+
**Factory Bot:**
|
|
198
|
+
```ruby
|
|
199
|
+
factory :user do
|
|
200
|
+
sequence(:email) { |n| "user#{n}@example.com" }
|
|
201
|
+
sequence(:username) { |n| "user_#{n}" }
|
|
202
|
+
end
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**FakeDataDSL:**
|
|
206
|
+
```dsl
|
|
207
|
+
User:
|
|
208
|
+
id: id_sequence
|
|
209
|
+
email: email(unique: true)
|
|
210
|
+
username: username
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## When to Use Each
|
|
216
|
+
|
|
217
|
+
### Use Factory Bot When:
|
|
218
|
+
|
|
219
|
+
1. **Deep Rails integration needed**
|
|
220
|
+
- Automatic association handling
|
|
221
|
+
- Callbacks (after_create, etc.)
|
|
222
|
+
- ActiveRecord features
|
|
223
|
+
|
|
224
|
+
2. **Complex test setup**
|
|
225
|
+
- Nested associations
|
|
226
|
+
- Transactional rollback
|
|
227
|
+
- Database state management
|
|
228
|
+
|
|
229
|
+
3. **Traits are essential**
|
|
230
|
+
- Many variations of same model
|
|
231
|
+
- Composable configurations
|
|
232
|
+
|
|
233
|
+
### Use FakeDataDSL When:
|
|
234
|
+
|
|
235
|
+
1. **Schema-first approach**
|
|
236
|
+
- Define data contracts
|
|
237
|
+
- Share schemas across teams
|
|
238
|
+
- Generate docs from schemas
|
|
239
|
+
|
|
240
|
+
2. **Testing modes needed**
|
|
241
|
+
- Edge case testing
|
|
242
|
+
- Invalid data testing
|
|
243
|
+
- Validation testing
|
|
244
|
+
|
|
245
|
+
3. **Non-Rails contexts**
|
|
246
|
+
- API testing
|
|
247
|
+
- Data migration
|
|
248
|
+
- Load testing
|
|
249
|
+
|
|
250
|
+
4. **Large data volumes**
|
|
251
|
+
- Streaming generation
|
|
252
|
+
- Memory efficiency
|
|
253
|
+
- Database seeding
|
|
254
|
+
|
|
255
|
+
5. **Behavior simulation**
|
|
256
|
+
- Latency testing
|
|
257
|
+
- Failure testing
|
|
258
|
+
- Chaos engineering
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Migration Guide
|
|
263
|
+
|
|
264
|
+
### From Factory Bot to FakeDataDSL
|
|
265
|
+
|
|
266
|
+
#### Step 1: Convert Factories to Schemas
|
|
267
|
+
|
|
268
|
+
**Before (Factory Bot):**
|
|
269
|
+
```ruby
|
|
270
|
+
# spec/factories/users.rb
|
|
271
|
+
FactoryBot.define do
|
|
272
|
+
factory :user do
|
|
273
|
+
id { SecureRandom.uuid }
|
|
274
|
+
name { Faker::Name.name }
|
|
275
|
+
email { Faker::Internet.email }
|
|
276
|
+
age { rand(18..65) }
|
|
277
|
+
role { 'user' }
|
|
278
|
+
|
|
279
|
+
trait :admin do
|
|
280
|
+
role { 'admin' }
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
trait :verified do
|
|
284
|
+
verified { true }
|
|
285
|
+
verified_at { Time.current }
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**After (FakeDataDSL):**
|
|
292
|
+
```dsl
|
|
293
|
+
# spec/schemas/user.dsl
|
|
294
|
+
User:
|
|
295
|
+
id: uuid
|
|
296
|
+
name: name
|
|
297
|
+
email: email
|
|
298
|
+
age: number(18..65)
|
|
299
|
+
role: enum(user:80%, admin:10%, moderator:10%)
|
|
300
|
+
verified: boolean(false:80%)
|
|
301
|
+
verified_at?: past_date(1y)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
#### Step 2: Create Helper Module
|
|
305
|
+
|
|
306
|
+
```ruby
|
|
307
|
+
# spec/support/fake_data.rb
|
|
308
|
+
module FakeDataHelpers
|
|
309
|
+
TRAITS = {
|
|
310
|
+
user: {
|
|
311
|
+
admin: { 'role' => 'admin' },
|
|
312
|
+
verified: { 'verified' => true, 'verified_at' => Time.current.iso8601 }
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
def fake(name, *traits, **overrides)
|
|
317
|
+
data = fake_schema(name).generate
|
|
318
|
+
|
|
319
|
+
traits.each do |trait|
|
|
320
|
+
trait_data = TRAITS.dig(name, trait) || {}
|
|
321
|
+
data.merge!(trait_data)
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
data.merge(overrides.stringify_keys)
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def create_fake(name, *traits, **overrides)
|
|
328
|
+
model_class = name.to_s.camelize.constantize
|
|
329
|
+
model_class.create!(fake(name, *traits, **overrides))
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def create_fake_list(name, count, *traits, **overrides)
|
|
333
|
+
count.times.map { create_fake(name, *traits, **overrides) }
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
private
|
|
337
|
+
|
|
338
|
+
def fake_schema(name)
|
|
339
|
+
@registry ||= FakeDataDSL::Registry.new.tap do |r|
|
|
340
|
+
r.load_dir('spec/schemas')
|
|
341
|
+
end
|
|
342
|
+
@registry.schema(name.to_s.camelize)
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
#### Step 3: Update Specs
|
|
348
|
+
|
|
349
|
+
**Before:**
|
|
350
|
+
```ruby
|
|
351
|
+
RSpec.describe User do
|
|
352
|
+
let(:user) { create(:user) }
|
|
353
|
+
let(:admin) { create(:user, :admin) }
|
|
354
|
+
end
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
**After:**
|
|
358
|
+
```ruby
|
|
359
|
+
RSpec.describe User do
|
|
360
|
+
include FakeDataHelpers
|
|
361
|
+
|
|
362
|
+
let(:user) { create_fake(:user) }
|
|
363
|
+
let(:admin) { create_fake(:user, :admin) }
|
|
364
|
+
end
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Gradual Migration
|
|
368
|
+
|
|
369
|
+
You can use both during migration:
|
|
370
|
+
|
|
371
|
+
```ruby
|
|
372
|
+
# spec/support/factories_and_fake.rb
|
|
373
|
+
|
|
374
|
+
# Keep Factory Bot for complex cases
|
|
375
|
+
FactoryBot.define do
|
|
376
|
+
factory :order_with_items do
|
|
377
|
+
# Complex associations
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
# Use FakeDataDSL for simple cases
|
|
382
|
+
module FakeDataHelpers
|
|
383
|
+
def fake_user(**overrides)
|
|
384
|
+
schema.generate.merge(overrides.stringify_keys)
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# In specs
|
|
389
|
+
RSpec.describe OrdersController do
|
|
390
|
+
# Use Factory Bot for complex setup
|
|
391
|
+
let(:order) { create(:order_with_items) }
|
|
392
|
+
|
|
393
|
+
# Use FakeDataDSL for simple data
|
|
394
|
+
let(:user_params) { fake_user }
|
|
395
|
+
end
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
## Using Together
|
|
401
|
+
|
|
402
|
+
### Best of Both Worlds
|
|
403
|
+
|
|
404
|
+
```ruby
|
|
405
|
+
# spec/factories/users.rb
|
|
406
|
+
FactoryBot.define do
|
|
407
|
+
factory :user do
|
|
408
|
+
# Use FakeDataDSL for data generation
|
|
409
|
+
transient do
|
|
410
|
+
fake_data { FakeDataHelpers.fake(:user) }
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
id { fake_data['id'] }
|
|
414
|
+
name { fake_data['name'] }
|
|
415
|
+
email { fake_data['email'] }
|
|
416
|
+
|
|
417
|
+
# Keep Factory Bot traits
|
|
418
|
+
trait :admin do
|
|
419
|
+
role { 'admin' }
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
# Keep callbacks
|
|
423
|
+
after(:create) do |user|
|
|
424
|
+
user.send_welcome_email
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Hybrid Approach
|
|
431
|
+
|
|
432
|
+
```ruby
|
|
433
|
+
# spec/support/hybrid_factories.rb
|
|
434
|
+
|
|
435
|
+
module HybridFactories
|
|
436
|
+
# Use FakeDataDSL for data
|
|
437
|
+
def fake(name, **options)
|
|
438
|
+
registry.schema(name.to_s.camelize).generate(**options)
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
# Use Factory Bot for model creation with associations
|
|
442
|
+
def create_with_fake(name, *traits, **overrides)
|
|
443
|
+
data = fake(name)
|
|
444
|
+
FactoryBot.create(name, *traits, data.merge(overrides))
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Decision Matrix
|
|
450
|
+
|
|
451
|
+
| Scenario | Recommendation |
|
|
452
|
+
|----------|---------------|
|
|
453
|
+
| Simple model, no associations | FakeDataDSL |
|
|
454
|
+
| Complex associations | Factory Bot |
|
|
455
|
+
| Edge case testing | FakeDataDSL |
|
|
456
|
+
| After callbacks needed | Factory Bot |
|
|
457
|
+
| Large batch generation | FakeDataDSL |
|
|
458
|
+
| Transactional tests | Factory Bot |
|
|
459
|
+
| API data contracts | FakeDataDSL |
|
|
460
|
+
| Integration tests | Either/Both |
|
|
461
|
+
|
|
462
|
+
---
|
|
463
|
+
|
|
464
|
+
## Summary
|
|
465
|
+
|
|
466
|
+
| Aspect | Factory Bot | FakeDataDSL |
|
|
467
|
+
|--------|-------------|-------------|
|
|
468
|
+
| Best for | Model creation | Data generation |
|
|
469
|
+
| Syntax | Ruby DSL | Custom DSL |
|
|
470
|
+
| Learning curve | Medium | Low |
|
|
471
|
+
| Rails integration | Excellent | Good |
|
|
472
|
+
| Testing modes | No | Yes |
|
|
473
|
+
| Streaming | No | Yes |
|
|
474
|
+
| Behaviors | No | Yes |
|
|
475
|
+
|
|
476
|
+
**Recommendation:** Use both! Factory Bot for complex Rails model creation, FakeDataDSL for data generation, testing modes, and behavior simulation.
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## Next Steps
|
|
481
|
+
|
|
482
|
+
- [RSpec Integration](rspec.md) - RSpec testing patterns
|
|
483
|
+
- [Rails Integration](rails.md) - Rails-specific setup
|
|
484
|
+
- [CI/CD Integration](ci_cd.md) - Continuous integration
|
|
485
|
+
|