Class: Lutaml::Cli::ElementIdentifier

Inherits:
Object
  • Object
show all
Defined in:
lib/lutaml/cli/element_identifier.rb

Overview

ElementIdentifier parses and manages element references

Provides a unified syntax for referring to UML elements:

  • “package:ModelRoot::Core”

  • “class:ModelRoot::Core::Building”

  • “diagram:ClassDiagram1”

  • “attribute:ModelRoot::Core::Building::name”

Supports auto-detection when type prefix is omitted.

Examples:

Parse an identifier with explicit type

id = ElementIdentifier.parse("class:Building")
id.type # => :class
id.path # => "Building"

Parse an identifier with auto-detection

id = ElementIdentifier.parse("ModelRoot::Core::Building")
id.type # => :class (auto-detected from pattern)
id.path # => "ModelRoot::Core::Building"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(type, path) ⇒ ElementIdentifier

Initialize an identifier

Parameters:

  • type (Symbol)

    Element type

  • path (String)

    Element path/name



64
65
66
67
# File 'lib/lutaml/cli/element_identifier.rb', line 64

def initialize(type, path)
  @type = type
  @path = path
end

Instance Attribute Details

#pathObject (readonly)

Returns the value of attribute path.



27
28
29
# File 'lib/lutaml/cli/element_identifier.rb', line 27

def path
  @path
end

#typeObject (readonly)

Returns the value of attribute type.



27
28
29
# File 'lib/lutaml/cli/element_identifier.rb', line 27

def type
  @type
end

Class Method Details

.detect_type(identifier) ⇒ Symbol

Detect element type from identifier pattern

Uses heuristics to determine type:

  • Multiple

    separators → likely a class

  • Starts with uppercase → likely a class or package

  • Contains “Diagram” → likely a diagram

  • Otherwise → package (safest default)

Parameters:

  • identifier (String)

    Identifier without type prefix

Returns:

  • (Symbol)

    Detected type



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/lutaml/cli/element_identifier.rb', line 96

def self.detect_type(identifier) # rubocop:disable Metrics/MethodLength
  # Check for diagram patterns
  return :diagram if identifier.match?(/diagram/i)

  # Count package separators
  separator_count = identifier.scan("::").size

  case separator_count
  when 0
    # No separators - single name
    # Could be package, class, or diagram
    if identifier.match?(/^[A-Z]/)
      # Starts with uppercase - likely a class or package name
      # Default to package as it's more general
      :package
    else
      # Lowercase start - could be attribute or diagram name
      :diagram
    end
  when 1..Float::INFINITY
    # One or more separators - likely qualified class name
    # e.g., Package::Class or ModelRoot::Package::Class
    :class
  else
    # Default
    :package
  end
end

.has_type_prefix?(identifier) ⇒ Boolean

Check if this identifier has an explicit type prefix

Parameters:

  • identifier (String)

    Identifier string

Returns:

  • (Boolean)

    True if has explicit type prefix



80
81
82
83
84
# File 'lib/lutaml/cli/element_identifier.rb', line 80

def self.has_type_prefix?(identifier)
  identifier.include?(":") &&
    ResourceRegistry.type_registered?(identifier.split(":",
                                                       2).first.to_sym)
end

.parse(identifier) ⇒ ElementIdentifier

Parse an element identifier string

or just “path” registered

Parameters:

  • identifier (String)

    Element identifier in format “type:path”

Returns:

Raises:

  • (ArgumentError)

    If identifier is invalid or type is not



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/lutaml/cli/element_identifier.rb', line 36

def self.parse(identifier) # rubocop:disable Metrics/MethodLength
  if identifier.nil? || identifier.empty?
    raise ArgumentError,
          "Identifier cannot be nil or empty"
  end

  if identifier.include?(":")
    type, path = identifier.split(":", 2)
    type_sym = type.to_sym

    unless ResourceRegistry.type_registered?(type_sym)
      raise ArgumentError, "Unknown element type: #{type}. " \
                           "Valid types: " \
                           "#{ResourceRegistry.types.join(', ')}"
    end

    new(type_sym, path)
  else
    # Auto-detect type from pattern
    detected_type = detect_type(identifier)
    new(detected_type, identifier)
  end
end

Instance Method Details

#parent_pathString?

Get the parent path (everything before last ::)

Returns:

  • (String, nil)

    Parent path or nil if not qualified



142
143
144
145
146
147
# File 'lib/lutaml/cli/element_identifier.rb', line 142

def parent_path
  return nil unless qualified?

  parts = @path.split("::")
  parts[0...-1].join("::")
end

#qualified?Boolean

Check if identifier is a qualified name (contains ::)

Returns:

  • (Boolean)

    True if qualified



128
129
130
# File 'lib/lutaml/cli/element_identifier.rb', line 128

def qualified?
  @path.include?("::")
end

#simple_nameString

Get the simple name (last component after ::)

Returns:

  • (String)

    Simple name



135
136
137
# File 'lib/lutaml/cli/element_identifier.rb', line 135

def simple_name
  qualified? ? @path.split("::").last : @path
end

#to_hHash

Convert to hash representation

Returns:

  • (Hash)

    Hash with type and path keys



152
153
154
155
156
157
158
159
# File 'lib/lutaml/cli/element_identifier.rb', line 152

def to_h
  {
    type: @type,
    path: @path,
    simple_name: simple_name,
    qualified: qualified?,
  }
end

#to_sString

Get a human-readable string representation

Returns:

  • (String)

    String representation



72
73
74
# File 'lib/lutaml/cli/element_identifier.rb', line 72

def to_s
  "#{type}:#{path}"
end