Class: Reqif::ReqifFloat

Inherits:
Lutaml::Model::Type::Float
  • Object
show all
Defined in:
lib/reqif/reqif_float.rb

Overview

Custom Float type that handles ReqIF float serialization. Preserves decimal notation for simple values and uses scientific notation only when necessary (very large/small numbers).

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.cast(value, options = {}) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/reqif/reqif_float.rb', line 68

def self.cast(value, options = {})
  return nil if value.nil?
  return value if Lutaml::Model::Utils.uninitialized?(value)

  unless options.equal?(EMPTY_OPTIONS)
    Lutaml::Model::Services::Type::Validator::Number.validate!(value,
                                                               options)
  end

  case value
  when String then BigDecimal(value).to_f
  when Float then value
  when BigDecimal then value.to_f
  else Float(value.to_s)
  end
end

.format_float_as_decimal(float_value) ⇒ Object

Format as decimal if it can be done cleanly



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/reqif/reqif_float.rb', line 27

def self.format_float_as_decimal(float_value)
  # Use a reasonable precision to avoid floating point artifacts
  # Check if the value can be represented cleanly in decimal
  decimal_str = format("%.10g", float_value)

  # Skip if it's in scientific notation (contains 'e' or 'E')
  return nil if decimal_str.include?("e") || decimal_str.include?("E")

  # Verify round-trip: parse back and check if we get the same value
  parsed = BigDecimal(decimal_str).to_f
  return decimal_str if parsed == float_value

  # Try with higher precision
  decimal_str = format("%.15g", float_value)
  return nil if decimal_str.include?("e") || decimal_str.include?("E")

  parsed = BigDecimal(decimal_str).to_f
  return decimal_str if parsed == float_value

  nil # Couldn't represent cleanly
end

.format_scientific(float_value) ⇒ Object

Format in scientific notation



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/reqif/reqif_float.rb', line 50

def self.format_scientific(float_value)
  formatted = format("%.15e", float_value).upcase
  mantissa, exp = formatted.split("E")

  # Strip trailing zeros from mantissa
  mantissa = mantissa.sub(/\.?0+$/, "")
  mantissa = "0" if mantissa.empty?
  # Remove decimal point if it becomes trailing (e.g. "1.")
  mantissa = mantissa.chomp(".")

  # Handle exponent sign and strip leading zeros
  sign = exp.start_with?("-") ? "-" : ""
  digits = exp.sub(/^[+-]/, "").sub(/\A0+/, "")
  digits = "0" if digits.empty?

  "#{mantissa}E#{sign}#{digits}"
end

.reqif_format(float_value) ⇒ String

Format a float value for ReqIF. Uses decimal notation for values that can be represented cleanly, otherwise uses scientific notation with uppercase E.

Parameters:

  • f (Float)

    The float value

Returns:

  • (String)

    ReqIF formatted string



17
18
19
20
21
22
23
24
# File 'lib/reqif/reqif_float.rb', line 17

def self.reqif_format(float_value)
  # Try to represent as a clean decimal first
  decimal_str = format_float_as_decimal(float_value)
  return decimal_str if decimal_str

  # Fall back to scientific notation
  format_scientific(float_value)
end

.to_xml(value) ⇒ Object



85
86
87
88
89
90
91
92
# File 'lib/reqif/reqif_float.rb', line 85

def self.to_xml(value)
  return nil if value.nil?

  result = cast(value)
  return nil if result.nil?

  reqif_format(result)
end

Instance Method Details

#to_xmlObject



94
95
96
# File 'lib/reqif/reqif_float.rb', line 94

def to_xml
  self.class.to_xml(value)
end