Module: Lutaml::Model::Utils

Defined in:
lib/lutaml/model/utils.rb

Constant Summary collapse

UNINITIALIZED =
Lutaml::Model::UninitializedClass.instance
CACHE_SIZE_LIMIT =

Cache size limit to prevent memory leaks

1000

Class Method Summary collapse

Class Method Details

.add_accessor_if_not_defined(klass, attribute) ⇒ Object



205
206
207
208
# File 'lib/lutaml/model/utils.rb', line 205

def add_accessor_if_not_defined(klass, attribute)
  add_getter_if_not_defined(klass, attribute)
  add_setter_if_not_defined(klass, attribute)
end

.add_boolean_accessor_if_not_defined(klass, attribute) ⇒ Object



210
211
212
213
# File 'lib/lutaml/model/utils.rb', line 210

def add_boolean_accessor_if_not_defined(klass, attribute)
  add_boolean_getter_if_not_defined(klass, attribute)
  add_setter_if_not_defined(klass, attribute)
end

.add_boolean_getter_if_not_defined(klass, attribute) ⇒ Object



221
222
223
224
225
# File 'lib/lutaml/model/utils.rb', line 221

def add_boolean_getter_if_not_defined(klass, attribute)
  add_method_if_not_defined(klass, "#{attribute}?") do
    !!instance_variable_get(:"@__#{attribute}")
  end
end

.add_getter_if_not_defined(klass, attribute) ⇒ Object



215
216
217
218
219
# File 'lib/lutaml/model/utils.rb', line 215

def add_getter_if_not_defined(klass, attribute)
  add_method_if_not_defined(klass, attribute) do
    instance_variable_get(:"@__#{attribute}")
  end
end

.add_if_present(hash, key, value) ⇒ Object



132
133
134
# File 'lib/lutaml/model/utils.rb', line 132

def add_if_present(hash, key, value)
  hash[key] = value if value
end

.add_method(instance, method_name, &block) ⇒ Object



168
169
170
171
172
173
174
175
176
# File 'lib/lutaml/model/utils.rb', line 168

def add_method(instance, method_name, &block)
  if instance.is_a?(Class)
    instance.class_eval do
      define_method(method_name, &block)
    end
  else
    instance.define_singleton_method(method_name, &block)
  end
end

.add_method_if_not_defined(klass, method_name, &block) ⇒ Object



197
198
199
200
201
202
203
# File 'lib/lutaml/model/utils.rb', line 197

def add_method_if_not_defined(klass, method_name, &block)
  unless klass.method_defined?(method_name)
    klass.class_eval do
      define_method(method_name, &block)
    end
  end
end

.add_setter_if_not_defined(klass, attribute) ⇒ Object



227
228
229
230
231
# File 'lib/lutaml/model/utils.rb', line 227

def add_setter_if_not_defined(klass, attribute)
  add_method_if_not_defined(klass, "#{attribute}=") do |value|
    instance_variable_set(:"@__#{attribute}", value)
  end
end

.add_singleton_method_if_not_defined(instance, method_name) ⇒ Object



178
179
180
181
182
# File 'lib/lutaml/model/utils.rb', line 178

def add_singleton_method_if_not_defined(instance, method_name, &)
  return if instance.respond_to?(method_name)

  instance.define_singleton_method(method_name, &)
end

.base_class_name(klass) ⇒ Object

Extract the base name of the class



96
97
98
# File 'lib/lutaml/model/utils.rb', line 96

def base_class_name(klass)
  klass.to_s.split("::").last
end

.base_class_snake_case(klass) ⇒ Object

Convert the extracted base class to snake case format



101
102
103
# File 'lib/lutaml/model/utils.rb', line 101

def base_class_snake_case(klass)
  snake_case(base_class_name(klass))
end

.blank?(value) ⇒ Boolean

Returns:

  • (Boolean)


117
118
119
# File 'lib/lutaml/model/utils.rb', line 117

def blank?(value)
  value.respond_to?(:empty?) ? value.empty? : value.nil?
end

.camel_case(str) ⇒ Object

Convert string to camel case (cached)



34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/lutaml/model/utils.rb', line 34

def camel_case(str)
  return "" if str.nil? || str.empty?

  @camel_case_cache ||= {}
  cached = @camel_case_cache[str]
  return cached if cached

  result = str.split("/").map { |part| camelize_part(part) }.join("::")

  # Evict oldest entry if cache is full
  @camel_case_cache.shift if @camel_case_cache.size >= CACHE_SIZE_LIMIT
  @camel_case_cache[str] = result
end

.classify(str) ⇒ Object

Convert string to class name



49
50
51
52
53
54
55
56
57
58
# File 'lib/lutaml/model/utils.rb', line 49

def classify(str)
  str = str.to_s.delete(".")
  str = str.sub(/^[a-z\d]*/) { |match| camel_case(match) || match }

  str.gsub("::", "/").gsub(%r{(?:_|-|(/))([a-z\d]*)}i) do
    word = Regexp.last_match(2)
    substituted = camel_case(word) || word
    Regexp.last_match(1) ? "::#{substituted}" : substituted
  end
end

.clear_cachesObject

Clear all caches (call between schema compilations)



13
14
15
16
# File 'lib/lutaml/model/utils.rb', line 13

def clear_caches
  @camel_case_cache = {}
  @snake_case_cache = {}
end

.deep_dup(object) ⇒ Object



233
234
235
236
237
238
239
240
241
242
# File 'lib/lutaml/model/utils.rb', line 233

def deep_dup(object)
  return object if object.nil?
  return object if immutable?(object)

  case object
  when ::Hash then deep_dup_hash(object)
  when Array then deep_dup_array(object)
  else deep_dup_object(object)
  end
end

.empty?(value) ⇒ Boolean

Returns:

  • (Boolean)


128
129
130
# File 'lib/lutaml/model/utils.rb', line 128

def empty?(value)
  value.respond_to?(:empty?) ? value.empty? : false
end

.empty_collection?(collection) ⇒ Boolean

Returns:

  • (Boolean)


121
122
123
124
125
126
# File 'lib/lutaml/model/utils.rb', line 121

def empty_collection?(collection)
  return false if collection.nil?
  return false unless [Array, Hash].include?(collection.class)

  collection.empty?
end

.fetch_str_or_sym(hash, key, default = nil) ⇒ Object

Fetch the value from the hash using the key in string or symbol format

Examples:

hash = { "key" => "value" }
fetch_str_or_sym(hash, "key") # => "value"
fetch_str_or_sym(hash, :key) # => "value"
fetch_str_or_sym(hash, "invalid_key") # => nil

Parameters:

  • hash (Hash)

    the hash to fetch the value from

  • key (String, Symbol)

    the key to fetch the value for

Returns:

  • (Object)

    the value associated with the key



158
159
160
161
162
163
164
165
166
# File 'lib/lutaml/model/utils.rb', line 158

def fetch_str_or_sym(hash, key, default = nil)
  if hash.key?(key.to_s)
    hash[key.to_s]
  elsif hash.key?(key.to_sym)
    hash[key.to_sym]
  else
    default
  end
end

.immutable?(object) ⇒ Boolean

Check if object is immutable and should not be duplicated

Returns:

  • (Boolean)


245
246
247
248
249
250
251
252
253
254
255
# File 'lib/lutaml/model/utils.rb', line 245

def immutable?(object)
  object.is_a?(Symbol) ||
    object.is_a?(TrueClass) ||
    object.is_a?(FalseClass) ||
    object.is_a?(Numeric) ||
    object.is_a?(Class) ||
    object.is_a?(Module) ||
    object.is_a?(Proc) ||
    object.is_a?(Method) ||
    (object.is_a?(Range) && immutable_range?(object))
end

.immutable_range?(range) ⇒ Boolean

Check if Range has immutable bounds

Returns:

  • (Boolean)


258
259
260
# File 'lib/lutaml/model/utils.rb', line 258

def immutable_range?(range)
  immutable?(range.begin) && (range.end.nil? || immutable?(range.end))
end

.initialized?(value) ⇒ Boolean

Returns:

  • (Boolean)


105
106
107
# File 'lib/lutaml/model/utils.rb', line 105

def initialized?(value)
  !value.equal?(UNINITIALIZED)
end

.pluralize(str) ⇒ Object

Simple English pluralization for method names. Handles common cases; not a full inflector.



81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/lutaml/model/utils.rb', line 81

def pluralize(str)
  str = str.to_s
  return str if str.empty?

  if str.end_with?("s", "x", "z", "ch", "sh")
    "#{str}es"
  elsif str.end_with?("y") && str.length > 1 && !%w[a e i o
                                                    u].include?(str[-2])
    "#{str[0..-2]}ies"
  else
    "#{str}s"
  end
end

.present?(value) ⇒ Boolean

Returns:

  • (Boolean)


113
114
115
# File 'lib/lutaml/model/utils.rb', line 113

def present?(value)
  !blank?(value)
end

.resolve_child_register(child_class, parent_register) ⇒ Symbol?

Deprecated.

Use Register.resolve_for_child instead. This method will be removed in a future version.

Determines the appropriate register for a child model during deserialization.

Parameters:

  • child_class (Class)

    The child model class

  • parent_register (Symbol, nil)

    The parent’s register/context ID

Returns:

  • (Symbol, nil)

    The register ID to use for the child



192
193
194
195
# File 'lib/lutaml/model/utils.rb', line 192

def resolve_child_register(child_class, parent_register)
  Lutaml::Model::Register.resolve_for_child(child_class,
                                            parent_register)
end

.safe_load(file, constant) ⇒ Boolean

Safely attempts to require a file and check for a constant

Parameters:

  • file (String)

    the file to require

  • constant (Symbol)

    the constant name to check for

Returns:

  • (Boolean)

    true if the constant is defined, false otherwise



23
24
25
26
27
28
29
30
31
# File 'lib/lutaml/model/utils.rb', line 23

def safe_load(file, constant)
  return true if Object.const_defined?(constant)

  require file

  Object.const_defined?(constant)
rescue LoadError
  false
end

.snake_case(str) ⇒ Object

Convert string to snake case (cached)



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/lutaml/model/utils.rb', line 61

def snake_case(str)
  str = str.to_s.tr(".", "_")
  return str unless /[A-Z-]|::/.match?(str)

  @snake_case_cache ||= {}
  cached = @snake_case_cache[str]
  return cached if cached

  result = str.gsub("::", "/")
    .gsub(/([A-Z][A-Z]*)(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) { "#{$1 || $2}_" }
    .tr("-", "_")
    .downcase

  # Evict oldest entry if cache is full
  @snake_case_cache.shift if @snake_case_cache.size >= CACHE_SIZE_LIMIT
  @snake_case_cache[str] = result
end

.string_or_symbol_key?(hash, key) ⇒ Boolean

Check if the hash contains the given key in string or symbol format

Examples:

hash = { "key" => "value" }
string_or_symbol_key?(hash, "key") # => true
string_or_symbol_key?(hash, :key) # => true
string_or_symbol_key?(hash, "invalid_key") # => false

Parameters:

  • hash (Hash)

    the hash to check

  • key (String, Symbol)

    the key to check

Returns:

  • (Boolean)

    true if the hash contains the key, false otherwise



145
146
147
# File 'lib/lutaml/model/utils.rb', line 145

def string_or_symbol_key?(hash, key)
  hash.key?(key.to_s) || hash.key?(key.to_sym)
end

.uninitialized?(value) ⇒ Boolean

Returns:

  • (Boolean)


109
110
111
# File 'lib/lutaml/model/utils.rb', line 109

def uninitialized?(value)
  value.equal?(UNINITIALIZED)
end