hulse 0.5 → 0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +17 -1
- data/hulse.gemspec +1 -0
- data/lib/hulse/house_floor.rb +40 -0
- data/lib/hulse/record.rb +104 -0
- data/lib/hulse/version.rb +1 -1
- data/lib/hulse.rb +3 -0
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 24805bee84bd7c6a90544f7d70c98c0eb32661c2
|
4
|
+
data.tar.gz: f8e91bcffaca717a42d71e1f5bd1903fa52da684
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3171a1108d9677464ff0ddd67f3780ae37128dd0118f68efba14215f1033647ebd92fd19d6da0fbf7d7e14a14dce7649ddd17a48f702638f6770a393e06465eb
|
7
|
+
data.tar.gz: c7739d66a725f05131c0d4e696a6647bd0c2b535eb453a9ef06b52a53e26459516673e1a420b097936aed8da074bbdfaa5acdcad1187151b8074255d7c6e9e34
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Hulse
|
2
2
|
|
3
|
-
Hulse is a Ruby gem for accessing
|
3
|
+
Hulse is a Ruby gem for accessing raw data and information published by and about the U.S. Congress. It works using Ruby 1.9.3, 2.0, 2.1 and 2.2. It is not a wrapper for existing non-governmental APIs of congressional information. Instead, it loads, parses and scrapes official sources.
|
4
|
+
|
5
|
+
Hulse can be used to get House and Senate roll call votes from the official sources on [house.gov](http://clerk.house.gov/evs/2013/index.asp) and [senate.gov](http://www.senate.gov/pagelayout/legislative/a_three_sections_with_teasers/votes.htm).
|
4
6
|
|
5
7
|
Hulse has two vote classes, `HouseVote` and `SenateVote`, which create Ruby objects using the XML attributes available from roll call vote data (voice votes are not covered by Hulse or available as data from official sources). Hulse makes a few changes, renaming some attributes for clarity and consistency, and collapsing each House vote's date and time into a single datetime attribute. Otherwise it does not alter the original data.
|
6
8
|
|
@@ -8,6 +10,8 @@ Hulse has two vote classes, `HouseVote` and `SenateVote`, which create Ruby obje
|
|
8
10
|
|
9
11
|
Hulse also has two member classes, `HouseMember` and `SenateMember`, which create Ruby objects using the XML made available by the Clerk of the House and the Secretary of the Senate. House members have some basic information, including the unique `bioguide_id`, along with office details and committee and subcommittee assignment data. For vacant seats, information on the seat's previous occupant is available. Senate members have less information, but their data includes the Senate class and the URLs of their websites and email forms.
|
10
12
|
|
13
|
+
Hulse has two other classes, `HouseFloor` and `Record`. The former provides a wrapper to [XML data on floor activity](http://clerk.house.gov/floorsummary/floor.aspx?day=20150729) published by the Clerk of the House, including timestamps and descriptions. The `Record` class provides a basic wrapper to the [Congressional Record](https://www.congress.gov/congressional-record), the daily listing of activities by the House and Senate, as well as some methods for accessing specific portions of it, particularly the titles and permalinks of articles.
|
14
|
+
|
11
15
|
Hulse is named for [Carl Hulse](https://www.nytimes.com/learning/students/ask_reporters/Carl_Hulse.html), a longtime congressional correspondent for The New York Times.
|
12
16
|
|
13
17
|
## Installation
|
@@ -47,6 +51,18 @@ For Senate votes, you can grab a year's SenateVote objects (with a limited set o
|
|
47
51
|
2.0.0p353 :007 > senate_2013.first
|
48
52
|
=> <Hulse::SenateVote:0x000001017f0d58 @congress=113, @session=1, @year=2013, @vote_number="00291", @vote_date=<Date: 2013-12-20 ((2456647j,0s,0n),+0s,2299161j)>, @issue="PN921", @question="On the Cloture Motion", @vote_result="Agreed to", @vote_count={:yeas=>"59", :nays=>"34"}, @vote_title="Motion to Invoke Cloture on the Nomination of Janet L. Yellen to be Chairman of the Board of Governors of the Federal Reserve System">
|
49
53
|
```
|
54
|
+
House and Senate members have a `current` class method that retrieves the latest XML data from the House and Senate websites and creates Ruby objects. The House file has more data, including vacancies, than the Senate file does.
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
irb(main):003:> require 'hulse'
|
58
|
+
irb(main):003:0> members = Hulse::HouseMember.current
|
59
|
+
irb(main):004:0> members.first
|
60
|
+
=> <Hulse::HouseMember:0x007fc6cb37f020 @bioguide_id="Y000033", @sort_name="YOUNG,DON", @last_name="Young", @first_name="Don", @middle_name=nil, @suffix=nil, @courtesy="Mr.", @official_name="Don Young", @formal_name="Mr. Young of Alaska", @party="R", @caucus_party="R", @state_postal="AK", @state_name="Alaska", @district="At Large", @district_code="AK00", @hometown="Fort Yukon", @office_building="RHOB", @office_room="2314", @office_zip="20515-0200", @phone="(202) 225-5765", @last_elected_date=#<Date: 2014-11-04 ((2456966j,0s,0n),+0s,2299161j)>, @sworn_date=#<Date: 2015-01-12 ((2457035j,0s,0n),+0s,2299161j)>, @committees=[{"comcode"=>"II00", "rank"=>"2"}, {"comcode"=>"PW00", "rank"=>"2"}], @subcommittees=[{"subcomcode"=>"II10", "rank"=>"2"}, {"subcomcode"=>"II13", "rank"=>"2"}, {"subcomcode"=>"II24", "rank"=>"1", "leadership"=>"Chairman"}, {"subcomcode"=>"PW05", "rank"=>"2"}, {"subcomcode"=>"PW07", "rank"=>"2"}, {"subcomcode"=>"PW12", "rank"=>"2"}], @is_vacant=false, @footnote=nil, @predecessor=nil, @vacancy_date=nil>
|
61
|
+
```
|
62
|
+
|
63
|
+
## Tests
|
64
|
+
|
65
|
+
Hulse uses `MiniTest` for development. To run the tests, do `rake test`.
|
50
66
|
|
51
67
|
## Authors
|
52
68
|
|
data/hulse.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_development_dependency "rake"
|
23
23
|
spec.add_development_dependency "minitest"
|
24
24
|
spec.add_dependency "httparty"
|
25
|
+
spec.add_dependency "nokogiri"
|
25
26
|
spec.add_dependency "oj"
|
26
27
|
spec.add_dependency "american_date"
|
27
28
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Hulse
|
2
|
+
class HouseFloor
|
3
|
+
|
4
|
+
attr_reader :legislative_day, :finished, :actions, :congress, :session, :url, :next_session
|
5
|
+
|
6
|
+
def initialize(params={})
|
7
|
+
params.each_pair do |k,v|
|
8
|
+
instance_variable_set("@#{k}", v)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.latest_dates
|
13
|
+
url = "http://clerk.house.gov/floorsummary/floor-rss.ashx"
|
14
|
+
response = HTTParty.get(url)
|
15
|
+
xml = response.parsed_response
|
16
|
+
xml['rss']['channel']['item'].map{|i| Date.parse(i['pubDate']).to_s}.uniq
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.date(date)
|
20
|
+
url = "http://clerk.house.gov/floorsummary/Download.aspx?file=#{date.to_s.gsub('-','')}.xml"
|
21
|
+
response = HTTParty.get(url)
|
22
|
+
xml = HTTParty::Parser.call(response.parsed_response, :xml)
|
23
|
+
self.create_from_xml(xml)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.create_from_xml(xml)
|
27
|
+
actions = []
|
28
|
+
xml['legislative_activity']['floor_actions']['floor_action'].each do |action|
|
29
|
+
actions << action.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
30
|
+
end
|
31
|
+
results = self.new(congress: xml['legislative_activity']['legislative_congress']['congress'].to_i,
|
32
|
+
session: xml['legislative_activity']['legislative_congress']['session'].to_i,
|
33
|
+
legislative_day: xml['legislative_activity']['legislative_day']['__content__'].strip,
|
34
|
+
finished: xml['legislative_activity']['floor_actions']['legislative_day_finished']['__content__'],
|
35
|
+
url: "http://clerk.house.gov/floorsummary/floor.aspx?day=#{xml['legislative_activity']['legislative_day']['date']}",
|
36
|
+
next_session: DateTime.parse(xml['legislative_activity']['floor_actions']['legislative_day_finished']['next_legislative_day_convenes']),
|
37
|
+
actions: actions)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/hulse/record.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
module Hulse
|
2
|
+
class Record
|
3
|
+
|
4
|
+
attr_reader :date, :section, :topics, :html
|
5
|
+
|
6
|
+
def initialize(params={})
|
7
|
+
params.each_pair do |k,v|
|
8
|
+
instance_variable_set("@#{k}", v)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
section
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.base_url(date=nil)
|
17
|
+
if date
|
18
|
+
year, month, day = date.year, date.month, date.day
|
19
|
+
else
|
20
|
+
date = Date.today-1
|
21
|
+
year, month, day = date.year, date.month, date.day
|
22
|
+
end
|
23
|
+
"https://www.congress.gov/congressional-record/#{year}/#{month}/#{day}/"
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.daily_digest(date=nil)
|
27
|
+
doc = HTTParty.get(base_url(date)+'daily-digest')
|
28
|
+
html = Nokogiri::HTML(doc.parsed_response)
|
29
|
+
(html/:pre).text
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.senate(date=nil)
|
33
|
+
doc = HTTParty.get(base_url(date)+'senate-section')
|
34
|
+
create_from_html(Nokogiri::HTML(doc.parsed_response), date, 'senate')
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.house(date=nil)
|
38
|
+
doc = HTTParty.get(base_url(date)+'house-section')
|
39
|
+
create_from_html(Nokogiri::HTML(doc.parsed_response), date, 'house')
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.extension_of_remarks(date=nil)
|
43
|
+
doc = HTTParty.get(base_url(date)+'extensions-of-remarks-section')
|
44
|
+
create_from_html(Nokogiri::HTML(doc.parsed_response), date, 'extension')
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.create_from_html(html, date, section)
|
48
|
+
section_topics = topics(html)
|
49
|
+
self.new(date: date,
|
50
|
+
section: section,
|
51
|
+
topics: section_topics,
|
52
|
+
html: html
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.topics(html)
|
57
|
+
(html/:td).map{|d| d.children[1]}.compact.map{|l| {url: l['href'], title: l.text.strip}}
|
58
|
+
end
|
59
|
+
|
60
|
+
def has_senate_explanations?
|
61
|
+
topics.select{|l| l[:title].include?("VOTE EXPLANATION")}.empty? ? false : true
|
62
|
+
end
|
63
|
+
|
64
|
+
def senate_explanations
|
65
|
+
topics.select{|l| l[:title].include?("VOTE EXPLANATION")}
|
66
|
+
end
|
67
|
+
|
68
|
+
def has_personal_explanations?
|
69
|
+
topics.select{|l| l[:title].include?("PERSONAL EXPLANATION")}.empty? ? false : true
|
70
|
+
end
|
71
|
+
|
72
|
+
def personal_explanations
|
73
|
+
topics.select{|l| l[:title].include?("PERSONAL EXPLANATION")}
|
74
|
+
end
|
75
|
+
|
76
|
+
def has_committee_elections?
|
77
|
+
topics.select{|l| l[:title].include?("COMMITTEE ELECTION")}.empty? ? false : true
|
78
|
+
end
|
79
|
+
|
80
|
+
def committee_elections
|
81
|
+
topics.select{|l| l[:title].include?("COMMITTEE ELECTION")}
|
82
|
+
end
|
83
|
+
|
84
|
+
def has_committee_resignations?
|
85
|
+
topics.select{|l| l[:title].include?("COMMITTEE RESIGNATION")}.empty? ? false : true
|
86
|
+
end
|
87
|
+
|
88
|
+
def chairman_designations
|
89
|
+
topics.select{|l| l[:title].include?("DESIGNATING THE CHAIRMAN")}
|
90
|
+
end
|
91
|
+
|
92
|
+
def ranking_designations
|
93
|
+
topics.select{|l| l[:title].include?("DESIGNATING THE RANKING")}
|
94
|
+
end
|
95
|
+
|
96
|
+
def leaves_of_absence
|
97
|
+
topics.select{|l| l[:title].include?("LEAVE OF ABSENCE")}
|
98
|
+
end
|
99
|
+
|
100
|
+
def committee_leaves_of_absence
|
101
|
+
topics.select{|l| l[:title].include?("COMMITTEE LEAVE OF ABSENCE")}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/lib/hulse/version.rb
CHANGED
data/lib/hulse.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
require 'httparty'
|
2
2
|
require 'oj'
|
3
|
+
require 'nokogiri'
|
3
4
|
require "hulse/version"
|
5
|
+
require "hulse/record"
|
4
6
|
require "hulse/house_vote"
|
5
7
|
require "hulse/house_member"
|
8
|
+
require "hulse/house_floor"
|
6
9
|
require "hulse/senate_vote"
|
7
10
|
require "hulse/senate_member"
|
8
11
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hulse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.6'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Derek Willis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-08-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: nokogiri
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: oj
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,8 +123,10 @@ files:
|
|
109
123
|
- Rakefile
|
110
124
|
- hulse.gemspec
|
111
125
|
- lib/hulse.rb
|
126
|
+
- lib/hulse/house_floor.rb
|
112
127
|
- lib/hulse/house_member.rb
|
113
128
|
- lib/hulse/house_vote.rb
|
129
|
+
- lib/hulse/record.rb
|
114
130
|
- lib/hulse/senate_member.rb
|
115
131
|
- lib/hulse/senate_vote.rb
|
116
132
|
- lib/hulse/version.rb
|
@@ -136,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
136
152
|
version: '0'
|
137
153
|
requirements: []
|
138
154
|
rubyforge_project:
|
139
|
-
rubygems_version: 2.
|
155
|
+
rubygems_version: 2.4.5
|
140
156
|
signing_key:
|
141
157
|
specification_version: 4
|
142
158
|
summary: Hulse is a Ruby gem for accessing House and Senate roll call votes and member
|