hoverbird-ny-times-congress 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,12 +3,11 @@ NY Times Congress
3
3
 
4
4
  A Ruby wrapper for the New York Times Congress API.
5
5
  ---------------------
6
- The NY Times has graciously been scraping the web for data related to the United States Congress! This is a Ruby library and command-shell intended to make it even easier to get at that data and turn it into useful information.
6
+ The NY Times has been quietly scraping the web for data related to the United States Congress, and making the data freely available through a public [API](http://open.blogs.nytimes.com/2009/01/08/introducing-the-congress-api/). [ny-times-congress](http://github.com/hoverbird/ny-times-congress/) aims to make it even easier to write Ruby applications using this data, and also provides a command shell for interacting with the API directly.
7
7
 
8
8
  Introdushing Congresh
9
9
  ---------------------
10
- The Congress Shell (congresh for short/cute) is a simple interactive prompt for interacting with the API. It provides a few conveniences to make it easy to get at the current chambers of congress.
11
-
10
+ The Congress Shell (congresh for short/cute) is a simple interactive prompt that wraps IRB. It includes your API key (see setup below) and provides a few conveniences for test-driving the API.
12
11
 
13
12
  Congress.new
14
13
  ---------------------
@@ -16,7 +15,7 @@ You get a Congress object either by calling Congress.new with the session and ch
16
15
 
17
16
  current_senate = Senate
18
17
  current_house = House
19
- 2007_senate = Congressnew(109, 'senate')
18
+ 2007_senate = Congress.new(109, 'senate')
20
19
  2008_house = Congress.new(110, 'house')
21
20
 
22
21
  Through a Congress object, you can get a list of its representatives as a hash, keyed by congressional Bio ID.
@@ -26,15 +25,17 @@ Through a Congress object, you can get a list of its representatives as a hash,
26
25
  Legislator
27
26
  ---------------------
28
27
 
29
- hillary = senators.values.find {|legislator| legislator.name == "Hillary Clinton"}
28
+ $ senators.values.find {|legislator| legislator.name == "Hillary Clinton"}
30
29
 
31
30
  or
32
31
 
33
- hillary = senators['C001041']
32
+ $ senators['C001041']
34
33
 
35
- For full details on Bios and roles, use:
34
+ You can also grav a Legislator directly by their Bio ID. This call includes full details on the congressperson's roles, biographical info and more:
36
35
 
37
- Legislator.find('C001041')
36
+ $ Legislator.find('C001041')
37
+
38
+ When accessing a Legislator from a collection of congress members, they include only a limited set of attributes. However, the library will make a second API call and lazy-load full attributes if you ask for them specifically. So even though a Legislator object returned through Congress.members don't have the #gender attribute, if you call for a specific Legislators gender, that data will be fetched and populated just in time.
38
39
 
39
40
 
40
41
  Roll Call Votes
@@ -42,11 +43,29 @@ Roll Call Votes
42
43
 
43
44
  To find a vote in any congress, you need to know the session (usually 1 or 2, although rarely congress will go into a 3rd session) and then the ID of the vote:
44
45
 
45
- Senate.roll_call_vote(session_number, vote_number)
46
+ $ Senate.roll_call_vote(session_number, vote_number)
46
47
 
47
48
  You can also find recent votes for any given senator:
48
- hillary = Legislator.find('C001041')
49
- hillary.votes
49
+
50
+ $ hillary = Legislator.find('C001041')
51
+ $ hillary.votes
52
+
53
+
54
+ Setup
55
+ _____________________
56
+
57
+ Add Github to your rubygems sources (if you haven't already) and then install the gem:
58
+ $ gem sources -a http://gems.github.com
59
+ $ sudo gem install hoverbird-ny-times-congress
60
+
61
+ You'll also need to [get an API key]:http://developer.nytimes.com/apps/register from the [NY Times Developer Network]: http://developer.nytimes.com/. If you set the key returned to an environment variable as shown below, Congresh will pick it up and include it in all your requests. You can keep this in your bash profile, but I also recommend putting all your developer keys in a separate .api_keys file in your path
62
+
63
+ export NYTIMES_CONGRESS_API_KEY="123456789ETC"
64
+
65
+ Within your app, you can also set this directly like so:
66
+
67
+ NYTimes::Congress::Base.api_key = "123456789ETC"
68
+
50
69
 
51
70
  Acknowledgements
52
71
  ---------------------
data/Rakefile CHANGED
@@ -25,11 +25,14 @@ Rake::RDocTask.new do |rdoc|
25
25
  rdoc.rdoc_files.include('lib/**/*.rb')
26
26
  end
27
27
 
28
- require 'rake/testtask'
29
- Rake::TestTask.new(:test) do |t|
30
- t.libs << 'lib' << 'test'
31
- t.pattern = 'test/**/*_test.rb'
32
- t.verbose = false
28
+ begin
29
+ require 'spec/rake/spectask'
30
+ desc "Run all examples"
31
+ Spec::Rake::SpecTask.new('spec') do |t|
32
+ t.spec_files = FileList['spec/**/*_spec.rb']
33
+ end
34
+ rescue LoadError
35
+ puts "RSpec is not available. You'll need it to test ny-times-congress."
33
36
  end
34
37
 
35
38
  begin
@@ -50,4 +53,4 @@ rescue LoadError
50
53
  puts "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
51
54
  end
52
55
 
53
- task :default => :test
56
+ task :default => :spec
data/TODO ADDED
@@ -0,0 +1,2 @@
1
+ * Auto-fill current session number based on the year.
2
+ * Select congress members by state.
@@ -1,4 +1,4 @@
1
1
  ---
2
- :minor: 1
3
- :patch: 0
4
2
  :major: 1
3
+ :minor: 2
4
+ :patch: 0
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  include NYTimes::Congress
3
3
 
4
- if ENV['NYTIMES_CONGRESS_API_KEY']
5
- NYTimes::Congress::Base.api_key = ENV['NYTIMES_CONGRESS_API_KEY']
4
+ if ENV['NY_TIMES_CONGRESS_API_KEY']
5
+ NYTimes::Congress::Base.api_key = ENV['NY_TIMES_CONGRESS_API_KEY']
6
6
 
7
7
  Senate = Congress.new(111, :senate)
8
8
  House = Congress.new(111, :house)
@@ -39,17 +39,16 @@ module NYTimes
39
39
  end
40
40
 
41
41
  def roles_for(roles_array)
42
- roles_array.collect {|e| Role.new e}
42
+ roles_array.collect {|e| Role.new(e)}
43
43
  end
44
44
 
45
45
  def votes_for(votes_array)
46
- votes_array.collect {|vote_hash| RollCallVote.new vote_hash['vote'] }
46
+ votes_array.collect {|vote_hash| RollCallVote.new(vote_hash['vote'])}
47
47
  end
48
48
 
49
49
  def positions_for(votes_array)
50
50
  votes_array.collect do |vote_hash|
51
- vote = vote_hash['vote']
52
- Position.new vote['member_id'], vote['vote_position'], vote
51
+ Position.new(vote_hash['member_id'], vote_hash['vote_position'])
53
52
  end
54
53
  end
55
54
 
@@ -1,10 +1,10 @@
1
1
  module NYTimes
2
2
  module Congress
3
3
  class Base
4
- API_NAME = 'congress'
5
- API_SERVER = 'api.nytimes.com'
6
- API_VERSION = 2
7
- API_BASE = "/svc/politics/v#{API_VERSION}/us/legislative/#{API_NAME}"
4
+ API_NAME = 'congress'
5
+ API_SERVER = 'api.nytimes.com'
6
+ API_VERSION = 2
7
+ API_BASE = "/svc/politics/v#{API_VERSION}/us/legislative/#{API_NAME}"
8
8
 
9
9
  @@api_key = nil
10
10
  @@copyright = nil
@@ -40,7 +40,7 @@ module NYTimes
40
40
 
41
41
  full_params = params.merge 'api-key' => @@api_key
42
42
  uri = build_request_url(path, full_params)
43
-
43
+
44
44
  reply = uri.read
45
45
  reply = JSON.parse(reply)
46
46
 
@@ -64,7 +64,7 @@ module NYTimes
64
64
  EVAL
65
65
  end
66
66
  end
67
+
67
68
  end
68
-
69
69
  end
70
70
  end
@@ -5,12 +5,12 @@ module NYTimes
5
5
  include AttributeTransformation
6
6
 
7
7
  def initialize(number, chamber)
8
- @number = integer_for number
9
- @chamber = symbol_for chamber
8
+ @number = integer_for(number)
9
+ @chamber = symbol_for(chamber)
10
10
  raise AttributeError unless number && chamber
11
11
  end
12
12
 
13
- def members(params = {})
13
+ def members(params = {})
14
14
  @members ||= fetch_members
15
15
  end
16
16
 
@@ -36,8 +36,8 @@ module NYTimes
36
36
 
37
37
  def api_path
38
38
  "#{number}/#{chamber}"
39
- end
40
-
39
+ end
41
40
  end
41
+
42
42
  end
43
43
  end
@@ -5,14 +5,17 @@ module NYTimes
5
5
  ATTRIBUTE_MAP = { :date_for => [:date_of_birth],
6
6
  :roles_for => [:roles],
7
7
  :integer_for => [:govtrack_id, :district],
8
- :string_for => [:url, :state, :gender, :name, :party] }
8
+ :string_for => [:url, :state, :gender, :name, :party,
9
+ :missed_votes_pct, :votes_with_party_pct] }
9
10
 
10
11
  ATTRIBUTES = ATTRIBUTE_MAP.values.flatten
11
12
  ATTRIBUTES.each {|attribute| define_lazy_reader_for_attribute_named attribute }
12
13
 
13
14
  def self.find(id)
14
- response = invoke("members/#{id}.json")['results']
15
- new(response.first)
15
+ response = invoke("members/#{id}.json")
16
+ require 'ruby-debug'
17
+ debugger if response.inspect unless response.has_key?('results')
18
+ new(response['results'].first)
16
19
  end
17
20
  attr_reader :attributes, :id
18
21
 
@@ -46,7 +49,7 @@ module NYTimes
46
49
  end
47
50
 
48
51
  def load_fully
49
- full_legislator = self.class.find(id)
52
+ full_legislator = Legislator.find(id)
50
53
  attributes.merge!(full_legislator.attributes)
51
54
  @fully_loaded = true
52
55
  end
@@ -6,11 +6,10 @@ module NYTimes
6
6
 
7
7
  VALUES = ['Yes', 'No', 'Not Voting', 'Present', 'Speaker']
8
8
 
9
- def initialize(member_id, vote_position, vote)
10
- raise "Member ID required" unless member_id
9
+ def initialize(member_id, vote_position, vote = nil)
11
10
  @member_id = member_id
12
11
  @vote_position = vote_position
13
- @vote = RollCallVote.new(extra_attrs)
12
+ @vote = vote
14
13
  end
15
14
 
16
15
  def legislator
@@ -36,5 +35,3 @@ module NYTimes
36
35
  end
37
36
  end
38
37
  end
39
-
40
- # {"votes"=>[{"vote"=>{"chamber"=>"Senate", "time"=>"11:57:00", "date"=>"2008-06-10", "roll_call"=>"147", "session"=>"2", "member_id"=>"B001210", "congress"=>"110", "position"=>"Not Voting"}}], "total_votes"=>"100", "member_id"=>"B001210", "offset"=>"0"}
@@ -6,7 +6,8 @@ module NYTimes
6
6
  ATTRIBUTE_MAP = {
7
7
  :date_for => [:date],
8
8
  :integer_for => [:session_number, :congress, :roll_call],
9
- :string_for => [:chamber, :bill_number, :question, :vote_type, :time, :result, :description],
9
+ :symbol_for => [:chamber],
10
+ :string_for => [:bill_number, :question, :vote_type, :time, :result, :description],
10
11
  :positions_for => [:positions]
11
12
  }
12
13
  attr_reader *ATTRIBUTE_MAP.values.flatten
@@ -10,7 +10,7 @@ describe Base do
10
10
  end
11
11
 
12
12
  it "returns a string matching the expected URL" do
13
- url.should eql expected_url
13
+ url.should eql(expected_url)
14
14
  end
15
15
 
16
16
  end
@@ -22,8 +22,8 @@ describe Base do
22
22
  end
23
23
 
24
24
  it "makes a call to a given url and parses the returned JSON into a response hash" do
25
- FakeWeb.register_uri(api_url_for('congress/111/senate/members.json'), :string => example_data)
26
- @response = NYTimes::Congress::Base.invoke("congress/111/senate/members.json")
25
+ FakeWeb.register_uri(api_url_for('111/senate/members.json'), :string => example_data)
26
+ @response = NYTimes::Congress::Base.invoke("111/senate/members.json")
27
27
  response.should == JSON.parse(example_data)
28
28
  end
29
29
 
@@ -9,11 +9,11 @@ describe Congress do
9
9
 
10
10
  describe "initializing with a congress number and chamber symbol", :shared => true do
11
11
  it "is numbered with an Integer" do
12
- congress.number.should be_kind_of Integer
12
+ congress.number.should be_kind_of(Integer)
13
13
  end
14
14
 
15
15
  it "has a symbol representing the chamber" do
16
- congress.chamber.should be_kind_of Symbol
16
+ congress.chamber.should be_kind_of(Symbol)
17
17
  end
18
18
  end
19
19
 
@@ -29,7 +29,7 @@ describe Congress do
29
29
  attr_accessor :members
30
30
 
31
31
  def example_data
32
- File.read('example_data/members.json')
32
+ members_response
33
33
  end
34
34
 
35
35
  before do
@@ -38,13 +38,13 @@ describe Congress do
38
38
  end
39
39
 
40
40
  it "should return an hash of Legislators keyed by ID" do
41
- members.should be_kind_of Hash
41
+ members.should be_kind_of(Hash)
42
42
  members.values.all? {|e| e.class.should == Legislator}
43
- members['R000409'].name.should == "Dana Rohrabacher"
43
+ members['M000303'].name.should == "John McCain"
44
44
  end
45
45
 
46
46
  it "should return all members" do
47
- members.size.should == 448
47
+ members.size.should == 102
48
48
  end
49
49
 
50
50
  end
@@ -1,49 +1,75 @@
1
1
  def member_response
2
- File.read('example_data/member.json')
2
+ File.read(File.dirname(__FILE__) + '/member.json')
3
+ end
4
+
5
+ def members_response
6
+ File.read(File.dirname(__FILE__) + '/members.json')
7
+ end
8
+
9
+ def roll_call_votes_response
10
+ File.read(File.dirname(__FILE__) + '/roll_call_votes.json')
3
11
  end
4
12
 
5
13
  def limited_legislator_attributes
6
14
  <<-JSON
7
- {"id":"B000444",
8
- "name":"Joseph Biden",
9
- "party":"D",
10
- "state":"DE",
11
- "district":"N/A"}
15
+ {
16
+ "id": "L000304",
17
+ "name": "Joseph I. Lieberman",
18
+ "first_name": "Joseph I.",
19
+ "middle_name": "I.",
20
+ "last_name": "Lieberman",
21
+ "party": "ID",
22
+ "state": "CT",
23
+ "missed_votes_pct": "0.00",
24
+ "votes_with_party_pct": "93.44"
25
+ }
12
26
  JSON
13
27
  end
14
28
 
15
29
  def full_legislator_attributes
16
30
  <<-JSON
17
31
  {
18
- "member_id":"B000444",
19
- "name":"Joseph Biden",
20
- "date_of_birth":"1942-11-20",
21
- "gender":"M",
22
- "url":"http://biden.senate.gov",
23
- "govtrack_id":"300008",
24
- "roles":[
25
- {
26
- "congress":"111",
27
- "chamber":"Senate",
28
- "title":"Senator, 2nd Class",
29
- "state":"DE",
30
- "party":"D",
31
- "district":"N/A",
32
- "start_date":"2009-01-06",
33
- "end_date":"2009-01-20"
34
- },
32
+ "status":"OK",
33
+ "copyright":"Copyright (c) 2009 The New York Times Company. All Rights Reserved.",
34
+ "results":[
35
35
  {
36
- "congress":"110",
37
- "chamber":"Senate",
38
- "title":"Senator, 2nd Class",
39
- "state":"DE",
40
- "party":"D",
41
- "district":"N/A",
42
- "start_date":"2007-01-04",
43
- "end_date":"2009-01-03"
36
+ "member_id": "L000304",
37
+ "name": "Joseph I. Lieberman",
38
+ "first_name": "Joseph I.",
39
+ "middle_name": "I.",
40
+ "last_name": "Lieberman",
41
+ "date_of_birth": "1942-02-24",
42
+ "gender": "M",
43
+ "url": "http://lieberman.senate.gov/",
44
+ "govtrack_id": "300067",
45
+ "roles": [
46
+ {
47
+ "congress": "111",
48
+ "chamber": "Senate",
49
+ "title": "Senator, 1st Class",
50
+ "state": "CT",
51
+ "party": "ID",
52
+ "district": "N/A",
53
+ "start_date": "2009-01-06",
54
+ "end_date": "2011-01-04",
55
+ "missed_votes_pct": "0.00",
56
+ "votes_with_party_pct": "93.44"
57
+ }, {
58
+ "congress": "110",
59
+ "chamber": "Senate",
60
+ "title": "Senator, 1st Class",
61
+ "state": "CT",
62
+ "party": "ID",
63
+ "district": "N/A",
64
+ "start_date": "2007-01-04",
65
+ "end_date": "2009-01-03",
66
+ "missed_votes_pct": "3.20",
67
+ "votes_with_party_pct": "86.79"
68
+ }
69
+ ]
44
70
  }
45
- ]
46
- }
71
+ ]
72
+ }
47
73
  JSON
48
74
  end
49
75
 
@@ -5,6 +5,9 @@
5
5
  {
6
6
  "member_id": "L000304",
7
7
  "name": "Joseph I. Lieberman",
8
+ "first_name": "Joseph I.",
9
+ "middle_name": "I.",
10
+ "last_name": "Lieberman",
8
11
  "date_of_birth": "1942-02-24",
9
12
  "gender": "M",
10
13
  "url": "http://lieberman.senate.gov/",
@@ -18,7 +21,9 @@
18
21
  "party": "ID",
19
22
  "district": "N/A",
20
23
  "start_date": "2009-01-06",
21
- "end_date": "2011-01-04"
24
+ "end_date": "2011-01-04",
25
+ "missed_votes_pct": "0.00",
26
+ "votes_with_party_pct": "93.44"
22
27
  }, {
23
28
  "congress": "110",
24
29
  "chamber": "Senate",
@@ -27,7 +32,9 @@
27
32
  "party": "ID",
28
33
  "district": "N/A",
29
34
  "start_date": "2007-01-04",
30
- "end_date": "2009-01-03"
35
+ "end_date": "2009-01-03",
36
+ "missed_votes_pct": "3.20",
37
+ "votes_with_party_pct": "86.79"
31
38
  }, {
32
39
  "congress": "109",
33
40
  "chamber": "Senate",
@@ -36,7 +43,9 @@
36
43
  "party": "D",
37
44
  "district": "N/A",
38
45
  "start_date": "2005-01-04",
39
- "end_date": "2006-12-09"
46
+ "end_date": "2006-12-09",
47
+ "missed_votes_pct": "7.44",
48
+ "votes_with_party_pct": "88.78"
40
49
  }, {
41
50
  "congress": "108",
42
51
  "chamber": "Senate",
@@ -45,7 +54,9 @@
45
54
  "party": "D",
46
55
  "district": "N/A",
47
56
  "start_date": "2003-01-07",
48
- "end_date": "2004-12-08"
57
+ "end_date": "2004-12-08",
58
+ "missed_votes_pct": "39.11",
59
+ "votes_with_party_pct": "92.21"
49
60
  }, {
50
61
  "congress": "107",
51
62
  "chamber": "Senate",
@@ -54,7 +65,9 @@
54
65
  "party": "D",
55
66
  "district": "N/A",
56
67
  "start_date": "2001-01-03",
57
- "end_date": "2002-11-22"
68
+ "end_date": "2002-11-22",
69
+ "missed_votes_pct": "1.90",
70
+ "votes_with_party_pct": "92.11"
58
71
  }, {
59
72
  "congress": "106",
60
73
  "chamber": "Senate",
@@ -63,7 +76,9 @@
63
76
  "party": "D",
64
77
  "district": "N/A",
65
78
  "start_date": "1999-01-06",
66
- "end_date": "2000-12-15"
79
+ "end_date": "2000-12-15",
80
+ "missed_votes_pct": "10.12",
81
+ "votes_with_party_pct": "90.56"
67
82
  }, {
68
83
  "congress": "105",
69
84
  "chamber": "Senate",
@@ -72,7 +87,9 @@
72
87
  "party": "D",
73
88
  "district": "N/A",
74
89
  "start_date": "1997-01-07",
75
- "end_date": "1998-12-19"
90
+ "end_date": "1998-12-19",
91
+ "missed_votes_pct": "0.65",
92
+ "votes_with_party_pct": "85.03"
76
93
  }, {
77
94
  "congress": "104",
78
95
  "chamber": "Senate",
@@ -81,7 +98,9 @@
81
98
  "party": "D",
82
99
  "district": "N/A",
83
100
  "start_date": "1995-01-04",
84
- "end_date": "1996-10-04"
101
+ "end_date": "1996-10-04",
102
+ "missed_votes_pct": "1.21",
103
+ "votes_with_party_pct": "61.50"
85
104
  }, {
86
105
  "congress": "103",
87
106
  "chamber": "Senate",
@@ -90,7 +109,9 @@
90
109
  "party": "D",
91
110
  "district": "N/A",
92
111
  "start_date": "1993-01-05",
93
- "end_date": "1994-12-01"
112
+ "end_date": "1994-12-01",
113
+ "missed_votes_pct": "1.38",
114
+ "votes_with_party_pct": "83.94"
94
115
  }, {
95
116
  "congress": "102",
96
117
  "chamber": "Senate",
@@ -99,7 +120,9 @@
99
120
  "party": "D",
100
121
  "district": "N/A",
101
122
  "start_date": "1991-01-03",
102
- "end_date": "1993-01-03"
123
+ "end_date": "1993-01-03",
124
+ "missed_votes_pct": "1.09",
125
+ "votes_with_party_pct": "84.19"
103
126
  }, {
104
127
  "congress": "101",
105
128
  "chamber": "Senate",
@@ -108,8 +131,10 @@
108
131
  "party": "D",
109
132
  "district": "N/A",
110
133
  "start_date": "1989-01-03",
111
- "end_date": "1991-01-03"
134
+ "end_date": "1991-01-03",
135
+ "missed_votes_pct": "0.63",
136
+ "votes_with_party_pct": "84.86"
112
137
  } ]
113
138
  }
114
139
  ]
115
- }
140
+ }