mxrb 0.1.4 → 0.1.5
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 +4 -4
- data/docs/de-DE/validation-matrix.md +3 -3
- data/docs/en-US/validation-matrix.md +3 -3
- data/docs/pt-BR/validation-matrix.md +3 -3
- data/lib/mxrb/model/page.rb +131 -2
- data/lib/mxrb/ruby_app/exporter.rb +966 -207
- data/lib/mxrb/ruby_app.rb +9 -1
- data/lib/mxrb/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e51d4e375ddb7b88ccce5938f52509af44491bffd29750c8be8d749d651c150a
|
|
4
|
+
data.tar.gz: 9ae4445757a494e29f96cfad382f0077c4fc8ca72e2c9172cbf9c5e74f2f7e0d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9863efee0dd4e177f41e15142beb0282c219bc11b5a4e4d1e5c1dfec69ff80b3069fd5138cf5f027afdd1e53bd61e14d59487097904342bbcfa8d8cf3e4f372d
|
|
7
|
+
data.tar.gz: 326698d03a28eb9fad7bc6e7323e61430739f9b21c9f8ca2b4889a6a8a5a750ec6d6644d2bc4dbfdd2e950250ba4eab895d3ea81a3c155570e68c7fb3463fbae
|
|
@@ -56,9 +56,9 @@ Gate.
|
|
|
56
56
|
## Semantik, Tests und Runtime
|
|
57
57
|
|
|
58
58
|
- 1.778 Artefakte und 3.387 Referenzen;
|
|
59
|
-
- 1.
|
|
60
|
-
- 100 % Zeilenabdeckung (
|
|
61
|
-
- 100 % Branch-Abdeckung (9.
|
|
59
|
+
- 1.337 Beispiele, keine Fehler;
|
|
60
|
+
- 100 % Zeilenabdeckung (24.082/24.082);
|
|
61
|
+
- 100 % Branch-Abdeckung (9.883/9.883);
|
|
62
62
|
- Sudoku-Modellbewertung: 7/7;
|
|
63
63
|
- funktionale Runtime-Tests: 3/3 lokal und 3/3 in Docker.
|
|
64
64
|
|
|
@@ -237,9 +237,9 @@ instead of dumping the complete removed and added flow bodies.
|
|
|
237
237
|
|
|
238
238
|
## Ruby evaluations and coverage gate
|
|
239
239
|
|
|
240
|
-
The current suite contains 1,
|
|
241
|
-
(
|
|
242
|
-
(9,
|
|
240
|
+
The current suite contains 1,337 examples and passes with 100.00% line coverage
|
|
241
|
+
(24,082/24,082 executable library lines) and 100.00% branch coverage
|
|
242
|
+
(9,883/9,883 branches).
|
|
243
243
|
Run the enforced gate with:
|
|
244
244
|
|
|
245
245
|
```sh
|
|
@@ -100,9 +100,9 @@ sem MDL.
|
|
|
100
100
|
|
|
101
101
|
## Avaliações, cobertura e runtime
|
|
102
102
|
|
|
103
|
-
- 1.
|
|
104
|
-
- 100% das linhas:
|
|
105
|
-
- 100% dos branches: 9.
|
|
103
|
+
- 1.337 exemplos, zero falhas;
|
|
104
|
+
- 100% das linhas: 24.082/24.082;
|
|
105
|
+
- 100% dos branches: 9.883/9.883;
|
|
106
106
|
- avaliação Sudoku: 7/7 checks;
|
|
107
107
|
- testes funcionais Sudoku: 3/3 localmente em 34,16 s;
|
|
108
108
|
- testes funcionais Sudoku: 3/3 no Docker em 39,52 s.
|
data/lib/mxrb/model/page.rb
CHANGED
|
@@ -243,11 +243,140 @@ module Mxrb
|
|
|
243
243
|
end
|
|
244
244
|
|
|
245
245
|
def pluggable_widget(widget)
|
|
246
|
-
|
|
246
|
+
widget_id = widget.dig("Type", "WidgetId").to_s
|
|
247
|
+
return native_widget(widget) if widget_id.empty?
|
|
248
|
+
|
|
249
|
+
case widget_id
|
|
247
250
|
when "com.mendix.widget.web.datagrid.Datagrid" then data_grid2_widget(widget)
|
|
248
251
|
when "com.mendix.widget.web.combobox.Combobox" then combo_box_widget(widget)
|
|
249
252
|
when "com.mendix.widget.web.gallery.Gallery" then gallery_widget(widget)
|
|
250
|
-
else
|
|
253
|
+
else generic_pluggable_widget(widget)
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def generic_pluggable_widget(widget)
|
|
258
|
+
object_type = widget.dig("Type", "ObjectType")
|
|
259
|
+
properties = pluggable_properties(widget["Object"], object_type)
|
|
260
|
+
children = nested_pluggable_widgets(properties)
|
|
261
|
+
properties = strip_pluggable_widgets(properties)
|
|
262
|
+
options = appearance_options(widget).merge(
|
|
263
|
+
widget_id: widget.dig("Type", "WidgetId"),
|
|
264
|
+
widget_name: widget.dig("Type", "WidgetName"),
|
|
265
|
+
platform: widget.dig("Type", "SupportedPlatform"),
|
|
266
|
+
properties:
|
|
267
|
+
).compact
|
|
268
|
+
{
|
|
269
|
+
type: :pluggable_widget, name: widget["Name"] || "widget",
|
|
270
|
+
options:, children:, events: pluggable_events(properties)
|
|
271
|
+
}
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def pluggable_properties(object, object_type)
|
|
275
|
+
return {} unless object.is_a?(Hash) && object_type.is_a?(Hash)
|
|
276
|
+
|
|
277
|
+
types = parse_array(object_type["PropertyTypes"])
|
|
278
|
+
types_by_id = types.to_h { [IO::BsonCodec.extract_id(_1["$ID"]), _1] }
|
|
279
|
+
parse_array(object["Properties"]).each_with_object({}) do |property, result|
|
|
280
|
+
type = types_by_id[IO::BsonCodec.extract_id(property["TypePointer"])]
|
|
281
|
+
next unless type
|
|
282
|
+
|
|
283
|
+
result[type["PropertyKey"].to_s] = pluggable_value(
|
|
284
|
+
property["Value"], type["ValueType"]
|
|
285
|
+
)
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def pluggable_value(value, value_type)
|
|
290
|
+
return nil unless value.is_a?(Hash)
|
|
291
|
+
|
|
292
|
+
type = value_type.is_a?(Hash) ? value_type["Type"].to_s : ""
|
|
293
|
+
widgets = parse_array(value["Widgets"])
|
|
294
|
+
unless widgets.empty?
|
|
295
|
+
parsed = []
|
|
296
|
+
parse_widgets(widgets, parsed)
|
|
297
|
+
return { widgets: parsed }
|
|
298
|
+
end
|
|
299
|
+
objects = parse_array(value["Objects"])
|
|
300
|
+
unless objects.empty?
|
|
301
|
+
object_type = value_type.is_a?(Hash) ? value_type["ObjectType"] : nil
|
|
302
|
+
return { objects: objects.map { pluggable_properties(_1, object_type) } }
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
return extract_text(value["TextTemplate"]) if value["TextTemplate"].is_a?(Hash)
|
|
306
|
+
return value.dig("AttributeRef", "Attribute") if value["AttributeRef"].is_a?(Hash)
|
|
307
|
+
return pluggable_data_source(value["DataSource"]) if value["DataSource"].is_a?(Hash)
|
|
308
|
+
return value["Expression"] unless value["Expression"].to_s.empty?
|
|
309
|
+
return value["Image"] unless value["Image"].to_s.empty?
|
|
310
|
+
return value["Form"] unless value["Form"].to_s.empty?
|
|
311
|
+
|
|
312
|
+
primitive = value["PrimitiveValue"]
|
|
313
|
+
return primitive == true || primitive.to_s.casecmp("true").zero? if type == "Boolean"
|
|
314
|
+
return primitive.to_i if type == "Integer"
|
|
315
|
+
return primitive.to_f if %w[Decimal Number].include?(type)
|
|
316
|
+
return primitive unless primitive.nil? || primitive.to_s.empty?
|
|
317
|
+
|
|
318
|
+
action = value["Action"]
|
|
319
|
+
return pluggable_action(action) if action.is_a?(Hash) && action["$Type"] != "Forms$NoAction"
|
|
320
|
+
return value["Selection"] unless value["Selection"].to_s.empty? || value["Selection"] == "None"
|
|
321
|
+
|
|
322
|
+
nil
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def pluggable_data_source(source)
|
|
326
|
+
{
|
|
327
|
+
data_source: source.dig("EntityRef", "Entity") || source["Entity"],
|
|
328
|
+
xpath: source["XPathConstraint"].to_s,
|
|
329
|
+
sort: parse_array(source.dig("SortBar", "SortItems")).map do |item|
|
|
330
|
+
{
|
|
331
|
+
attribute: item.dig("AttributeRef", "Attribute"),
|
|
332
|
+
direction: item["SortDirection"].to_s
|
|
333
|
+
}.compact
|
|
334
|
+
end
|
|
335
|
+
}.compact
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def pluggable_action(action)
|
|
339
|
+
candidates = {
|
|
340
|
+
"nanoflow" => action["Nanoflow"],
|
|
341
|
+
"microflow" => action["Microflow"],
|
|
342
|
+
"page" => action["Form"]
|
|
343
|
+
}
|
|
344
|
+
kind, handler = candidates.find { |_candidate, value| !value.to_s.empty? }
|
|
345
|
+
kind ||= "action"
|
|
346
|
+
handler ||= action["$Type"]
|
|
347
|
+
{ kind:, handler: handler.to_s }
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def nested_pluggable_widgets(value, found = [])
|
|
351
|
+
case value
|
|
352
|
+
when Hash
|
|
353
|
+
widgets = value[:widgets] || value["widgets"]
|
|
354
|
+
found.concat(Array(widgets)) if widgets
|
|
355
|
+
value.each_value { nested_pluggable_widgets(_1, found) }
|
|
356
|
+
when Array then value.each { nested_pluggable_widgets(_1, found) }
|
|
357
|
+
end
|
|
358
|
+
found.uniq { [_1[:name] || _1["name"], _1[:type] || _1["type"]] }
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
def strip_pluggable_widgets(value)
|
|
362
|
+
case value
|
|
363
|
+
when Hash
|
|
364
|
+
value.each_with_object({}) do |(key, child), result|
|
|
365
|
+
next if key.to_s == "widgets"
|
|
366
|
+
|
|
367
|
+
result[key] = strip_pluggable_widgets(child)
|
|
368
|
+
end
|
|
369
|
+
when Array then value.map { strip_pluggable_widgets(_1) }
|
|
370
|
+
else value
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
def pluggable_events(properties)
|
|
375
|
+
properties.filter_map do |key, value|
|
|
376
|
+
next unless value.is_a?(Hash) && value[:handler]
|
|
377
|
+
|
|
378
|
+
event = key.to_s.match?(/change/i) ? :on_change : :on_click
|
|
379
|
+
value.merge(event:)
|
|
251
380
|
end
|
|
252
381
|
end
|
|
253
382
|
|