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,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
5
+ module Synthra
6
+ # Configuration File Support
7
+ #
8
+ # Loads configuration from YAML files following Rails conventions.
9
+ # Supports environment-specific configuration.
10
+ #
11
+ # @example synthra.yml
12
+ # default_mode: random
13
+ # seed: 12345
14
+ # locale: en
15
+ # limits:
16
+ # max_array_size: 100
17
+ # max_recursion: 5
18
+ #
19
+ # test:
20
+ # seed: 42 # Deterministic in tests
21
+ #
22
+ # development:
23
+ # seed: null # Random in dev
24
+ #
25
+ module ConfigFile
26
+ # Default config file locations (searched in order)
27
+ CONFIG_PATHS = [
28
+ "config/synthra.yml",
29
+ "synthra.yml",
30
+ ".synthra.yml"
31
+ ].freeze
32
+
33
+ class << self
34
+ # Load configuration from file
35
+ #
36
+ # @param path [String, nil] explicit path or nil to search defaults
37
+ # @param env [String, Symbol] environment name (default: RAILS_ENV or RACK_ENV or 'development')
38
+ # @return [Hash] configuration hash
39
+ #
40
+ def load(path = nil, env: nil)
41
+ path ||= find_config_file
42
+ return {} unless path && File.exist?(path)
43
+
44
+ env ||= determine_environment
45
+
46
+ raw_config = YAML.safe_load(
47
+ File.read(path),
48
+ permitted_classes: [Symbol, Date, Time],
49
+ aliases: true
50
+ ) || {}
51
+
52
+ # Merge base config with environment-specific config
53
+ base_config = raw_config.except(*known_environments)
54
+ env_config = raw_config[env.to_s] || {}
55
+
56
+ deep_merge(base_config, env_config)
57
+ end
58
+
59
+ # Apply configuration to Synthra
60
+ #
61
+ # @param config [Hash] configuration hash
62
+ # @return [void]
63
+ #
64
+ def apply(config)
65
+ Synthra.configure do |c|
66
+ # Core settings
67
+ c.default_mode = config["default_mode"].to_sym if config["default_mode"]
68
+ c.max_unique_retries = config["max_unique_retries"] if config["max_unique_retries"]
69
+ c.allow_eval = config["allow_eval"] if config.key?("allow_eval")
70
+ c.fast_mode = config["fast_mode"] if config.key?("fast_mode")
71
+
72
+ # Field handling
73
+ c.optional_field_presence_rate = config["optional_field_presence_rate"] if config["optional_field_presence_rate"]
74
+ c.nullable_field_null_rate = config["nullable_field_null_rate"] if config["nullable_field_null_rate"]
75
+
76
+ # Limits
77
+ if config["limits"]
78
+ c.limits.max_latency_ms = config["limits"]["max_latency_ms"] if config["limits"]["max_latency_ms"]
79
+ c.limits.max_recursion = config["limits"]["max_recursion"] if config["limits"]["max_recursion"]
80
+ c.limits.max_array_size = config["limits"]["max_array_size"] if config["limits"]["max_array_size"]
81
+ c.limits.max_text_length = config["limits"]["max_text_length"] if config["limits"]["max_text_length"]
82
+ end
83
+ end
84
+ end
85
+
86
+ # Load and apply configuration in one step
87
+ #
88
+ # @param path [String, nil] config file path
89
+ # @param env [String, Symbol] environment
90
+ # @return [Hash] loaded configuration
91
+ #
92
+ def load_and_apply(path = nil, env: nil)
93
+ config = load(path, env: env)
94
+ apply(config) if config.any?
95
+ config
96
+ end
97
+
98
+ # Find configuration file in default locations
99
+ #
100
+ # @return [String, nil] path to config file or nil
101
+ #
102
+ def find_config_file
103
+ CONFIG_PATHS.find { |p| File.exist?(p) }
104
+ end
105
+
106
+ private
107
+
108
+ def determine_environment
109
+ ENV["RAILS_ENV"] || ENV["RACK_ENV"] || ENV["SYNTHRA_ENV"] || "development"
110
+ end
111
+
112
+ def known_environments
113
+ %w[development test production staging]
114
+ end
115
+
116
+ def deep_merge(base, override)
117
+ result = base.dup
118
+ override.each do |key, value|
119
+ if base[key].is_a?(Hash) && value.is_a?(Hash)
120
+ result[key] = deep_merge(base[key], value)
121
+ else
122
+ result[key] = value
123
+ end
124
+ end
125
+ result
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,281 @@
1
+ # frozen_string_literal: true
2
+
3
+ # =============================================================================
4
+
5
+ # Synthra Configuration
6
+ # =============================================================================
7
+ #
8
+ # This file defines the global configuration settings for Synthra.
9
+ # Configuration can be modified using the Synthra.configure block
10
+ # or by directly accessing Synthra.configuration.
11
+ #
12
+ # @example Configure Synthra
13
+ # Synthra.configure do |config|
14
+ # config.default_mode = :edge
15
+ # config.max_unique_retries = 500
16
+ # config.limits.max_latency_ms = 5000
17
+ # end
18
+ #
19
+ # =============================================================================
20
+
21
+
22
+ module Synthra
23
+
24
+ # Global configuration settings for Synthra
25
+ #
26
+ # The Configuration class holds all global settings that affect how
27
+ # Synthra behaves. Settings include default generation mode,
28
+ # uniqueness retry limits, and resource limits.
29
+ #
30
+ # Access the configuration via {Synthra.configuration} or
31
+ # modify it using {Synthra.configure}.
32
+ #
33
+ # @example Access configuration
34
+ # config = Synthra.configuration
35
+ # config.default_mode # => :random
36
+ # config.max_unique_retries # => 1000
37
+ #
38
+ # @example Modify configuration
39
+ # Synthra.configure do |config|
40
+ # config.default_mode = :mixed
41
+ # config.null_optional = true
42
+ # end
43
+ #
44
+ # @example Reset to defaults
45
+ # Synthra.reset_configuration!
46
+ #
47
+
48
+ class Configuration
49
+
50
+ # Valid generation modes
51
+ #
52
+ # @return [Array<Symbol>] the list of valid mode symbols
53
+ #
54
+ # Modes:
55
+ # - :random - Standard fake data generation using Faker
56
+ # - :edge - Generate edge case values (empty strings, nulls, extremes)
57
+ # - :invalid - Generate intentionally invalid data for validation testing
58
+ # - :hostile - Generate security attack payloads (SQL injection, XSS, buffer overflow)
59
+ # - :mixed - Probabilistically mix all modes (80% random, 15% edge, 5% invalid)
60
+ #
61
+
62
+ VALID_MODES = %i[random edge invalid hostile mixed].freeze
63
+
64
+
65
+ # @!attribute allow_eval
66
+ # Whether to allow eval() in custom expressions (default: false)
67
+ # @return [Boolean] true to allow eval, false to disallow
68
+ # @note Enabling eval is a security risk and should only be used
69
+ # in trusted environments
70
+
71
+ attr_accessor :allow_eval
72
+
73
+
74
+ # @!attribute max_unique_retries
75
+ # Maximum attempts to generate a unique value before giving up
76
+ # @return [Integer] the maximum retry count (default: 1000)
77
+ # @see UniquenessError raised when limit is exceeded
78
+
79
+ attr_accessor :max_unique_retries
80
+
81
+
82
+ # @!attribute null_optional
83
+ # Whether optional fields should default to null/nil
84
+ # @return [Boolean] true to default optional to null (default: false)
85
+
86
+ attr_accessor :null_optional
87
+
88
+
89
+ # @!attribute registry_cache_size
90
+ # Maximum number of AST entries to cache in the registry
91
+ # @return [Integer] the maximum cache size (default: 100)
92
+
93
+ attr_accessor :registry_cache_size
94
+
95
+
96
+ # @!attribute logger
97
+ # Optional logger for observability (Logger instance or compatible object)
98
+ # @return [Logger, nil] logger instance or nil
99
+
100
+ attr_accessor :logger
101
+
102
+
103
+ # @!attribute warn_on_shared_misuse
104
+ # Whether to emit warnings when shared() is used outside generate_many()
105
+ # @return [Boolean] true to emit warnings (default: true)
106
+ # @note When shared() is used with generate() instead of generate_many(),
107
+ # values won't be shared across calls, which may be unintended behavior
108
+
109
+ attr_accessor :warn_on_shared_misuse
110
+
111
+
112
+ # @!attribute validate_paths_on_load
113
+ # Whether to automatically validate copy() paths when loading schemas
114
+ # @return [Boolean] true to validate on load (default: true)
115
+ # @note This catches typos in copy() paths at load time rather than
116
+ # at generation time, preventing silent nil values
117
+
118
+ attr_accessor :validate_paths_on_load
119
+
120
+
121
+ # @!attribute optional_field_presence_rate
122
+ # Probability that an optional field will be included in output (default: 0.8 = 80%)
123
+ # @return [Float] probability between 0.0 and 1.0
124
+
125
+ attr_accessor :optional_field_presence_rate
126
+
127
+
128
+ # @!attribute nullable_field_null_rate
129
+ # Probability that a nullable field will be null (default: 0.1 = 10%)
130
+ # @return [Float] probability between 0.0 and 1.0
131
+
132
+ attr_accessor :nullable_field_null_rate
133
+
134
+
135
+ # @!attribute fast_mode
136
+ # Whether to use FastEngine for batch generation (default: false)
137
+ # @return [Boolean] true to use FastEngine, false to use standard Engine
138
+ # @note FastEngine is optimized for batch generation but is NOT thread-safe
139
+
140
+ attr_accessor :fast_mode
141
+
142
+
143
+ # @!attribute metrics_collector
144
+ # Optional metrics collector for observability
145
+ # @return [Object, nil] metrics collector instance or nil
146
+
147
+ attr_accessor :metrics_collector
148
+
149
+
150
+ # @!attribute on_field_generated
151
+ # Optional callback invoked when a field is generated
152
+ # @return [Proc, nil] callback proc or nil
153
+ # @note Callback receives (field_name, value, context) as arguments
154
+
155
+ attr_accessor :on_field_generated
156
+
157
+
158
+ # @!attribute [r] default_mode
159
+ # The default generation mode when not explicitly specified
160
+ # @return [Symbol] one of :random, :edge, :invalid, :hostile, :mixed
161
+ # @see #default_mode= to set this value
162
+
163
+ attr_reader :default_mode
164
+
165
+
166
+ # Create a new Configuration with default values
167
+ #
168
+ # @return [Configuration] a new configuration instance
169
+ #
170
+ # @example
171
+ # config = Synthra::Configuration.new
172
+ # config.default_mode # => :random
173
+ #
174
+
175
+ def initialize
176
+ reset!
177
+ end
178
+
179
+
180
+ # Access the resource limits configuration
181
+ #
182
+ # The limits object controls maximum values for latency, recursion
183
+ # depth, and array sizes to prevent runaway generation.
184
+ #
185
+ # @return [Limits] the limits configuration object
186
+ #
187
+ # @example Configure limits
188
+ # Synthra.configure do |config|
189
+ # config.limits.max_latency_ms = 10000 # 10 seconds
190
+ # config.limits.max_recursion = 5 # 5 levels deep
191
+ # config.limits.max_array_size = 100 # 100 elements max
192
+ # end
193
+ #
194
+
195
+ def limits
196
+ @limits ||= Limits.new
197
+ end
198
+
199
+
200
+ # Set the default generation mode
201
+ #
202
+ # @param mode [Symbol] the generation mode
203
+ # @option mode :random Standard fake data generation
204
+ # @option mode :edge Edge case values (empty, null, extremes)
205
+ # @option mode :invalid Intentionally invalid data
206
+ # @option mode :hostile Security attack payloads (SQL injection, XSS, etc.)
207
+ # @option mode :mixed Probabilistic mix of all modes
208
+ # @raise [ArgumentError] if mode is not one of the valid modes
209
+ # @return [Symbol] the set mode
210
+ #
211
+ # @example
212
+ # config.default_mode = :edge
213
+ #
214
+ # @example Invalid mode
215
+ # config.default_mode = :unknown
216
+ # # => ArgumentError: Invalid mode: unknown. Valid modes: random, edge, invalid, mixed
217
+ #
218
+
219
+ def default_mode=(mode)
220
+ unless VALID_MODES.include?(mode)
221
+ raise ArgumentError, "Invalid mode: #{mode}. Valid modes: #{VALID_MODES.join(", ")}"
222
+ end
223
+
224
+ @default_mode = mode
225
+ end
226
+
227
+
228
+ # Reset all configuration settings to their defaults
229
+ #
230
+ # This method restores all settings to their initial values:
231
+ # - allow_eval: false
232
+ # - default_mode: :random
233
+ # - max_unique_retries: 1000
234
+ # - null_optional: false
235
+ # - limits: new Limits instance with defaults
236
+ #
237
+ # @return [void]
238
+ #
239
+ # @example Reset after tests
240
+ # after(:each) do
241
+ # Synthra.configuration.reset!
242
+ # end
243
+ #
244
+
245
+ def reset!
246
+ @allow_eval = false
247
+ @default_mode = :random
248
+ @max_unique_retries = 1000
249
+ @null_optional = false
250
+ @limits = nil # Will be lazily initialized with defaults
251
+ @logger = nil
252
+ @metrics_collector = nil
253
+ @on_field_generated = nil
254
+ @registry_cache_size = 100
255
+ @warn_on_shared_misuse = true # Warn when shared() used outside generate_many()
256
+ @validate_paths_on_load = true # Auto-validate copy() paths on schema load
257
+ @optional_field_presence_rate = Synthra::OPTIONAL_FIELD_PRESENCE_RATE
258
+ @nullable_field_null_rate = Synthra::NULLABLE_FIELD_NULL_RATE
259
+ @fast_mode = false # Use standard Engine by default (thread-safe)
260
+ end
261
+
262
+
263
+ # Check if observability features are enabled
264
+ #
265
+ # Returns true if any of the observability features (metrics, logging,
266
+ # or field generation callbacks) are configured. Used to optimize the
267
+ # hot path by avoiding unnecessary checks.
268
+ #
269
+ # @return [Boolean] true if observability is enabled
270
+ #
271
+ # @example
272
+ # config.observability_enabled? # => false (by default)
273
+ # config.logger = Logger.new(STDOUT)
274
+ # config.observability_enabled? # => true
275
+ #
276
+
277
+ def observability_enabled?
278
+ !!(@metrics_collector || @logger || @on_field_generated)
279
+ end
280
+ end
281
+ end