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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d95f5a294643904d99fdac9afbf3d0e6f08e1aa209c8aff81b812daec751c9e
4
- data.tar.gz: eba324a63596fc22694d5fb672a3a1bc072e937d1d4d92715c0f907c68f23931
3
+ metadata.gz: e51d4e375ddb7b88ccce5938f52509af44491bffd29750c8be8d749d651c150a
4
+ data.tar.gz: 9ae4445757a494e29f96cfad382f0077c4fc8ca72e2c9172cbf9c5e74f2f7e0d
5
5
  SHA512:
6
- metadata.gz: f3499ae32520b02952d2ded0622ec8be158a8d7e3ae36da5937b4cd5e187fb963100ad01925917f1d583db5b50dcf52b5a171abc09c128267dfcdb4d812ffe59
7
- data.tar.gz: d8c1c51f90002b755ad9a3f03e4656c352cb09744ff8a893cae380cbb9d0b3b81074acbf758c788935b30ae6741efe8df7d5f87cfc06f3b2d25424211914c64c
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.329 Beispiele, keine Fehler;
60
- - 100 % Zeilenabdeckung (23.771/23.771);
61
- - 100 % Branch-Abdeckung (9.704/9.704);
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,329 examples and passes with 100.00% line coverage
241
- (23,771/23,771 executable library lines) and 100.00% branch coverage
242
- (9,704/9,704 branches).
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.329 exemplos, zero falhas;
104
- - 100% das linhas: 23.771/23.771;
105
- - 100% dos branches: 9.704/9.704;
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.
@@ -243,11 +243,140 @@ module Mxrb
243
243
  end
244
244
 
245
245
  def pluggable_widget(widget)
246
- case widget.dig("Type", "WidgetId")
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 native_widget(widget)
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