Class: SecApi::Fact

Inherits:
Dry::Struct
  • Object
show all
Includes:
DeepFreezable
Defined in:
lib/sec_api/objects/fact.rb

Overview

Immutable value object representing a single XBRL fact from SEC filings.

A fact represents a single data point in financial statements, containing the value along with its context (period, units, precision).

Examples:

Creating a Fact with all attributes

fact = SecApi::Fact.new(
  value: "394328000000",
  decimals: "-6",
  unit_ref: "usd",
  period: SecApi::Period.new(start_date: "2022-09-25", end_date: "2023-09-30")
)
fact.to_numeric # => 394328000000.0

Creating from API response

fact = SecApi::Fact.from_api({
  "value" => "394328000000",
  "decimals" => "-6",
  "unitRef" => "usd",
  "period" => {"startDate" => "2022-09-25", "endDate" => "2023-09-30"}
})

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attributes) ⇒ Fact

Returns a new instance of Fact.



100
101
102
103
104
# File 'lib/sec_api/objects/fact.rb', line 100

def initialize(attributes)
  super
  deep_freeze(segment) if segment
  freeze
end

Class Method Details

.from_api(data) ⇒ Fact

Parses API response data into a Fact object.

Examples:

Fact.from_api({
  "value" => "1000000",
  "decimals" => "-3",
  "unitRef" => "usd",
  "period" => {"instant" => "2023-09-30"}
})

Parameters:

  • data (Hash)

    API response with camelCase or snake_case keys

Returns:

  • (Fact)

    Immutable Fact object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/sec_api/objects/fact.rb', line 119

def self.from_api(data)
  raw_value = data[:value] || data["value"]

  if raw_value.nil?
    raise ValidationError, "XBRL fact missing required 'value' field. " \
      "Received: #{data.inspect}"
  end

  period_data = data[:period] || data["period"]

  if period_data.nil?
    raise ValidationError, "XBRL fact missing required 'period' field. " \
      "Received: #{data.inspect}"
  end

  segment_data = data[:segment] || data["segment"]

  normalized = {
    value: raw_value.to_s,
    decimals: data[:decimals] || data["decimals"],
    unit_ref: data[:unitRef] || data["unitRef"] || data[:unit_ref] || data["unit_ref"],
    period: Period.from_api(period_data),
    segment: segment_data
  }

  new(normalized)
end

Instance Method Details

#numeric?Boolean

Note:

Leading plus signs (+123) return false as XBRL values use unadorned positive numbers. Only explicit minus signs are supported.

Checks if the value can be safely converted to a numeric type.

This predicate is useful for filtering facts before numeric operations, as XBRL facts may contain text values like “N/A” or formatted strings like “1,000,000” that won’t convert properly.

Supports:

  • Integers (positive and negative)

  • Decimals (positive and negative)

  • Scientific notation (e.g., “1.5e10”, “-2.5E-3”)

  • Leading/trailing whitespace around valid numbers

Does NOT support (returns false):

  • Comma-formatted numbers (“1,000,000”)

  • Currency symbols (“$100”)

  • Percentages (“10%”)

  • Text values (“N/A”, “none”)

  • Empty or whitespace-only strings

Examples:

Check before conversion

fact = Fact.new(value: "394328000000")
fact.numeric?  # => true
fact.to_numeric  # => 394328000000.0

Filter numeric facts

facts.select(&:numeric?).map(&:to_numeric)

Returns:

  • (Boolean)

    true if value is a valid numeric string



92
93
94
95
96
97
98
# File 'lib/sec_api/objects/fact.rb', line 92

def numeric?
  return false if value.strip.empty?

  # Match integers, decimals, and scientific notation
  # Allows optional leading/trailing whitespace, minus sign only (no +)
  !!value.match?(/\A\s*-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\s*\z/)
end

#to_numericFloat

Converts the string value to a Float for calculations.

Examples:

fact = Fact.new(value: "394328000000")
fact.to_numeric # => 394328000000.0

Returns:

  • (Float)

    Numeric value (0.0 for non-numeric strings)



56
57
58
# File 'lib/sec_api/objects/fact.rb', line 56

def to_numeric
  value.to_f
end