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
@@ -0,0 +1,372 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # ============================================================================
5
+ # FakeDataDSL - Behaviors Examples
6
+ # ============================================================================
7
+ # This file demonstrates behavior simulation features.
8
+ # Run with: cd fake_data_dsl && ruby tech_example/12_behaviors.rb
9
+ # ============================================================================
10
+
11
+ # Load the local gem
12
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
13
+ require 'fake_data_dsl'
14
+ require 'json'
15
+ require 'benchmark'
16
+
17
+ puts "=" * 70
18
+ puts "FakeDataDSL Behaviors Examples"
19
+ puts "=" * 70
20
+ puts
21
+
22
+ # ============================================================================
23
+ # Example 1: Latency Simulation
24
+ # ============================================================================
25
+ puts "1. LATENCY SIMULATION"
26
+ puts "-" * 40
27
+
28
+ latency_schema = FakeDataDSL.parse(<<~DSL)
29
+ SlowAPI:
30
+ @latency 100..300ms
31
+
32
+ id: uuid
33
+ data: text(50..200)
34
+ timestamp: now
35
+ DSL
36
+
37
+ puts "Generating with latency (100-300ms):"
38
+ 5.times do |i|
39
+ time = Benchmark.realtime { latency_schema.generate }
40
+ puts " Request #{i + 1}: #{(time * 1000).round}ms"
41
+ end
42
+ puts
43
+
44
+ # ============================================================================
45
+ # Example 2: Failure Simulation
46
+ # ============================================================================
47
+ puts "2. FAILURE SIMULATION"
48
+ puts "-" * 40
49
+
50
+ failure_schema = FakeDataDSL.parse(<<~DSL)
51
+ FlakyService:
52
+ @failure 30%
53
+
54
+ id: uuid
55
+ status: enum(success, pending)
56
+ DSL
57
+
58
+ puts "Attempting 10 generations (30% failure rate):"
59
+ success_count = 0
60
+ failure_count = 0
61
+
62
+ 10.times do |i|
63
+ begin
64
+ failure_schema.generate
65
+ success_count += 1
66
+ puts " Attempt #{i + 1}: SUCCESS"
67
+ rescue FakeDataDSL::Errors::SimulatedFailure
68
+ failure_count += 1
69
+ puts " Attempt #{i + 1}: FAILED (simulated)"
70
+ end
71
+ end
72
+ puts "Results: #{success_count} successes, #{failure_count} failures"
73
+ puts
74
+
75
+ # ============================================================================
76
+ # Example 3: Partial Data Simulation
77
+ # ============================================================================
78
+ puts "3. PARTIAL DATA SIMULATION"
79
+ puts "-" * 40
80
+
81
+ partial_schema = FakeDataDSL.parse(<<~DSL)
82
+ IncompleteResponse:
83
+ @partial_data 40%
84
+
85
+ id: uuid
86
+ name: name
87
+ email: email
88
+ phone: phone
89
+ address: address
90
+ DSL
91
+
92
+ puts "Generating with partial data (40% field drop rate):"
93
+ 5.times do |i|
94
+ response = partial_schema.generate
95
+ fields_present = response.keys
96
+ puts " Response #{i + 1}: #{fields_present.length} fields present: #{fields_present.join(', ')}"
97
+ end
98
+ puts
99
+
100
+ # ============================================================================
101
+ # Example 4: Connection Drop Simulation
102
+ # ============================================================================
103
+ puts "4. CONNECTION DROP SIMULATION"
104
+ puts "-" * 40
105
+
106
+ connection_schema = FakeDataDSL.parse(<<~DSL)
107
+ UnstableConnection:
108
+ @close_connection 20%
109
+
110
+ data: text(100..500)
111
+ DSL
112
+
113
+ puts "Attempting 10 requests (20% connection drop rate):"
114
+ connected = 0
115
+ dropped = 0
116
+
117
+ 10.times do |i|
118
+ begin
119
+ connection_schema.generate
120
+ connected += 1
121
+ puts " Request #{i + 1}: Connected"
122
+ rescue FakeDataDSL::Errors::SimulatedConnectionDrop
123
+ dropped += 1
124
+ puts " Request #{i + 1}: Connection dropped"
125
+ end
126
+ end
127
+ puts "Results: #{connected} connected, #{dropped} dropped"
128
+ puts
129
+
130
+ # ============================================================================
131
+ # Example 5: HTTP Error Simulation
132
+ # ============================================================================
133
+ puts "5. HTTP ERROR SIMULATION"
134
+ puts "-" * 40
135
+
136
+ error_schema = FakeDataDSL.parse(<<~DSL)
137
+ ErrorProneAPI:
138
+ @simulate_error 500 20%
139
+ @simulate_error 503 10%
140
+
141
+ success: boolean(true:90%)
142
+ data: object
143
+ DSL
144
+
145
+ puts "Attempting 15 requests (500: 20%, 503: 10%):"
146
+ results = { success: 0, "500" => 0, "503" => 0 }
147
+
148
+ 15.times do |i|
149
+ begin
150
+ error_schema.generate
151
+ results[:success] += 1
152
+ puts " Request #{i + 1}: 200 OK"
153
+ rescue FakeDataDSL::Errors::SimulatedError => e
154
+ results[e.status_code.to_s] += 1
155
+ puts " Request #{i + 1}: #{e.status_code} Error"
156
+ end
157
+ end
158
+ puts "Results: #{results}"
159
+ puts
160
+
161
+ # ============================================================================
162
+ # Example 6: Combined Behaviors (Real-World API)
163
+ # ============================================================================
164
+ puts "6. COMBINED BEHAVIORS (Real-World API)"
165
+ puts "-" * 40
166
+
167
+ realistic_api = FakeDataDSL.parse(<<~DSL)
168
+ RealisticAPI:
169
+ @latency 50..500ms
170
+ @failure 5%
171
+ @simulate_error 500 2%
172
+ @simulate_error 503 1%
173
+ @partial_data 10%
174
+
175
+ request_id: uuid
176
+ success: boolean(true:95%)
177
+ data: text(100..500)
178
+ timestamp: now
179
+ DSL
180
+
181
+ puts "Simulating 10 API calls:"
182
+ 10.times do |i|
183
+ start_time = Time.now
184
+ begin
185
+ response = realistic_api.generate
186
+ elapsed = ((Time.now - start_time) * 1000).round
187
+ fields = response.keys.length
188
+ puts " Call #{i + 1}: 200 OK (#{elapsed}ms, #{fields} fields)"
189
+ rescue FakeDataDSL::Errors::SimulatedFailure
190
+ elapsed = ((Time.now - start_time) * 1000).round
191
+ puts " Call #{i + 1}: Service Error (#{elapsed}ms)"
192
+ rescue FakeDataDSL::Errors::SimulatedError => e
193
+ elapsed = ((Time.now - start_time) * 1000).round
194
+ puts " Call #{i + 1}: HTTP #{e.status_code} (#{elapsed}ms)"
195
+ end
196
+ end
197
+ puts
198
+
199
+ # ============================================================================
200
+ # Example 7: Field-Level Behaviors
201
+ # ============================================================================
202
+ puts "7. FIELD-LEVEL BEHAVIORS"
203
+ puts "-" * 40
204
+
205
+ field_behavior_schema = FakeDataDSL.parse(<<~DSL)
206
+ UserProfile:
207
+ id: uuid
208
+ name: name
209
+ email: email
210
+ avatar: url @partial_data 50%
211
+ bio: text(100..300) @partial_data 30%
212
+ DSL
213
+
214
+ puts "Generating profiles (avatar 50% missing, bio 30% missing):"
215
+ stats = { avatar: 0, bio: 0 }
216
+ 10.times do |i|
217
+ profile = field_behavior_schema.generate
218
+ avatar_present = profile.key?('avatar')
219
+ bio_present = profile.key?('bio')
220
+ stats[:avatar] += 1 if avatar_present
221
+ stats[:bio] += 1 if bio_present
222
+ puts " Profile #{i + 1}: avatar=#{avatar_present ? '✓' : '✗'}, bio=#{bio_present ? '✓' : '✗'}"
223
+ end
224
+ puts "Present: avatar #{stats[:avatar]}/10, bio #{stats[:bio]}/10"
225
+ puts
226
+
227
+ # ============================================================================
228
+ # Example 8: Custom Behavior
229
+ # ============================================================================
230
+ puts "8. CUSTOM BEHAVIOR"
231
+ puts "-" * 40
232
+
233
+ # Register a custom logging behavior
234
+ FakeDataDSL.register_behavior(:log) do |result, _context, value|
235
+ puts "[LOG] Generated #{result.keys.length} fields"
236
+ puts "[LOG] Config: #{value.inspect}" if value
237
+ result
238
+ end
239
+
240
+ # Note: Custom behaviors need to be added to schema manually or through DSL extension
241
+ # This is a demonstration of the registration API
242
+
243
+ puts "Custom behavior registered. Usage in DSL:"
244
+ puts <<~DSL
245
+ Schema:
246
+ @log true
247
+
248
+ id: uuid
249
+ name: name
250
+ DSL
251
+ puts
252
+
253
+ # ============================================================================
254
+ # Example 9: Retry Pattern Testing
255
+ # ============================================================================
256
+ puts "9. RETRY PATTERN TESTING"
257
+ puts "-" * 40
258
+
259
+ retry_test_schema = FakeDataDSL.parse(<<~DSL)
260
+ RetryableAPI:
261
+ @failure 40%
262
+
263
+ data: text(50..100)
264
+ DSL
265
+
266
+ def fetch_with_retry(schema, max_retries: 3)
267
+ retries = 0
268
+ begin
269
+ schema.generate
270
+ rescue FakeDataDSL::Errors::SimulatedFailure
271
+ retries += 1
272
+ if retries <= max_retries
273
+ puts " Retry #{retries}..."
274
+ sleep(0.1 * retries) # Exponential backoff simulation
275
+ retry
276
+ else
277
+ raise
278
+ end
279
+ end
280
+ end
281
+
282
+ puts "Testing retry pattern (max 3 retries, 40% failure rate):"
283
+ 5.times do |i|
284
+ puts " Request #{i + 1}:"
285
+ begin
286
+ start = Time.now
287
+ result = fetch_with_retry(retry_test_schema)
288
+ elapsed = ((Time.now - start) * 1000).round
289
+ puts " SUCCESS after #{elapsed}ms"
290
+ rescue FakeDataDSL::Errors::SimulatedFailure
291
+ puts " FAILED after max retries"
292
+ end
293
+ end
294
+ puts
295
+
296
+ # ============================================================================
297
+ # Example 10: Chaos Engineering
298
+ # ============================================================================
299
+ puts "10. CHAOS ENGINEERING SCENARIO"
300
+ puts "-" * 40
301
+
302
+ chaos_schema = FakeDataDSL.parse(<<~DSL)
303
+ ChaosAPI:
304
+ @latency 100..2000ms
305
+ @failure 15%
306
+ @close_connection 5%
307
+ @simulate_error 500 5%
308
+ @simulate_error 502 3%
309
+ @simulate_error 503 2%
310
+ @partial_data 20%
311
+
312
+ transaction_id: uuid
313
+ amount: number(100..10000)
314
+ status: enum(pending, completed, failed)
315
+ timestamp: now
316
+ DSL
317
+
318
+ puts "Chaos test - 20 requests with aggressive failure modes:"
319
+ results = {
320
+ success: 0,
321
+ failure: 0,
322
+ connection_drop: 0,
323
+ http_500: 0,
324
+ http_502: 0,
325
+ http_503: 0,
326
+ total_latency: 0
327
+ }
328
+
329
+ 20.times do |i|
330
+ start = Time.now
331
+ begin
332
+ response = chaos_schema.generate
333
+ elapsed = (Time.now - start) * 1000
334
+ results[:success] += 1
335
+ results[:total_latency] += elapsed
336
+ status = "OK (#{elapsed.round}ms, #{response.keys.length} fields)"
337
+ rescue FakeDataDSL::Errors::SimulatedFailure
338
+ results[:failure] += 1
339
+ status = "FAILURE"
340
+ rescue FakeDataDSL::Errors::SimulatedConnectionDrop
341
+ results[:connection_drop] += 1
342
+ status = "CONNECTION DROP"
343
+ rescue FakeDataDSL::Errors::SimulatedError => e
344
+ case e.status_code
345
+ when 500 then results[:http_500] += 1
346
+ when 502 then results[:http_502] += 1
347
+ when 503 then results[:http_503] += 1
348
+ end
349
+ status = "HTTP #{e.status_code}"
350
+ end
351
+
352
+ print "."
353
+ end
354
+ puts
355
+
356
+ puts "\nChaos Test Results:"
357
+ puts " Successful: #{results[:success]}"
358
+ puts " Failures: #{results[:failure]}"
359
+ puts " Connection drops: #{results[:connection_drop]}"
360
+ puts " HTTP 500: #{results[:http_500]}"
361
+ puts " HTTP 502: #{results[:http_502]}"
362
+ puts " HTTP 503: #{results[:http_503]}"
363
+ if results[:success] > 0
364
+ avg_latency = results[:total_latency] / results[:success]
365
+ puts " Avg latency (success): #{avg_latency.round}ms"
366
+ end
367
+ puts
368
+
369
+ puts "=" * 70
370
+ puts "Behaviors examples completed!"
371
+ puts "=" * 70
372
+
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # ============================================================================
5
+ # FakeDataDSL - Twitter/X Direct Message Webhook Example
6
+ # ============================================================================
7
+ # 100% schema-driven - NO Ruby code needed for data transformation!
8
+ #
9
+ # Features demonstrated:
10
+ # - shared() - recipient is the SAME for all 10 webhooks (like a real inbox)
11
+ # - copy() - links sender_id, recipient_id, for_user_id
12
+ # - map_by_field() - creates dynamic user ID keys
13
+ # - generate_many() - efficient batch generation
14
+ #
15
+ # Run: cd fake_data_dsl && ruby tech_example/13_twitter_dm_example.rb
16
+ # ============================================================================
17
+
18
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
19
+ require 'fake_data_dsl'
20
+ require 'json'
21
+
22
+ puts "=" * 70
23
+ puts "FakeDataDSL - Twitter DM Webhook Generator"
24
+ puts "=" * 70
25
+ puts
26
+
27
+ # ============================================================================
28
+ # 100% SCHEMA - shared() makes recipient same across all records!
29
+ # ============================================================================
30
+ registry = FakeDataDSL::Registry.new
31
+ registry.load_string(<<~DSL)
32
+ TwitterDMWebhook:
33
+ eventName: const("new_twitter_direct_message")
34
+ eventData: EventData
35
+
36
+ EventData:
37
+ users: map_by_field("id", sender: TwitterUser, recipient: shared(TwitterUser))
38
+ for_user_id: copy("users.recipient.id")
39
+ direct_message_events: array(DirectMessageEvent, 1..1)
40
+
41
+ DirectMessageEvent:
42
+ type: const("message_create")
43
+ id: snowflake_id
44
+ created_timestamp: unix_timestamp_ms
45
+ message_create: MessageCreate
46
+
47
+ MessageCreate:
48
+ target: Target
49
+ sender_id: copy("users.sender.id")
50
+ message_data: MessageData
51
+
52
+ Target:
53
+ recipient_id: copy("users.recipient.id")
54
+
55
+ MessageData:
56
+ text: message_text
57
+ entities: Entities
58
+ WEB_HOOK_RECEIVE_TIME: unix_timestamp_ms
59
+
60
+ Entities:
61
+ hashtags: empty_array
62
+ symbols: empty_array
63
+ user_mentions: empty_array
64
+ urls: empty_array
65
+
66
+ TwitterUser:
67
+ id: snowflake_id
68
+ created_timestamp: unix_timestamp_ms
69
+ name: full_name
70
+ screen_name: social_handle
71
+ location: city
72
+ description: text(20..100)
73
+ url: url
74
+ protected: boolean
75
+ verified: boolean
76
+ followers_count: number(10..1000000)
77
+ friends_count: number(5..5000)
78
+ statuses_count: number(10..500000)
79
+ profile_image_url: url
80
+ profile_image_url_https: url
81
+ DSL
82
+
83
+ # ============================================================================
84
+ # Generate 10 Twitter DM Webhooks - recipient is SHARED across all!
85
+ # ============================================================================
86
+
87
+ puts "Generating 10 Twitter DM Webhook Events..."
88
+ puts "Note: ALL events go to the SAME recipient (shared)!"
89
+ puts "-" * 70
90
+ puts
91
+
92
+ schema = registry.schema("TwitterDMWebhook")
93
+
94
+ # ONE LINE - generate_many with shared context!
95
+ webhooks = schema.generate_many(10, registry: registry)
96
+
97
+ # Show first 3 in detail
98
+ webhooks.first(3).each_with_index do |webhook, i|
99
+ puts "Event #{i + 1}:"
100
+ puts JSON.pretty_generate(webhook)
101
+ puts
102
+ puts "-" * 70
103
+ puts
104
+ end
105
+
106
+ # Verify recipient is shared across all webhooks
107
+ recipient_ids = webhooks.map { |w| w.dig("eventData", "for_user_id") }.uniq
108
+ sender_ids = webhooks.map { |w| w.dig("eventData", "direct_message_events", 0, "message_create", "sender_id") }.uniq
109
+
110
+ puts "=" * 70
111
+ puts "VERIFICATION:"
112
+ puts " Unique recipient IDs: #{recipient_ids.length} (should be 1 - SHARED)"
113
+ puts " Unique sender IDs: #{sender_ids.length} (should be 10 - DIFFERENT)"
114
+ puts "-" * 70
115
+ puts "✓ 100% schema-driven - NO Ruby transformation code!"
116
+ puts "✓ shared() keeps recipient same across all webhooks"
117
+ puts "✓ copy() links sender_id, recipient_id, for_user_id"
118
+ puts "✓ map_by_field() creates dynamic user ID keys"
119
+ puts "✓ generate_many() for efficient batch generation"
120
+ puts "=" * 70