servactory 2.16.1 → 3.0.0.rc1

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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +38 -9
  3. data/config/locales/de.yml +134 -0
  4. data/config/locales/en.yml +15 -0
  5. data/config/locales/es.yml +134 -0
  6. data/config/locales/fr.yml +134 -0
  7. data/config/locales/it.yml +134 -0
  8. data/config/locales/ru.yml +15 -0
  9. data/lib/generators/README.md +45 -0
  10. data/lib/generators/servactory/base.rb +82 -0
  11. data/lib/generators/servactory/extension/USAGE +54 -0
  12. data/lib/generators/servactory/extension/extension_generator.rb +41 -0
  13. data/lib/generators/servactory/extension/templates/extension.rb.tt +62 -0
  14. data/lib/generators/servactory/install/USAGE +27 -0
  15. data/lib/generators/servactory/install/install_generator.rb +94 -0
  16. data/lib/generators/servactory/{templates/services/application_service/base.rb → install/templates/application_service/base.rb.tt} +29 -19
  17. data/lib/generators/servactory/{templates/services/application_service/exceptions.rb → install/templates/application_service/exceptions.rb.tt} +1 -1
  18. data/lib/generators/servactory/{templates/services/application_service/result.rb → install/templates/application_service/result.rb.tt} +1 -1
  19. data/lib/generators/servactory/rspec/USAGE +46 -0
  20. data/lib/generators/servactory/rspec/rspec_generator.rb +95 -0
  21. data/lib/generators/servactory/rspec/templates/service_spec.rb.tt +58 -0
  22. data/lib/generators/servactory/service/USAGE +51 -0
  23. data/lib/generators/servactory/service/service_generator.rb +56 -0
  24. data/lib/generators/servactory/service/templates/service.rb.tt +22 -0
  25. data/lib/servactory/actions/collection.rb +56 -1
  26. data/lib/servactory/actions/dsl.rb +11 -11
  27. data/lib/servactory/actions/tools/rules.rb +1 -1
  28. data/lib/servactory/actions/tools/runner.rb +111 -28
  29. data/lib/servactory/base.rb +1 -7
  30. data/lib/servactory/configuration/actions/aliases/collection.rb +5 -0
  31. data/lib/servactory/configuration/actions/rescue_handlers/collection.rb +5 -0
  32. data/lib/servactory/configuration/actions/shortcuts/collection.rb +5 -0
  33. data/lib/servactory/configuration/collection_mode/class_names_collection.rb +5 -0
  34. data/lib/servactory/configuration/config.rb +36 -0
  35. data/lib/servactory/configuration/configurable.rb +95 -0
  36. data/lib/servactory/configuration/dsl.rb +3 -27
  37. data/lib/servactory/configuration/factory.rb +20 -20
  38. data/lib/servactory/configuration/hash_mode/class_names_collection.rb +5 -0
  39. data/lib/servactory/configuration/option_helpers/option_helpers_collection.rb +5 -0
  40. data/lib/servactory/context/warehouse/inputs.rb +2 -2
  41. data/lib/servactory/context/workspace/inputs.rb +2 -2
  42. data/lib/servactory/context/workspace/internals.rb +2 -2
  43. data/lib/servactory/context/workspace/outputs.rb +2 -2
  44. data/lib/servactory/context/workspace.rb +11 -7
  45. data/lib/servactory/dsl.rb +10 -8
  46. data/lib/servactory/maintenance/attributes/tools/validation.rb +1 -1
  47. data/lib/servactory/result.rb +2 -2
  48. data/lib/servactory/stroma/dsl.rb +118 -0
  49. data/lib/servactory/stroma/entry.rb +32 -0
  50. data/lib/servactory/stroma/exceptions/base.rb +45 -0
  51. data/lib/servactory/stroma/exceptions/invalid_hook_type.rb +29 -0
  52. data/lib/servactory/stroma/exceptions/key_already_registered.rb +32 -0
  53. data/lib/servactory/stroma/exceptions/registry_frozen.rb +33 -0
  54. data/lib/servactory/stroma/exceptions/registry_not_finalized.rb +33 -0
  55. data/lib/servactory/stroma/exceptions/unknown_hook_target.rb +39 -0
  56. data/lib/servactory/stroma/hooks/applier.rb +63 -0
  57. data/lib/servactory/stroma/hooks/collection.rb +103 -0
  58. data/lib/servactory/stroma/hooks/factory.rb +80 -0
  59. data/lib/servactory/stroma/hooks/hook.rb +74 -0
  60. data/lib/servactory/stroma/registry.rb +94 -0
  61. data/lib/servactory/stroma/settings/collection.rb +90 -0
  62. data/lib/servactory/stroma/settings/registry_settings.rb +88 -0
  63. data/lib/servactory/stroma/settings/setting.rb +113 -0
  64. data/lib/servactory/stroma/state.rb +59 -0
  65. data/lib/servactory/test_kit/fake_type.rb +23 -0
  66. data/lib/servactory/test_kit/result.rb +45 -0
  67. data/lib/servactory/test_kit/rspec/helpers/argument_matchers.rb +97 -0
  68. data/lib/servactory/test_kit/rspec/helpers/concerns/error_messages.rb +179 -0
  69. data/lib/servactory/test_kit/rspec/helpers/concerns/service_class_validation.rb +74 -0
  70. data/lib/servactory/test_kit/rspec/helpers/fluent.rb +110 -0
  71. data/lib/servactory/test_kit/rspec/helpers/input_validator.rb +149 -0
  72. data/lib/servactory/test_kit/rspec/helpers/legacy.rb +228 -0
  73. data/lib/servactory/test_kit/rspec/helpers/mock_executor.rb +256 -0
  74. data/lib/servactory/test_kit/rspec/helpers/output_validator.rb +121 -0
  75. data/lib/servactory/test_kit/rspec/helpers/service_mock_builder.rb +422 -0
  76. data/lib/servactory/test_kit/rspec/helpers/service_mock_config.rb +129 -0
  77. data/lib/servactory/test_kit/rspec/helpers.rb +51 -84
  78. data/lib/servactory/test_kit/rspec/matchers/base/attribute_matcher.rb +324 -0
  79. data/lib/servactory/test_kit/rspec/matchers/base/submatcher.rb +133 -0
  80. data/lib/servactory/test_kit/rspec/matchers/base/submatcher_context.rb +101 -0
  81. data/lib/servactory/test_kit/rspec/matchers/base/submatcher_registry.rb +205 -0
  82. data/lib/servactory/test_kit/rspec/matchers/concerns/attribute_data_access.rb +100 -0
  83. data/lib/servactory/test_kit/rspec/matchers/concerns/error_message_builder.rb +106 -0
  84. data/lib/servactory/test_kit/rspec/matchers/concerns/value_comparison.rb +97 -0
  85. data/lib/servactory/test_kit/rspec/matchers/have_service_input_matcher.rb +89 -219
  86. data/lib/servactory/test_kit/rspec/matchers/have_service_internal_matcher.rb +74 -166
  87. data/lib/servactory/test_kit/rspec/matchers/have_service_output_matcher.rb +238 -0
  88. data/lib/servactory/test_kit/rspec/matchers/result/be_failure_service_matcher.rb +257 -0
  89. data/lib/servactory/test_kit/rspec/matchers/result/be_success_service_matcher.rb +185 -0
  90. data/lib/servactory/test_kit/rspec/matchers/submatchers/input/default_submatcher.rb +81 -0
  91. data/lib/servactory/test_kit/rspec/matchers/submatchers/input/optional_submatcher.rb +62 -0
  92. data/lib/servactory/test_kit/rspec/matchers/submatchers/input/required_submatcher.rb +93 -0
  93. data/lib/servactory/test_kit/rspec/matchers/submatchers/input/valid_with_submatcher.rb +271 -0
  94. data/lib/servactory/test_kit/rspec/matchers/submatchers/shared/consists_of_submatcher.rb +85 -0
  95. data/lib/servactory/test_kit/rspec/matchers/submatchers/shared/inclusion_submatcher.rb +120 -0
  96. data/lib/servactory/test_kit/rspec/matchers/submatchers/shared/message_submatcher.rb +115 -0
  97. data/lib/servactory/test_kit/rspec/matchers/submatchers/shared/must_submatcher.rb +82 -0
  98. data/lib/servactory/test_kit/rspec/matchers/submatchers/shared/schema_submatcher.rb +102 -0
  99. data/lib/servactory/test_kit/rspec/matchers/submatchers/shared/target_submatcher.rb +125 -0
  100. data/lib/servactory/test_kit/rspec/matchers/submatchers/shared/types_submatcher.rb +77 -0
  101. data/lib/servactory/test_kit/rspec/matchers.rb +126 -285
  102. data/lib/servactory/test_kit/utils/faker.rb +62 -2
  103. data/lib/servactory/tool_kit/dynamic_options/consists_of.rb +166 -0
  104. data/lib/servactory/tool_kit/dynamic_options/format.rb +195 -8
  105. data/lib/servactory/tool_kit/dynamic_options/inclusion.rb +219 -17
  106. data/lib/servactory/tool_kit/dynamic_options/max.rb +143 -0
  107. data/lib/servactory/tool_kit/dynamic_options/min.rb +143 -0
  108. data/lib/servactory/tool_kit/dynamic_options/multiple_of.rb +157 -8
  109. data/lib/servactory/tool_kit/dynamic_options/must.rb +194 -0
  110. data/lib/servactory/tool_kit/dynamic_options/schema.rb +226 -2
  111. data/lib/servactory/tool_kit/dynamic_options/target.rb +252 -0
  112. data/lib/servactory/version.rb +4 -4
  113. data/lib/servactory.rb +4 -0
  114. metadata +73 -19
  115. data/lib/generators/servactory/install_generator.rb +0 -21
  116. data/lib/generators/servactory/rspec_generator.rb +0 -88
  117. data/lib/generators/servactory/service_generator.rb +0 -49
  118. data/lib/servactory/configuration/setup.rb +0 -97
  119. data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/consists_of_matcher.rb +0 -68
  120. data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/inclusion_matcher.rb +0 -73
  121. data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/message_matcher.rb +0 -91
  122. data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/must_matcher.rb +0 -72
  123. data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/schema_matcher.rb +0 -92
  124. data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/types_matcher.rb +0 -72
  125. data/lib/servactory/test_kit/rspec/matchers/have_service_input_matchers/default_matcher.rb +0 -69
  126. data/lib/servactory/test_kit/rspec/matchers/have_service_input_matchers/optional_matcher.rb +0 -63
  127. data/lib/servactory/test_kit/rspec/matchers/have_service_input_matchers/required_matcher.rb +0 -81
  128. data/lib/servactory/test_kit/rspec/matchers/have_service_input_matchers/valid_with_matcher.rb +0 -199
@@ -0,0 +1,134 @@
1
+ it:
2
+ servactory:
3
+ common:
4
+ undefined_method:
5
+ missing_name: "[%{service_class_name}] %{error_text}"
6
+ methods:
7
+ call:
8
+ not_used: "[%{service_class_name}] Niente da eseguire. Usa `make` o crea un metodo `call`."
9
+ cannot_be_overwritten: "[%{service_class_name}] I seguenti metodi non possono essere sovrascritti: %{list_of_methods}"
10
+ inputs:
11
+ undefined:
12
+ for_fetch: "[%{service_class_name}] Attributo di input non definito `%{input_name}`"
13
+ for_assign: "[%{service_class_name}] Attributo di input non definito `%{input_name}`"
14
+ validations:
15
+ must:
16
+ default_error: "[%{service_class_name}] L'input `%{input_name}` deve \"%{code}\""
17
+ syntax_error: "[%{service_class_name}] Errore di sintassi in `%{code}` dell'input `%{input_name}`: %{exception_message}"
18
+ dynamic_options:
19
+ consists_of:
20
+ required: "[%{service_class_name}] Elemento richiesto mancante nella collezione di input `%{input_name}`"
21
+ wrong_type: "[%{service_class_name}] Tipo di collezione di input errato `%{input_name}`, previsto `%{expected_type}`, ricevuto `%{given_type}`"
22
+ wrong_element_type: "[%{service_class_name}] Tipo di elemento errato nella collezione di input `%{input_name}`, previsto `%{expected_type}`, ricevuto `%{given_type}`"
23
+ format:
24
+ default: "[%{service_class_name}] L'input `%{input_name}` non corrisponde al formato `%{format_name}`"
25
+ wrong_pattern: "[%{service_class_name}] L'input `%{input_name}` non corrisponde al formato `%{format_name}`"
26
+ wrong_type: "[%{service_class_name}] L'input `%{input_name}` deve essere una stringa per la validazione del formato `%{format_name}`"
27
+ unknown: "[%{service_class_name}] Formato sconosciuto `%{format_name}` specificato per l'input `%{input_name}`"
28
+ inclusion:
29
+ default: "[%{service_class_name}] Valore errato in `%{input_name}`, deve essere uno di `%{input_inclusion}`, ricevuto `%{value}`"
30
+ invalid_option: "[%{service_class_name}] L'input `%{input_name}` ha valore mancante nell'opzione `%{option_name}`"
31
+ min:
32
+ default: "[%{service_class_name}] L'input `%{input_name}` ha ricevuto il valore `%{value}`, che è inferiore a `%{option_value}`"
33
+ max:
34
+ default: "[%{service_class_name}] L'input `%{input_name}` ha ricevuto il valore `%{value}`, che è superiore a `%{option_value}`"
35
+ multiple_of:
36
+ default: "[%{service_class_name}] L'input `%{input_name}` ha il valore `%{value}`, che non è un multiplo di `%{option_value}`"
37
+ blank: "[%{service_class_name}] L'input `%{input_name}` ha un valore non valido `%{option_value}` nell'opzione `%{option_name}`"
38
+ divided_by_0: "[%{service_class_name}] L'input `%{input_name}` ha un valore non valido `%{option_value}` nell'opzione `%{option_name}`"
39
+ schema:
40
+ wrong_type: "[%{service_class_name}] Tipo errato dell'input `%{input_name}`, previsto `%{expected_type}`, ricevuto `%{given_type}`"
41
+ wrong_element_type: "[%{service_class_name}] Tipo errato nell'hash di input `%{input_name}`, per `%{key_name}` previsto `%{expected_type}`, ricevuto `%{given_type}`"
42
+ wrong_element_value: "[%{service_class_name}] Valore errato nell'hash di input `%{input_name}`, per `%{key_name}` valore previsto di tipo `%{expected_type}`, ricevuto `%{given_type}`"
43
+ target:
44
+ default: "[%{service_class_name}] L'input `%{input_name}` ha obiettivo errato, deve essere `%{expected_target}`, ricevuto `%{value}`"
45
+ invalid_option: "[%{service_class_name}] L'input `%{input_name}` ha valore mancante nell'opzione `%{option_name}`"
46
+ required:
47
+ default_error:
48
+ default: "[%{service_class_name}] L'input richiesto `%{input_name}` è mancante"
49
+ type:
50
+ default_error:
51
+ default: "[%{service_class_name}] Tipo errato dell'input `%{input_name}`, previsto `%{expected_type}`, ricevuto `%{given_type}`"
52
+ tools:
53
+ find_unnecessary:
54
+ error: "[%{service_class_name}] Attributi inattesi: `%{unnecessary_attributes}`"
55
+ rules:
56
+ error: "[%{service_class_name}] Conflitto nelle opzioni dell'input `%{input_name}`: `%{conflict_code}`"
57
+ internals:
58
+ undefined:
59
+ for_fetch: "[%{service_class_name}] Attributo interno non definito `%{internal_name}`"
60
+ for_assign: "[%{service_class_name}] Attributo interno non definito `%{internal_name}`"
61
+ validations:
62
+ must:
63
+ default_error: "[%{service_class_name}] L'attributo interno `%{internal_name}` deve \"%{code}\""
64
+ syntax_error: "[%{service_class_name}] Errore di sintassi in `%{code}` dell'attributo interno `%{internal_name}`: %{exception_message}"
65
+ dynamic_options:
66
+ consists_of:
67
+ required: "[%{service_class_name}] Elemento richiesto mancante nella collezione dell'attributo interno `%{internal_name}`"
68
+ wrong_type: "[%{service_class_name}] Tipo di collezione errato dell'attributo interno `%{internal_name}`, previsto `%{expected_type}`, ricevuto `%{given_type}`"
69
+ wrong_element_type: "[%{service_class_name}] Tipo di elemento errato nella collezione dell'attributo interno `%{internal_name}`, previsto `%{expected_type}`, ricevuto `%{given_type}`"
70
+ format:
71
+ default: "[%{service_class_name}] L'attributo interno `%{internal_name}` non corrisponde al formato `%{format_name}`"
72
+ wrong_pattern: "[%{service_class_name}] L'attributo interno `%{internal_name}` non corrisponde al formato `%{format_name}`"
73
+ wrong_type: "[%{service_class_name}] L'attributo interno `%{internal_name}` deve essere una stringa per la validazione del formato `%{format_name}`"
74
+ unknown: "[%{service_class_name}] Formato sconosciuto `%{format_name}` specificato per l'attributo interno `%{internal_name}`"
75
+ inclusion:
76
+ default: "[%{service_class_name}] Valore errato in `%{internal_name}`, deve essere uno di `%{internal_inclusion}`, ricevuto `%{value}`"
77
+ invalid_option: "[%{service_class_name}] L'attributo interno `%{internal_name}` ha valore mancante nell'opzione `%{option_name}`"
78
+ min:
79
+ default: "[%{service_class_name}] L'attributo interno `%{internal_name}` ha ricevuto il valore `%{value}`, che è inferiore a `%{option_value}`"
80
+ max:
81
+ default: "[%{service_class_name}] L'attributo interno `%{internal_name}` ha ricevuto il valore `%{value}`, che è superiore a `%{option_value}`"
82
+ multiple_of:
83
+ default: "[%{service_class_name}] L'attributo interno `%{internal_name}` ha il valore `%{value}`, che non è un multiplo di `%{option_value}`"
84
+ blank: "[%{service_class_name}] L'attributo interno `%{internal_name}` ha un valore non valido `%{option_value}` nell'opzione `%{option_name}`"
85
+ divided_by_0: "[%{service_class_name}] L'attributo interno `%{internal_name}` ha un valore non valido `%{option_value}` nell'opzione `%{option_name}`"
86
+ schema:
87
+ wrong_type: "[%{service_class_name}] Tipo errato dell'attributo interno `%{internal_name}`, previsto `%{expected_type}`, ricevuto `%{given_type}`"
88
+ wrong_element_type: "[%{service_class_name}] Tipo errato nell'hash dell'attributo interno `%{internal_name}`, per `%{key_name}` previsto `%{expected_type}`, ricevuto `%{given_type}`"
89
+ wrong_element_value: "[%{service_class_name}] Valore errato nell'hash dell'attributo interno `%{internal_name}`, per `%{key_name}` valore previsto di tipo `%{expected_type}`, ricevuto `%{given_type}`"
90
+ target:
91
+ default: "[%{service_class_name}] L'attributo interno `%{internal_name}` ha obiettivo errato, deve essere `%{expected_target}`, ricevuto `%{value}`"
92
+ invalid_option: "[%{service_class_name}] L'attributo interno `%{internal_name}` ha valore mancante nell'opzione `%{option_name}`"
93
+ type:
94
+ default_error:
95
+ default: "[%{service_class_name}] Tipo errato dell'attributo interno `%{internal_name}`, previsto `%{expected_type}`, ricevuto `%{given_type}`"
96
+ outputs:
97
+ undefined:
98
+ for_fetch: "[%{service_class_name}] Attributo di output non definito `%{output_name}`"
99
+ for_assign: "[%{service_class_name}] Attributo di output non definito `%{output_name}`"
100
+ validations:
101
+ must:
102
+ default_error: "[%{service_class_name}] L'attributo di output `%{output_name}` deve \"%{code}\""
103
+ syntax_error: "[%{service_class_name}] Errore di sintassi in `%{code}` dell'attributo di output `%{output_name}`: %{exception_message}"
104
+ dynamic_options:
105
+ consists_of:
106
+ required: "[%{service_class_name}] Elemento richiesto mancante nella collezione dell'attributo di output `%{output_name}`"
107
+ wrong_type: "[%{service_class_name}] Tipo di collezione errato dell'attributo di output `%{output_name}`, previsto `%{expected_type}`, ricevuto `%{given_type}`"
108
+ wrong_element_type: "[%{service_class_name}] Tipo di elemento errato nella collezione dell'attributo di output `%{output_name}`, previsto `%{expected_type}`, ricevuto `%{given_type}`"
109
+ format:
110
+ default: "[%{service_class_name}] L'attributo di output `%{output_name}` non corrisponde al formato `%{format_name}`"
111
+ wrong_pattern: "[%{service_class_name}] L'attributo di output `%{output_name}` non corrisponde al formato `%{format_name}`"
112
+ wrong_type: "[%{service_class_name}] L'attributo di output `%{output_name}` deve essere una stringa per la validazione del formato `%{format_name}`"
113
+ unknown: "[%{service_class_name}] Formato sconosciuto `%{format_name}` specificato per l'attributo di output `%{output_name}`"
114
+ inclusion:
115
+ default: "[%{service_class_name}] Valore errato in `%{output_name}`, deve essere uno di `%{output_inclusion}`, ricevuto `%{value}`"
116
+ invalid_option: "[%{service_class_name}] L'attributo di output `%{output_name}` ha valore mancante nell'opzione `%{option_name}`"
117
+ min:
118
+ default: "[%{service_class_name}] L'attributo di output `%{output_name}` ha ricevuto il valore `%{value}`, che è inferiore a `%{option_value}`"
119
+ max:
120
+ default: "[%{service_class_name}] L'attributo di output `%{output_name}` ha ricevuto il valore `%{value}`, che è superiore a `%{option_value}`"
121
+ multiple_of:
122
+ default: "[%{service_class_name}] L'attributo di output `%{output_name}` ha il valore `%{value}`, che non è un multiplo di `%{option_value}`"
123
+ blank: "[%{service_class_name}] L'attributo di output `%{output_name}` ha un valore non valido `%{option_value}` nell'opzione `%{option_name}`"
124
+ divided_by_0: "[%{service_class_name}] L'attributo di output `%{output_name}` ha un valore non valido `%{option_value}` nell'opzione `%{option_name}`"
125
+ schema:
126
+ wrong_type: "[%{service_class_name}] Tipo errato dell'attributo di output `%{output_name}`, previsto `%{expected_type}`, ricevuto `%{given_type}`"
127
+ wrong_element_type: "[%{service_class_name}] Tipo errato nell'hash dell'attributo di output `%{output_name}`, per `%{key_name}` previsto `%{expected_type}`, ricevuto `%{given_type}`"
128
+ wrong_element_value: "[%{service_class_name}] Valore errato nell'hash dell'attributo di output `%{output_name}`, per `%{key_name}` valore previsto di tipo `%{expected_type}`, ricevuto `%{given_type}`"
129
+ target:
130
+ default: "[%{service_class_name}] L'attributo di output `%{output_name}` ha obiettivo errato, deve essere `%{expected_target}`, ricevuto `%{value}`"
131
+ invalid_option: "[%{service_class_name}] L'attributo di output `%{output_name}` ha valore mancante nell'opzione `%{option_name}`"
132
+ type:
133
+ default_error:
134
+ default: "[%{service_class_name}] Tipo errato dell'attributo di output `%{output_name}`, previsto `%{expected_type}`, ricevuto `%{given_type}`"
@@ -23,9 +23,11 @@ ru:
23
23
  format:
24
24
  default: "[%{service_class_name}] Инпут `%{input_name}` не соответствует формату `%{format_name}`"
25
25
  wrong_pattern: "[%{service_class_name}] Инпут `%{input_name}` не соответствует формату `%{format_name}`"
26
+ wrong_type: "[%{service_class_name}] Инпут `%{input_name}` должен быть строкой для валидации формата `%{format_name}`"
26
27
  unknown: "[%{service_class_name}] Указан неизвестный формат `%{format_name}` у инпута `%{input_name}`"
27
28
  inclusion:
28
29
  default: "[%{service_class_name}] Неправильное значение в `%{input_name}`, должно быть одним из `%{input_inclusion}`, получено `%{value}`"
30
+ invalid_option: "[%{service_class_name}] Инпут `%{input_name}` имеет незаполненное значение в опции `%{option_name}`"
29
31
  min:
30
32
  default: "[%{service_class_name}] Инпут `%{input_name}` получил значение `%{value}`, которое меньше `%{option_value}`"
31
33
  max:
@@ -38,6 +40,9 @@ ru:
38
40
  wrong_type: "[%{service_class_name}] Неправильный тип инпута `%{input_name}`, ожидалось `%{expected_type}`, получено `%{given_type}`"
39
41
  wrong_element_type: "[%{service_class_name}] Неправильный тип в хеше инпута `%{input_name}`, для `%{key_name}` ожидалось `%{expected_type}`, получено `%{given_type}`"
40
42
  wrong_element_value: "[%{service_class_name}] Неправильное значение в хеше инпута `%{input_name}`, для `%{key_name}` ожидалось значение с типом `%{expected_type}`, получено `%{given_type}`"
43
+ target:
44
+ default: "[%{service_class_name}] Инпут `%{input_name}` имеет неправильное значение, должно быть `%{expected_target}`, получено `%{value}`"
45
+ invalid_option: "[%{service_class_name}] Инпут `%{input_name}` имеет незаполненное значение в опции `%{option_name}`"
41
46
  required:
42
47
  default_error:
43
48
  default: "[%{service_class_name}] Обязательный инпут `%{input_name}` отсутствует"
@@ -65,9 +70,11 @@ ru:
65
70
  format:
66
71
  default: "[%{service_class_name}] Внутренний атрибут `%{internal_name}` не соответствует формату `%{format_name}`"
67
72
  wrong_pattern: "[%{service_class_name}] Внутренний атрибут `%{internal_name}` не соответствует формату `%{format_name}`"
73
+ wrong_type: "[%{service_class_name}] Внутренний атрибут `%{internal_name}` должен быть строкой для валидации формата `%{format_name}`"
68
74
  unknown: "[%{service_class_name}] Указан неизвестный формат `%{format_name}` у внутреннего атрибута `%{internal_name}`"
69
75
  inclusion:
70
76
  default: "[%{service_class_name}] Неправильное значение в `%{internal_name}`, должно быть одним из `%{internal_inclusion}`, получено `%{value}`"
77
+ invalid_option: "[%{service_class_name}] Внутренний атрибут `%{internal_name}` имеет незаполненное значение в опции `%{option_name}`"
71
78
  min:
72
79
  default: "[%{service_class_name}] Внутренний атрибут `%{internal_name}` получил значение `%{value}`, которое меньше `%{option_value}`"
73
80
  max:
@@ -80,6 +87,9 @@ ru:
80
87
  wrong_type: "[%{service_class_name}] Неправильный тип внутреннего атрибута `%{internal_name}`, ожидалось `%{expected_type}`, получено `%{given_type}`"
81
88
  wrong_element_type: "[%{service_class_name}] Неправильный тип в хеше внутреннего атрибута `%{internal_name}`, для `%{key_name}` ожидалось `%{expected_type}`, получено `%{given_type}`"
82
89
  wrong_element_value: "[%{service_class_name}] Неправильное значение в хеше внутреннего атрибута `%{internal_name}`, для `%{key_name}` ожидалось значение с типом `%{expected_type}`, получено `%{given_type}`"
90
+ target:
91
+ default: "[%{service_class_name}] Внутренний атрибут `%{internal_name}` имеет неправильное значение, должно быть `%{expected_target}`, получено `%{value}`"
92
+ invalid_option: "[%{service_class_name}] Внутренний атрибут `%{internal_name}` имеет незаполненное значение в опции `%{option_name}`"
83
93
  type:
84
94
  default_error:
85
95
  default: "[%{service_class_name}] Неправильный тип внутреннего атрибута `%{internal_name}`, ожидалось `%{expected_type}`, получено `%{given_type}`"
@@ -99,9 +109,11 @@ ru:
99
109
  format:
100
110
  default: "[%{service_class_name}] Выходящий атрибут `%{output_name}` не соответствует формату `%{format_name}`"
101
111
  wrong_pattern: "[%{service_class_name}] Выходящий атрибут `%{output_name}` не соответствует формату `%{format_name}`"
112
+ wrong_type: "[%{service_class_name}] Выходящий атрибут `%{output_name}` должен быть строкой для валидации формата `%{format_name}`"
102
113
  unknown: "[%{service_class_name}] Указан неизвестный формат `%{format_name}` у выходящего атрибута `%{output_name}`"
103
114
  inclusion:
104
115
  default: "[%{service_class_name}] Неправильное значение в `%{output_name}`, должно быть одним из `%{output_inclusion}`, получено `%{value}`"
116
+ invalid_option: "[%{service_class_name}] Выходящий атрибут `%{output_name}` имеет незаполненное значение в опции `%{option_name}`"
105
117
  min:
106
118
  default: "[%{service_class_name}] Выходящий атрибут `%{output_name}` получил значение `%{value}`, которое меньше `%{option_value}`"
107
119
  max:
@@ -114,6 +126,9 @@ ru:
114
126
  wrong_type: "[%{service_class_name}] Неправильный тип выходящего атрибута `%{output_name}`, ожидалось `%{expected_type}`, получено `%{given_type}`"
115
127
  wrong_element_type: "[%{service_class_name}] Неправильный тип в хеше выходящего атрибута `%{output_name}`, для `%{key_name}` ожидалось `%{expected_type}`, получено `%{given_type}`"
116
128
  wrong_element_value: "[%{service_class_name}] Неправильное значение в хеше выходящего атрибута `%{output_name}`, для `%{key_name}` ожидалось значение с типом `%{expected_type}`, получено `%{given_type}`"
129
+ target:
130
+ default: "[%{service_class_name}] Выходящий атрибут `%{output_name}` имеет неправильное значение, должно быть `%{expected_target}`, получено `%{value}`"
131
+ invalid_option: "[%{service_class_name}] Выходящий атрибут `%{output_name}` имеет незаполненное значение в опции `%{option_name}`"
117
132
  type:
118
133
  default_error:
119
134
  default: "[%{service_class_name}] Неправильный тип выходящего атрибута `%{output_name}`, ожидалось `%{expected_type}`, получено `%{given_type}`"
@@ -0,0 +1,45 @@
1
+ # Servactory Generators
2
+
3
+ ## Installation
4
+
5
+ ```bash
6
+ rails generate servactory:install [options]
7
+ ```
8
+
9
+ **Options:**
10
+ - `--namespace` — Base namespace (default: `ApplicationService`)
11
+ - `--path` — Path to install service files (default: `app/services`)
12
+ - `--locales` — Locales to install (available: `en`, `ru`, `de`, `fr`, `es`, `it`)
13
+ - `--minimal` — Generate minimal setup without configuration examples
14
+
15
+ ## Service
16
+
17
+ ```bash
18
+ rails generate servactory:service NAME [inputs] [options]
19
+ ```
20
+
21
+ **Arguments:**
22
+ - `NAME` — Service name (e.g., `Users::Create`, `ProcessOrder`)
23
+ - `inputs` — Input attributes with optional types (e.g., `email:string name:String user:User`)
24
+
25
+ **Options:**
26
+ - `--base-class` — Base class for service (default: `ApplicationService::Base`)
27
+ - `--path` — Path to generate service files (default: `app/services`)
28
+ - `--skip-output` — Skip default output declaration
29
+
30
+ ## RSpec
31
+
32
+ ```bash
33
+ rails generate servactory:rspec NAME [inputs] [options]
34
+ ```
35
+
36
+ Generates RSpec spec for a Servactory service.
37
+
38
+ **Arguments:**
39
+ - `NAME` — Service name (e.g., `Users::Create`)
40
+ - `inputs` — Input attributes with optional types (e.g., `email:string name:String`)
41
+
42
+ **Options:**
43
+ - `--call-method` — Primary call method: `call` or `call!` (default: `call!`)
44
+ - `--path` — Path to service files (default: `app/services`). Spec path is auto-derived: `app/X` → `spec/X`, `lib/X` → `spec/X`
45
+ - `--skip-pending` — Skip pending placeholder
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/base"
4
+ require "rails/generators/named_base"
5
+
6
+ module Servactory
7
+ module Generators
8
+ class Base < Rails::Generators::Base
9
+ def self.gem_root
10
+ @gem_root ||= File.expand_path("../../..", __dir__)
11
+ end
12
+
13
+ def self.gem_locales_path
14
+ @gem_locales_path ||= File.join(gem_root, "config", "locales")
15
+ end
16
+
17
+ private
18
+
19
+ def gem_root
20
+ self.class.gem_root
21
+ end
22
+
23
+ def gem_locales_path
24
+ self.class.gem_locales_path
25
+ end
26
+ end
27
+
28
+ class NamedBase < Rails::Generators::NamedBase
29
+ VALID_INPUT_NAME_REGEX = /\A[a-z_][a-zA-Z0-9_]*\z/
30
+
31
+ TYPE_MAPPING = {
32
+ "string" => "String",
33
+ "integer" => "Integer",
34
+ "float" => "Float",
35
+ "boolean" => "[TrueClass, FalseClass]",
36
+ "bool" => "[TrueClass, FalseClass]",
37
+ "array" => "Array",
38
+ "hash" => "Hash",
39
+ "symbol" => "Symbol",
40
+ "date" => "Date",
41
+ "datetime" => "DateTime",
42
+ "time" => "Time",
43
+ "nil" => "NilClass",
44
+ "nilclass" => "NilClass",
45
+ "decimal" => "BigDecimal",
46
+ "bigdecimal" => "BigDecimal"
47
+ }.freeze
48
+
49
+ private
50
+
51
+ def input_names
52
+ @input_names ||= parsed_inputs.map { |input| input[:name] }
53
+ end
54
+
55
+ def parsed_inputs
56
+ @parsed_inputs ||= inputs.map do |input_argument|
57
+ parts = input_argument.to_s.split(":", 2)
58
+ name = parts[0].strip
59
+ type = normalize_type(parts[1])
60
+
61
+ validate_input_name!(name)
62
+
63
+ { name:, type: }
64
+ end
65
+ end
66
+
67
+ def validate_input_name!(name)
68
+ return if name.match?(VALID_INPUT_NAME_REGEX)
69
+
70
+ raise ArgumentError, "Invalid input name '#{name}'. " \
71
+ "Input names must start with a lowercase letter or underscore, " \
72
+ "followed by letters, numbers, or underscores."
73
+ end
74
+
75
+ def normalize_type(type_string)
76
+ return "String" if type_string.blank?
77
+
78
+ TYPE_MAPPING[type_string.downcase] || type_string
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,54 @@
1
+ Description:
2
+ Generates a new Servactory extension module.
3
+
4
+ Usage:
5
+ rails generate servactory:extension NAME [options]
6
+
7
+ Arguments:
8
+ NAME The name of the extension (e.g., MyExtension, Admin::AuditTrail)
9
+
10
+ Options:
11
+ --path=PATH Path to generate extension files (default: app/services/application_service/extensions)
12
+ --namespace=NAMESPACE Base namespace for the extension module (default: ApplicationService)
13
+
14
+ Generated Structure:
15
+ The extension follows the standard Servactory extension pattern with:
16
+ - self.included(base) hook for module setup
17
+ - ClassMethods module for DSL methods (called at class definition time)
18
+ - InstanceMethods module for runtime behavior (call! override)
19
+ - stroma.settings integration for configuration storage
20
+
21
+ Examples:
22
+ rails generate servactory:extension MyExtension
23
+ Creates app/services/application_service/extensions/my_extension/dsl.rb
24
+ Module: ApplicationService::Extensions::MyExtension::DSL
25
+
26
+ rails generate servactory:extension Admin::AuditTrail
27
+ Creates app/services/application_service/extensions/admin/audit_trail/dsl.rb
28
+ Module: ApplicationService::Extensions::Admin::AuditTrail::DSL
29
+
30
+ rails generate servactory:extension MyExtension --path=lib/my_gem/extensions
31
+ Creates lib/my_gem/extensions/my_extension/dsl.rb
32
+
33
+ rails generate servactory:extension MyExtension --namespace=MyApp::Services
34
+ Creates extension with MyApp::Services::Extensions::MyExtension::DSL namespace
35
+
36
+ Usage in Service:
37
+ After generation, include the extension in your service base class:
38
+
39
+ # app/services/application_service/base.rb
40
+ module ApplicationService
41
+ class Base < Servactory::Base
42
+ extensions do
43
+ before :actions, ApplicationService::Extensions::MyExtension::DSL
44
+ end
45
+ end
46
+ end
47
+
48
+ Then use the DSL method in your services:
49
+
50
+ class MyService < ApplicationService::Base
51
+ my_extension!(my_setting: "value")
52
+
53
+ # ...
54
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Servactory
4
+ module Generators
5
+ class ExtensionGenerator < Rails::Generators::NamedBase
6
+ source_root File.expand_path("templates", __dir__)
7
+
8
+ class_option :path,
9
+ type: :string,
10
+ default: "app/services/application_service/extensions",
11
+ desc: "Path to generate extension files"
12
+
13
+ class_option :namespace,
14
+ type: :string,
15
+ default: "ApplicationService",
16
+ desc: "Base namespace for the extension module"
17
+
18
+ def create_extension
19
+ template "extension.rb.tt", extension_file_path
20
+ end
21
+
22
+ private
23
+
24
+ def extension_file_path
25
+ "#{extensions_path}/#{file_path}/dsl.rb"
26
+ end
27
+
28
+ def extensions_path
29
+ options[:path]
30
+ end
31
+
32
+ def base_namespace
33
+ options[:namespace]
34
+ end
35
+
36
+ def extension_key
37
+ file_path.tr("/", "_")
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module <%= base_namespace %>
4
+ module Extensions
5
+ module <%= class_name %>
6
+ module DSL
7
+ # Hook called when this module is included in a service base class.
8
+ # Sets up both class-level DSL methods and instance-level runtime behavior.
9
+ def self.included(base)
10
+ base.extend(ClassMethods)
11
+ base.include(InstanceMethods)
12
+ end
13
+
14
+ # Class-level DSL methods - called at service class definition time.
15
+ # Use these to configure extension behavior for the service class.
16
+ module ClassMethods
17
+ private
18
+
19
+ # Example DSL method that stores configuration in stroma settings.
20
+ # Usage in service: <%= extension_key %>!(my_setting: "value")
21
+ def <%= extension_key %>!(my_setting: nil)
22
+ stroma.settings[:actions][:<%= extension_key %>][:my_setting] = my_setting
23
+ end
24
+ end
25
+
26
+ # Instance-level methods - called at service runtime.
27
+ # Override call! to add behavior before, after, or around service execution.
28
+ module InstanceMethods
29
+ private
30
+
31
+ # Override call! to customize service execution flow.
32
+ #
33
+ # Common patterns:
34
+ # Before: validate/check conditions, then call super
35
+ # After: call super, then process outputs
36
+ # Around: wrap super in context (e.g., transaction { super })
37
+ # Error: call super with rescue block for error handling
38
+ #
39
+ # Available parameters for call!:
40
+ # def call!(**) - basic, most common
41
+ # def call!(incoming_arguments: {}, **) - access raw arguments before input processing
42
+ # def call!(collection_of_inputs:, collection_of_internals:, collection_of_outputs:, **) - full access
43
+ def call!(**)
44
+ # Access class-level configuration stored in stroma settings
45
+ my_setting = self.class.stroma.settings[:actions][:<%= extension_key %>][:my_setting]
46
+
47
+ # Example: Before pattern - validate before execution
48
+ # if my_setting.present?
49
+ # fail!(:my_error, message: "Error message") unless some_condition
50
+ # end
51
+
52
+ # Always call super to continue the execution chain
53
+ super
54
+
55
+ # Example: After pattern - process outputs after execution
56
+ # process_result(outputs) if my_setting.present?
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,27 @@
1
+ Description:
2
+ Installs Servactory base service configuration into your Rails application.
3
+
4
+ Usage:
5
+ rails generate servactory:install [options]
6
+
7
+ Options:
8
+ --namespace=NAMESPACE Base namespace for services (default: ApplicationService)
9
+ --locales=LOCALES Locales to install (available: en, ru, de, fr, es, it)
10
+ --minimal Generate minimal setup without configuration examples
11
+ --path=PATH Path to install service files (default: app/services)
12
+
13
+ Examples:
14
+ rails generate servactory:install
15
+ Creates app/services/application_service/ with base.rb, exceptions.rb, result.rb
16
+
17
+ rails generate servactory:install --path=lib/my_gem/services
18
+ Creates lib/my_gem/services/application_service/ for gem/library use
19
+
20
+ rails generate servactory:install --namespace=MyApp::Services
21
+ Creates app/services/my_app/services/ with all files
22
+
23
+ rails generate servactory:install --locales=en,de,fr
24
+ Also copies locale files to config/locales/ (available: en, ru, de, fr, es, it)
25
+
26
+ rails generate servactory:install --minimal
27
+ Creates minimal setup without configuration examples
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../base"
4
+
5
+ module Servactory
6
+ module Generators
7
+ class InstallGenerator < Servactory::Generators::Base
8
+ source_root File.expand_path("templates", __dir__)
9
+
10
+ VALID_NAMESPACE_REGEX = /\A[A-Z][a-zA-Z0-9_]*(::[A-Z][a-zA-Z0-9_]*)*\z/
11
+
12
+ class_option :namespace,
13
+ type: :string,
14
+ default: "ApplicationService",
15
+ desc: "Base namespace for services"
16
+
17
+ class_option :path,
18
+ type: :string,
19
+ default: "app/services",
20
+ desc: "Path to install service files"
21
+
22
+ class_option :locales,
23
+ type: :array,
24
+ default: [],
25
+ desc: "Locales to install (e.g., --locales=en,ru)"
26
+
27
+ class_option :minimal,
28
+ type: :boolean,
29
+ default: false,
30
+ desc: "Generate minimal setup without configuration examples"
31
+
32
+ def create_application_service
33
+ validate_namespace!
34
+
35
+ template "application_service/base.rb.tt", service_path("base.rb")
36
+ template "application_service/exceptions.rb.tt", service_path("exceptions.rb")
37
+ template "application_service/result.rb.tt", service_path("result.rb")
38
+
39
+ create_file service_path("dynamic_options/.keep"), ""
40
+ create_file service_path("extensions/.keep"), ""
41
+ end
42
+
43
+ def copy_locales
44
+ return if locales.blank?
45
+
46
+ locales.each do |locale|
47
+ locale_file = "servactory.#{locale}.yml"
48
+ source_path = File.join(gem_locales_path, "#{locale}.yml")
49
+
50
+ if File.exist?(source_path)
51
+ copy_file source_path, "config/locales/#{locale_file}"
52
+ else
53
+ say "Locale file not found: #{locale} (expected at #{source_path})", :yellow
54
+ end
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def validate_namespace!
61
+ return if namespace.match?(VALID_NAMESPACE_REGEX)
62
+
63
+ raise ArgumentError, "Invalid namespace '#{namespace}'. " \
64
+ "Namespace must be a valid Ruby constant name " \
65
+ "(e.g., 'ApplicationService', 'MyApp::Services')."
66
+ end
67
+
68
+ def namespace
69
+ options[:namespace]
70
+ end
71
+
72
+ def namespace_path
73
+ namespace.underscore
74
+ end
75
+
76
+ def base_path
77
+ options[:path]
78
+ end
79
+
80
+ def service_path(filename)
81
+ "#{base_path}/#{namespace_path}/#{filename}"
82
+ end
83
+
84
+ def locales
85
+ # Handle both "--locales=en,ru" (single string) and "--locales en ru" (array)
86
+ options[:locales].flat_map { |locale| locale.split(",") }
87
+ end
88
+
89
+ def minimal?
90
+ options[:minimal]
91
+ end
92
+ end
93
+ end
94
+ end