congress_gov 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.
Files changed (33) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +13 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +156 -0
  5. data/lib/congress_gov/client.rb +125 -0
  6. data/lib/congress_gov/configuration.rb +48 -0
  7. data/lib/congress_gov/error.rb +46 -0
  8. data/lib/congress_gov/resources/amendment.rb +107 -0
  9. data/lib/congress_gov/resources/base.rb +74 -0
  10. data/lib/congress_gov/resources/bill.rb +199 -0
  11. data/lib/congress_gov/resources/bound_congressional_record.rb +48 -0
  12. data/lib/congress_gov/resources/clerk_vote.rb +125 -0
  13. data/lib/congress_gov/resources/committee.rb +136 -0
  14. data/lib/congress_gov/resources/committee_meeting.rb +37 -0
  15. data/lib/congress_gov/resources/committee_print.rb +50 -0
  16. data/lib/congress_gov/resources/committee_report.rb +65 -0
  17. data/lib/congress_gov/resources/congress_info.rb +32 -0
  18. data/lib/congress_gov/resources/crs_report.rb +17 -0
  19. data/lib/congress_gov/resources/daily_congressional_record.rb +48 -0
  20. data/lib/congress_gov/resources/hearing.rb +37 -0
  21. data/lib/congress_gov/resources/house_communication.rb +51 -0
  22. data/lib/congress_gov/resources/house_requirement.rb +36 -0
  23. data/lib/congress_gov/resources/house_vote.rb +127 -0
  24. data/lib/congress_gov/resources/law.rb +53 -0
  25. data/lib/congress_gov/resources/member.rb +151 -0
  26. data/lib/congress_gov/resources/nomination.rb +74 -0
  27. data/lib/congress_gov/resources/senate_communication.rb +51 -0
  28. data/lib/congress_gov/resources/summary.rb +27 -0
  29. data/lib/congress_gov/resources/treaty.rb +75 -0
  30. data/lib/congress_gov/response.rb +109 -0
  31. data/lib/congress_gov/version.rb +6 -0
  32. data/lib/congress_gov.rb +180 -0
  33. metadata +237 -0
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CongressGov
4
+ module Resources
5
+ # Access Congressional Research Service reports from the Congress.gov API.
6
+ class CrsReport < Base
7
+ # List CRS reports.
8
+ #
9
+ # @param limit [Integer]
10
+ # @param offset [Integer]
11
+ # @return [CongressGov::Response]
12
+ def list(limit: 20, offset: 0)
13
+ client.get('crsreport', { limit: limit, offset: offset })
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CongressGov
4
+ module Resources
5
+ # Access daily Congressional Record data from the Congress.gov API.
6
+ class DailyCongressionalRecord < Base
7
+ # List daily congressional record volumes.
8
+ #
9
+ # @param limit [Integer]
10
+ # @param offset [Integer]
11
+ # @return [CongressGov::Response]
12
+ def list(limit: 20, offset: 0)
13
+ client.get('daily-congressional-record', { limit: limit, offset: offset })
14
+ end
15
+
16
+ # List issues for a specific volume.
17
+ #
18
+ # @param volume [Integer]
19
+ # @param limit [Integer]
20
+ # @param offset [Integer]
21
+ # @return [CongressGov::Response]
22
+ def list_by_volume(volume, limit: 20, offset: 0)
23
+ client.get("daily-congressional-record/#{volume}", { limit: limit, offset: offset })
24
+ end
25
+
26
+ # Get a specific issue.
27
+ #
28
+ # @param volume [Integer]
29
+ # @param issue [Integer]
30
+ # @return [CongressGov::Response]
31
+ def get_issue(volume, issue)
32
+ client.get("daily-congressional-record/#{volume}/#{issue}")
33
+ end
34
+
35
+ # Articles for a specific issue.
36
+ #
37
+ # @param volume [Integer]
38
+ # @param issue [Integer]
39
+ # @param limit [Integer]
40
+ # @param offset [Integer]
41
+ # @return [CongressGov::Response]
42
+ def articles(volume, issue, limit: 20, offset: 0)
43
+ client.get("daily-congressional-record/#{volume}/#{issue}/articles",
44
+ { limit: limit, offset: offset })
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CongressGov
4
+ module Resources
5
+ # Access hearing data from the Congress.gov API.
6
+ class Hearing < Base
7
+ # List hearings, optionally filtered by congress and chamber.
8
+ #
9
+ # @param congress [Integer]
10
+ # @param chamber [String]
11
+ # @param limit [Integer]
12
+ # @param offset [Integer]
13
+ # @return [CongressGov::Response]
14
+ def list(congress: nil, chamber: nil, limit: 20, offset: 0)
15
+ params = { limit: limit, offset: offset }
16
+
17
+ if congress && chamber
18
+ client.get("hearing/#{congress}/#{chamber.downcase}", params)
19
+ elsif congress
20
+ client.get("hearing/#{congress}", params)
21
+ else
22
+ client.get('hearing', params)
23
+ end
24
+ end
25
+
26
+ # Fetch a specific hearing.
27
+ #
28
+ # @param congress [Integer]
29
+ # @param chamber [String]
30
+ # @param jacket_number [Integer]
31
+ # @return [CongressGov::Response]
32
+ def get(congress, chamber, jacket_number)
33
+ client.get("hearing/#{congress}/#{chamber.downcase}/#{jacket_number}")
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CongressGov
4
+ module Resources
5
+ # Access House communication data from the Congress.gov API.
6
+ class HouseCommunication < Base
7
+ # Valid communication type codes: ec (Executive), ml (Memorial), pm (Presidential), pt (Petition).
8
+ COMMUNICATION_TYPES = %w[ec ml pm pt].freeze
9
+
10
+ # List house communications.
11
+ #
12
+ # @param congress [Integer] filter to a specific Congress
13
+ # @param communication_type [String] one of COMMUNICATION_TYPES
14
+ # @param limit [Integer]
15
+ # @param offset [Integer]
16
+ # @return [CongressGov::Response]
17
+ def list(congress: nil, communication_type: nil, limit: 20, offset: 0)
18
+ params = { limit: limit, offset: offset }
19
+
20
+ if congress && communication_type
21
+ validate_communication_type!(communication_type)
22
+ client.get("house-communication/#{congress}/#{communication_type.downcase}", params)
23
+ elsif congress
24
+ client.get("house-communication/#{congress}", params)
25
+ else
26
+ client.get('house-communication', params)
27
+ end
28
+ end
29
+
30
+ # Fetch a specific house communication.
31
+ #
32
+ # @param congress [Integer]
33
+ # @param communication_type [String]
34
+ # @param number [Integer]
35
+ # @return [CongressGov::Response]
36
+ def get(congress, communication_type, number)
37
+ validate_communication_type!(communication_type)
38
+ client.get("house-communication/#{congress}/#{communication_type.downcase}/#{number}")
39
+ end
40
+
41
+ private
42
+
43
+ def validate_communication_type!(communication_type)
44
+ return if COMMUNICATION_TYPES.include?(communication_type.to_s.downcase)
45
+
46
+ raise ArgumentError,
47
+ "communication type must be one of: #{COMMUNICATION_TYPES.join(', ')}"
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CongressGov
4
+ module Resources
5
+ # Access House requirement data from the Congress.gov API.
6
+ class HouseRequirement < Base
7
+ # List house requirements.
8
+ #
9
+ # @param limit [Integer]
10
+ # @param offset [Integer]
11
+ # @return [CongressGov::Response]
12
+ def list(limit: 20, offset: 0)
13
+ client.get('house-requirement', { limit: limit, offset: offset })
14
+ end
15
+
16
+ # Fetch a specific house requirement.
17
+ #
18
+ # @param number [Integer]
19
+ # @return [CongressGov::Response]
20
+ def get(number)
21
+ client.get("house-requirement/#{number}")
22
+ end
23
+
24
+ # Matching communications for a house requirement.
25
+ #
26
+ # @param number [Integer]
27
+ # @param limit [Integer]
28
+ # @param offset [Integer]
29
+ # @return [CongressGov::Response]
30
+ def matching_communications(number, limit: 20, offset: 0)
31
+ client.get("house-requirement/#{number}/matching-communications",
32
+ { limit: limit, offset: offset })
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CongressGov
4
+ module Resources
5
+ # Access House roll call vote data from the Congress.gov API.
6
+ class HouseVote < Base
7
+ # List all House roll call votes (no filters).
8
+ #
9
+ # @param limit [Integer]
10
+ # @param offset [Integer]
11
+ # @return [CongressGov::Response]
12
+ def list_all(limit: 20, offset: 0)
13
+ client.get('house-vote', { limit: limit, offset: offset })
14
+ end
15
+
16
+ # List House roll call votes for a specific Congress.
17
+ #
18
+ # @param congress [Integer] e.g. 119
19
+ # @param limit [Integer]
20
+ # @param offset [Integer]
21
+ # @return [CongressGov::Response]
22
+ def list_by_congress(congress:, limit: 20, offset: 0)
23
+ client.get("house-vote/#{congress}", { limit: limit, offset: offset })
24
+ end
25
+
26
+ # List House roll call votes for a Congress and session.
27
+ #
28
+ # @param congress [Integer] e.g. 119
29
+ # @param session [Integer] 1 or 2
30
+ # @param limit [Integer]
31
+ # @param offset [Integer]
32
+ # @param from_date [String] "YYYY-MM-DD"
33
+ # @param to_date [String] "YYYY-MM-DD"
34
+ # @return [CongressGov::Response]
35
+ def list(congress:, session:, limit: 20, offset: 0,
36
+ from_date: nil, to_date: nil)
37
+ params = { limit: limit, offset: offset }
38
+ params[:startDate] = from_date if from_date
39
+ params[:endDate] = to_date if to_date
40
+ client.get("house-vote/#{congress}/#{session}", params)
41
+ end
42
+
43
+ # Fetch a single House roll call vote record.
44
+ #
45
+ # @param congress [Integer]
46
+ # @param session [Integer]
47
+ # @param roll_call [Integer]
48
+ # @return [CongressGov::Response]
49
+ def get(congress:, session:, roll_call:)
50
+ client.get("house-vote/#{congress}/#{session}/#{roll_call}")
51
+ end
52
+
53
+ # Fetch how each member voted on a specific roll call.
54
+ #
55
+ # @param congress [Integer]
56
+ # @param session [Integer]
57
+ # @param roll_call [Integer]
58
+ # @param limit [Integer]
59
+ # @param offset [Integer]
60
+ # @return [CongressGov::Response]
61
+ def members(congress:, session:, roll_call:, limit: 250, offset: 0)
62
+ client.get("house-vote/#{congress}/#{session}/#{roll_call}/members",
63
+ { limit: limit, offset: offset })
64
+ end
65
+
66
+ # Convenience: return all member votes as a Hash keyed by bioguide ID.
67
+ #
68
+ # The members endpoint nests data under +houseRollCallVoteMemberVotes.results+.
69
+ # The bioguide field is +bioguideID+ (capital D).
70
+ #
71
+ # @param congress [Integer]
72
+ # @param session [Integer]
73
+ # @param roll_call [Integer]
74
+ # @return [Hash{String => String}] bioguide_id => voteCast
75
+ def member_votes_by_bioguide(congress:, session:, roll_call:)
76
+ result = {}
77
+ offset = 0
78
+ loop do
79
+ response = members(
80
+ congress: congress,
81
+ session: session,
82
+ roll_call: roll_call,
83
+ limit: 250,
84
+ offset: offset
85
+ )
86
+ member_list = extract_member_votes(response)
87
+ member_list.each do |member|
88
+ bioguide = member['bioguideID'] || member['bioguideId']
89
+ result[bioguide] = member['voteCast']
90
+ end
91
+ break unless response.has_next_page?
92
+
93
+ offset += 250
94
+ end
95
+ result
96
+ end
97
+
98
+ # Convenience: get the vote position for a single member on a roll call.
99
+ #
100
+ # @param congress [Integer]
101
+ # @param session [Integer]
102
+ # @param roll_call [Integer]
103
+ # @param bioguide_id [String]
104
+ # @return [String, nil] "Aye", "Nay", "Present", "Not Voting", or nil
105
+ def position_for_member(congress:, session:, roll_call:, bioguide_id:)
106
+ member_votes_by_bioguide(
107
+ congress: congress, session: session, roll_call: roll_call
108
+ )[bioguide_id]
109
+ end
110
+
111
+ private
112
+
113
+ # Extract the member votes array from the nested response structure.
114
+ # The API nests member votes under +houseRollCallVoteMemberVotes.results+.
115
+ # Falls back to +Response#results+ for compatibility with stubbed tests.
116
+ #
117
+ # @param response [CongressGov::Response]
118
+ # @return [Array<Hash>]
119
+ def extract_member_votes(response)
120
+ nested = response.raw.dig('houseRollCallVoteMemberVotes', 'results')
121
+ return nested if nested.is_a?(Array)
122
+
123
+ response.results
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CongressGov
4
+ module Resources
5
+ # Access law data from the Congress.gov API.
6
+ class Law < Base
7
+ # Valid law type codes: pub (public), priv (private).
8
+ LAW_TYPES = %w[pub priv].freeze
9
+
10
+ # List laws for a given congress.
11
+ #
12
+ # @param congress [Integer] e.g. 119
13
+ # @param limit [Integer]
14
+ # @param offset [Integer]
15
+ # @return [CongressGov::Response]
16
+ def list(congress, limit: 20, offset: 0)
17
+ client.get("law/#{congress}", { limit: limit, offset: offset })
18
+ end
19
+
20
+ # List laws for a given congress filtered by type.
21
+ #
22
+ # @param congress [Integer]
23
+ # @param law_type [String] 'pub' or 'priv'
24
+ # @param limit [Integer]
25
+ # @param offset [Integer]
26
+ # @return [CongressGov::Response]
27
+ def list_by_type(congress, law_type, limit: 20, offset: 0)
28
+ validate_law_type!(law_type)
29
+ client.get("law/#{congress}/#{law_type.downcase}", { limit: limit, offset: offset })
30
+ end
31
+
32
+ # Fetch a specific law.
33
+ #
34
+ # @param congress [Integer]
35
+ # @param law_type [String] 'pub' or 'priv'
36
+ # @param number [Integer]
37
+ # @return [CongressGov::Response]
38
+ def get(congress, law_type, number)
39
+ validate_law_type!(law_type)
40
+ client.get("law/#{congress}/#{law_type.downcase}/#{number}")
41
+ end
42
+
43
+ private
44
+
45
+ def validate_law_type!(law_type)
46
+ return if LAW_TYPES.include?(law_type.to_s.downcase)
47
+
48
+ raise ArgumentError,
49
+ "law type must be one of: #{LAW_TYPES.join(', ')}"
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CongressGov
4
+ module Resources
5
+ # Access member data from the Congress.gov API.
6
+ class Member < Base
7
+ # Fetch the current member representing a congressional district.
8
+ #
9
+ # @param state [String] two-letter state abbreviation e.g. "VA", "OH"
10
+ # @param district [Integer, String] district number e.g. 8 or "08"
11
+ # @param congress [Integer] congress number e.g. 119 (default: current 119th)
12
+ # @param current [Boolean] return only current members (default: true)
13
+ # @param limit [Integer]
14
+ # @param offset [Integer]
15
+ # @return [CongressGov::Response]
16
+ def by_district(state:, district:, congress: 119, current: true, limit: 10, offset: 0)
17
+ district_str = district.to_s.rjust(2, '0')
18
+ params = {
19
+ currentMember: current,
20
+ limit: limit,
21
+ offset: offset
22
+ }
23
+ client.get("member/congress/#{congress}/#{state.upcase}/#{district_str}", params)
24
+ end
25
+
26
+ # Fetch a member's full profile by bioguide ID.
27
+ #
28
+ # @param bioguide_id [String] e.g. "B001292" (Don Beyer, VA-08)
29
+ # @return [CongressGov::Response]
30
+ def get(bioguide_id)
31
+ client.get("member/#{bioguide_id}")
32
+ end
33
+
34
+ # Get a member's sponsored legislation.
35
+ #
36
+ # @param bioguide_id [String]
37
+ # @param limit [Integer] max 250
38
+ # @param offset [Integer]
39
+ # @return [CongressGov::Response]
40
+ def sponsored_legislation(bioguide_id, limit: 20, offset: 0)
41
+ client.get("member/#{bioguide_id}/sponsored-legislation",
42
+ { limit: limit, offset: offset })
43
+ end
44
+
45
+ # Get legislation a member has cosponsored.
46
+ #
47
+ # @param bioguide_id [String]
48
+ # @param limit [Integer]
49
+ # @param offset [Integer]
50
+ # @return [CongressGov::Response]
51
+ def cosponsored_legislation(bioguide_id, limit: 20, offset: 0)
52
+ client.get("member/#{bioguide_id}/cosponsored-legislation",
53
+ { limit: limit, offset: offset })
54
+ end
55
+
56
+ # List all current members of Congress (House + Senate).
57
+ #
58
+ # @param current [Boolean] only current members (default: true)
59
+ # @param limit [Integer]
60
+ # @param offset [Integer]
61
+ # @return [CongressGov::Response]
62
+ def list(current: true, limit: 250, offset: 0)
63
+ client.get('member', { currentMember: current, limit: limit, offset: offset })
64
+ end
65
+
66
+ # List members from a specific state.
67
+ #
68
+ # @param state [String] two-letter state abbreviation e.g. "VA", "OH"
69
+ # @param current [Boolean] return only current members (default: true)
70
+ # @param limit [Integer]
71
+ # @param offset [Integer]
72
+ # @return [CongressGov::Response]
73
+ def by_state(state:, current: true, limit: 250, offset: 0)
74
+ params = {
75
+ currentMember: current,
76
+ limit: limit,
77
+ offset: offset
78
+ }
79
+ client.get("member/#{state.upcase}", params)
80
+ end
81
+
82
+ # List members from a specific state and district.
83
+ #
84
+ # Uses GET /v3/member/:stateCode/:district (distinct from
85
+ # #by_district which uses /member/congress/:congress/…).
86
+ #
87
+ # @param state [String] two-letter state abbreviation
88
+ # @param district [Integer, String] district number
89
+ # @param current [Boolean] return only current members (default: true)
90
+ # @param limit [Integer]
91
+ # @param offset [Integer]
92
+ # @return [CongressGov::Response]
93
+ def by_state_district(state:, district:, current: true, limit: 10, offset: 0)
94
+ district_str = district.to_s.rjust(2, '0')
95
+ params = {
96
+ currentMember: current,
97
+ limit: limit,
98
+ offset: offset
99
+ }
100
+ client.get("member/#{state.upcase}/#{district_str}", params)
101
+ end
102
+
103
+ # List members for a specific congress.
104
+ #
105
+ # @param congress [Integer] congress number e.g. 119
106
+ # @param current [Boolean, nil] filter by current status (nil = omit param)
107
+ # @param limit [Integer]
108
+ # @param offset [Integer]
109
+ # @return [CongressGov::Response]
110
+ def by_congress(congress:, current: nil, limit: 250, offset: 0)
111
+ params = {
112
+ limit: limit,
113
+ offset: offset
114
+ }
115
+ params[:currentMember] = current unless current.nil?
116
+ client.get("member/congress/#{congress}", params)
117
+ end
118
+
119
+ # Convenience: return all pages of current members, yielding each page.
120
+ #
121
+ # @yield [Array] results from each page
122
+ def all_current
123
+ offset = 0
124
+ limit = 250
125
+ loop do
126
+ response = list(current: true, limit: limit, offset: offset)
127
+ yield response.results
128
+ break unless response.has_next_page?
129
+
130
+ offset += limit
131
+ end
132
+ end
133
+
134
+ # Convenience: returns the single current member for a district,
135
+ # or nil if none found.
136
+ #
137
+ # @param state [String]
138
+ # @param district [Integer, String]
139
+ # @param congress [Integer] defaults to 119th
140
+ # @return [Hash, nil]
141
+ def current_for_district(state:, district:, congress: 119)
142
+ response = by_district(state: state, district: district,
143
+ congress: congress, current: true, limit: 1)
144
+ members = response.results
145
+ return nil if members.empty?
146
+
147
+ members.first
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CongressGov
4
+ module Resources
5
+ # Access nomination data from the Congress.gov API.
6
+ class Nomination < Base
7
+ # List nominations, optionally filtered by congress.
8
+ #
9
+ # @param congress [Integer, nil] filter to a specific Congress
10
+ # @param limit [Integer]
11
+ # @param offset [Integer]
12
+ # @return [CongressGov::Response]
13
+ def list(congress: nil, limit: 20, offset: 0)
14
+ path = congress ? "nomination/#{congress}" : 'nomination'
15
+ client.get(path, { limit: limit, offset: offset })
16
+ end
17
+
18
+ # Fetch a nomination's full detail record.
19
+ #
20
+ # @param congress [Integer] e.g. 119
21
+ # @param number [Integer] nomination number
22
+ # @return [CongressGov::Response]
23
+ def get(congress, number)
24
+ client.get("nomination/#{congress}/#{number}")
25
+ end
26
+
27
+ # Fetch a specific ordinal for a nomination.
28
+ #
29
+ # @param congress [Integer]
30
+ # @param number [Integer]
31
+ # @param ordinal [Integer]
32
+ # @return [CongressGov::Response]
33
+ def get_ordinal(congress, number, ordinal)
34
+ client.get("nomination/#{congress}/#{number}/#{ordinal}")
35
+ end
36
+
37
+ # Actions taken on a nomination.
38
+ #
39
+ # @param congress [Integer]
40
+ # @param number [Integer]
41
+ # @param limit [Integer]
42
+ # @param offset [Integer]
43
+ # @return [CongressGov::Response]
44
+ def actions(congress, number, limit: 20, offset: 0)
45
+ client.get("nomination/#{congress}/#{number}/actions",
46
+ { limit: limit, offset: offset })
47
+ end
48
+
49
+ # Committees associated with a nomination.
50
+ #
51
+ # @param congress [Integer]
52
+ # @param number [Integer]
53
+ # @param limit [Integer]
54
+ # @param offset [Integer]
55
+ # @return [CongressGov::Response]
56
+ def committees(congress, number, limit: 20, offset: 0)
57
+ client.get("nomination/#{congress}/#{number}/committees",
58
+ { limit: limit, offset: offset })
59
+ end
60
+
61
+ # Hearings for a nomination.
62
+ #
63
+ # @param congress [Integer]
64
+ # @param number [Integer]
65
+ # @param limit [Integer]
66
+ # @param offset [Integer]
67
+ # @return [CongressGov::Response]
68
+ def hearings(congress, number, limit: 20, offset: 0)
69
+ client.get("nomination/#{congress}/#{number}/hearings",
70
+ { limit: limit, offset: offset })
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CongressGov
4
+ module Resources
5
+ # Access Senate communication data from the Congress.gov API.
6
+ class SenateCommunication < Base
7
+ # Valid communication type codes: ec (Executive), ml (Memorial), pm (Presidential), pt (Petition).
8
+ COMMUNICATION_TYPES = %w[ec ml pm pt].freeze
9
+
10
+ # List senate communications.
11
+ #
12
+ # @param congress [Integer] filter to a specific Congress
13
+ # @param communication_type [String] one of COMMUNICATION_TYPES
14
+ # @param limit [Integer]
15
+ # @param offset [Integer]
16
+ # @return [CongressGov::Response]
17
+ def list(congress: nil, communication_type: nil, limit: 20, offset: 0)
18
+ params = { limit: limit, offset: offset }
19
+
20
+ if congress && communication_type
21
+ validate_communication_type!(communication_type)
22
+ client.get("senate-communication/#{congress}/#{communication_type.downcase}", params)
23
+ elsif congress
24
+ client.get("senate-communication/#{congress}", params)
25
+ else
26
+ client.get('senate-communication', params)
27
+ end
28
+ end
29
+
30
+ # Fetch a specific senate communication.
31
+ #
32
+ # @param congress [Integer]
33
+ # @param communication_type [String]
34
+ # @param number [Integer]
35
+ # @return [CongressGov::Response]
36
+ def get(congress, communication_type, number)
37
+ validate_communication_type!(communication_type)
38
+ client.get("senate-communication/#{congress}/#{communication_type.downcase}/#{number}")
39
+ end
40
+
41
+ private
42
+
43
+ def validate_communication_type!(communication_type)
44
+ return if COMMUNICATION_TYPES.include?(communication_type.to_s.downcase)
45
+
46
+ raise ArgumentError,
47
+ "communication type must be one of: #{COMMUNICATION_TYPES.join(', ')}"
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CongressGov
4
+ module Resources
5
+ # Access bill summary data from the Congress.gov API.
6
+ class Summary < Base
7
+ # List bill summaries with optional congress and bill type filters.
8
+ #
9
+ # @param congress [Integer, nil] filter to a specific congress
10
+ # @param bill_type [String, nil] filter to a bill type (e.g. 'hr', 's')
11
+ # @param limit [Integer]
12
+ # @param offset [Integer]
13
+ # @return [CongressGov::Response]
14
+ def list(congress: nil, bill_type: nil, limit: 20, offset: 0)
15
+ params = { limit: limit, offset: offset }
16
+
17
+ if congress && bill_type
18
+ client.get("summaries/#{congress}/#{bill_type.downcase}", params)
19
+ elsif congress
20
+ client.get("summaries/#{congress}", params)
21
+ else
22
+ client.get('summaries', params)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end