Module: Ea::Transformers::QeaToXmi::Cardinality
- Defined in:
- lib/ea/transformers/qea_to_xmi/cardinality.rb
Overview
Pure-function cardinality / multiplicity parser for EA's
free-text bound fields (t_attribute.upperbound,
t_connector.sourcecard, etc.).
EA stores cardinality as opaque strings: 1, 0..1, 1..*,
*, occasionally unbounded or *-1. The XMI wire form needs
two separate child elements (<lowerValue value="N"/> and
<upperValue value="M"/>) — never a range string. This module
translates the EA form to a { lower:, upper: } pair.
Default-when-empty: EA's "no bound specified" maps to UML's
unspecified multiplicity, which Sparx renders as
<lowerValue value="0"/> and <upperValue value="-1"/>.
Always emitting both is required for round-trip parity with
real Sparx XMI (see TODO 26).
Constant Summary collapse
- UNLIMITED_TOKENS =
Tokens EA uses for "unbounded". Matched case-insensitively.
%w[* *-1 unbounded].freeze
- DEFAULT_LOWER =
UML defaults when EA carries no explicit bound.
"0"- DEFAULT_UPPER =
"-1"
Class Method Summary collapse
-
.defaults ⇒ Object
---- Internal helpers ----.
-
.normalize_bound(token) ⇒ Object
A single bound token (one side of
..or a bare scalar). -
.normalize_lower(raw) ⇒ String
Normalise a lower-bound token: empty/nil → "0" (UML default).
-
.normalize_upper(raw) ⇒ String
Normalise an upper-bound token:
*/unbounded→-1(UML LiteralUnlimitedNatural wire form). -
.parse(raw) ⇒ Hash{Symbol=>String}
{ lower:, upper: }always populated; never nil. - .parse_range(stripped) ⇒ Object
Class Method Details
.defaults ⇒ Object
---- Internal helpers ----
75 76 77 |
# File 'lib/ea/transformers/qea_to_xmi/cardinality.rb', line 75 def defaults { lower: DEFAULT_LOWER, upper: DEFAULT_UPPER } end |
.normalize_bound(token) ⇒ Object
A single bound token (one side of .. or a bare scalar).
Empty / * → UML unlimited (-1).
86 87 88 89 90 91 92 |
# File 'lib/ea/transformers/qea_to_xmi/cardinality.rb', line 86 def normalize_bound(token) return "-1" if token.nil? return "-1" if token.strip.empty? stripped = token.strip UNLIMITED_TOKENS.include?(stripped.downcase) ? "-1" : stripped end |
.normalize_lower(raw) ⇒ String
Normalise a lower-bound token: empty/nil → "0" (UML default).
66 67 68 69 70 71 |
# File 'lib/ea/transformers/qea_to_xmi/cardinality.rb', line 66 def normalize_lower(raw) return DEFAULT_LOWER if raw.nil? stripped = raw.to_s.strip stripped.empty? ? DEFAULT_LOWER : stripped end |
.normalize_upper(raw) ⇒ String
Normalise an upper-bound token: * / unbounded → -1
(UML LiteralUnlimitedNatural wire form).
54 55 56 57 58 59 60 61 |
# File 'lib/ea/transformers/qea_to_xmi/cardinality.rb', line 54 def normalize_upper(raw) return DEFAULT_UPPER if raw.nil? stripped = raw.to_s.strip return DEFAULT_UPPER if stripped.empty? UNLIMITED_TOKENS.include?(stripped.downcase) ? "-1" : stripped end |
.parse(raw) ⇒ Hash{Symbol=>String}
Returns { lower:, upper: } always
populated; never nil. Empty/nil input returns the UML default.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/ea/transformers/qea_to_xmi/cardinality.rb', line 34 def parse(raw) return defaults if raw.nil? || raw.to_s.strip.empty? stripped = raw.to_s.strip return parse_range(stripped) if stripped.include?("..") # Bare unlimited token (e.g. "*") means "many" — lower bound # is unspecified, which UML renders as 0..-1. Returning # `{ lower: "-1", upper: "-1" }` here would be invalid: # LiteralInteger cannot hold -1. return defaults if UNLIMITED_TOKENS.include?(stripped.downcase) single = normalize_bound(stripped) { lower: single, upper: single } end |
.parse_range(stripped) ⇒ Object
79 80 81 82 |
# File 'lib/ea/transformers/qea_to_xmi/cardinality.rb', line 79 def parse_range(stripped) lower, upper = stripped.split("..", 2) { lower: normalize_bound(lower), upper: normalize_bound(upper) } end |