Module: Ea::Sources::Qea::Xref::Parser

Defined in:
lib/ea/sources/qea/xref/parser.rb

Overview

Pure parser for EA's t_xref.Description mini-language. Stateless — every call returns a fresh Xref::Record.

Supported formats:

@STEREO;Name=X;FQName=Y;@ENDSTEREO;
@PROP=@NAME=..@ENDNAME;@TYPE=..@ENDTYPE;@VALU=..@ENDVALU;@PRMT=..@ENDPRMT;@ENDPROP;
<key>=<value>;<key>=<value>;

Unknown formats fall through to key=value parsing.

Constant Summary collapse

STEREO_REGEX =

Matches both legacy @STEREO;Name=X;GUID={..}; and the plateau form @STEREO;Name=X;FQName=Y;@ENDSTEREO;.

/
  @STEREO;
  (.*?)
  (?:@ENDSTEREO;|\z)
/mx.freeze
PROP_REGEX =

One Description can carry multiple @PROP=...@ENDPROP; blocks. Split, then classify each as PropertyDefinition or LegendDefinition.

/
  @PROP=
  (.*?)
  @ENDPROP;
/mx.freeze

Class Method Summary collapse

Class Method Details

.build_prop_record(block) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/ea/sources/qea/xref/parser.rb', line 77

def build_prop_record(block)
  name = extract_tagged_value(block, "NAME")
  type = extract_tagged_value(block, "TYPE")
  value = extract_tagged_value(block, "VALU")
  parameter = extract_tagged_value(block, "PRMT")

  if type&.start_with?("LEGEND_")
    LegendDefinition.new(
      name: name,
      legend_type: type,
      colors: parse_color_value(value),
      parameter: parameter
    )
  else
    PropertyDefinition.new(
      name: name,
      type: type,
      value: value,
      parameter: parameter
    )
  end
end

.extract_tagged_value(block, tag) ⇒ Object

Extracts the content between @TAG=...@ENDTAG; markers. Returns nil when the tag is absent.



102
103
104
105
106
# File 'lib/ea/sources/qea/xref/parser.rb', line 102

def extract_tagged_value(block, tag)
  pattern = /@#{tag}=(.*?)@END#{tag};/m.freeze
  match = block.match(pattern)
  match ? match[1] : nil
end

.parse(description) ⇒ Ea::Sources::Qea::Xref::Record

Parse one Description string into a typed Record.

Parameters:

  • description (String, nil)

Returns:



22
23
24
25
26
27
28
29
30
31
32
# File 'lib/ea/sources/qea/xref/parser.rb', line 22

def parse(description)
  return Record.new if description.nil? || description.empty?

  Record.new(
    stereotype: parse_stereotype(description),
    properties: parse_properties(description),
    legends: parse_legends(description),
    key_values: parse_key_values(description),
    raw: description
  )
end

.parse_color_value(value) ⇒ Object

EA encodes legend VALU as #key#=value; pairs. Returns a hash keyed by underscored symbol.



110
111
112
113
114
115
116
# File 'lib/ea/sources/qea/xref/parser.rb', line 110

def parse_color_value(value)
  return {} if value.nil? || value.empty?

  value.scan(/#([^#=]+)#=([^;]*);/).each_with_object({}) do |(k, v), acc|
    acc[k.downcase.to_sym] = v
  end
end

.parse_key_values(description) ⇒ Object

Legacy Key=Value;Key=Value; parsing. Skips content that looks like @STEREO or @PROP blocks to avoid noise.



120
121
122
123
124
125
126
127
128
129
130
# File 'lib/ea/sources/qea/xref/parser.rb', line 120

def parse_key_values(description)
  stripped = description
             .gsub(/@STEREO;.*?(?:@ENDSTEREO;|\z)/m, "")
             .gsub(/@PROP=.*?@ENDPROP;/m, "")
  pairs = stripped.split(";").map { |s| s.split("=", 2) }
  pairs.each_with_object({}) do |(k, v), acc|
    next if k.nil? || k.empty? || v.nil?

    acc[k.downcase.to_sym] = v
  end
end

.parse_legends(description) ⇒ Object



71
72
73
74
75
# File 'lib/ea/sources/qea/xref/parser.rb', line 71

def parse_legends(description)
  parse_properties(description).select do |prop|
    prop.is_a?(LegendDefinition)
  end
end

.parse_properties(description) ⇒ Object



63
64
65
66
67
68
69
# File 'lib/ea/sources/qea/xref/parser.rb', line 63

def parse_properties(description)
  blocks = description.scan(PROP_REGEX).flatten
  blocks.each_with_object([]) do |block, acc|
    record = build_prop_record(block)
    acc << record if record
  end
end

.parse_semicolon_fields(body) ⇒ Object

Parse Key=Value;Key=value; into a string-keyed hash. Used internally for the @STEREO body fields.



134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/ea/sources/qea/xref/parser.rb', line 134

def parse_semicolon_fields(body)
  body.split(";").each_with_object({}) do |part, acc|
    key, value = part.split("=", 2)
    next if key.nil? || key.empty? || value.nil?

    # Strip @END* terminators that may be attached when the
    # body wasn't cleanly split (defensive — usually already
    # consumed by STEREO_REGEX).
    cleaned = value.sub(/@END\w+\z/, "")
    acc[key] = cleaned
  end
end

.parse_stereotype(description) ⇒ Object



44
45
46
47
48
49
50
51
52
53
# File 'lib/ea/sources/qea/xref/parser.rb', line 44

def parse_stereotype(description)
  match = description.match(STEREO_REGEX)
  return nil unless match

  fields = parse_semicolon_fields(match[1])
  StereotypeApplication.new(
    name: fields["Name"],
    fqname: fields["FQName"]
  )
end