sec_query 1.0.5 → 1.0.6
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 +5 -13
- data/lib/sec_query.rb +1 -1
- data/lib/sec_query/entity.rb +31 -188
- data/lib/sec_query/filing.rb +29 -25
- data/lib/sec_query/sec_uri.rb +0 -1
- data/lib/sec_query/transaction.rb +1 -1
- data/lib/sec_query/version.rb +1 -1
- data/sec_query.gemspec +2 -1
- data/spec/sec_query/entity_spec.rb +73 -0
- data/spec/sec_query/filing_spec.rb +44 -1
- data/spec/sec_query/transaction_spec.rb +39 -0
- data/spec/spec_helper.rb +23 -0
- metadata +38 -26
- data/spec/sec_query/sec_query_spec.rb +0 -129
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
YTQ1MThkMWUwYzFlYTFiMDMxMzVhMDVhMTIwMGVlZDlkNWU1OWFiYQ==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0d2dde810ce6cded495db60a0e15cf12db156d9d
|
4
|
+
data.tar.gz: dfe37e5437bc0ec14d526c404700287023494101
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
YmE2YjI1Mjg5MTBhMjI5ODkwMGY1MGRjNjkyZDdkN2E3ZDg5M2E2MDU0MDA2
|
11
|
-
ZGU5MmFkOGEyOGZiNGNjMTU5YzNjMDdlZTFlYWU5N2RkODg1ZmE=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
NWY4MzFmZjJlYmE1YTMyYWViNzY1MzgxOTExMjkyZWY4ZjdmZDJlOGRiNGVh
|
14
|
-
MWEyODVhMTdiYmM4MTk1M2U3ZGE1Yzk5MTI4MjA3MGFkYmQ3MTU0OGEzMTJh
|
15
|
-
ZDcwMjU1MDliNzFiNDU2OTA0Y2U4YzYxNGE3ODYwZTA0NjA2ZmE=
|
6
|
+
metadata.gz: c9ae3373495a35a87f297ca8fbba54d15eadf7013273ac98c22ef5c4a64a8015feab56bfe1b531dd56fcd2fed98a761aee4346ba80e91438e6fafdebab4b1beb
|
7
|
+
data.tar.gz: e09c380cdcaf40ccff9deac2a5f24d7db825434d77f849993ced6396928b6df2a346fefa0546ea695876ce67fb8487e1e0414fa17e72e98eeff785ce1d9e0cf6
|
data/lib/sec_query.rb
CHANGED
data/lib/sec_query/entity.rb
CHANGED
@@ -1,52 +1,30 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
|
3
2
|
module SecQuery
|
4
3
|
# => SecQuery::Entity
|
5
4
|
# SecQuery::Entity is the root class which is responsible for requesting,
|
6
5
|
# parsing and initializing SecQuery::Entity intances from SEC Edgar.
|
7
6
|
class Entity
|
8
|
-
COLUMNS = [:
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
COLUMNS = [:cik, :name, :mailing_address, :business_address,
|
8
|
+
:assigned_sic, :assigned_sic_desc, :assigned_sic_href, :assitant_director, :cik_href,
|
9
|
+
:formerly_names, :state_location, :state_location_href, :state_of_incorporation]
|
12
10
|
attr_accessor(*COLUMNS)
|
13
11
|
|
14
12
|
def initialize(entity)
|
15
13
|
COLUMNS.each do |column|
|
16
|
-
instance_variable_set("@#{ column }", entity[column])
|
14
|
+
instance_variable_set("@#{ column }", entity[column.to_s])
|
17
15
|
end
|
18
16
|
end
|
19
17
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
temp[:url][:action] = :getcompany
|
24
|
-
temp[:cik] = Entity.cik(temp[:url], entity_args)
|
25
|
-
|
26
|
-
if !temp[:cik] || temp[:cik] == ''
|
27
|
-
puts "No Entity found for query: #{ temp[:url] }"
|
28
|
-
return false
|
29
|
-
end
|
30
|
-
|
31
|
-
### Get Document and Entity Type
|
32
|
-
doc = Entity.document(temp[:cik])
|
33
|
-
temp = Entity.parse_document(temp, doc)
|
34
|
-
|
35
|
-
### Get Additional Arguments and Query Additional Details
|
36
|
-
unless options.empty?
|
37
|
-
temp[:transactions] = []
|
38
|
-
temp[:filings] = []
|
39
|
-
options = Entity.options(temp, options)
|
40
|
-
temp = Entity.details(temp, options)
|
41
|
-
end
|
18
|
+
def filings
|
19
|
+
Filing.find(@cik)
|
20
|
+
end
|
42
21
|
|
43
|
-
|
44
|
-
|
45
|
-
@entity
|
22
|
+
def transactions
|
23
|
+
Transaction.find(@cik)
|
46
24
|
end
|
47
25
|
|
48
26
|
def self.query(url)
|
49
|
-
RestClient.get(url
|
27
|
+
RestClient.get(url) do |response, request, result, &block|
|
50
28
|
case response.code
|
51
29
|
when 200
|
52
30
|
return response
|
@@ -56,166 +34,31 @@ module SecQuery
|
|
56
34
|
end
|
57
35
|
end
|
58
36
|
|
59
|
-
def self.
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
tbl.each do |tr|
|
68
|
-
td = tr.search('td')
|
69
|
-
if td[1] && entity[:middle] && td[1].innerHTML.downcase == ("#{entity[:last]} #{entity[:first]} #{entity[:middle]}").downcase || td[1] && td[1].innerHTML.downcase == ("#{ entity[:last] } #{ entity[:first] }").downcase
|
70
|
-
cik = td[0].search('a').innerHTML
|
71
|
-
return cik
|
72
|
-
end
|
73
|
-
end
|
74
|
-
else
|
75
|
-
return false
|
76
|
-
end
|
77
|
-
else
|
78
|
-
cik = data.inner_text.scan(/\(([^)]+)\)/).to_s
|
79
|
-
cik = cik.gsub('[["', '').gsub('"]]', '')
|
80
|
-
return cik
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def self.document(cik)
|
85
|
-
url = SecURI.ownership_display_uri(action: :getissuer, CIK: cik)
|
86
|
-
response = query(url)
|
87
|
-
doc = Hpricot(response)
|
88
|
-
text = 'Ownership Reports from:'
|
89
|
-
type = 'issuer'
|
90
|
-
entity = doc.search('//table').search('//td').search("b[text()*='#{text}']")
|
91
|
-
if entity.empty?
|
92
|
-
url = SecURI.ownership_display_uri(action: :getowner, CIK: cik)
|
93
|
-
response = query(url)
|
94
|
-
doc = Hpricot(response)
|
95
|
-
text = 'Ownership Reports for entitys:'
|
96
|
-
type = 'owner'
|
97
|
-
entity = doc.search('//table').search('//td').search("b[text()*='#{text}']")
|
98
|
-
end
|
99
|
-
[doc, type]
|
100
|
-
end
|
101
|
-
|
102
|
-
def self.parse_document(temp, doc)
|
103
|
-
info = Entity.info(doc[0])
|
104
|
-
temp[:type] = doc[1]
|
105
|
-
temp[:name] = info[:name]
|
106
|
-
temp[:location] = info[:location]
|
107
|
-
temp[:sic] = info[:sic]
|
108
|
-
temp[:state_of_inc] = info[:state_of_inc]
|
109
|
-
temp[:formerly] = info[:formerly]
|
110
|
-
|
111
|
-
### Get Mailing Address
|
112
|
-
temp[:mailing_address] = Entity.mailing_address(doc[0])
|
113
|
-
|
114
|
-
### Get Business Address
|
115
|
-
temp[:business_address] = Entity.business_address(doc[0])
|
116
|
-
|
117
|
-
temp
|
118
|
-
end
|
119
|
-
|
120
|
-
def self.info(doc)
|
121
|
-
info = {}
|
122
|
-
lines = doc.search("//td[@bgcolor='#E6E6E6']")[0].parent.parent.search('//tr')
|
123
|
-
td = lines[0].search('//td//b').innerHTML
|
124
|
-
info[:name] = td.gsub(td.scan(/\(([^)]+)\)/).to_s, '').gsub('()', '').gsub('\n', '')
|
125
|
-
lines = lines[1].search('//table')[0].search('//tr//td')
|
126
|
-
|
127
|
-
if lines[0].search('a')[0]
|
128
|
-
info[:sic] = lines[0].search('a')[0].innerHTML
|
129
|
-
end
|
130
|
-
|
131
|
-
if lines[0].search('a')[1]
|
132
|
-
info[:location] = lines[0].search('a')[1].innerHTML
|
133
|
-
end
|
134
|
-
|
135
|
-
if lines[0].search('b')[0] && lines[0].search('b')[0].innerHTML.squeeze(' ') != ' '
|
136
|
-
info[:state_of_inc] = lines[0].search('b')[0].innerHTML
|
137
|
-
end
|
138
|
-
|
139
|
-
if lines[1] && lines[1].search('font')
|
140
|
-
info[:formerly] = lines[1].search('font').innerHTML
|
141
|
-
.gsub('formerly: ', '').gsub('<br />', '').gsub('\n', '; ')
|
142
|
-
end
|
143
|
-
|
144
|
-
info
|
145
|
-
end
|
146
|
-
|
147
|
-
def self.business_address(doc)
|
148
|
-
addie = doc.search('//table').search('//td')
|
149
|
-
.search("b[text()*='Business Address']")
|
150
|
-
if !addie.empty?
|
151
|
-
business_address = addie[0].parent.innerHTML
|
152
|
-
.gsub('<b class="blue">Business Address</b>', '').gsub('<br />', ' ')
|
153
|
-
return business_address
|
154
|
-
else
|
155
|
-
return false
|
156
|
-
end
|
37
|
+
def self.find(entity_args)
|
38
|
+
temp = {}
|
39
|
+
temp[:url] = SecURI.browse_edgar_uri(entity_args)
|
40
|
+
temp[:url][:action] = :getcompany
|
41
|
+
response = query(temp[:url].output_atom.to_s)
|
42
|
+
document = Nokogiri::HTML(response)
|
43
|
+
xml = document.xpath("//feed/company-info")
|
44
|
+
Entity.new(parse(xml))
|
157
45
|
end
|
158
46
|
|
159
|
-
def self.
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
47
|
+
def self.parse(xml)
|
48
|
+
content = Hash.from_xml(xml.to_s)
|
49
|
+
if content['company_info'].present?
|
50
|
+
content = content['company_info']
|
51
|
+
content['name'] = content.delete('conformed_name')
|
52
|
+
if content['formerly_names'].present?
|
53
|
+
content['formerly_names'] = content.delete('formerly_names')['names']
|
54
|
+
end
|
55
|
+
content['addresses']['address'].each do |address|
|
56
|
+
content["#{address['type']}_address"] = address
|
57
|
+
end
|
58
|
+
return content
|
166
59
|
else
|
167
|
-
return
|
60
|
+
return {}
|
168
61
|
end
|
169
62
|
end
|
170
|
-
|
171
|
-
def self.options(temp, options)
|
172
|
-
args = {}
|
173
|
-
if options.is_a?(Array) && options.length == 1 && options[0] == true
|
174
|
-
args[:relationships] = true
|
175
|
-
args[:transactions] = true
|
176
|
-
args[:filings] = true
|
177
|
-
elsif options.is_a?(Array) && options.length > 1
|
178
|
-
args[:relationships] = options[0]
|
179
|
-
args[:transactions] = options[1]
|
180
|
-
args[:filings] = options[2]
|
181
|
-
elsif options[0].is_a?(Hash)
|
182
|
-
args[:relationships] = options[0][:relationships]
|
183
|
-
args[:transactions] = options[0][:transactions]
|
184
|
-
args[:filings] = options[0][:filings]
|
185
|
-
end
|
186
|
-
args
|
187
|
-
end
|
188
|
-
|
189
|
-
def self.details(temp, options)
|
190
|
-
## Get Relationships for entity
|
191
|
-
if options[:relationships] == true
|
192
|
-
relationships = Relationship.find(temp)
|
193
|
-
temp[:relationships] = relationships
|
194
|
-
end
|
195
|
-
|
196
|
-
## Get Transactions for entity
|
197
|
-
if options[:transactions] && options[:transactions].is_a?(Hash)
|
198
|
-
temp = Transaction.find(
|
199
|
-
temp,
|
200
|
-
options[:transactions][:start],
|
201
|
-
options[:transactions][:count],
|
202
|
-
options[:transactions][:limit])
|
203
|
-
elsif options[:transactions] && options[:transactions] == true
|
204
|
-
temp = Transaction.find(temp, nil, nil, nil)
|
205
|
-
end
|
206
|
-
|
207
|
-
## Get Filings for entity
|
208
|
-
if options[:filings] && options[:filings].is_a?(Hash)
|
209
|
-
temp = Filing.find(
|
210
|
-
temp,
|
211
|
-
options[:filings][:start],
|
212
|
-
options[:filings][:count],
|
213
|
-
options[:filings][:limit])
|
214
|
-
elsif options[:filings] && options[:filings] == true
|
215
|
-
temp = Filing.find(temp, nil, nil, nil)
|
216
|
-
end
|
217
|
-
|
218
|
-
temp
|
219
|
-
end
|
220
63
|
end
|
221
64
|
end
|
data/lib/sec_query/filing.rb
CHANGED
@@ -4,7 +4,8 @@ module SecQuery
|
|
4
4
|
# => SecQuery::Filing
|
5
5
|
# SecQuery::Filing requests and parses filings for any given SecQuery::Entity
|
6
6
|
class Filing
|
7
|
-
COLUMNS = :cik, :title, :summary, :link, :term, :date, :file_id
|
7
|
+
COLUMNS = [:cik, :title, :summary, :link, :term, :date, :file_id]
|
8
|
+
|
8
9
|
attr_accessor(*COLUMNS)
|
9
10
|
|
10
11
|
def initialize(filing)
|
@@ -81,31 +82,34 @@ module SecQuery
|
|
81
82
|
end
|
82
83
|
end
|
83
84
|
|
84
|
-
def self.find(
|
85
|
-
|
86
|
-
|
87
|
-
url
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
85
|
+
def self.find(cik, start = 0, count = 80)
|
86
|
+
temp = {}
|
87
|
+
temp[:url] = SecURI.browse_edgar_uri({cik: cik})
|
88
|
+
temp[:url][:action] = :getcompany
|
89
|
+
temp[:url][:start] = start
|
90
|
+
temp[:url][:count] = count
|
91
|
+
response = Entity.query(temp[:url].output_atom.to_s)
|
92
|
+
document = Nokogiri::HTML(response)
|
93
|
+
parse(cik, document)
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.parse(cik, document)
|
97
|
+
filings = []
|
98
|
+
if document.xpath('//content').to_s.length > 0
|
99
|
+
document.xpath('//content').each do |e|
|
100
|
+
if e.xpath('//content/accession-nunber').to_s.length > 0
|
101
|
+
content = Hash.from_xml(e.to_s)['content']
|
102
|
+
content[:cik] = cik
|
103
|
+
content[:file_id] = content.delete('accession_nunber')
|
104
|
+
content[:date] = content.delete('filing_date')
|
105
|
+
content[:link] = content.delete('filing_href')
|
106
|
+
content[:term] = content.delete('filing_type')
|
107
|
+
content[:title] = content.delete('form_name')
|
108
|
+
filings << Filing.new(content)
|
109
|
+
end
|
110
|
+
end
|
108
111
|
end
|
112
|
+
filings
|
109
113
|
end
|
110
114
|
end
|
111
115
|
end
|
data/lib/sec_query/sec_uri.rb
CHANGED
data/lib/sec_query/version.rb
CHANGED
data/sec_query.gemspec
CHANGED
@@ -24,6 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.add_development_dependency 'vcr', '~> 2.9'
|
25
25
|
s.add_development_dependency 'webmock', '~> 1.17'
|
26
26
|
s.add_development_dependency 'rubocop', '~> 0.20'
|
27
|
+
s.add_development_dependency 'addressable', '~> 2.3'
|
27
28
|
s.add_runtime_dependency 'rest-client', '~> 1.6'
|
28
|
-
s.add_runtime_dependency '
|
29
|
+
s.add_runtime_dependency 'nokogiri', '~> 1.6'
|
29
30
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
include SecQuery
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
# Note: Shared Methods are available in spec_helper.rb
|
5
|
+
|
6
|
+
describe SecQuery::Entity do
|
7
|
+
|
8
|
+
describe "Company Queries", vcr: { cassette_name: "aapl"} do
|
9
|
+
|
10
|
+
let(:query){{name: "APPLE INC", sic: "3571", symbol: "aapl", cik:"0000320193"}}
|
11
|
+
|
12
|
+
[:symbol, :cik, :name].each do |key|
|
13
|
+
context "when quering by #{key}" do
|
14
|
+
describe "as hash" do
|
15
|
+
|
16
|
+
let(:entity){ SecQuery::Entity.find({ key => query[key] }) }
|
17
|
+
|
18
|
+
it "should be valid" do
|
19
|
+
is_valid?(entity)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should have a valid mailing address" do
|
23
|
+
is_valid_address?(entity.mailing_address)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should have a valid business address" do
|
27
|
+
is_valid_address?(entity.business_address)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "as string" do
|
32
|
+
it "should be valid" do
|
33
|
+
entity = SecQuery::Entity.find(query[key])
|
34
|
+
is_valid?(entity)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "People Queries", vcr: { cassette_name: "Steve Jobs"} do
|
42
|
+
|
43
|
+
let(:query){ { name: "JOBS STEVEN P", :cik => "0001007844" } }
|
44
|
+
|
45
|
+
[:cik, :name].each do |key|
|
46
|
+
context "when quering by #{key}" do
|
47
|
+
describe "as hash" do
|
48
|
+
|
49
|
+
let(:entity){ SecQuery::Entity.find({ key => query[key] }) }
|
50
|
+
|
51
|
+
it "should be valid" do
|
52
|
+
is_valid?(entity)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should have a valid mailing address" do
|
56
|
+
is_valid_address?(entity.mailing_address)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should have a valid business address" do
|
60
|
+
is_valid_address?(entity.business_address)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "as string" do
|
65
|
+
it "should be valid" do
|
66
|
+
entity = SecQuery::Entity.find(query[key])
|
67
|
+
is_valid?(entity)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
3
2
|
include SecQuery
|
4
3
|
require 'spec_helper'
|
5
4
|
|
@@ -38,4 +37,48 @@ describe SecQuery::Filing do
|
|
38
37
|
end
|
39
38
|
end
|
40
39
|
end
|
40
|
+
|
41
|
+
describe "::find" do
|
42
|
+
let(:query){{
|
43
|
+
name: "JOBS STEVEN P", :cik => "0001007844",
|
44
|
+
relationships:[
|
45
|
+
{cik: "0000320193", name: "APPLE INC"},
|
46
|
+
{cik: "0001001039", name: "WALT DISNEY CO/"},
|
47
|
+
{cik: "0001002114", name: "PIXAR \\CA\\"}
|
48
|
+
],
|
49
|
+
transactions:[
|
50
|
+
{filing_number: "0001181431-07-052839", reporting_owner: "APPLE INC", shares:120000.0},
|
51
|
+
{filing_number: "0001181431-07-052839", reporting_owner: "APPLE INC", shares: 40000.0},
|
52
|
+
{filing_number: "0001181431-07-052839", reporting_owner: "APPLE INC", shares: 40000.0},
|
53
|
+
{filing_number: "0001181431-07-052839", reporting_owner: "APPLE INC", shares: 40000.0},
|
54
|
+
{filing_number: "0001181431-06-028746", reporting_owner: "WALT DISNEY CO/", shares: 138000004.0},
|
55
|
+
{filing_number: "0001356184-06-000008", reporting_owner: "PIXAR \\CA\\", shares: 60000002.0},
|
56
|
+
{filing_number: "0001181431-06-019230", reporting_owner: "APPLE COMPUTER INC", shares: 4573553.0},
|
57
|
+
{filing_number: "0001181431-06-028747", reporting_owner: "WALT DISNEY CO/", shares: 0.0}
|
58
|
+
],
|
59
|
+
filings:[
|
60
|
+
{cik: "0001007844", file_id: "0001181431-07-052839"},
|
61
|
+
{cik: "0001007844", file_id: "0001356184-06-000008"},
|
62
|
+
{cik: "0001007844", file_id: "0001193125-06-103741"},
|
63
|
+
{cik: "0001007844", file_id: "0001181431-06-028747"},
|
64
|
+
{cik: "0001007844", file_id: "0001181431-06-028746"},
|
65
|
+
{cik: "0001007844", file_id: "0001181431-06-019230"},
|
66
|
+
{cik: "0001007844", file_id: "0001193125-06-019727"},
|
67
|
+
{cik: "0001007844", file_id: "0001104659-03-004723"}
|
68
|
+
]
|
69
|
+
}}
|
70
|
+
|
71
|
+
let(:entity) {SecQuery::Entity.find(query[:cik])}
|
72
|
+
|
73
|
+
describe "Filings", vcr: { cassette_name: "Steve Jobs"} do
|
74
|
+
it "should respond to filings" do
|
75
|
+
entity.should respond_to(:filings)
|
76
|
+
entity.filings.should be_kind_of(Array)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should be valid filing" do
|
80
|
+
is_valid_filing?(entity.filings.first)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
41
84
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
include SecQuery
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe SecQuery::Filing do
|
5
|
+
context "Owner" do
|
6
|
+
describe "Transactions", vcr: { cassette_name: "Steve Jobs"} do
|
7
|
+
let(:query){{
|
8
|
+
name: "JOBS STEVEN P", :cik => "0001007844",
|
9
|
+
transactions:[
|
10
|
+
{filing_number: "0001181431-07-052839", reporting_owner: "APPLE INC", shares:120000.0},
|
11
|
+
{filing_number: "0001181431-07-052839", reporting_owner: "APPLE INC", shares: 40000.0},
|
12
|
+
{filing_number: "0001181431-07-052839", reporting_owner: "APPLE INC", shares: 40000.0},
|
13
|
+
{filing_number: "0001181431-07-052839", reporting_owner: "APPLE INC", shares: 40000.0},
|
14
|
+
{filing_number: "0001181431-06-028746", reporting_owner: "WALT DISNEY CO/", shares: 138000004.0},
|
15
|
+
{filing_number: "0001356184-06-000008", reporting_owner: "PIXAR \\CA\\", shares: 60000002.0},
|
16
|
+
{filing_number: "0001181431-06-019230", reporting_owner: "APPLE COMPUTER INC", shares: 4573553.0},
|
17
|
+
{filing_number: "0001181431-06-028747", reporting_owner: "WALT DISNEY CO/", shares: 0.0}
|
18
|
+
]
|
19
|
+
}}
|
20
|
+
|
21
|
+
let(:entity) {SecQuery::Entity.find(query[:cik])}
|
22
|
+
|
23
|
+
# it "should respond to transactions" do
|
24
|
+
# entity.should respond_to(:transactions)
|
25
|
+
# entity.filings.should be_kind_of(Array)
|
26
|
+
# end
|
27
|
+
|
28
|
+
# it "should be valid transaction" do
|
29
|
+
# entity.transactions.first.inspect
|
30
|
+
# #is_valid_filing?(entity.filings.first)
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# it "should respond to content" do
|
34
|
+
# entity.filings.first.should respond_to(:content)
|
35
|
+
# puts entity.filings.first.content
|
36
|
+
# end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -4,3 +4,26 @@ require 'rubygems'
|
|
4
4
|
require 'bundler/setup'
|
5
5
|
require 'sec_query'
|
6
6
|
require 'support/vcr'
|
7
|
+
|
8
|
+
def is_valid?(entity)
|
9
|
+
entity.should_not be_nil
|
10
|
+
entity.name.should == query[:name]
|
11
|
+
entity.cik.should == query[:cik]
|
12
|
+
entity.instance_variables.each do |key|
|
13
|
+
SecQuery::Entity::COLUMNS.should include(key[1..-1].to_sym)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def is_valid_address?(address)
|
18
|
+
address.should_not be_nil
|
19
|
+
address.keys.each do |key|
|
20
|
+
['city', 'state', 'street1', 'street2', 'type', 'zip', 'phone'].should include(key)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def is_valid_filing?(filing)
|
25
|
+
filing.should_not be_nil
|
26
|
+
filing.instance_variables.each do |key|
|
27
|
+
SecQuery::Filing::COLUMNS.should include(key[1..-1].to_sym)
|
28
|
+
end
|
29
|
+
end
|
metadata
CHANGED
@@ -1,99 +1,113 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sec_query
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ty Rauber
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-05-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '2.14'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2.14'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: vcr
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '2.9'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '2.9'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: webmock
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '1.17'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.17'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rubocop
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - ~>
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0.20'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0.20'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: addressable
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.3'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.3'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rest-client
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
72
86
|
requirements:
|
73
|
-
- - ~>
|
87
|
+
- - "~>"
|
74
88
|
- !ruby/object:Gem::Version
|
75
89
|
version: '1.6'
|
76
90
|
type: :runtime
|
77
91
|
prerelease: false
|
78
92
|
version_requirements: !ruby/object:Gem::Requirement
|
79
93
|
requirements:
|
80
|
-
- - ~>
|
94
|
+
- - "~>"
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '1.6'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
98
|
+
name: nokogiri
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
|
-
- - ~>
|
101
|
+
- - "~>"
|
88
102
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
103
|
+
version: '1.6'
|
90
104
|
type: :runtime
|
91
105
|
prerelease: false
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
93
107
|
requirements:
|
94
|
-
- - ~>
|
108
|
+
- - "~>"
|
95
109
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
110
|
+
version: '1.6'
|
97
111
|
description: Search for company or person, by name, symbol or Central Index Key (CIK),
|
98
112
|
and retrieve relationships, transactions and filings.
|
99
113
|
email:
|
@@ -102,7 +116,7 @@ executables: []
|
|
102
116
|
extensions: []
|
103
117
|
extra_rdoc_files: []
|
104
118
|
files:
|
105
|
-
- .gitignore
|
119
|
+
- ".gitignore"
|
106
120
|
- Gemfile
|
107
121
|
- README.md
|
108
122
|
- Rakefile
|
@@ -113,13 +127,11 @@ files:
|
|
113
127
|
- lib/sec_query/sec_uri.rb
|
114
128
|
- lib/sec_query/transaction.rb
|
115
129
|
- lib/sec_query/version.rb
|
116
|
-
- pkg/sec_query-1.0.1.gem
|
117
|
-
- pkg/sec_query-1.0.2.gem
|
118
|
-
- pkg/sec_query-1.0.3.gem
|
119
130
|
- sec_query.gemspec
|
131
|
+
- spec/sec_query/entity_spec.rb
|
120
132
|
- spec/sec_query/filing_spec.rb
|
121
|
-
- spec/sec_query/sec_query_spec.rb
|
122
133
|
- spec/sec_query/sec_uri_spec.rb
|
134
|
+
- spec/sec_query/transaction_spec.rb
|
123
135
|
- spec/spec_helper.rb
|
124
136
|
- spec/support/vcr.rb
|
125
137
|
homepage: https://github.com/tyrauber/sec_query
|
@@ -132,12 +144,12 @@ require_paths:
|
|
132
144
|
- lib
|
133
145
|
required_ruby_version: !ruby/object:Gem::Requirement
|
134
146
|
requirements:
|
135
|
-
- -
|
147
|
+
- - ">="
|
136
148
|
- !ruby/object:Gem::Version
|
137
149
|
version: '0'
|
138
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
139
151
|
requirements:
|
140
|
-
- -
|
152
|
+
- - ">="
|
141
153
|
- !ruby/object:Gem::Version
|
142
154
|
version: '0'
|
143
155
|
requirements: []
|
@@ -148,9 +160,9 @@ specification_version: 4
|
|
148
160
|
summary: A ruby gem for querying the United States Securities and Exchange Commission
|
149
161
|
Edgar System.
|
150
162
|
test_files:
|
163
|
+
- spec/sec_query/entity_spec.rb
|
151
164
|
- spec/sec_query/filing_spec.rb
|
152
|
-
- spec/sec_query/sec_query_spec.rb
|
153
165
|
- spec/sec_query/sec_uri_spec.rb
|
166
|
+
- spec/sec_query/transaction_spec.rb
|
154
167
|
- spec/spec_helper.rb
|
155
168
|
- spec/support/vcr.rb
|
156
|
-
has_rdoc:
|
@@ -1,129 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
include SecQuery
|
4
|
-
require 'spec_helper'
|
5
|
-
|
6
|
-
describe SecQuery::Entity do
|
7
|
-
|
8
|
-
describe 'Company Queries', vcr: { cassette_name: 'aapl' } do
|
9
|
-
|
10
|
-
let(:apple) do
|
11
|
-
{ name: 'APPLE INC', sic: '3571', symbol: 'aapl', cik: '0000320193' }
|
12
|
-
end
|
13
|
-
|
14
|
-
context 'when quering by stock symbol' do
|
15
|
-
it 'lazely' do
|
16
|
-
entity = SecQuery::Entity.find(apple[:symbol])
|
17
|
-
entity.cik.should eql(apple[:cik])
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'explicitly' do
|
21
|
-
entity = SecQuery::Entity.find(symbol: apple[:symbol])
|
22
|
-
entity.cik.should eql(apple[:cik])
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
context 'when querying by entity name' do
|
27
|
-
it 'lazely' do
|
28
|
-
entity = SecQuery::Entity.find(apple[:name])
|
29
|
-
entity.cik.should eql(apple[:cik])
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'explicitly' do
|
33
|
-
entity = SecQuery::Entity.find(name: apple[:name])
|
34
|
-
entity.cik.should eql(apple[:cik])
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
context 'when querying by cik' do
|
39
|
-
it 'lazely' do
|
40
|
-
entity = SecQuery::Entity.find(apple[:cik])
|
41
|
-
entity.name.should match(apple[:name])
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'explicitly' do
|
45
|
-
entity = SecQuery::Entity.find(cik: apple[:cik])
|
46
|
-
entity.name.should match(apple[:name])
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
describe 'People Queries', vcr: { cassette_name: 'Steve Jobs' } do
|
52
|
-
let(:jobs) do
|
53
|
-
{ first: 'Steve', middle: 'P', last: 'Jobs', cik: '0001007844' }
|
54
|
-
end
|
55
|
-
|
56
|
-
context 'when querying by name' do
|
57
|
-
it 'first, middle and last name' do
|
58
|
-
entity = SecQuery::Entity.find(
|
59
|
-
first: jobs[:first],
|
60
|
-
middle: jobs[:middle],
|
61
|
-
last: jobs[:last])
|
62
|
-
entity.cik.should eql(jobs[:cik])
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
describe 'Relationships, Transactions and Filings', vcr: { cassette_name: 'Steve Jobs' } do
|
68
|
-
## Using Steve, because data should not change in the future. RIP.
|
69
|
-
|
70
|
-
let(:jobs) do
|
71
|
-
{ first: 'Steve', middle: 'P', last: 'Jobs', cik: '0001007844',
|
72
|
-
relationships: [
|
73
|
-
{ cik: '0000320193', name: 'APPLE INC' },
|
74
|
-
{ cik: '0001001039', name: 'WALT DISNEY CO/' },
|
75
|
-
{ cik: '0001002114', name: 'PIXAR \\CA\\' }
|
76
|
-
],
|
77
|
-
transactions: [
|
78
|
-
{ filing_number: '0001181431-07-052839', reporting_owner: 'APPLE INC', shares: 120000.0 },
|
79
|
-
{ filing_number: '0001181431-07-052839', reporting_owner: 'APPLE INC', shares: 40000.0 },
|
80
|
-
{ filing_number: '0001181431-07-052839', reporting_owner: 'APPLE INC', shares: 40000.0 },
|
81
|
-
{ filing_number: '0001181431-07-052839', reporting_owner: 'APPLE INC', shares: 40000.0 },
|
82
|
-
{ filing_number: '0001181431-06-028746', reporting_owner: 'WALT DISNEY CO/', shares: 138000004.0 },
|
83
|
-
{ filing_number: '0001356184-06-000008', reporting_owner: 'PIXAR \\CA\\', shares: 60000002.0 },
|
84
|
-
{ filing_number: '0001181431-06-019230', reporting_owner: 'APPLE COMPUTER INC', shares: 4573553.0 },
|
85
|
-
{ filing_number: '0001181431-06-028747', reporting_owner: 'WALT DISNEY CO/', shares: 0.0 }
|
86
|
-
],
|
87
|
-
filings: [
|
88
|
-
{ cik: '0001007844', file_id: '0001181431-07-052839' },
|
89
|
-
{ cik: '0001007844', file_id: '0001356184-06-000008' },
|
90
|
-
{ cik: '0001007844', file_id: '0001193125-06-103741' },
|
91
|
-
{ cik: '0001007844', file_id: '0001181431-06-028747' },
|
92
|
-
{ cik: '0001007844', file_id: '0001181431-06-028746' },
|
93
|
-
{ cik: '0001007844', file_id: '0001181431-06-019230' },
|
94
|
-
{ cik: '0001007844', file_id: '0001193125-06-019727' },
|
95
|
-
{ cik: '0001007844', file_id: '0001104659-03-004723' }
|
96
|
-
]
|
97
|
-
}
|
98
|
-
end
|
99
|
-
|
100
|
-
let(:entity) do
|
101
|
-
SecQuery::Entity.find(
|
102
|
-
{ first: 'Steve',
|
103
|
-
middle: 'P',
|
104
|
-
last: 'Jobs',
|
105
|
-
cik: '0001007844' },
|
106
|
-
true)
|
107
|
-
end
|
108
|
-
|
109
|
-
context 'when quering entities with option "true"' do
|
110
|
-
it 'should provide relationships' do
|
111
|
-
entity.relationships.each_with_index do |r, i|
|
112
|
-
r.cik.should eql(jobs[:relationships][i][:cik])
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
it 'should provide transactions' do
|
117
|
-
entity.transactions.each_with_index do |t, i|
|
118
|
-
t.filing_number.should eql(jobs[:transactions][i][:filing_number])
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
it 'should provide filings' do
|
123
|
-
entity.filings.each_with_index do |f, i|
|
124
|
-
f.file_id.should eql(jobs[:filings][i][:file_id])
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|