ruby-edgar 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +120 -0
- data/lib/edgar/attachment.rb +69 -0
- data/lib/edgar/attachments.rb +75 -0
- data/lib/edgar/company.rb +217 -0
- data/lib/edgar/config.rb +62 -0
- data/lib/edgar/data_objects.rb +521 -0
- data/lib/edgar/entity.rb +98 -0
- data/lib/edgar/entity_data.rb +189 -0
- data/lib/edgar/entity_facts.rb +322 -0
- data/lib/edgar/filing.rb +170 -0
- data/lib/edgar/filing_facts.rb +312 -0
- data/lib/edgar/filing_header.rb +124 -0
- data/lib/edgar/filing_homepage.rb +118 -0
- data/lib/edgar/filing_index.rb +87 -0
- data/lib/edgar/filing_sections.rb +43 -0
- data/lib/edgar/filings.rb +216 -0
- data/lib/edgar/financials.rb +361 -0
- data/lib/edgar/http_client.rb +116 -0
- data/lib/edgar/ttm_calculator.rb +185 -0
- data/lib/edgar/version.rb +5 -0
- data/lib/edgar/xbrl/xbrl.rb +134 -0
- data/lib/edgar.rb +83 -0
- metadata +164 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Edgar
|
|
4
|
+
# Calculates Trailing Twelve Months (TTM) values from quarterly financial facts.
|
|
5
|
+
#
|
|
6
|
+
# Matches Python edgartools' TTMCalculator algorithm:
|
|
7
|
+
# 1. Classify facts by period duration (quarter: 70-120d, YTD_6M: 140-229d,
|
|
8
|
+
# YTD_9M: 230-329d, annual: 330-420d)
|
|
9
|
+
# 2. Derive Q2=YTD_6M-Q1, Q3=YTD_9M-YTD_6M, Q4=FY-YTD_9M
|
|
10
|
+
# 3. Take 4 most recent quarters and sum them.
|
|
11
|
+
# Falls back to fp-based quarterly selection when values lack start dates.
|
|
12
|
+
class TTMCalculator
|
|
13
|
+
QUARTER_MIN_DAYS = 70
|
|
14
|
+
QUARTER_MAX_DAYS = 120
|
|
15
|
+
YTD_6M_MIN_DAYS = 140
|
|
16
|
+
YTD_6M_MAX_DAYS = 229
|
|
17
|
+
YTD_9M_MIN_DAYS = 230
|
|
18
|
+
YTD_9M_MAX_DAYS = 329
|
|
19
|
+
ANNUAL_MIN_DAYS = 330
|
|
20
|
+
ANNUAL_MAX_DAYS = 420
|
|
21
|
+
|
|
22
|
+
PERIODIC_FORMS = %w[10-K 10-K/A 10-Q 10-Q/A 20-F 20-F/A 40-F 40-F/A 6-K 6-K/A].freeze
|
|
23
|
+
|
|
24
|
+
def initialize(values)
|
|
25
|
+
@values = values
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Returns a hash with "end" and "val" keys, or nil if insufficient data.
|
|
29
|
+
def calculate
|
|
30
|
+
all_quarters = quarterize(@values)
|
|
31
|
+
return nil if all_quarters.length < 4
|
|
32
|
+
|
|
33
|
+
ttm_qs = all_quarters.last(4)
|
|
34
|
+
sum = ttm_qs.sum { |v| v["val"].to_f }
|
|
35
|
+
{ "end" => ttm_qs.last["end"], "val" => sum }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def quarterize(values)
|
|
41
|
+
quarters, ytd_6m, ytd_9m, annual_facts = classify_by_duration(values)
|
|
42
|
+
|
|
43
|
+
return fp_based_quarters(values) if all_empty?(quarters, ytd_6m, ytd_9m, annual_facts)
|
|
44
|
+
|
|
45
|
+
quarters = dedup_by_end(quarters)
|
|
46
|
+
ytd_6m = dedup_by_end(ytd_6m)
|
|
47
|
+
ytd_9m = dedup_by_end(ytd_9m)
|
|
48
|
+
annual_facts = dedup_by_end(annual_facts)
|
|
49
|
+
|
|
50
|
+
derived = []
|
|
51
|
+
derived.concat(derive_q2(quarters, ytd_6m))
|
|
52
|
+
derived.concat(derive_q3(ytd_6m, ytd_9m))
|
|
53
|
+
derived.concat(derive_q4(quarters, ytd_9m, annual_facts))
|
|
54
|
+
|
|
55
|
+
all_quarters = quarters + derived
|
|
56
|
+
all_quarters = dedup_by_end(all_quarters)
|
|
57
|
+
all_quarters.sort_by { |v| v["end"] || v["start"] || "" }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def all_empty?(*arrays)
|
|
61
|
+
arrays.all?(&:empty?)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def classify_by_duration(values)
|
|
65
|
+
quarters = []
|
|
66
|
+
ytd_6m = []
|
|
67
|
+
ytd_9m = []
|
|
68
|
+
annual_facts = []
|
|
69
|
+
|
|
70
|
+
values.each do |v|
|
|
71
|
+
days = duration_days(v["start"], v["end"])
|
|
72
|
+
next unless days
|
|
73
|
+
|
|
74
|
+
if days.between?(QUARTER_MIN_DAYS, QUARTER_MAX_DAYS)
|
|
75
|
+
quarters << v
|
|
76
|
+
elsif days.between?(YTD_6M_MIN_DAYS, YTD_6M_MAX_DAYS)
|
|
77
|
+
ytd_6m << v
|
|
78
|
+
elsif days.between?(YTD_9M_MIN_DAYS, YTD_9M_MAX_DAYS)
|
|
79
|
+
ytd_9m << v
|
|
80
|
+
elsif days.between?(ANNUAL_MIN_DAYS, ANNUAL_MAX_DAYS)
|
|
81
|
+
annual_facts << v
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
[quarters, ytd_6m, ytd_9m, annual_facts]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def fp_based_quarters(values)
|
|
89
|
+
has_fp = values.first&.key?("fp")
|
|
90
|
+
return [] unless has_fp
|
|
91
|
+
|
|
92
|
+
quarterly = values.select { |v| %w[Q1 Q2 Q3 Q4].include?(v["fp"]) }
|
|
93
|
+
quarterly.sort_by { |v| v["end"] || v["start"] || "" }
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def duration_days(start_str, end_str)
|
|
97
|
+
return nil unless start_str && end_str
|
|
98
|
+
|
|
99
|
+
(Date.parse(end_str) - Date.parse(start_str)).to_i
|
|
100
|
+
rescue ArgumentError
|
|
101
|
+
nil
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def dedup_by_end(values)
|
|
105
|
+
return [] if values.empty?
|
|
106
|
+
|
|
107
|
+
by_end = {}
|
|
108
|
+
values.each do |v|
|
|
109
|
+
key = v["end"]
|
|
110
|
+
next unless key
|
|
111
|
+
|
|
112
|
+
existing = by_end[key]
|
|
113
|
+
by_end[key] = v if existing.nil? || (filing_priority(v) <=> filing_priority(existing)).positive?
|
|
114
|
+
end
|
|
115
|
+
by_end.values.sort_by { |v| v["end"] || "" }
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def filing_priority(value)
|
|
119
|
+
form = value["form"] || ""
|
|
120
|
+
tier = PERIODIC_FORMS.include?(form) ? 1 : 0
|
|
121
|
+
[tier, value["filed"] || ""]
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def derive_q2(quarters, ytd_6m)
|
|
125
|
+
derived = []
|
|
126
|
+
ytd_6m.each do |ytd6|
|
|
127
|
+
q1 = find_prior_by_end(quarters, before: ytd6["end"])
|
|
128
|
+
next unless q1
|
|
129
|
+
|
|
130
|
+
q2_val = ytd6["val"].to_f - q1["val"].to_f
|
|
131
|
+
next if q2_val.negative?
|
|
132
|
+
|
|
133
|
+
derived << { "val" => q2_val, "end" => ytd6["end"], "fp" => "Q2" }
|
|
134
|
+
end
|
|
135
|
+
derived
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def derive_q3(ytd_6m, ytd_9m)
|
|
139
|
+
derived = []
|
|
140
|
+
ytd_9m.each do |ytd9|
|
|
141
|
+
ytd6 = find_prior_by_end(ytd_6m, before: ytd9["end"])
|
|
142
|
+
next unless ytd6
|
|
143
|
+
|
|
144
|
+
q3_val = ytd9["val"].to_f - ytd6["val"].to_f
|
|
145
|
+
next if q3_val.negative?
|
|
146
|
+
|
|
147
|
+
derived << { "val" => q3_val, "end" => ytd9["end"], "fp" => "Q3" }
|
|
148
|
+
end
|
|
149
|
+
derived
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def derive_q4(quarters, ytd_9m, annual_facts)
|
|
153
|
+
derived = []
|
|
154
|
+
annual_facts.each do |fy|
|
|
155
|
+
ytd9 = find_prior_by_end(ytd_9m, before: fy["end"])
|
|
156
|
+
unless ytd9
|
|
157
|
+
fy_quarters = quarters.select do |q|
|
|
158
|
+
q["end"] && fy["end"] && q["end"] < fy["end"] &&
|
|
159
|
+
fy["start"] && q["start"] && q["start"] >= fy["start"]
|
|
160
|
+
end
|
|
161
|
+
fy_quarters = dedup_by_end(fy_quarters)
|
|
162
|
+
next if fy_quarters.length < 3
|
|
163
|
+
|
|
164
|
+
q1q2q3 = fy_quarters.last(3)
|
|
165
|
+
q4_val = fy["val"].to_f - q1q2q3.sum { |q| q["val"].to_f }
|
|
166
|
+
next if q4_val.negative?
|
|
167
|
+
|
|
168
|
+
derived << { "val" => q4_val, "end" => fy["end"], "fp" => "Q4" }
|
|
169
|
+
next
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
q4_val = fy["val"].to_f - ytd9["val"].to_f
|
|
173
|
+
next if q4_val.negative?
|
|
174
|
+
|
|
175
|
+
derived << { "val" => q4_val, "end" => fy["end"], "fp" => "Q4" }
|
|
176
|
+
end
|
|
177
|
+
derived
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def find_prior_by_end(values, before:)
|
|
181
|
+
candidates = values.select { |v| v["end"] && before && v["end"] < before }
|
|
182
|
+
candidates.max_by { |v| v["end"] || "" }
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "nokogiri"
|
|
4
|
+
|
|
5
|
+
module Edgar
|
|
6
|
+
module XBRL
|
|
7
|
+
# Parses XBRL XML documents for financial fact extraction.
|
|
8
|
+
class XBRL
|
|
9
|
+
attr_reader :raw
|
|
10
|
+
|
|
11
|
+
def initialize(xml_content)
|
|
12
|
+
@raw = xml_content
|
|
13
|
+
@doc = parse_document(xml_content)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def context_refs
|
|
17
|
+
@doc.css("context").map do |ctx|
|
|
18
|
+
id = ctx["id"]
|
|
19
|
+
entity = ctx.at_css("entity")
|
|
20
|
+
period = ctx.at_css("period")
|
|
21
|
+
start_el = period&.at_css("startDate")
|
|
22
|
+
end_el = period&.at_css("endDate")
|
|
23
|
+
instant_el = period&.at_css("instant")
|
|
24
|
+
# Detect segment dimensions (product/service, geographic, etc.)
|
|
25
|
+
segment = entity&.at_css("segment")
|
|
26
|
+
{
|
|
27
|
+
id: id,
|
|
28
|
+
entity: entity&.text&.strip,
|
|
29
|
+
start_date: start_el&.text&.strip,
|
|
30
|
+
end_date: end_el&.text&.strip,
|
|
31
|
+
instant: instant_el&.text&.strip,
|
|
32
|
+
segmented: !segment.nil?
|
|
33
|
+
}
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def facts
|
|
38
|
+
xbrl_elements = @doc.xpath("//*[local-name() != 'context' and local-name() != 'unit' and local-name() != 'schemaRef' and local-name() != 'linkbaseRef']").select do |el|
|
|
39
|
+
ns = el.namespace
|
|
40
|
+
ns&.href&.include?("xbrl")
|
|
41
|
+
end
|
|
42
|
+
xbrl_elements.map do |el|
|
|
43
|
+
{
|
|
44
|
+
name: el.name,
|
|
45
|
+
namespace: el.namespace&.href,
|
|
46
|
+
value: el.text.strip,
|
|
47
|
+
context_ref: el["contextRef"],
|
|
48
|
+
unit_ref: el["unitRef"],
|
|
49
|
+
decimals: el["decimals"],
|
|
50
|
+
signature: el["signature"]
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def units
|
|
56
|
+
@doc.css("unit").map do |u|
|
|
57
|
+
{ id: u["id"], measure: u.at_css("measure")&.text&.strip }
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def financial_concepts
|
|
62
|
+
ns_prefixes = @doc.namespaces.select { |_, v| v&.include?("us-gaap") || v&.include?("dei") }
|
|
63
|
+
return [] if ns_prefixes.empty?
|
|
64
|
+
|
|
65
|
+
financial_ns = ns_prefixes.map { |k, _| k.sub("xmlns:", "") }
|
|
66
|
+
xpath_expr = financial_ns.map { |p| "//#{p}:*" }.join(" | ")
|
|
67
|
+
@doc.xpath(xpath_expr).filter_map do |el|
|
|
68
|
+
next unless el["contextRef"]
|
|
69
|
+
|
|
70
|
+
{
|
|
71
|
+
name: el.name,
|
|
72
|
+
value: el.text.strip,
|
|
73
|
+
context_ref: el["contextRef"],
|
|
74
|
+
unit_ref: el["unitRef"],
|
|
75
|
+
decimals: el["decimals"]
|
|
76
|
+
}
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def to_s
|
|
81
|
+
"#<XBRL facts=#{facts.length}>"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
def parse_document(content)
|
|
87
|
+
Nokogiri::XML(content) { |config| config.strict.noblanks }
|
|
88
|
+
rescue Nokogiri::XML::SyntaxError
|
|
89
|
+
Nokogiri::XML(content)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Parses Inline XBRL (iXBRL) HTML documents with embedded financial facts.
|
|
94
|
+
class InlineXBRL < XBRL
|
|
95
|
+
def facts
|
|
96
|
+
inline_elements = @doc.css("[name]").select do |el|
|
|
97
|
+
el["name"].to_s.include?(":") && el["contextref"]
|
|
98
|
+
end
|
|
99
|
+
inline_elements.map do |el|
|
|
100
|
+
{
|
|
101
|
+
name: el["name"],
|
|
102
|
+
value: el.text.strip,
|
|
103
|
+
context_ref: el["contextref"],
|
|
104
|
+
unit_ref: el["unitref"],
|
|
105
|
+
decimals: el["decimals"],
|
|
106
|
+
format: el["format"],
|
|
107
|
+
scale: el["scale"]
|
|
108
|
+
}
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def context_refs
|
|
113
|
+
@doc.css("context").map do |ctx|
|
|
114
|
+
{
|
|
115
|
+
id: ctx["id"],
|
|
116
|
+
start_date: ctx.at_css("startDate")&.text&.strip,
|
|
117
|
+
end_date: ctx.at_css("endDate")&.text&.strip,
|
|
118
|
+
instant: ctx.at_css("instant")&.text&.strip
|
|
119
|
+
}
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def financial_concepts
|
|
124
|
+
facts.select { |f| f[:name]&.include?("us-gaap") || f[:name]&.include?("dei") }
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
private
|
|
128
|
+
|
|
129
|
+
def parse_document(content)
|
|
130
|
+
Nokogiri::HTML(content)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
data/lib/edgar.rb
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "zeitwerk"
|
|
4
|
+
require "json"
|
|
5
|
+
require "zlib"
|
|
6
|
+
require "stringio"
|
|
7
|
+
require "date"
|
|
8
|
+
|
|
9
|
+
loader = Zeitwerk::Loader.for_gem
|
|
10
|
+
loader.inflector.inflect(
|
|
11
|
+
"http_client" => "HTTPClient",
|
|
12
|
+
"xbrl" => "XBRL",
|
|
13
|
+
"ttm_calculator" => "TTMCalculator"
|
|
14
|
+
)
|
|
15
|
+
loader.setup
|
|
16
|
+
|
|
17
|
+
# Main entry point for the Edgar library providing SEC EDGAR filing access.
|
|
18
|
+
module Edgar
|
|
19
|
+
class << self
|
|
20
|
+
def http_client
|
|
21
|
+
@http_client ||= HTTPClient.new
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
attr_writer :http_client
|
|
25
|
+
|
|
26
|
+
def configure
|
|
27
|
+
yield(self)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def company(identifier)
|
|
31
|
+
if identifier.is_a?(Integer) || identifier.to_s.match?(/^\d+$/)
|
|
32
|
+
Company.new(cik: identifier.to_i)
|
|
33
|
+
else
|
|
34
|
+
Company.new(ticker: identifier.to_s)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def identity=(email)
|
|
39
|
+
ENV["EDGAR_IDENTITY"] = email
|
|
40
|
+
@http_client = nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def get_filings(year, quarter)
|
|
44
|
+
Filings.from_quarter(year, quarter)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def current_filings
|
|
48
|
+
today = Date.today
|
|
49
|
+
Filings.from_quarter(today.year, ((today.month - 1) / 3) + 1)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def get_entity(cik)
|
|
53
|
+
Entity.new(cik: cik)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def find_company(name, limit: 10)
|
|
57
|
+
Company.search(name, limit: limit)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def find(identifier)
|
|
61
|
+
return nil unless identifier
|
|
62
|
+
|
|
63
|
+
str = identifier.to_s.strip
|
|
64
|
+
return Company.new(cik: str.to_i) if str.match?(/^\d{10}$/)
|
|
65
|
+
return Company.new(cik: str.to_i) if str.match?(/^\d+$/) && str.length >= 6
|
|
66
|
+
return Company.new(ticker: str) if str.match?(/^[A-Za-z]{1,5}$/)
|
|
67
|
+
|
|
68
|
+
Company.search(str, limit: 1).first
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def obj(filing)
|
|
72
|
+
DataObjects.for(filing)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def reset!
|
|
76
|
+
@http_client = nil
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def version
|
|
80
|
+
VERSION
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ruby-edgar
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Edgar Tools Ruby Port
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-07-12 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: faraday
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '2.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: faraday-retry
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '2.0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '2.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: nokogiri
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.15'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.15'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: zeitwerk
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '2.6'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '2.6'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rspec
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '3.12'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '3.12'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: vcr
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '6.0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '6.0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: webmock
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '3.18'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '3.18'
|
|
111
|
+
description: A Ruby port of the edgartools Python library for accessing and analyzing
|
|
112
|
+
SEC EDGAR filings, including company lookups, filing retrieval, and financial data
|
|
113
|
+
extraction.
|
|
114
|
+
email:
|
|
115
|
+
executables: []
|
|
116
|
+
extensions: []
|
|
117
|
+
extra_rdoc_files: []
|
|
118
|
+
files:
|
|
119
|
+
- README.md
|
|
120
|
+
- lib/edgar.rb
|
|
121
|
+
- lib/edgar/attachment.rb
|
|
122
|
+
- lib/edgar/attachments.rb
|
|
123
|
+
- lib/edgar/company.rb
|
|
124
|
+
- lib/edgar/config.rb
|
|
125
|
+
- lib/edgar/data_objects.rb
|
|
126
|
+
- lib/edgar/entity.rb
|
|
127
|
+
- lib/edgar/entity_data.rb
|
|
128
|
+
- lib/edgar/entity_facts.rb
|
|
129
|
+
- lib/edgar/filing.rb
|
|
130
|
+
- lib/edgar/filing_facts.rb
|
|
131
|
+
- lib/edgar/filing_header.rb
|
|
132
|
+
- lib/edgar/filing_homepage.rb
|
|
133
|
+
- lib/edgar/filing_index.rb
|
|
134
|
+
- lib/edgar/filing_sections.rb
|
|
135
|
+
- lib/edgar/filings.rb
|
|
136
|
+
- lib/edgar/financials.rb
|
|
137
|
+
- lib/edgar/http_client.rb
|
|
138
|
+
- lib/edgar/ttm_calculator.rb
|
|
139
|
+
- lib/edgar/version.rb
|
|
140
|
+
- lib/edgar/xbrl/xbrl.rb
|
|
141
|
+
homepage:
|
|
142
|
+
licenses:
|
|
143
|
+
- MIT
|
|
144
|
+
metadata: {}
|
|
145
|
+
post_install_message:
|
|
146
|
+
rdoc_options: []
|
|
147
|
+
require_paths:
|
|
148
|
+
- lib
|
|
149
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
150
|
+
requirements:
|
|
151
|
+
- - ">="
|
|
152
|
+
- !ruby/object:Gem::Version
|
|
153
|
+
version: '3.0'
|
|
154
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
|
+
requirements:
|
|
156
|
+
- - ">="
|
|
157
|
+
- !ruby/object:Gem::Version
|
|
158
|
+
version: '0'
|
|
159
|
+
requirements: []
|
|
160
|
+
rubygems_version: 3.3.7
|
|
161
|
+
signing_key:
|
|
162
|
+
specification_version: 4
|
|
163
|
+
summary: Ruby library to access SEC EDGAR filings
|
|
164
|
+
test_files: []
|