mxrb 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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.de-DE.md +108 -0
- data/README.md +172 -0
- data/README.pt-BR.md +109 -0
- data/bin/mxrb +1613 -0
- data/docs/README.md +10 -0
- data/docs/de-DE/README.md +24 -0
- data/docs/de-DE/architectural-patterns.md +26 -0
- data/docs/de-DE/architectural-standard.md +48 -0
- data/docs/de-DE/architecture.md +76 -0
- data/docs/de-DE/compiler.md +162 -0
- data/docs/de-DE/conventions.md +19 -0
- data/docs/de-DE/design-system.md +52 -0
- data/docs/de-DE/entity-dsl.md +53 -0
- data/docs/de-DE/native-runtime-quality-report.md +74 -0
- data/docs/de-DE/oql-sql.md +211 -0
- data/docs/de-DE/platform-api-integration.md +36 -0
- data/docs/de-DE/platform-operations.md +243 -0
- data/docs/de-DE/project-structure.md +32 -0
- data/docs/de-DE/ruby-first-roadmap.md +116 -0
- data/docs/de-DE/scaffolds.md +59 -0
- data/docs/de-DE/semantic-refactoring.md +56 -0
- data/docs/de-DE/team-server.md +33 -0
- data/docs/de-DE/validation-matrix.md +64 -0
- data/docs/de-DE/vetclinic-acceptance.md +24 -0
- data/docs/de-DE/writing.md +138 -0
- data/docs/en-US/README.md +24 -0
- data/docs/en-US/architectural-patterns.md +151 -0
- data/docs/en-US/architectural-standard.md +89 -0
- data/docs/en-US/architecture.md +170 -0
- data/docs/en-US/compiler.md +157 -0
- data/docs/en-US/conventions.md +82 -0
- data/docs/en-US/design-system.md +163 -0
- data/docs/en-US/entity-dsl.md +53 -0
- data/docs/en-US/native-runtime-quality-report.md +73 -0
- data/docs/en-US/oql-sql.md +201 -0
- data/docs/en-US/platform-api-integration.md +36 -0
- data/docs/en-US/platform-operations.md +244 -0
- data/docs/en-US/project-structure.md +49 -0
- data/docs/en-US/ruby-first-roadmap.md +186 -0
- data/docs/en-US/scaffolds.md +57 -0
- data/docs/en-US/semantic-refactoring.md +198 -0
- data/docs/en-US/team-server.md +32 -0
- data/docs/en-US/validation-matrix.md +257 -0
- data/docs/en-US/vetclinic-acceptance.md +23 -0
- data/docs/en-US/writing.md +655 -0
- data/docs/pt-BR/README.md +24 -0
- data/docs/pt-BR/architectural-patterns.md +25 -0
- data/docs/pt-BR/architectural-standard.md +533 -0
- data/docs/pt-BR/architecture.md +300 -0
- data/docs/pt-BR/compiler.md +162 -0
- data/docs/pt-BR/conventions.md +19 -0
- data/docs/pt-BR/design-system.md +65 -0
- data/docs/pt-BR/entity-dsl.md +116 -0
- data/docs/pt-BR/native-runtime-quality-report.md +73 -0
- data/docs/pt-BR/oql-sql.md +208 -0
- data/docs/pt-BR/platform-api-integration.md +36 -0
- data/docs/pt-BR/platform-operations.md +260 -0
- data/docs/pt-BR/project-structure.md +32 -0
- data/docs/pt-BR/ruby-first-roadmap.md +239 -0
- data/docs/pt-BR/scaffolds.md +104 -0
- data/docs/pt-BR/semantic-refactoring.md +55 -0
- data/docs/pt-BR/team-server.md +59 -0
- data/docs/pt-BR/validation-matrix.md +86 -0
- data/docs/pt-BR/vetclinic-acceptance.md +50 -0
- data/docs/pt-BR/writing.md +177 -0
- data/examples/sudoku_evaluation.rb +14 -0
- data/examples/sudoku_functional_test.rb +28 -0
- data/lib/mxrb/architecture/graph.rb +124 -0
- data/lib/mxrb/architecture/validator.rb +98 -0
- data/lib/mxrb/benchmark.rb +33 -0
- data/lib/mxrb/compare.rb +390 -0
- data/lib/mxrb/compiler/adapter.rb +96 -0
- data/lib/mxrb/compiler/artifact_document_compiler.rb +102 -0
- data/lib/mxrb/compiler/artifact_materializer.rb +53 -0
- data/lib/mxrb/compiler/client_model_materializer.rb +42 -0
- data/lib/mxrb/compiler/code_action_document_compiler.rb +64 -0
- data/lib/mxrb/compiler/code_action_materializer.rb +35 -0
- data/lib/mxrb/compiler/code_action_type_compiler.rb +32 -0
- data/lib/mxrb/compiler/combo_box_bundle_compiler.rb +314 -0
- data/lib/mxrb/compiler/compatibility_analyzer.rb +169 -0
- data/lib/mxrb/compiler/constants_materializer.rb +111 -0
- data/lib/mxrb/compiler/data_grid_bundle_compiler.rb +290 -0
- data/lib/mxrb/compiler/database_connector_action_compiler.rb +280 -0
- data/lib/mxrb/compiler/deployment_asset_copier.rb +60 -0
- data/lib/mxrb/compiler/deployment_bootstrapper.rb +208 -0
- data/lib/mxrb/compiler/deployment_materializer.rb +43 -0
- data/lib/mxrb/compiler/deployment_metadata.rb +64 -0
- data/lib/mxrb/compiler/domain_document_compiler.rb +153 -0
- data/lib/mxrb/compiler/domain_model_materializer.rb +35 -0
- data/lib/mxrb/compiler/domain_security_compiler.rb +82 -0
- data/lib/mxrb/compiler/gallery_bundle_compiler.rb +190 -0
- data/lib/mxrb/compiler/generic_widget_bundle_compiler.rb +281 -0
- data/lib/mxrb/compiler/image_bundle_compiler.rb +216 -0
- data/lib/mxrb/compiler/java_proxy_generator.rb +509 -0
- data/lib/mxrb/compiler/legacy_data_grid_compiler.rb +267 -0
- data/lib/mxrb/compiler/legacy_page_builder.rb +287 -0
- data/lib/mxrb/compiler/mda.rb +99 -0
- data/lib/mxrb/compiler/microflow_document_compiler.rb +85 -0
- data/lib/mxrb/compiler/microflow_materializer.rb +48 -0
- data/lib/mxrb/compiler/microflow_node_compiler.rb +250 -0
- data/lib/mxrb/compiler/model_package.rb +116 -0
- data/lib/mxrb/compiler/model_values.rb +67 -0
- data/lib/mxrb/compiler/nanoflow_program_compiler.rb +483 -0
- data/lib/mxrb/compiler/navigation_document_compiler.rb +93 -0
- data/lib/mxrb/compiler/packager.rb +100 -0
- data/lib/mxrb/compiler/page_bundle_builder.rb +56 -0
- data/lib/mxrb/compiler/page_bundle_compiler.rb +2004 -0
- data/lib/mxrb/compiler/page_document_compiler.rb +77 -0
- data/lib/mxrb/compiler/portable_packager.rb +356 -0
- data/lib/mxrb/compiler/project_jar_archive.rb +84 -0
- data/lib/mxrb/compiler/project_jar_builder.rb +121 -0
- data/lib/mxrb/compiler/project_materializer.rb +139 -0
- data/lib/mxrb/compiler/project_model_orderer.rb +52 -0
- data/lib/mxrb/compiler/runtime_data_types.rb +31 -0
- data/lib/mxrb/compiler/runtime_model_schema.rb +90 -0
- data/lib/mxrb/compiler/schemas/runtime-10.24.0.73019.json +1052 -0
- data/lib/mxrb/compiler/schemas/runtime-11.json +1215 -0
- data/lib/mxrb/compiler/schemas/runtime-6.10.8.json +1148 -0
- data/lib/mxrb/compiler/schemas/runtime-7.17.0.json +1144 -0
- data/lib/mxrb/compiler/schemas/runtime-7.5.0.json +1215 -0
- data/lib/mxrb/compiler/schemas/runtime-9.6.1.29396.json +868 -0
- data/lib/mxrb/compiler/schemas/system-model-10.24.0.73019.b64 +1135 -0
- data/lib/mxrb/compiler/schemas/system-model-11.12.1.b64 +815 -0
- data/lib/mxrb/compiler/schemas/system-model-6.10.8.b64 +497 -0
- data/lib/mxrb/compiler/schemas/system-model-7.17.0.b64 +519 -0
- data/lib/mxrb/compiler/schemas/system-model-7.5.0.b64 +504 -0
- data/lib/mxrb/compiler/schemas/system-model-9.6.1.29396.b64 +816 -0
- data/lib/mxrb/compiler/security_materializer.rb +104 -0
- data/lib/mxrb/compiler/settings_document_compiler.rb +45 -0
- data/lib/mxrb/compiler/settings_materializer.rb +25 -0
- data/lib/mxrb/compiler/source_model.rb +128 -0
- data/lib/mxrb/compiler/system_model_seed.rb +88 -0
- data/lib/mxrb/compiler/system_queue_materializer.rb +54 -0
- data/lib/mxrb/compiler/system_text_materializer.rb +49 -0
- data/lib/mxrb/compiler/translation_materializer.rb +95 -0
- data/lib/mxrb/compiler/web_bundle_builder.rb +155 -0
- data/lib/mxrb/compiler/web_list_data_source.rb +139 -0
- data/lib/mxrb/compiler/web_operation_compiler.rb +614 -0
- data/lib/mxrb/compiler/web_shell_materializer.rb +194 -0
- data/lib/mxrb/compiler/widget_package_extractor.rb +63 -0
- data/lib/mxrb/doctor.rb +116 -0
- data/lib/mxrb/dsl/builder.rb +1636 -0
- data/lib/mxrb/errors.rb +18 -0
- data/lib/mxrb/evaluation.rb +131 -0
- data/lib/mxrb/exporter.rb +1716 -0
- data/lib/mxrb/frontend/migrator.rb +775 -0
- data/lib/mxrb/functional.rb +307 -0
- data/lib/mxrb/github/annotator.rb +161 -0
- data/lib/mxrb/initializer.rb +257 -0
- data/lib/mxrb/integrity/validator.rb +136 -0
- data/lib/mxrb/io/bson_codec.rb +145 -0
- data/lib/mxrb/io/mpr_file.rb +558 -0
- data/lib/mxrb/io/mxunit_codec.rb +42 -0
- data/lib/mxrb/marketplace.rb +380 -0
- data/lib/mxrb/model/association.rb +98 -0
- data/lib/mxrb/model/attribute.rb +100 -0
- data/lib/mxrb/model/connector.rb +17 -0
- data/lib/mxrb/model/design_materializer.rb +133 -0
- data/lib/mxrb/model/design_migration.rb +126 -0
- data/lib/mxrb/model/design_system.rb +111 -0
- data/lib/mxrb/model/domain_model.rb +51 -0
- data/lib/mxrb/model/entity.rb +180 -0
- data/lib/mxrb/model/menu.rb +38 -0
- data/lib/mxrb/model/microflow.rb +100 -0
- data/lib/mxrb/model/module.rb +142 -0
- data/lib/mxrb/model/navigation.rb +127 -0
- data/lib/mxrb/model/page.rb +410 -0
- data/lib/mxrb/model/project.rb +187 -0
- data/lib/mxrb/model/unit.rb +48 -0
- data/lib/mxrb/module_initializer.rb +75 -0
- data/lib/mxrb/official_marketplace/content_api.rb +292 -0
- data/lib/mxrb/official_marketplace/dependency_resolver.rb +329 -0
- data/lib/mxrb/official_marketplace/lifecycle.rb +367 -0
- data/lib/mxrb/official_marketplace/module_package_importer.rb +318 -0
- data/lib/mxrb/official_marketplace/widget_package_installer.rb +414 -0
- data/lib/mxrb/official_marketplace.rb +720 -0
- data/lib/mxrb/oql/analyzer.rb +155 -0
- data/lib/mxrb/oql/index_advisor.rb +85 -0
- data/lib/mxrb/oql/plan_analyzer.rb +185 -0
- data/lib/mxrb/oql/server.rb +132 -0
- data/lib/mxrb/oql/sql_server_plan_analyzer.rb +190 -0
- data/lib/mxrb/oql/sql_server_workload_analyzer.rb +80 -0
- data/lib/mxrb/oql/workload_analyzer.rb +175 -0
- data/lib/mxrb/oql/workload_baseline.rb +60 -0
- data/lib/mxrb/oql.rb +424 -0
- data/lib/mxrb/project_lifecycle.rb +76 -0
- data/lib/mxrb/protocols/plan.rb +86 -0
- data/lib/mxrb/protocols.rb +123 -0
- data/lib/mxrb/runtime/database_workspace.rb +677 -0
- data/lib/mxrb/runtime/docker_executor.rb +41 -0
- data/lib/mxrb/runtime/docker_workspace.rb +29 -0
- data/lib/mxrb/runtime/executor.rb +169 -0
- data/lib/mxrb/runtime/java_locator.rb +26 -0
- data/lib/mxrb/runtime/native.rb +474 -0
- data/lib/mxrb/runtime/sql_server_database.rb +146 -0
- data/lib/mxrb/runtime/toolchain.rb +82 -0
- data/lib/mxrb/scaffold/cli.rb +113 -0
- data/lib/mxrb/scaffold/generator.rb +246 -0
- data/lib/mxrb/scaffold/help.rb +80 -0
- data/lib/mxrb/scaffold/page_templates.rb +54 -0
- data/lib/mxrb/scaffold/recipes.rb +198 -0
- data/lib/mxrb/scaffold/registry.rb +82 -0
- data/lib/mxrb/scaffold/templates.rb +723 -0
- data/lib/mxrb/scaffold/transaction.rb +84 -0
- data/lib/mxrb/schema/tables.rb +55 -0
- data/lib/mxrb/semantic/analyzer.rb +473 -0
- data/lib/mxrb/semantic/batch_plan.rb +68 -0
- data/lib/mxrb/semantic/domain_mutator.rb +419 -0
- data/lib/mxrb/semantic/embedder.rb +51 -0
- data/lib/mxrb/semantic/extractor.rb +290 -0
- data/lib/mxrb/semantic/index.rb +623 -0
- data/lib/mxrb/semantic/inliner.rb +216 -0
- data/lib/mxrb/semantic/mover.rb +153 -0
- data/lib/mxrb/semantic/onnx_embedder.rb +34 -0
- data/lib/mxrb/semantic/remover.rb +70 -0
- data/lib/mxrb/semantic/renamer.rb +211 -0
- data/lib/mxrb/semantic/tfidf_embedder.rb +46 -0
- data/lib/mxrb/semantic/vec_store.rb +75 -0
- data/lib/mxrb/team_server.rb +390 -0
- data/lib/mxrb/templates/project/10.24.0.73019.json +32 -0
- data/lib/mxrb/templates/project/11.12.1.json +32 -0
- data/lib/mxrb/templates/project/6.10.8.json +50 -0
- data/lib/mxrb/templates/project/7.17.0.json +50 -0
- data/lib/mxrb/templates/project/7.5.0.json +50 -0
- data/lib/mxrb/templates/project/9.6.1.29396.json +50 -0
- data/lib/mxrb/version.rb +5 -0
- data/lib/mxrb/widget_package.rb +338 -0
- data/lib/mxrb/widget_synchronizer.rb +31 -0
- data/lib/mxrb/writer.rb +3775 -0
- data/lib/mxrb.rb +188 -0
- data/marketplace/catalog.json +10 -0
- data/marketplace/modules/shared-kernel/domain/README.md +4 -0
- data/marketplace/modules/shared-kernel/module.rb +5 -0
- data/marketplace/modules/shared-kernel/mxrb-module.json +9 -0
- metadata +447 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Criação e edição de projetos
|
|
2
|
+
|
|
3
|
+
**Português** · [English](../en-US/writing.md) · [Deutsch](../de-DE/writing.md)
|
|
4
|
+
|
|
5
|
+
`mxrb generate` avalia uma definição Ruby e cria ou atualiza o MPR. Nomes
|
|
6
|
+
Mendix são chaves estáveis, portanto reaplicar a definição não duplica units.
|
|
7
|
+
|
|
8
|
+
Para iniciar em uma pasta vazia:
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
mxrb init vet_clinic
|
|
12
|
+
cd vet_clinic
|
|
13
|
+
bundle install
|
|
14
|
+
bundle exec mxrb generate project.rb
|
|
15
|
+
bundle exec mxrb validate VetClinic.mpr
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`init` aceita snake_case ou PascalCase, cria `Gemfile`, `project.rb` e o módulo
|
|
19
|
+
principal em `modules/VetClinic`. O scaffold inclui somente código próprio: o
|
|
20
|
+
módulo `System` é implícito no Runtime; Administration e Atlas são módulos de
|
|
21
|
+
marketplace. O comando aborta sem alterar nada quando o diretório já existe.
|
|
22
|
+
|
|
23
|
+
Para adicionar outro módulo de aplicação a partir da raiz do projeto:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
mxrb module new appointments
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
O comando cria `modules/Appointments`, reutiliza o mesmo scaffold de
|
|
30
|
+
domain/application e conecta o `module.rb` no `project.rb`. A operação aborta
|
|
31
|
+
atomicamente se o módulo já existir ou se o arquivo de projeto não puder ser
|
|
32
|
+
atualizado. Use `--target DIR` ao executar fora da raiz do projeto.
|
|
33
|
+
|
|
34
|
+
Os scaffolds de artefatos, apresentação, infraestrutura, testes, design e CI
|
|
35
|
+
estão no [catálogo de scaffolds](scaffolds.md). Para entidades, consulte a
|
|
36
|
+
[referência completa da DSL](entity-dsl.md).
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
Mxrb.define("Shop.mpr") do
|
|
40
|
+
mendix_version "11.12.1"
|
|
41
|
+
self.module :Sales do
|
|
42
|
+
entity :Order do
|
|
43
|
+
string :Number, documentation: "Número estável do pedido"
|
|
44
|
+
decimal :Total, default: 0
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
bundle exec mxrb generate shop.rb
|
|
52
|
+
bundle exec mxrb validate Shop.mpr
|
|
53
|
+
bundle exec mxrb export Shop.mpr exported-shop
|
|
54
|
+
bundle exec mxrb compare original.mpr rebuilt.mpr
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Avaliações de modelo
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
artifact "Sales.Order", kind: :entity
|
|
61
|
+
no_call_cycles
|
|
62
|
+
no_missing_internal_references
|
|
63
|
+
check("Order possui Total") do |project|
|
|
64
|
+
project.find_artifact("Sales.Order.Total", kind: :attribute)
|
|
65
|
+
end
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Execute com `mxrb evaluate App.mpr evaluation.rb`.
|
|
69
|
+
|
|
70
|
+
## Testes funcionais
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
microflow "cria pedido",
|
|
74
|
+
call: "Sales.ACT_CreateOrder",
|
|
75
|
+
before: { call: "Sales.TEST_Preparar" },
|
|
76
|
+
after: { call: "Sales.TEST_Limpar" },
|
|
77
|
+
expect: {
|
|
78
|
+
return: "true",
|
|
79
|
+
count: { entity: "Sales.Order", xpath: "[Status = 'Open']", equals: 1 }
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Use `mxrb test App.mpr functional_test.rb`; acrescente `--docker` para executar
|
|
84
|
+
JDK, MxBuild e Runtime em containers descartáveis. Use `--native` para executar
|
|
85
|
+
o grafo do microflow no Runtime de modelo em Ruby, sem Java, `mx` ou `mxbuild`.
|
|
86
|
+
O modo nativo cobre CRUD, variáveis, decisões, chamadas, agregações e logs em
|
|
87
|
+
uma store transacional; Java, REST, UI e conectores ainda falham explicitamente
|
|
88
|
+
e fazem rollback. Não há JUnit nem MDL. O MPR original nunca é alterado.
|
|
89
|
+
Use `--json resultado.json` e/ou `--junit resultado.xml` para relatórios de CI.
|
|
90
|
+
JUnit é apenas o formato XML de intercâmbio neste caso; o MXRB o grava
|
|
91
|
+
diretamente em Ruby, sem instalar ou executar o framework Java JUnit.
|
|
92
|
+
|
|
93
|
+
## Cobertura
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
bundle exec rspec
|
|
97
|
+
MXRB_COVERAGE=1 bundle exec rspec
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Marketplace de módulos Ruby
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
mxrb module search
|
|
104
|
+
mxrb module search security
|
|
105
|
+
mxrb module add shared-kernel
|
|
106
|
+
mxrb module add ./pacote-local --target ./projeto-exportado
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Catálogos JSON podem vir da gem, de um caminho local ou de HTTPS com
|
|
110
|
+
`--registry`. Pacotes possuem `mxrb-module.json` e podem ser embutidos,
|
|
111
|
+
diretórios locais ou repositórios Git. A instalação usa staging, rejeita
|
|
112
|
+
caminhos inseguros e grava `.mxrb/modules.lock.json` com versão, origem, ref e
|
|
113
|
+
SHA-256 dos arquivos instalados.
|
|
114
|
+
|
|
115
|
+
## Baseline nativo e estruturas profundas
|
|
116
|
+
|
|
117
|
+
`mxrb export` grava `.mxrb/native_units.json` como baseline sem perdas e
|
|
118
|
+
`.mxrb/native_units.rb` com cada payload BSON expandido em Hashes Ruby
|
|
119
|
+
editáveis. Entradas `native_unit` expõem todos os campos de imagens, constantes,
|
|
120
|
+
datasets, serviços, configurações, templates e tipos futuros; valores binários
|
|
121
|
+
usam `bson_binary`. Alterações nesse Ruby sobrepõem o baseline antes das escritas
|
|
122
|
+
tipadas. Corpos de flow possuem `body_fingerprint`: o grafo nativo é reutilizado
|
|
123
|
+
quando o Ruby não mudou e regenerado após uma edição.
|
|
124
|
+
|
|
125
|
+
A DSL cobre criação/alteração/retrieve/commit/delete, chamadas de microflow,
|
|
126
|
+
Java, JavaScript, nanoflow e app service, páginas, REST, listas, decisões,
|
|
127
|
+
loops, eventos de erro e rescue.
|
|
128
|
+
|
|
129
|
+
## Páginas, navegação e segurança
|
|
130
|
+
|
|
131
|
+
Controles core possuem métodos concisos: `text`, `text_box`, `number_input`,
|
|
132
|
+
`text_area`, `check_box`, `date_picker`, `button`, `container`, `snippet` e
|
|
133
|
+
`tab_control` com widgets dentro de cada `tab_page`. Esses controles usam o
|
|
134
|
+
modelo Forms moderno do Mendix 11. `data_grid` gera Data Grid 2; `drop_down` e
|
|
135
|
+
`reference_selector` geram Combo Box.
|
|
136
|
+
|
|
137
|
+
Widgets pluggable precisam dos `.mpk` em `widgets/`. Depois de instalar os
|
|
138
|
+
pacotes, sincronize o schema específico da versão e aplique as propriedades
|
|
139
|
+
Ruby com:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
bundle exec mxrb widgets sync project.rb MeuApp.mpr
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Para outros MPKs existe `pluggable_widget`, com widget id e mapa de
|
|
146
|
+
propriedades. Widgets importados ainda desconhecidos são preservados como
|
|
147
|
+
`native_widget` e `deep_structure`, sem perder configuração no ciclo
|
|
148
|
+
export/generate. Toda página importada também expõe `deep_structure({...})`.
|
|
149
|
+
Menus combinam DSL curta e estrutura profunda.
|
|
150
|
+
Project roles, module roles e `allowed_roles` são editáveis em Ruby.
|
|
151
|
+
|
|
152
|
+
## MPR v2
|
|
153
|
+
|
|
154
|
+
O manifesto registra `format_version: v2`; a geração cria automaticamente os
|
|
155
|
+
arquivos `mprcontents/*.mxunit`.
|
|
156
|
+
|
|
157
|
+
## Análise semântica
|
|
158
|
+
|
|
159
|
+
```ruby
|
|
160
|
+
project.references_to("Sales.Order")
|
|
161
|
+
project.callers_of("Sales.Process")
|
|
162
|
+
project.impact_of("Sales.Order")
|
|
163
|
+
project.plan_rename("Sales.Order", to: "Invoice")
|
|
164
|
+
project.plan_remove("Sales.FluxoSemUso")
|
|
165
|
+
project.plan_move("Sales.Processar", to: "Sales.Automacao")
|
|
166
|
+
project.analyze
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Na CLI, use `refs`, `callers`, `callees`, `impact`, `rename`, `remove`, `move`,
|
|
170
|
+
`lint`, `report`, `diff`, `find`, `describe` e `tree`. O lint nativo verifica
|
|
171
|
+
acesso de entidades persistentes, papéis de páginas/flows, documentação de
|
|
172
|
+
contratos públicos, alvos de navegação e mapeamentos duplicados de module role.
|
|
173
|
+
Use `mxrb cache status|warm|clear app.mpr` para métricas e manutenção do índice.
|
|
174
|
+
Refatorações apenas
|
|
175
|
+
mostram a prévia, salvo quando `--apply` é informado. A remoção é bloqueada se
|
|
176
|
+
houver referências recebidas ou units filhas; movimentos ficam no mesmo
|
|
177
|
+
módulo e rejeitam ciclos de pastas.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Executable model expectations: plain Ruby, no MDL.
|
|
4
|
+
artifact "Sudoku.Game", kind: :entity
|
|
5
|
+
artifact "Sudoku.Game_Play", kind: :page
|
|
6
|
+
artifact "Sudoku.ACT_DealGame", kind: :microflow
|
|
7
|
+
|
|
8
|
+
no_call_cycles
|
|
9
|
+
no_missing_internal_references
|
|
10
|
+
maximum_unreferenced 250, severity: :warning
|
|
11
|
+
|
|
12
|
+
check "Sudoku exposes its three domain entities" do |project|
|
|
13
|
+
project.search_artifacts("Sudoku.", kind: :entity).size == 3
|
|
14
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# First functional slice: each microflow must complete without an unhandled
|
|
4
|
+
# runtime exception. The source project is never modified.
|
|
5
|
+
microflow "creates an easy game",
|
|
6
|
+
call: "Sudoku.ACT_NewEasy",
|
|
7
|
+
expect: {
|
|
8
|
+
count: [
|
|
9
|
+
{ entity: "Sudoku.Game", equals: 1 },
|
|
10
|
+
{ entity: "Sudoku.Cell", equals: 81 }
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
microflow "creates a medium game",
|
|
14
|
+
call: "Sudoku.ACT_NewMedium",
|
|
15
|
+
expect: {
|
|
16
|
+
count: [
|
|
17
|
+
{ entity: "Sudoku.Game", equals: 2 },
|
|
18
|
+
{ entity: "Sudoku.Cell", equals: 162 }
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
microflow "creates a hard game",
|
|
22
|
+
call: "Sudoku.ACT_NewHard",
|
|
23
|
+
expect: {
|
|
24
|
+
count: [
|
|
25
|
+
{ entity: "Sudoku.Game", equals: 3 },
|
|
26
|
+
{ entity: "Sudoku.Cell", equals: 243 }
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mxrb
|
|
4
|
+
module Architecture
|
|
5
|
+
Node = Data.define(:id, :module_name, :kind, :name, :metadata)
|
|
6
|
+
Edge = Data.define(:from, :to, :relation, :metadata)
|
|
7
|
+
|
|
8
|
+
class Graph
|
|
9
|
+
attr_reader :nodes, :edges
|
|
10
|
+
|
|
11
|
+
def initialize(definition)
|
|
12
|
+
@definition = definition
|
|
13
|
+
@nodes = {}
|
|
14
|
+
@edges = []
|
|
15
|
+
build
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def node_id(module_name, kind, name)
|
|
19
|
+
"#{module_name}::#{kind}::#{name}"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def find(module_name, kind, name)
|
|
23
|
+
@nodes[node_id(module_name, kind, name)]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def dependencies_of(node)
|
|
27
|
+
@edges.select { _1.from == node.id }.filter_map { @nodes[_1.to] }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def build
|
|
33
|
+
@definition.fetch(:modules).each do |mod|
|
|
34
|
+
add_module_nodes(mod)
|
|
35
|
+
add_module_edges(mod)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def add_module_nodes(mod)
|
|
40
|
+
module_name = mod.fetch(:name)
|
|
41
|
+
{
|
|
42
|
+
entity: mod.fetch(:entities),
|
|
43
|
+
page: mod.fetch(:pages),
|
|
44
|
+
microflow: mod.fetch(:microflows),
|
|
45
|
+
nanoflow: mod.fetch(:nanoflows, []),
|
|
46
|
+
repository: mod.fetch(:repositories, [])
|
|
47
|
+
}.each do |kind, items|
|
|
48
|
+
items.each { add_node(module_name, kind, _1.fetch(:name), _1) }
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def add_module_edges(mod)
|
|
53
|
+
module_name = mod.fetch(:name)
|
|
54
|
+
mod.fetch(:entities).each do |entity|
|
|
55
|
+
from = id(module_name, :entity, entity.fetch(:name))
|
|
56
|
+
entity.fetch(:associations, []).each do |association|
|
|
57
|
+
add_edge(from, ref(module_name, :entity, association.fetch(:target)), :association)
|
|
58
|
+
end
|
|
59
|
+
Array(entity[:lifecycle]).each do |callback|
|
|
60
|
+
add_edge(from, ref(module_name, :microflow, callback.fetch(:handler)), callback.fetch(:event))
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
mod.fetch(:pages).each do |page|
|
|
65
|
+
from = id(module_name, :page, page.fetch(:name))
|
|
66
|
+
if (source = page[:data_source])
|
|
67
|
+
add_edge(from, ref(module_name, source.fetch(:kind), source.fetch(:name)), :data_source)
|
|
68
|
+
end
|
|
69
|
+
page.fetch(:events, []).each do |event|
|
|
70
|
+
next if event.fetch(:kind).to_sym == :action
|
|
71
|
+
|
|
72
|
+
add_edge(from, ref(module_name, event.fetch(:kind), event.fetch(:handler)), event.fetch(:event),
|
|
73
|
+
target: event[:target])
|
|
74
|
+
end
|
|
75
|
+
page.fetch(:widgets, []).each do |widget|
|
|
76
|
+
widget.fetch(:events, []).each do |event|
|
|
77
|
+
next if event.fetch(:kind).to_sym == :action
|
|
78
|
+
|
|
79
|
+
add_edge(
|
|
80
|
+
from,
|
|
81
|
+
ref(module_name, event.fetch(:kind), event.fetch(:handler)),
|
|
82
|
+
event.fetch(:event),
|
|
83
|
+
target: widget.fetch(:name), widget_type: widget.fetch(:type)
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
(mod.fetch(:microflows) + mod.fetch(:nanoflows, [])).each do |flow|
|
|
90
|
+
from = id(module_name, flow.fetch(:runtime) == :client ? :nanoflow : :microflow, flow.fetch(:name))
|
|
91
|
+
flow.fetch(:calls, []).each do |call|
|
|
92
|
+
add_edge(from, ref(module_name, call.fetch(:kind), call.fetch(:name)), :calls)
|
|
93
|
+
end
|
|
94
|
+
flow.fetch(:repositories, []).each do |repository|
|
|
95
|
+
add_edge(from, ref(module_name, :repository, repository), :uses_repository)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def add_node(module_name, kind, name, metadata)
|
|
101
|
+
identifier = id(module_name, kind, name)
|
|
102
|
+
@nodes[identifier] = Node.new(identifier, module_name, kind, name, metadata)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def add_edge(from, to, relation, metadata = {})
|
|
106
|
+
@edges << Edge.new(from, to, relation.to_sym, metadata)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def id(module_name, kind, name)
|
|
110
|
+
node_id(module_name, kind, name)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def ref(current_module, kind, raw_name)
|
|
114
|
+
text = raw_name.to_s
|
|
115
|
+
if text.include?(".")
|
|
116
|
+
module_name, name = text.split(".", 2)
|
|
117
|
+
id(module_name, kind, name)
|
|
118
|
+
else
|
|
119
|
+
id(current_module, kind, text)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mxrb
|
|
4
|
+
module Architecture
|
|
5
|
+
class Validator
|
|
6
|
+
Result = Data.define(:errors, :warnings) do
|
|
7
|
+
def valid? = errors.empty?
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def initialize(graph)
|
|
11
|
+
@graph = graph
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def validate
|
|
15
|
+
errors = []
|
|
16
|
+
warnings = []
|
|
17
|
+
validate_targets(errors)
|
|
18
|
+
validate_layers(errors)
|
|
19
|
+
validate_cycles(errors)
|
|
20
|
+
Result.new(errors.freeze, warnings.freeze)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def validate!
|
|
24
|
+
result = validate
|
|
25
|
+
return result if result.valid?
|
|
26
|
+
|
|
27
|
+
raise ValidationError, "architecture validation failed:\n- #{result.errors.join("\n- ")}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def validate_targets(errors)
|
|
33
|
+
@graph.edges.each do |edge|
|
|
34
|
+
next if @graph.nodes.key?(edge.to)
|
|
35
|
+
next if late_bound_page_nanoflow?(edge)
|
|
36
|
+
next if platform_owned_target?(edge.to)
|
|
37
|
+
|
|
38
|
+
errors << "#{edge.from} #{edge.relation} references missing #{edge.to}"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def late_bound_page_nanoflow?(edge)
|
|
43
|
+
from = @graph.nodes[edge.from]
|
|
44
|
+
from&.kind == :page && edge.to.include?("::nanoflow::")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def platform_owned_target?(target)
|
|
48
|
+
target.start_with?("System::")
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def validate_layers(errors)
|
|
52
|
+
@graph.edges.each do |edge|
|
|
53
|
+
from = @graph.nodes[edge.from]
|
|
54
|
+
to = @graph.nodes[edge.to]
|
|
55
|
+
next unless from && to
|
|
56
|
+
|
|
57
|
+
if from.kind == :page && to.kind == :repository
|
|
58
|
+
errors << "#{from.id} cannot access repository #{to.id} directly"
|
|
59
|
+
end
|
|
60
|
+
if from.kind == :entity && edge.relation.to_s.start_with?("on_") && to.kind == :nanoflow
|
|
61
|
+
errors << "#{from.id} lifecycle cannot call client-side #{to.id}"
|
|
62
|
+
end
|
|
63
|
+
# Entity-to-entity associations are allowed cross-module in Mendix domain model
|
|
64
|
+
next if edge.relation == :association && from.kind == :entity && to.kind == :entity
|
|
65
|
+
if from.module_name != to.module_name && !to.metadata.fetch(:public, false)
|
|
66
|
+
errors << "#{from.id} references internal artifact #{to.id} from another module"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def validate_cycles(errors)
|
|
72
|
+
adjacency = Hash.new { |h, k| h[k] = [] }
|
|
73
|
+
@graph.edges.select { %i[calls].include?(_1.relation) }.each do |edge|
|
|
74
|
+
adjacency[edge.from] << edge.to if @graph.nodes.key?(edge.to)
|
|
75
|
+
end
|
|
76
|
+
visiting = {}
|
|
77
|
+
visited = {}
|
|
78
|
+
stack = []
|
|
79
|
+
|
|
80
|
+
visit = lambda do |node|
|
|
81
|
+
return if visited[node]
|
|
82
|
+
if visiting[node]
|
|
83
|
+
start = stack.index(node) || 0
|
|
84
|
+
errors << "call cycle detected: #{(stack[start..] + [node]).join(' -> ')}"
|
|
85
|
+
return
|
|
86
|
+
end
|
|
87
|
+
visiting[node] = true
|
|
88
|
+
stack << node
|
|
89
|
+
adjacency[node].each { visit.call(_1) }
|
|
90
|
+
stack.pop
|
|
91
|
+
visiting.delete(node)
|
|
92
|
+
visited[node] = true
|
|
93
|
+
end
|
|
94
|
+
@graph.nodes.each_key { visit.call(_1) }
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mxrb
|
|
4
|
+
BenchmarkResult = Data.define(:iterations, :open_seconds, :index_seconds, :validate_seconds, :units)
|
|
5
|
+
|
|
6
|
+
# Repeatable wall-clock benchmark for the main read-only MPR operations.
|
|
7
|
+
class Benchmark
|
|
8
|
+
def initialize(path, iterations: 3, clock: Process.method(:clock_gettime))
|
|
9
|
+
@path = File.expand_path(path)
|
|
10
|
+
@iterations = Integer(iterations)
|
|
11
|
+
@clock = clock
|
|
12
|
+
raise ArgumentError, 'iterations must be between 1 and 100' unless (1..100).cover?(@iterations)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def run
|
|
16
|
+
open_time, units = measure { Mxrb.open(@path) { _1.all_units.size } }
|
|
17
|
+
index_time, = measure { Mxrb.open(@path) { _1.semantic_index.artifacts.size } }
|
|
18
|
+
validate_time, = measure { Mxrb.validate(@path).valid? }
|
|
19
|
+
BenchmarkResult.new(@iterations, open_time, index_time, validate_time, units)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def measure
|
|
25
|
+
value = nil
|
|
26
|
+
started = now
|
|
27
|
+
@iterations.times { value = yield }
|
|
28
|
+
[((now - started) / @iterations).round(6), value]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def now = @clock.call(Process::CLOCK_MONOTONIC)
|
|
32
|
+
end
|
|
33
|
+
end
|