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,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Synthra
4
+ module Types
5
+ module TechnologyInternet
6
+ # Email type
7
+ class Email < Base
8
+ # Generate a random email address
9
+ #
10
+ # Uses Faker::Internet to generate realistic email addresses.
11
+ #
12
+ # @param rng [Generator::RNG] random number generator (not directly used)
13
+ # @param args [Hash] type arguments (not used for basic email)
14
+ # @return [String] generated email address
15
+ #
16
+ # @example
17
+ # generate_random(rng, {})
18
+ # # => "maria.garcia@example.com"
19
+ #
20
+ def generate_random(rng, context, args)
21
+ adapter = faker_adapter(context)
22
+ if adapter
23
+ adapter.email
24
+
25
+ else
26
+ Faker::Internet.email
27
+ end
28
+
29
+ rescue StandardError
30
+ "#{rng.sample(['user', 'test', 'admin'])}@#{rng.sample(['example.com', 'test.com', 'demo.com'])}"
31
+ end
32
+
33
+
34
+ def generate_edge(rng, context, args)
35
+ ["", "a@b", "user@", "@domain", "user@domain"].sample(random: rng.instance_variable_get(:@random))
36
+ end
37
+
38
+ def generate_invalid(rng, context, args)
39
+ ["notanemail", "@missing.local", "missing@", "double@@at.com", "spaces in@email.com", nil, 123].sample(random: rng.instance_variable_get(:@random))
40
+ end
41
+ end
42
+
43
+ # Phone type
44
+ class Phone < Base
45
+ def generate_random(rng, context, args)
46
+ adapter = faker_adapter(context)
47
+ if adapter
48
+ adapter.phone_number
49
+
50
+ else
51
+ Faker::PhoneNumber.phone_number
52
+ end
53
+
54
+ rescue StandardError
55
+ rng.sample(["+1-555-123-4567", "+44-20-1234-5678", "+33-1-23-45-67-89"])
56
+ end
57
+
58
+
59
+ def generate_edge(rng, context, args)
60
+ ["", "+1-555-000-0000", "000-000-0000"].sample(random: rng.instance_variable_get(:@random))
61
+ end
62
+
63
+ def generate_invalid(rng, context, args)
64
+ [nil, 123, [], {}, "not a phone"].sample(random: rng.instance_variable_get(:@random))
65
+ end
66
+ end
67
+
68
+ # Url type
69
+ class Url < Base
70
+ def generate_random(rng, context, args)
71
+ adapter = faker_adapter(context)
72
+ if adapter
73
+ adapter.url
74
+
75
+ else
76
+ Faker::Internet.url
77
+ end
78
+
79
+ rescue StandardError
80
+ "https://#{rng.sample(['example.com', 'test.com', 'demo.com'])}/#{rng.sample(['page', 'path', 'resource'])}"
81
+ end
82
+
83
+
84
+ def generate_edge(rng, context, args)
85
+ ["", "http://", "http://a", "https://example.com"].sample(random: rng.instance_variable_get(:@random))
86
+ end
87
+
88
+ def generate_invalid(rng, context, args)
89
+ [nil, 123, [], {}, "not-a-url", "missing-protocol.com"].sample(random: rng.instance_variable_get(:@random))
90
+ end
91
+ end
92
+
93
+ # Domain type
94
+ class Domain < Base
95
+ # Generate random domain name
96
+ #
97
+ # @param rng [Generator::RNG] random number generator (not directly used)
98
+ # @param context [Generator::Context] generation context
99
+ # @param args [Hash] type arguments (not used)
100
+ # @return [String] generated domain name
101
+ #
102
+ def generate_random(rng, context, args)
103
+ adapter = faker_adapter(context)
104
+ if adapter
105
+ adapter.domain_name
106
+
107
+ else
108
+ Faker::Internet.domain_name
109
+ end
110
+
111
+ rescue StandardError
112
+ "#{rng.sample(['example', 'test', 'demo'])}.#{rng.sample(['com', 'org', 'net'])}"
113
+ end
114
+
115
+
116
+ def generate_edge(rng, context, args)
117
+ ["", "a.b", "very-long-domain-name-that-exceeds-normal-limits.com"].sample(random: rng.instance_variable_get(:@random))
118
+ end
119
+
120
+ def generate_invalid(rng, context, args)
121
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
122
+ end
123
+ end
124
+
125
+ # UserAgent type
126
+ class UserAgent < Base
127
+ # Generate random user agent
128
+ #
129
+ # @param rng [Generator::RNG] random number generator (not directly used)
130
+ # @param context [Generator::Context] generation context
131
+ # @param args [Hash] type arguments (not used)
132
+ # @return [String] generated user agent string
133
+ #
134
+ def generate_random(rng, context, args)
135
+ adapter = faker_adapter(context)
136
+ if adapter
137
+ adapter.user_agent
138
+
139
+ else
140
+ Faker::Internet.user_agent
141
+ end
142
+
143
+ rescue StandardError
144
+ rng.sample([
145
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
146
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
147
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
148
+ ])
149
+ end
150
+
151
+
152
+ def generate_edge(rng, context, args)
153
+ ["", "Mozilla/5.0", "Invalid User Agent"].sample(random: rng.instance_variable_get(:@random))
154
+ end
155
+
156
+ def generate_invalid(rng, context, args)
157
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Synthra
4
+ module Types
5
+ module TechnologyInternet
6
+ # MobileDeviceBrand type
7
+ class MobileDeviceBrand < Base
8
+ BRANDS = ["Apple", "Samsung", "Google", "Huawei", "Xiaomi", "OnePlus", "LG", "Motorola"].freeze
9
+
10
+ def generate_random(rng, context, args)
11
+ rng.sample(BRANDS)
12
+ end
13
+
14
+ def generate_edge(rng, context, args)
15
+ ["", "Apple", "Samsung"].sample(random: rng.instance_variable_get(:@random))
16
+ end
17
+
18
+ def generate_invalid(rng, context, args)
19
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
20
+ end
21
+ end
22
+
23
+ # MobileDeviceModel type
24
+ class MobileDeviceModel < Base
25
+ MODELS = [
26
+ "iPhone 14", "iPhone 13", "Galaxy S23", "Galaxy S22",
27
+ "Pixel 7", "Pixel 6", "P50", "Mi 13", "OnePlus 11"
28
+ ].freeze
29
+
30
+ def generate_random(rng, context, args)
31
+ rng.sample(MODELS)
32
+ end
33
+
34
+ def generate_edge(rng, context, args)
35
+ ["", "iPhone 14", "A"].sample(random: rng.instance_variable_get(:@random))
36
+ end
37
+
38
+ def generate_invalid(rng, context, args)
39
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
40
+ end
41
+ end
42
+
43
+ # MobileDeviceOs type
44
+ class MobileDeviceOs < Base
45
+ OS_TYPES = ["iOS", "Android", "Windows Mobile", "BlackBerry OS"].freeze
46
+
47
+ def generate_random(rng, context, args)
48
+ rng.sample(OS_TYPES)
49
+ end
50
+
51
+ def generate_edge(rng, context, args)
52
+ ["", "iOS", "Android"].sample(random: rng.instance_variable_get(:@random))
53
+ end
54
+
55
+ def generate_invalid(rng, context, args)
56
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
57
+ end
58
+ end
59
+
60
+ # MobileDeviceReleaseDate type
61
+ class MobileDeviceReleaseDate < Base
62
+ def generate_random(rng, context, args)
63
+ # Generate date between 2015 and 2024
64
+ year = rng.int(2015, 2024)
65
+ month = rng.int(1, 12)
66
+ day = rng.int(1, 28)
67
+ Date.new(year, month, day)
68
+ end
69
+
70
+ def generate_edge(rng, context, args)
71
+ [Date.new(2015, 1, 1), Date.new(2024, 12, 31)].sample(random: rng.instance_variable_get(:@random))
72
+ end
73
+
74
+ def generate_invalid(rng, context, args)
75
+ [nil, "not a date", 123, [], {}].sample(random: rng.instance_variable_get(:@random))
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Synthra
4
+ module Types
5
+ module TechnologyInternet
6
+ # Language type
7
+ class Language < Base
8
+ LANGUAGES = [
9
+ "English", "Spanish", "French", "German", "Italian", "Portuguese",
10
+ "Russian", "Chinese", "Japanese", "Korean", "Arabic", "Hindi"
11
+ ].freeze
12
+
13
+ def generate_random(rng, context, args)
14
+ rng.sample(LANGUAGES)
15
+ end
16
+
17
+ def generate_edge(rng, context, args)
18
+ ["", "English", "A"].sample(random: rng.instance_variable_get(:@random))
19
+ end
20
+
21
+ def generate_invalid(rng, context, args)
22
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
23
+ end
24
+ end
25
+
26
+ # LanguageCode type
27
+ class LanguageCode < Base
28
+ LANGUAGE_CODES = ["en", "es", "fr", "de", "it", "pt", "ru", "zh", "ja", "ko", "ar", "hi"].freeze
29
+
30
+ def generate_random(rng, context, args)
31
+ rng.sample(LANGUAGE_CODES)
32
+ end
33
+
34
+ def generate_edge(rng, context, args)
35
+ ["", "en", "xx"].sample(random: rng.instance_variable_get(:@random))
36
+ end
37
+
38
+ def generate_invalid(rng, context, args)
39
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
40
+ end
41
+ end
42
+
43
+ # MimeType type
44
+ class MimeType < Base
45
+ MIME_TYPES = [
46
+ "text/plain", "text/html", "text/css", "text/javascript",
47
+ "application/json", "application/xml", "application/pdf",
48
+ "image/jpeg", "image/png", "image/gif", "image/svg+xml",
49
+ "video/mp4", "video/quicktime", "audio/mpeg", "audio/wav"
50
+ ].freeze
51
+
52
+ def generate_random(rng, context, args)
53
+ rng.sample(MIME_TYPES)
54
+ end
55
+
56
+ def generate_edge(rng, context, args)
57
+ ["", "text/plain", "application/json"].sample(random: rng.instance_variable_get(:@random))
58
+ end
59
+
60
+ def generate_invalid(rng, context, args)
61
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
62
+ end
63
+ end
64
+
65
+ # TopLevelDomain type
66
+ class TopLevelDomain < Base
67
+ TLDS = [".com", ".org", ".net", ".edu", ".gov", ".io", ".co", ".ai", ".dev", ".app"].freeze
68
+
69
+ def generate_random(rng, context, args)
70
+ rng.sample(TLDS)
71
+ end
72
+
73
+ def generate_edge(rng, context, args)
74
+ ["", ".com", ".xxx"].sample(random: rng.instance_variable_get(:@random))
75
+ end
76
+
77
+ def generate_invalid(rng, context, args)
78
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
79
+ end
80
+ end
81
+
82
+ # Base64ImageUrl type
83
+ class Base64ImageUrl < Base
84
+ def generate_random(rng, context, args)
85
+ # Generate a data URL with base64 encoded image
86
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
87
+ end
88
+
89
+ def generate_edge(rng, context, args)
90
+ ["", "data:image/png;base64,invalid"].sample(random: rng.instance_variable_get(:@random))
91
+ end
92
+
93
+ def generate_invalid(rng, context, args)
94
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
95
+ end
96
+ end
97
+
98
+ # DummyImageUrl type
99
+ class DummyImageUrl < Base
100
+ def generate_random(rng, context, args)
101
+ min_height = args[:minHeight] || 100
102
+ max_height = args[:maxHeight] || 800
103
+ min_width = args[:minWidth] || 100
104
+ max_width = args[:maxWidth] || 1200
105
+ format = args[:format] || "jpg"
106
+
107
+ height = rng.int(min_height, max_height)
108
+ width = rng.int(min_width, max_width)
109
+ "https://dummyimage.com/#{width}x#{height}/000/fff.#{format}"
110
+ end
111
+
112
+ def generate_edge(rng, context, args)
113
+ ["", "https://dummyimage.com/1x1/000/fff.jpg"].sample(random: rng.instance_variable_get(:@random))
114
+ end
115
+
116
+ def generate_invalid(rng, context, args)
117
+ [nil, 123, [], {}].sample(random: rng.instance_variable_get(:@random))
118
+ end
119
+ end
120
+
121
+ # MongodbObjectId type
122
+ class MongodbObjectId < Base
123
+ def generate_random(rng, context, args)
124
+ # MongoDB ObjectID is 24 hex characters
125
+ chars = ('0'..'9').to_a + ('a'..'f').to_a
126
+ 24.times.map { rng.sample(chars) }.join
127
+ end
128
+
129
+ def generate_edge(rng, context, args)
130
+ ["000000000000000000000000", "ffffffffffffffffffffffff"].sample(random: rng.instance_variable_get(:@random))
131
+ end
132
+
133
+ def generate_invalid(rng, context, args)
134
+ [nil, "not an id", "invalid", [], {}].sample(random: rng.instance_variable_get(:@random))
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Synthra
4
+ module Types
5
+ module TechnologyInternet
6
+ # Ip type
7
+ class Ip < Base
8
+ # Generate a random IPv4 address
9
+ #
10
+ # @param rng [Generator::RNG] random number generator
11
+ # @param context [Generator::Context] generation context
12
+ # @param args [Hash] type arguments (not used)
13
+ # @return [String] IPv4 address string
14
+ #
15
+ def generate_random(rng, context, args)
16
+ adapter = faker_adapter(context)
17
+ if adapter
18
+ adapter.ip_v4_address
19
+
20
+ else
21
+ Faker::Internet.ip_v4_address
22
+ end
23
+
24
+ rescue StandardError
25
+ "#{rng.int(1, 255)}.#{rng.int(0, 255)}.#{rng.int(0, 255)}.#{rng.int(1, 255)}"
26
+ end
27
+
28
+
29
+ def generate_edge(rng, context, args)
30
+ ["0.0.0.0", "255.255.255.255", "127.0.0.1"].sample(random: rng.instance_variable_get(:@random))
31
+ end
32
+
33
+ def generate_invalid(rng, context, args)
34
+ [nil, "not an ip", "256.256.256.256", [], {}].sample(random: rng.instance_variable_get(:@random))
35
+ end
36
+ end
37
+
38
+ # Ipv6 type
39
+ class Ipv6 < Base
40
+ # Generate a random IPv6 address
41
+ #
42
+ # @param rng [Generator::RNG] random number generator
43
+ # @param context [Generator::Context] generation context
44
+ # @param args [Hash] type arguments (not used)
45
+ # @return [String] IPv6 address string
46
+ #
47
+ def generate_random(rng, context, args)
48
+ adapter = faker_adapter(context)
49
+ if adapter
50
+ adapter.ip_v6_address
51
+
52
+ else
53
+ # Manual IPv6 generation fallback
54
+ 8.times.map { format("%x", rng.int(0, 65535)) }.join(":")
55
+ end
56
+
57
+ rescue StandardError
58
+ 8.times.map { format("%x", rng.int(0, 65535)) }.join(":") # Fallback
59
+ end
60
+
61
+
62
+ def generate_edge(rng, context, args)
63
+ ["::1", "fe80::1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"].sample(random: rng.instance_variable_get(:@random))
64
+ end
65
+
66
+ def generate_invalid(rng, context, args)
67
+ [nil, "not:an:ipv6", "::g", [], {}].sample(random: rng.instance_variable_get(:@random))
68
+ end
69
+ end
70
+
71
+ # MacAddress type
72
+ class MacAddress < Base
73
+ # Generate random MAC address
74
+ #
75
+ # @param rng [Generator::RNG] random number generator
76
+ # @param context [Generator::Context] generation context
77
+ # @param args [Hash] type arguments
78
+ # @option args [Symbol] :format format type (:colon, :dash, :none)
79
+ # @return [String] generated MAC address
80
+ #
81
+ def generate_random(rng, context, args)
82
+ format_type = args[:format] || :colon
83
+
84
+ # Generate 6 octets (12 hex digits)
85
+ octets = 6.times.map { format("%02X", rng.int(0, 255)) }
86
+
87
+ case format_type
88
+ when :dash
89
+ octets.join("-")
90
+ when :none
91
+ octets.join
92
+ else # :colon
93
+ octets.join(":")
94
+ end
95
+ end
96
+
97
+ def generate_edge(rng, context, args)
98
+ ["00:00:00:00:00:00", "FF:FF:FF:FF:FF:FF"].sample(random: rng.instance_variable_get(:@random))
99
+ end
100
+
101
+ def generate_invalid(rng, context, args)
102
+ [nil, "not a mac", "invalid", [], {}].sample(random: rng.instance_variable_get(:@random))
103
+ end
104
+ end
105
+
106
+ # IpV4Cidr type
107
+ class IpV4Cidr < Base
108
+ def generate_random(rng, context, args)
109
+ # Generate IP with CIDR notation (e.g., 192.168.1.0/24)
110
+ ip = TechnologyInternet::Ip.new.generate_random(rng, context, {})
111
+ cidr = rng.int(8, 30) # Common CIDR ranges
112
+ "#{ip}/#{cidr}"
113
+ end
114
+
115
+ def generate_edge(rng, context, args)
116
+ ["0.0.0.0/0", "255.255.255.255/32"].sample(random: rng.instance_variable_get(:@random))
117
+ end
118
+
119
+ def generate_invalid(rng, context, args)
120
+ [nil, "not cidr", "invalid", [], {}].sample(random: rng.instance_variable_get(:@random))
121
+ end
122
+ end
123
+
124
+ # IpV6Cidr type
125
+ class IpV6Cidr < Base
126
+ def generate_random(rng, context, args)
127
+ # Generate IPv6 with CIDR notation
128
+ ipv6 = TechnologyInternet::Ipv6.new.generate_random(rng, context, {})
129
+ cidr = rng.int(64, 128) # Common IPv6 CIDR ranges
130
+ "#{ipv6}/#{cidr}"
131
+ end
132
+
133
+ def generate_edge(rng, context, args)
134
+ ["::/0", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"].sample(random: rng.instance_variable_get(:@random))
135
+ end
136
+
137
+ def generate_invalid(rng, context, args)
138
+ [nil, "not cidr", "invalid", [], {}].sample(random: rng.instance_variable_get(:@random))
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Synthra
4
+ module Types
5
+ # Template type generator.
6
+ #
7
+ # Substitutes +${field}+ (and legacy +{field}+) placeholders with the
8
+ # already-generated value of that field in the same record. Field values
9
+ # come from the generation +context+, which holds every field generated
10
+ # before this one (fields are generated in definition order).
11
+ #
12
+ # first: name
13
+ # greeting: template("Hello ${first}") # => "Hello Ada Lovelace"
14
+ #
15
+ # A referenced field that is not (yet) available is left as the literal
16
+ # placeholder text rather than blanking the whole string.
17
+ class Template < Base
18
+ # Matches ${field} or {field}; the field name is captured.
19
+ PLACEHOLDER = /\$\{([^}]+)\}|\{([^}]+)\}/
20
+
21
+ def generate_random(rng, context, args)
22
+ pattern = args[:pattern] || args[:template] || ""
23
+ return "" if pattern.to_s.empty?
24
+
25
+ values = context_values(context)
26
+
27
+ pattern.to_s.gsub(PLACEHOLDER) do
28
+ key = (Regexp.last_match(1) || Regexp.last_match(2)).strip
29
+ if values.key?(key)
30
+ values[key].to_s
31
+ else
32
+ Regexp.last_match(0) # leave the literal placeholder untouched
33
+ end
34
+ end
35
+ end
36
+
37
+ def generate_edge(rng, context, args)
38
+ rng.sample(["", "${missing}", "template"])
39
+ end
40
+
41
+ def generate_invalid(rng, context, args)
42
+ rng.sample([nil, 123, [], {}])
43
+ end
44
+
45
+ private
46
+
47
+ # Flatten the context into a String-keyed lookup of field => value.
48
+ # Accepts a Context, a Hash, or anything responding to #each.
49
+ #
50
+ # @param context [Object]
51
+ # @return [Hash{String=>Object}]
52
+ def context_values(context)
53
+ return {} unless context.respond_to?(:each)
54
+
55
+ values = {}
56
+ context.each do |key, value|
57
+ values[key.to_s] = value
58
+ end
59
+ values
60
+ end
61
+
62
+ # Look up a single value from a context by key.
63
+ #
64
+ # Retained as a public-by-#send helper for callers/tests that resolve one
65
+ # key at a time (e.g. lazy interpolation). The primary generate_random path
66
+ # uses context_values for bulk substitution; this mirrors that resolution
67
+ # order (hash-style [] first, then a same-named method) for a single key.
68
+ #
69
+ # @param context [Object] context object (Hash, Context, or any object)
70
+ # @param key [String] key to retrieve
71
+ # @return [Object] value (stringified) or "" if not found
72
+ def get_context_value(context, key)
73
+ return "" if context.nil?
74
+
75
+ if context.respond_to?(:[])
76
+ value = context[key] || context[key.to_sym]
77
+ return value.to_s if value
78
+ end
79
+
80
+ if context.respond_to?(key)
81
+ begin
82
+ return context.public_send(key).to_s
83
+ rescue NoMethodError
84
+ return "" # empty result
85
+ end
86
+ end
87
+
88
+ ""
89
+ end
90
+ end
91
+ end
92
+ end