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.
Files changed (302) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +4 -0
  3. data/.rubocop.yml +40 -0
  4. data/.yardopts +18 -0
  5. data/ACCESS_DOCS.md +116 -0
  6. data/ADVANCED_FEATURES_SUMMARY.md +245 -0
  7. data/CHANGELOG.md +498 -0
  8. data/CODE_OF_CONDUCT.md +122 -0
  9. data/CONTRIBUTING.md +307 -0
  10. data/DOCUMENTATION.md +204 -0
  11. data/DOCUMENTATION_GUIDE.md +194 -0
  12. data/LICENSE +22 -0
  13. data/README.md +1458 -0
  14. data/Rakefile +128 -0
  15. data/benchmark/README.md +591 -0
  16. data/benchmark/batch_generation.rb +63 -0
  17. data/benchmark/engine_comparison.rb +295 -0
  18. data/benchmark/single_record.rb +108 -0
  19. data/benchmark/streaming.rb +74 -0
  20. data/docs/ACTIVERECORD_INFERENCE.md +524 -0
  21. data/docs/API_SERVER.md +278 -0
  22. data/docs/CONFIG_FILE.md +315 -0
  23. data/docs/DATA_CONTRACTS.md +312 -0
  24. data/docs/ENHANCED_REPL.md +304 -0
  25. data/docs/FACTORY_BOT.md +271 -0
  26. data/docs/GITHUB_ACTION.md +420 -0
  27. data/docs/GRAPHQL_EXPORT.md +303 -0
  28. data/docs/GRAPHQL_FEDERATION.md +651 -0
  29. data/docs/HOW_TO_GENERATE_DOCS.md +252 -0
  30. data/docs/LSP.md +189 -0
  31. data/docs/MIGRATION_GENERATOR.md +547 -0
  32. data/docs/MOCK_SERVER.md +280 -0
  33. data/docs/NATIVE_ENGINE.md +298 -0
  34. data/docs/OPENAPI_EXPORT.md +252 -0
  35. data/docs/PERFORMANCE_MODE.md +228 -0
  36. data/docs/PERSONAS.md +547 -0
  37. data/docs/PROPERTY_TESTING.md +284 -0
  38. data/docs/PROTOBUF_EXPORT.md +276 -0
  39. data/docs/QUALITY_METRICS.md +555 -0
  40. data/docs/QUICK_REFERENCE.md +88 -0
  41. data/docs/RAILS_ENGINE.md +404 -0
  42. data/docs/RAILS_INTEGRATION.md +454 -0
  43. data/docs/README.md +175 -0
  44. data/docs/REPL_QUICK_REFERENCE.md +149 -0
  45. data/docs/RUST_INTEGRATION_GUIDE.md +1376 -0
  46. data/docs/SCENARIOS.md +576 -0
  47. data/docs/SECURITY_TESTING.md +318 -0
  48. data/docs/SNAPSHOT_TESTING.md +308 -0
  49. data/docs/STRING_TEXT_TYPES_REFERENCE.md +512 -0
  50. data/docs/TERRAFORM_EXPORT.md +447 -0
  51. data/docs/TIME_TRAVEL.md +507 -0
  52. data/docs/USAGE_GUIDE.md +980 -0
  53. data/docs/WEBHOOK_SIMULATOR.md +579 -0
  54. data/docs/advanced_features.md +183 -0
  55. data/docs/api_reference.md +153 -0
  56. data/docs/behaviors.md +138 -0
  57. data/docs/best_practices.md +191 -0
  58. data/docs/dsl_reference.md +172 -0
  59. data/docs/examples.md +162 -0
  60. data/docs/generation_modes.md +125 -0
  61. data/docs/getting_started.md +92 -0
  62. data/docs/index.html +177 -0
  63. data/docs/strategic/CLOUD_REGISTRY_ARCHITECTURE.md +268 -0
  64. data/docs/strategic/SIMD_OPTIMIZATION_STRATEGY.md +153 -0
  65. data/docs/troubleshooting.md +215 -0
  66. data/docs/type_reference.md +224 -0
  67. data/examples/hostile_mode_demo.rb +64 -0
  68. data/exe/synthra +6 -0
  69. data/ext/synthra_native/Cargo.lock +972 -0
  70. data/ext/synthra_native/Cargo.toml +46 -0
  71. data/ext/synthra_native/extconf.rb +41 -0
  72. data/ext/synthra_native/src/generator.rs +397 -0
  73. data/ext/synthra_native/src/lib.rs +229 -0
  74. data/ext/synthra_native/src/types.rs +1485 -0
  75. data/lib/generators/synthra/install_generator.rb +86 -0
  76. data/lib/generators/synthra/templates/api_response.dsl +15 -0
  77. data/lib/generators/synthra/templates/fake_data.rake +116 -0
  78. data/lib/generators/synthra/templates/synthra.yml +31 -0
  79. data/lib/generators/synthra/templates/synthra_support.rb +19 -0
  80. data/lib/generators/synthra/templates/user.dsl +11 -0
  81. data/lib/synthra/activerecord_inference.rb +394 -0
  82. data/lib/synthra/api.rb +381 -0
  83. data/lib/synthra/api_server.rb +718 -0
  84. data/lib/synthra/behaviors/applicator.rb +165 -0
  85. data/lib/synthra/behaviors/base.rb +155 -0
  86. data/lib/synthra/behaviors/close_connection.rb +60 -0
  87. data/lib/synthra/behaviors/deprecated.rb +100 -0
  88. data/lib/synthra/behaviors/failure.rb +69 -0
  89. data/lib/synthra/behaviors/latency.rb +103 -0
  90. data/lib/synthra/behaviors/partial_data.rb +83 -0
  91. data/lib/synthra/behaviors/randomize_order.rb +74 -0
  92. data/lib/synthra/behaviors/registry.rb +238 -0
  93. data/lib/synthra/behaviors/simulate_error.rb +79 -0
  94. data/lib/synthra/cli/commands/base.rb +105 -0
  95. data/lib/synthra/cli/commands/diff.rb +227 -0
  96. data/lib/synthra/cli/commands/docs.rb +67 -0
  97. data/lib/synthra/cli/commands/export.rb +150 -0
  98. data/lib/synthra/cli/commands/generate.rb +72 -0
  99. data/lib/synthra/cli/commands/import.rb +80 -0
  100. data/lib/synthra/cli/commands/lint.rb +53 -0
  101. data/lib/synthra/cli/commands/live.rb +57 -0
  102. data/lib/synthra/cli/commands/seed.rb +99 -0
  103. data/lib/synthra/cli/commands/validate.rb +28 -0
  104. data/lib/synthra/cli.rb +2471 -0
  105. data/lib/synthra/config_file.rb +129 -0
  106. data/lib/synthra/configuration.rb +281 -0
  107. data/lib/synthra/contracts_registry.rb +408 -0
  108. data/lib/synthra/database_seeder.rb +268 -0
  109. data/lib/synthra/deterministic_ids.rb +218 -0
  110. data/lib/synthra/documentation_generator.rb +414 -0
  111. data/lib/synthra/engine.rb +251 -0
  112. data/lib/synthra/errors.rb +1169 -0
  113. data/lib/synthra/export/base.rb +85 -0
  114. data/lib/synthra/export/csv.rb +101 -0
  115. data/lib/synthra/export/graphql.rb +266 -0
  116. data/lib/synthra/export/graphql_federation.rb +377 -0
  117. data/lib/synthra/export/graphviz.rb +258 -0
  118. data/lib/synthra/export/javascript.rb +327 -0
  119. data/lib/synthra/export/json_data.rb +61 -0
  120. data/lib/synthra/export/json_schema.rb +290 -0
  121. data/lib/synthra/export/openapi.rb +514 -0
  122. data/lib/synthra/export/protobuf.rb +483 -0
  123. data/lib/synthra/export/python.rb +560 -0
  124. data/lib/synthra/export/sql.rb +381 -0
  125. data/lib/synthra/export/sql_insert.rb +152 -0
  126. data/lib/synthra/export/terraform.rb +501 -0
  127. data/lib/synthra/export/type_mapping.rb +389 -0
  128. data/lib/synthra/export/typescript.rb +300 -0
  129. data/lib/synthra/export/xml_data.rb +104 -0
  130. data/lib/synthra/export/yaml_data.rb +56 -0
  131. data/lib/synthra/export.rb +404 -0
  132. data/lib/synthra/factory_bot_integration.rb +157 -0
  133. data/lib/synthra/field.rb +440 -0
  134. data/lib/synthra/functions/registry.rb +104 -0
  135. data/lib/synthra/generator/context.rb +372 -0
  136. data/lib/synthra/generator/engine.rb +336 -0
  137. data/lib/synthra/generator/faker_adapter.rb +425 -0
  138. data/lib/synthra/generator/modes.rb +444 -0
  139. data/lib/synthra/generator/resolver.rb +256 -0
  140. data/lib/synthra/generator/rng.rb +273 -0
  141. data/lib/synthra/generator/streamer.rb +63 -0
  142. data/lib/synthra/generator/uniqueness.rb +118 -0
  143. data/lib/synthra/initializer.rb +97 -0
  144. data/lib/synthra/limits.rb +279 -0
  145. data/lib/synthra/live_preview.rb +518 -0
  146. data/lib/synthra/loader_config.rb +78 -0
  147. data/lib/synthra/lsp/server.rb +689 -0
  148. data/lib/synthra/migration_generator.rb +301 -0
  149. data/lib/synthra/mixin.rb +174 -0
  150. data/lib/synthra/mock_server.rb +458 -0
  151. data/lib/synthra/native_engine.rb +304 -0
  152. data/lib/synthra/openapi_importer.rb +228 -0
  153. data/lib/synthra/output/json_formatter.rb +40 -0
  154. data/lib/synthra/output/ndjson_formatter.rb +55 -0
  155. data/lib/synthra/parser/ast.rb +1287 -0
  156. data/lib/synthra/parser/lexer.rb +1152 -0
  157. data/lib/synthra/parser/parser.rb +1664 -0
  158. data/lib/synthra/parser/tokens.rb +461 -0
  159. data/lib/synthra/performance_mode.rb +364 -0
  160. data/lib/synthra/personas.rb +397 -0
  161. data/lib/synthra/property_testing.rb +172 -0
  162. data/lib/synthra/quality_metrics.rb +405 -0
  163. data/lib/synthra/rails_test_helper.rb +248 -0
  164. data/lib/synthra/registry.rb +533 -0
  165. data/lib/synthra/relationships.rb +193 -0
  166. data/lib/synthra/repl/enhanced_repl.rb +607 -0
  167. data/lib/synthra/repl/formatter.rb +191 -0
  168. data/lib/synthra/scenarios.rb +423 -0
  169. data/lib/synthra/schema.rb +605 -0
  170. data/lib/synthra/schema_inheritance.rb +104 -0
  171. data/lib/synthra/schema_versioning.rb +212 -0
  172. data/lib/synthra/snapshot_testing.rb +199 -0
  173. data/lib/synthra/time_travel.rb +338 -0
  174. data/lib/synthra/type_definitions.rb +274 -0
  175. data/lib/synthra/types/address_location/addresses.rb +125 -0
  176. data/lib/synthra/types/address_location/airports.rb +200 -0
  177. data/lib/synthra/types/address_location/banks_hospitals.rb +207 -0
  178. data/lib/synthra/types/address_location/locations.rb +406 -0
  179. data/lib/synthra/types/base.rb +48 -0
  180. data/lib/synthra/types/commerce_products/commerce.rb +119 -0
  181. data/lib/synthra/types/commerce_products/companies.rb +71 -0
  182. data/lib/synthra/types/commerce_products/construction.rb +126 -0
  183. data/lib/synthra/types/commerce_products/products.rb +205 -0
  184. data/lib/synthra/types/core/collections.rb +513 -0
  185. data/lib/synthra/types/core/defaults.rb +76 -0
  186. data/lib/synthra/types/core/enums.rb +102 -0
  187. data/lib/synthra/types/core/identifiers.rb +445 -0
  188. data/lib/synthra/types/core/primitives.rb +586 -0
  189. data/lib/synthra/types/core/references.rb +466 -0
  190. data/lib/synthra/types/core/sequences.rb +304 -0
  191. data/lib/synthra/types/crypto/crypto.rb +162 -0
  192. data/lib/synthra/types/date_time/dates.rb +387 -0
  193. data/lib/synthra/types/finance_banking/banking.rb +424 -0
  194. data/lib/synthra/types/finance_banking/credit_cards.rb +24 -0
  195. data/lib/synthra/types/finance_banking/identifiers.rb +93 -0
  196. data/lib/synthra/types/formula.rb +184 -0
  197. data/lib/synthra/types/health_medical/medical.rb +150 -0
  198. data/lib/synthra/types/hostile_payloads.rb +122 -0
  199. data/lib/synthra/types/json_array.rb +51 -0
  200. data/lib/synthra/types/media_entertainment/media.rb +62 -0
  201. data/lib/synthra/types/naughty_string.rb +30 -0
  202. data/lib/synthra/types/personal_names/chinese.rb +41 -0
  203. data/lib/synthra/types/personal_names/identifiers.rb +187 -0
  204. data/lib/synthra/types/personal_names/names.rb +246 -0
  205. data/lib/synthra/types/personal_names/national_id.rb +89 -0
  206. data/lib/synthra/types/personal_names/titles_suffixes.rb +41 -0
  207. data/lib/synthra/types/regex.rb +248 -0
  208. data/lib/synthra/types/registry.rb +182 -0
  209. data/lib/synthra/types/repeating_element.rb +50 -0
  210. data/lib/synthra/types/scenario.rb +29 -0
  211. data/lib/synthra/types/technology_internet/apps.rb +67 -0
  212. data/lib/synthra/types/technology_internet/communication.rb +162 -0
  213. data/lib/synthra/types/technology_internet/devices.rb +80 -0
  214. data/lib/synthra/types/technology_internet/formats.rb +139 -0
  215. data/lib/synthra/types/technology_internet/networking.rb +143 -0
  216. data/lib/synthra/types/template.rb +92 -0
  217. data/lib/synthra/types/text_content/business.rb +128 -0
  218. data/lib/synthra/types/text_content/colors.rb +70 -0
  219. data/lib/synthra/types/text_content/misc.rb +237 -0
  220. data/lib/synthra/types/text_content/security.rb +130 -0
  221. data/lib/synthra/types/text_content/text_generation.rb +532 -0
  222. data/lib/synthra/types/travel/travel.rb +150 -0
  223. data/lib/synthra/utils/string_distance.rb +133 -0
  224. data/lib/synthra/validator/dsl_validator.rb +339 -0
  225. data/lib/synthra/validator/path_validator.rb +615 -0
  226. data/lib/synthra/version.rb +35 -0
  227. data/lib/synthra/webhook_simulator.rb +341 -0
  228. data/lib/synthra.rb +259 -0
  229. data/schemas/address.dsl +16 -0
  230. data/schemas/api_response.dsl +8 -0
  231. data/schemas/error_payload.dsl +9 -0
  232. data/schemas/order.dsl +10 -0
  233. data/schemas/order_item.dsl +8 -0
  234. data/schemas/payment.dsl +11 -0
  235. data/schemas/social_post.dsl +13 -0
  236. data/schemas/user.dsl +10 -0
  237. data/scripts/batch_fix_all.rb +96 -0
  238. data/scripts/delete_old_files.rb +32 -0
  239. data/scripts/fix_all_grouped_files.rb +137 -0
  240. data/scripts/fix_all_indentation.rb +48 -0
  241. data/scripts/fix_all_syntax.rb +124 -0
  242. data/scripts/fix_grouped_files.rb +184 -0
  243. data/scripts/fix_syntax_errors.rb +108 -0
  244. data/scripts/group_domain_types.rb +112 -0
  245. data/scripts/group_domain_types_fixed.rb +150 -0
  246. data/scripts/merge_domains_to_one_file.rb +68 -0
  247. data/scripts/move_existing_types.rb +130 -0
  248. data/scripts/split_grouped_types.rb +142 -0
  249. data/tech_docs/README.md +134 -0
  250. data/tech_docs/advanced/streaming.md +405 -0
  251. data/tech_docs/advanced/thread_safety.md +253 -0
  252. data/tech_docs/api/overview.md +485 -0
  253. data/tech_docs/appendices/type_chart.md +193 -0
  254. data/tech_docs/basic_concepts.md +383 -0
  255. data/tech_docs/behaviors/overview.md +346 -0
  256. data/tech_docs/dsl/complex_types.md +790 -0
  257. data/tech_docs/dsl/core_types.md +464 -0
  258. data/tech_docs/dsl/datetime_types.md +325 -0
  259. data/tech_docs/dsl/field_modifiers.md +414 -0
  260. data/tech_docs/dsl/grammar.md +431 -0
  261. data/tech_docs/dsl/schema_definition.md +399 -0
  262. data/tech_docs/export/README.md +276 -0
  263. data/tech_docs/installation.md +273 -0
  264. data/tech_docs/integration/ci_cd.md +707 -0
  265. data/tech_docs/integration/ci_cd_guide.md +579 -0
  266. data/tech_docs/integration/factory_bot.md +485 -0
  267. data/tech_docs/integration/rails.md +630 -0
  268. data/tech_docs/integration/rspec.md +449 -0
  269. data/tech_docs/modes/overview.md +350 -0
  270. data/tech_docs/performance/NATIVE_RUST_EXTENSION.md +1270 -0
  271. data/tech_docs/performance/OPTIMIZATION_GUIDE.md +901 -0
  272. data/tech_docs/quick_start.md +256 -0
  273. data/tech_docs/templates/README.md +805 -0
  274. data/tech_docs/tutorials/advanced.md +371 -0
  275. data/tech_docs/tutorials/getting_started.md +189 -0
  276. data/tech_docs/tutorials/intermediate.md +231 -0
  277. data/tech_docs/tutorials/template_gallery.md +569 -0
  278. data/tech_example/01_basic_usage.rb +238 -0
  279. data/tech_example/02_types_demo.rb +336 -0
  280. data/tech_example/04_cli_usage.md +429 -0
  281. data/tech_example/05_database_seeding.rb +283 -0
  282. data/tech_example/07_rspec_integration.rb +359 -0
  283. data/tech_example/10_custom_types.rb +387 -0
  284. data/tech_example/12_behaviors.rb +372 -0
  285. data/tech_example/13_twitter_dm_example.rb +120 -0
  286. data/tech_example/14_exact_json_structure.rb +253 -0
  287. data/tech_example/16_lsp_server.rb +56 -0
  288. data/tech_example/17_property_testing.rb +92 -0
  289. data/tech_example/18_enhanced_repl.rb +120 -0
  290. data/tech_example/19_security_fuzzing.rb +145 -0
  291. data/tech_example/NEW_FEATURES.md +169 -0
  292. data/tech_example/README.md +118 -0
  293. data/tech_example/schemas/api_response.dsl +123 -0
  294. data/tech_example/schemas/ecommerce.dsl +121 -0
  295. data/tech_example/schemas/twitter_dm.dsl +109 -0
  296. data/tech_example/schemas/user.dsl +36 -0
  297. data/vscode-extension/README.md +246 -0
  298. data/vscode-extension/language-configuration.json +31 -0
  299. data/vscode-extension/package.json +55 -0
  300. data/vscode-extension/snippets/fakedatadsl.json +198 -0
  301. data/vscode-extension/syntaxes/fakedatadsl.tmLanguage.json +128 -0
  302. metadata +478 -0
data/docs/SCENARIOS.md ADDED
@@ -0,0 +1,576 @@
1
+ # Scenario-Based Test Data Fixtures
2
+
3
+ FakeDataDSL Scenarios let you define **complex, interconnected test data** with named references, lazy evaluation, and inheritance. Think of it as "Fixtures 2.0" that combines the best of Rails fixtures and Factory Bot.
4
+
5
+ ## Quick Start
6
+
7
+ ```ruby
8
+ # Define a scenario
9
+ FakeDataDSL::Scenarios.define(:e_commerce_checkout) do
10
+ # Define entities with 'let'
11
+ let(:buyer) { User.generate(role: "customer", verified: true) }
12
+ let(:seller) { User.generate(role: "merchant") }
13
+ let(:product) { Product.generate(seller: seller, price: 99.99) }
14
+ let(:cart) { ShoppingCart.generate(user: buyer, items: [product]) }
15
+ let(:order) { Order.generate(user: buyer, cart: cart, status: "pending") }
16
+ end
17
+
18
+ # Use in tests
19
+ RSpec.describe "Checkout" do
20
+ include_scenario :e_commerce_checkout
21
+
22
+ it "completes the order" do
23
+ expect(order.status).to eq("pending")
24
+ order.complete!
25
+ expect(order.status).to eq("completed")
26
+ end
27
+ end
28
+ ```
29
+
30
+ ## Defining Scenarios
31
+
32
+ ### Basic Scenario
33
+
34
+ ```ruby
35
+ FakeDataDSL::Scenarios.define(:basic_user) do
36
+ let(:user) { User.generate }
37
+ let(:profile) { Profile.generate(user: user) }
38
+ end
39
+ ```
40
+
41
+ ### With Schema References
42
+
43
+ ```ruby
44
+ FakeDataDSL::Scenarios.define(:blog_post) do
45
+ # Reference other scenarios
46
+ include_scenario :basic_user
47
+
48
+ let(:category) { Category.generate(name: "Technology") }
49
+ let(:post) {
50
+ Post.generate(
51
+ author: user, # From included scenario
52
+ category: category,
53
+ published: true
54
+ )
55
+ }
56
+ let(:comments) {
57
+ 3.times.map { Comment.generate(post: post, author: User.generate) }
58
+ }
59
+ end
60
+ ```
61
+
62
+ ### DSL File Syntax
63
+
64
+ You can also define scenarios in `.dsl` files:
65
+
66
+ ```ruby
67
+ # db/schemas/scenarios/e_commerce.dsl
68
+ @scenario "e_commerce_checkout"
69
+ Users:
70
+ buyer: User(role: "customer", verified: true)
71
+ seller: User(role: "merchant")
72
+
73
+ Products:
74
+ laptop: Product(seller: @seller, price: 999.99, stock: 10)
75
+ phone: Product(seller: @seller, price: 499.99, stock: 5)
76
+
77
+ Cart:
78
+ cart: ShoppingCart(user: @buyer)
79
+ items:
80
+ - CartItem(product: @laptop, quantity: 1)
81
+ - CartItem(product: @phone, quantity: 2)
82
+
83
+ Order:
84
+ pending_order: Order(user: @buyer, status: "pending")
85
+ from_cart: @cart
86
+ ```
87
+
88
+ ## Using Scenarios
89
+
90
+ ### RSpec Integration
91
+
92
+ ```ruby
93
+ # spec/rails_helper.rb
94
+ require 'fake_data_dsl/scenarios'
95
+
96
+ RSpec.configure do |config|
97
+ config.include FakeDataDSL::Scenarios::RSpecHelpers
98
+ end
99
+ ```
100
+
101
+ ```ruby
102
+ # spec/features/checkout_spec.rb
103
+ RSpec.describe "Checkout", type: :feature do
104
+ include_scenario :e_commerce_checkout
105
+
106
+ it "shows cart total" do
107
+ visit cart_path(cart)
108
+ expect(page).to have_content("$1,499.97") # laptop + 2 phones
109
+ end
110
+
111
+ it "processes payment" do
112
+ login_as buyer
113
+ visit checkout_path(order)
114
+ click_button "Pay Now"
115
+ expect(order.reload.status).to eq("paid")
116
+ end
117
+ end
118
+ ```
119
+
120
+ ### Minitest Integration
121
+
122
+ ```ruby
123
+ # test/test_helper.rb
124
+ require 'fake_data_dsl/scenarios'
125
+
126
+ class ActiveSupport::TestCase
127
+ include FakeDataDSL::Scenarios::MinitestHelpers
128
+ end
129
+ ```
130
+
131
+ ```ruby
132
+ # test/integration/checkout_test.rb
133
+ class CheckoutTest < ActionDispatch::IntegrationTest
134
+ include_scenario :e_commerce_checkout
135
+
136
+ test "completes checkout" do
137
+ post checkout_path(order), params: { payment_method: "credit_card" }
138
+ assert_equal "completed", order.reload.status
139
+ end
140
+ end
141
+ ```
142
+
143
+ ## Lazy Evaluation
144
+
145
+ Scenario entities are lazily evaluated - they're only created when accessed:
146
+
147
+ ```ruby
148
+ FakeDataDSL::Scenarios.define(:expensive_setup) do
149
+ let(:user) { User.generate } # Not created yet
150
+ let(:large_dataset) {
151
+ 1000.times.map { Record.generate(user: user) }
152
+ } # Not created yet
153
+ end
154
+
155
+ RSpec.describe "Performance" do
156
+ include_scenario :expensive_setup
157
+
158
+ it "accesses user" do
159
+ expect(user).to be_present # NOW user is created
160
+ # large_dataset is never created in this test
161
+ end
162
+
163
+ it "accesses dataset" do
164
+ expect(large_dataset.count).to eq(1000) # NOW both are created
165
+ end
166
+ end
167
+ ```
168
+
169
+ ## Entity References
170
+
171
+ ### Forward References
172
+
173
+ ```ruby
174
+ FakeDataDSL::Scenarios.define(:circular) do
175
+ let(:team) { Team.generate(lead: lead) } # References 'lead' defined below
176
+ let(:lead) { User.generate(team: team) } # References 'team' defined above
177
+ end
178
+ ```
179
+
180
+ ### Cross-Scenario References
181
+
182
+ ```ruby
183
+ FakeDataDSL::Scenarios.define(:users) do
184
+ let(:admin) { User.generate(role: "admin") }
185
+ let(:regular) { User.generate(role: "user") }
186
+ end
187
+
188
+ FakeDataDSL::Scenarios.define(:permissions) do
189
+ include_scenario :users
190
+
191
+ let(:admin_permissions) { Permission.generate(user: admin, level: "full") }
192
+ let(:user_permissions) { Permission.generate(user: regular, level: "read") }
193
+ end
194
+ ```
195
+
196
+ ## Scenario Inheritance
197
+
198
+ ### Extending Scenarios
199
+
200
+ ```ruby
201
+ FakeDataDSL::Scenarios.define(:base_user) do
202
+ let(:user) { User.generate }
203
+ let(:profile) { Profile.generate(user: user) }
204
+ end
205
+
206
+ FakeDataDSL::Scenarios.define(:admin_user, extends: :base_user) do
207
+ # Override user definition
208
+ let(:user) { User.generate(role: "admin", permissions: ["all"]) }
209
+
210
+ # Add new entities
211
+ let(:audit_log) { AuditLog.generate(admin: user) }
212
+ end
213
+ ```
214
+
215
+ ### Multiple Inheritance
216
+
217
+ ```ruby
218
+ FakeDataDSL::Scenarios.define(:full_checkout,
219
+ extends: [:e_commerce_checkout, :payment_setup, :shipping_setup]
220
+ ) do
221
+ let(:complete_order) {
222
+ Order.generate(
223
+ user: buyer,
224
+ cart: cart,
225
+ payment: payment_method,
226
+ shipping: shipping_address,
227
+ status: "complete"
228
+ )
229
+ }
230
+ end
231
+ ```
232
+
233
+ ## Context and State
234
+
235
+ ### Shared Context
236
+
237
+ ```ruby
238
+ FakeDataDSL::Scenarios.define(:multi_tenant) do
239
+ let(:tenant) { Tenant.generate }
240
+
241
+ # All entities share the tenant context
242
+ with_context(tenant_id: -> { tenant.id }) do
243
+ let(:user) { User.generate } # Automatically gets tenant_id
244
+ let(:product) { Product.generate } # Automatically gets tenant_id
245
+ let(:order) { Order.generate(user: user) } # Automatically gets tenant_id
246
+ end
247
+ end
248
+ ```
249
+
250
+ ### Conditional Entities
251
+
252
+ ```ruby
253
+ FakeDataDSL::Scenarios.define(:feature_flags) do
254
+ let(:user) { User.generate }
255
+
256
+ let(:premium_feature) {
257
+ if user.subscription == "premium"
258
+ PremiumFeature.generate(user: user)
259
+ end
260
+ }
261
+
262
+ let(:beta_feature) {
263
+ BetaFeature.generate(user: user) if ENV["ENABLE_BETA"]
264
+ }
265
+ end
266
+ ```
267
+
268
+ ## Parameterized Scenarios
269
+
270
+ ### With Arguments
271
+
272
+ ```ruby
273
+ FakeDataDSL::Scenarios.define(:order_with_items) do |count: 3, status: "pending"|
274
+ let(:user) { User.generate }
275
+ let(:items) { count.times.map { OrderItem.generate } }
276
+ let(:order) { Order.generate(user: user, items: items, status: status) }
277
+ end
278
+
279
+ # Usage
280
+ RSpec.describe "Orders" do
281
+ include_scenario :order_with_items, count: 5, status: "shipped"
282
+
283
+ it "has correct items" do
284
+ expect(order.items.count).to eq(5)
285
+ expect(order.status).to eq("shipped")
286
+ end
287
+ end
288
+ ```
289
+
290
+ ### Dynamic Scenarios
291
+
292
+ ```ruby
293
+ FakeDataDSL::Scenarios.define(:scaled_data) do |scale: 1|
294
+ let(:users) { (10 * scale).times.map { User.generate } }
295
+ let(:products) { (100 * scale).times.map { Product.generate } }
296
+ let(:orders) { (50 * scale).times.map { Order.generate } }
297
+ end
298
+
299
+ # Small dataset for unit tests
300
+ include_scenario :scaled_data, scale: 1
301
+
302
+ # Large dataset for load tests
303
+ include_scenario :scaled_data, scale: 100
304
+ ```
305
+
306
+ ## Scenario Variants
307
+
308
+ ### Named Variants
309
+
310
+ ```ruby
311
+ FakeDataDSL::Scenarios.define(:user_states) do
312
+ variant(:active) do
313
+ let(:user) { User.generate(active: true, verified: true) }
314
+ end
315
+
316
+ variant(:pending) do
317
+ let(:user) { User.generate(active: false, verified: false) }
318
+ end
319
+
320
+ variant(:suspended) do
321
+ let(:user) { User.generate(active: false, suspended_at: Time.current) }
322
+ end
323
+ end
324
+
325
+ # Usage
326
+ include_scenario :user_states, variant: :suspended
327
+ ```
328
+
329
+ ### Mode-Based Variants
330
+
331
+ ```ruby
332
+ FakeDataDSL::Scenarios.define(:edge_cases) do
333
+ variant(:happy_path, mode: :random) do
334
+ let(:user) { User.generate }
335
+ end
336
+
337
+ variant(:edge_cases, mode: :edge) do
338
+ let(:user) { User.generate } # Will use edge case values
339
+ end
340
+
341
+ variant(:hostile, mode: :hostile) do
342
+ let(:user) { User.generate } # Will use hostile values
343
+ end
344
+ end
345
+ ```
346
+
347
+ ## Hooks
348
+
349
+ ### Setup and Teardown
350
+
351
+ ```ruby
352
+ FakeDataDSL::Scenarios.define(:with_hooks) do
353
+ before do
354
+ Rails.cache.clear
355
+ Sidekiq::Testing.inline!
356
+ end
357
+
358
+ after do
359
+ Sidekiq::Testing.fake!
360
+ end
361
+
362
+ let(:user) { User.generate }
363
+ end
364
+ ```
365
+
366
+ ### Entity Callbacks
367
+
368
+ ```ruby
369
+ FakeDataDSL::Scenarios.define(:with_callbacks) do
370
+ let(:user) {
371
+ User.generate.tap do |u|
372
+ u.confirm! # Run after creation
373
+ u.update!(last_login: Time.current)
374
+ end
375
+ }
376
+ end
377
+ ```
378
+
379
+ ## Database Integration
380
+
381
+ ### Creating Records
382
+
383
+ ```ruby
384
+ FakeDataDSL::Scenarios.define(:persisted) do
385
+ # create() persists to database
386
+ let(:user) { create(:user) }
387
+ let(:order) { create(:order, user: user) }
388
+ end
389
+
390
+ FakeDataDSL::Scenarios.define(:in_memory) do
391
+ # build() stays in memory
392
+ let(:user) { build(:user) }
393
+ let(:order) { build(:order, user: user) }
394
+ end
395
+ ```
396
+
397
+ ### Transactional Scenarios
398
+
399
+ ```ruby
400
+ FakeDataDSL::Scenarios.define(:transactional) do
401
+ transactional! # Wrap in transaction, rollback after test
402
+
403
+ let(:user) { create(:user) }
404
+ let(:order) { create(:order) }
405
+ end
406
+ ```
407
+
408
+ ## Debugging Scenarios
409
+
410
+ ### Inspect Scenario
411
+
412
+ ```ruby
413
+ scenario = FakeDataDSL::Scenarios.find(:e_commerce_checkout)
414
+ scenario.entities # => [:buyer, :seller, :product, :cart, :order]
415
+ scenario.dependencies # => { order: [:buyer, :cart], cart: [:buyer, :product], ... }
416
+ ```
417
+
418
+ ### Visualization
419
+
420
+ ```ruby
421
+ # Generate dependency graph
422
+ FakeDataDSL::Scenarios.find(:e_commerce_checkout).to_dot
423
+ # => "digraph { buyer -> cart; cart -> order; ... }"
424
+ ```
425
+
426
+ ### Logging
427
+
428
+ ```ruby
429
+ FakeDataDSL::Scenarios.configure do |config|
430
+ config.logger = Rails.logger
431
+ config.log_level = :debug
432
+ end
433
+
434
+ # Now see:
435
+ # [FakeDataDSL::Scenarios] Creating :user
436
+ # [FakeDataDSL::Scenarios] Creating :order (depends on :user, :cart)
437
+ ```
438
+
439
+ ## API Reference
440
+
441
+ ### Scenarios.define
442
+
443
+ ```ruby
444
+ FakeDataDSL::Scenarios.define(name, options = {}, &block)
445
+ ```
446
+
447
+ **Parameters:**
448
+ - `name` - Symbol name for the scenario
449
+ - `options[:extends]` - Parent scenario(s) to inherit from
450
+ - `block` - Scenario definition block
451
+
452
+ ### Scenario#let
453
+
454
+ ```ruby
455
+ let(name, &block)
456
+ ```
457
+
458
+ Defines a lazy-evaluated entity.
459
+
460
+ ### Scenario#create
461
+
462
+ ```ruby
463
+ create(schema_name, overrides = {})
464
+ ```
465
+
466
+ Creates and persists a record using the schema.
467
+
468
+ ### Scenario#build
469
+
470
+ ```ruby
471
+ build(schema_name, overrides = {})
472
+ ```
473
+
474
+ Builds a record in memory (not persisted).
475
+
476
+ ### include_scenario
477
+
478
+ ```ruby
479
+ include_scenario(name, **options)
480
+ ```
481
+
482
+ Includes a scenario in a test, making all entities available.
483
+
484
+ ## Best Practices
485
+
486
+ ### 1. Keep Scenarios Focused
487
+
488
+ ```ruby
489
+ # Good: Single purpose
490
+ FakeDataDSL::Scenarios.define(:checkout_ready) do
491
+ let(:buyer) { create(:user, :verified) }
492
+ let(:cart) { create(:cart, user: buyer, items: [product]) }
493
+ end
494
+
495
+ # Bad: Too much unrelated data
496
+ FakeDataDSL::Scenarios.define(:everything) do
497
+ let(:user) { ... }
498
+ let(:admin) { ... }
499
+ let(:product) { ... }
500
+ let(:report) { ... }
501
+ # ...50 more entities
502
+ end
503
+ ```
504
+
505
+ ### 2. Use Inheritance for Variations
506
+
507
+ ```ruby
508
+ FakeDataDSL::Scenarios.define(:base_order) do
509
+ let(:user) { create(:user) }
510
+ let(:order) { create(:order, user: user) }
511
+ end
512
+
513
+ FakeDataDSL::Scenarios.define(:pending_order, extends: :base_order) do
514
+ let(:order) { create(:order, user: user, status: "pending") }
515
+ end
516
+
517
+ FakeDataDSL::Scenarios.define(:shipped_order, extends: :base_order) do
518
+ let(:order) { create(:order, user: user, status: "shipped") }
519
+ end
520
+ ```
521
+
522
+ ### 3. Document Dependencies
523
+
524
+ ```ruby
525
+ FakeDataDSL::Scenarios.define(:complex_workflow) do
526
+ # This scenario sets up a complete order fulfillment workflow
527
+ # Dependencies:
528
+ # - buyer: Customer placing the order
529
+ # - seller: Merchant fulfilling the order
530
+ # - product: Item being purchased
531
+ # - order: The order connecting buyer and seller
532
+ # - shipment: Delivery tracking
533
+
534
+ let(:buyer) { ... }
535
+ let(:seller) { ... }
536
+ # ...
537
+ end
538
+ ```
539
+
540
+ ## Troubleshooting
541
+
542
+ ### Circular Dependencies
543
+
544
+ ```ruby
545
+ # Error: Circular dependency detected: user -> team -> user
546
+
547
+ # Fix: Break the cycle with nil defaults
548
+ FakeDataDSL::Scenarios.define(:team_setup) do
549
+ let(:team) { create(:team, lead: nil) }
550
+ let(:user) { create(:user, team: team) }
551
+
552
+ after do
553
+ team.update!(lead: user)
554
+ end
555
+ end
556
+ ```
557
+
558
+ ### Entity Not Found
559
+
560
+ ```ruby
561
+ # Error: Unknown entity: :admin
562
+
563
+ # Fix: Check includes
564
+ FakeDataDSL::Scenarios.define(:needs_admin) do
565
+ include_scenario :users # Make sure this defines :admin
566
+
567
+ let(:action) { AdminAction.create(admin: admin) }
568
+ end
569
+ ```
570
+
571
+ ## See Also
572
+
573
+ - [Factory Bot Integration](FACTORY_BOT.md)
574
+ - [Personas](PERSONAS.md)
575
+ - [Time Travel](TIME_TRAVEL.md)
576
+ - [Property Testing](PROPERTY_TESTING.md)