pollster 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.
- data/.gitignore +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +18 -0
- data/LICENSE +23 -0
- data/README.md +145 -0
- data/Rakefile +8 -0
- data/lib/pollster.rb +3 -0
- data/lib/pollster/base.rb +45 -0
- data/lib/pollster/chart.rb +69 -0
- data/lib/pollster/poll.rb +43 -0
- data/lib/pollster/version.rb +3 -0
- data/pollster.gemspec +20 -0
- data/test/test_pollster.rb +26 -0
- metadata +77 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (c) 2012, The Huffington Post
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
12
|
+
and/or other materials provided with the distribution.
|
13
|
+
|
14
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
15
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
16
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
17
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
18
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
19
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
20
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
21
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
22
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
23
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
::::::::: :::::::: ::: ::: :::::::: ::::::::::: :::::::::: ::::::::: | ,*
|
2
|
+
:+: :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: | ,*
|
3
|
+
+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ | ,*,*
|
4
|
+
+#++:++#+ +#+ +:+ +#+ +#+ +#++:++#++ +#+ +#++:++# +#++:++#: | ,*, ,*
|
5
|
+
+#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ | ,* *,*
|
6
|
+
#+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# | ,*
|
7
|
+
### ######## ########## ########## ######## ### ########## ### ### |*
|
8
|
+
- - - - - - - - - - -
|
9
|
+
|
10
|
+
|
11
|
+
A Ruby wrapper for the [Pollster API](http://elections.huffingtonpost.com/pollster/api)
|
12
|
+
which provides access to political opinion polling data and trend estimates from The Huffington Post.
|
13
|
+
|
14
|
+
The Pollster gem has been tested under Ruby 1.8.7, 1.9.2 and 1.9.3.
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
gem install pollster
|
19
|
+
|
20
|
+
## Getting Started
|
21
|
+
|
22
|
+
require 'pollster'
|
23
|
+
include Pollster
|
24
|
+
|
25
|
+
See the current estimate of the president's job approval
|
26
|
+
|
27
|
+
Chart.find('obama-job-approval').estimates
|
28
|
+
|
29
|
+
List charts about 2012 senate races
|
30
|
+
|
31
|
+
Chart.where(:topic => '2012-senate')
|
32
|
+
|
33
|
+
List charts about Wisconsin
|
34
|
+
|
35
|
+
Chart.where(:state => 'WI')
|
36
|
+
|
37
|
+
Calculate the margin between Obama and Romney from a recent general election poll
|
38
|
+
|
39
|
+
poll = Poll.where(:chart => '2012-general-election-romney-vs-obama').first
|
40
|
+
question = poll.questions.detect { |question| question[:chart] == '2012-general-election-romney-vs-obama' }
|
41
|
+
obama = question[:responses].detect { |response| response[:choice] == "Obama" }
|
42
|
+
romney = question[:responses].detect { |response| response[:choice] == "Romney" }
|
43
|
+
obama[:value] - romney[:value]
|
44
|
+
|
45
|
+
See the methodology used in recent polls about the Affordable Care Act
|
46
|
+
|
47
|
+
chart = Chart.find 'us-health-bill'
|
48
|
+
chart.polls.map { |poll| [poll.pollster, poll.method] }
|
49
|
+
|
50
|
+
## Usage
|
51
|
+
|
52
|
+
Pollster provides two classes:
|
53
|
+
|
54
|
+
Pollster::Chart
|
55
|
+
|
56
|
+
represents the current estimates for a Pollster chart (e.g. [Romney vs. Obama](http://elections.huffingtonpost.com/pollster/2012-general-election-romney-vs-obama))
|
57
|
+
|
58
|
+
Pollster::Poll
|
59
|
+
|
60
|
+
represents a specific poll conducted by a polling firm.
|
61
|
+
|
62
|
+
### Accessing data
|
63
|
+
|
64
|
+
List all the charts available from Pollster:
|
65
|
+
|
66
|
+
>> Pollster::Chart.all
|
67
|
+
=> [<Pollster::Chart: 2012 Iowa GOP Primary>,
|
68
|
+
<Pollster::Chart: 2012 New Hampshire GOP Primary>,
|
69
|
+
<Pollster::Chart: 2012 South Carolina GOP Primary>,
|
70
|
+
<Pollster::Chart: 2012 Florida GOP Primary>,
|
71
|
+
<Pollster::Chart: 2012 Nevada GOP Primary>,
|
72
|
+
...]
|
73
|
+
|
74
|
+
This response is not paginated; all charts will be returned.
|
75
|
+
|
76
|
+
A specific chart may be accessed using Pollster::Chart#find, giving the chart's slug as an argument:
|
77
|
+
|
78
|
+
>> Pollster::Chart.find('2012-iowa-gop-primary')
|
79
|
+
=> <Pollster::Chart: 2012 Iowa GOP Primary>
|
80
|
+
|
81
|
+
All the charts for a topic or state may be accessed using Pollster::Chart#where:
|
82
|
+
|
83
|
+
>> Pollster::Chart.where(:state => 'MD')
|
84
|
+
=> [<Pollster::Chart: 2012 Maryland GOP Primary>,
|
85
|
+
<Pollster::Chart: 2012 Maryland House: 6th District>,
|
86
|
+
<Pollster::Chart: 2012 Maryland President: Romney vs. Obama>]
|
87
|
+
|
88
|
+
>> Pollster::Chart.where(:topic => '2012-senate')
|
89
|
+
=> [<Pollster::Chart: 2012 Massachusetts Senate: Brown vs Warren>,
|
90
|
+
<Pollster::Chart: 2012 Ohio Senate: Brown vs Mandel>,
|
91
|
+
<Pollster::Chart: 2012 Arizona Senate: Flake vs. Carmona>,
|
92
|
+
<Pollster::Chart: 2012 Florida Senate: Mack vs. Nelson>,
|
93
|
+
...]
|
94
|
+
|
95
|
+
>> Pollster::Chart.where(:topic => '2012-senate', :state => 'MA')
|
96
|
+
=> [<Pollster::Chart: 2012 Massachusetts Senate: Brown vs Warren>]
|
97
|
+
|
98
|
+
List the polls that were used to create the estimate for a specific chart:
|
99
|
+
|
100
|
+
>> chart = Pollster::Chart.find('2012-iowa-gop-primary')
|
101
|
+
>> chart.polls
|
102
|
+
=> [#<Pollster::Poll:...
|
103
|
+
@end_date=#<Date: 2012-01-01 (4911855/2,0,2299161)>,
|
104
|
+
@id=12385,
|
105
|
+
@method="Automated Phone",
|
106
|
+
@pollster="InsiderAdvantage",
|
107
|
+
@questions=
|
108
|
+
[{:name=>"2012 Iowa GOP Primary",
|
109
|
+
:chart=>"2012-iowa-gop-primary",
|
110
|
+
:topic=>"2012-gop-primary",
|
111
|
+
:state=>"IA",
|
112
|
+
:responses=>
|
113
|
+
[{:choice=>"Undecided",
|
114
|
+
:value=>2,
|
115
|
+
:subpopulation=>"Likely Voters",
|
116
|
+
:number_of_observations=>729,
|
117
|
+
:margin_of_error=>nil},
|
118
|
+
{:choice=>"Bachmann",
|
119
|
+
:value=>6,
|
120
|
+
:subpopulation=>"Likely Voters",
|
121
|
+
:number_of_observations=>729,
|
122
|
+
:margin_of_error=>nil},
|
123
|
+
{:choice=>"Romney",
|
124
|
+
:value=>23,
|
125
|
+
:subpopulation=>"Likely Voters",
|
126
|
+
:number_of_observations=>729,
|
127
|
+
:margin_of_error=>nil},
|
128
|
+
...]
|
129
|
+
|
130
|
+
You may also list all polls available through Pollster:
|
131
|
+
|
132
|
+
>> Pollster::Poll.all
|
133
|
+
|
134
|
+
This response is paginated, with 10 polls per page. To access subsequent pages, provide a page argument:
|
135
|
+
|
136
|
+
>> Pollster::Poll.all(:page => 5)
|
137
|
+
|
138
|
+
## Authors
|
139
|
+
|
140
|
+
- Aaron Bycoffe, bycoffe@huffingtonpost.com
|
141
|
+
- Jay Boice, jay.boice@huffingtonpost.com
|
142
|
+
|
143
|
+
## Copyright
|
144
|
+
|
145
|
+
Copyright © 2012 The Huffington Post. See LICENSE for details.
|
data/Rakefile
ADDED
data/lib/pollster.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'uri'
|
3
|
+
require 'net/http'
|
4
|
+
require 'date'
|
5
|
+
require 'time'
|
6
|
+
require 'zlib'
|
7
|
+
|
8
|
+
module Pollster
|
9
|
+
|
10
|
+
class Base
|
11
|
+
API_SERVER = 'elections.huffingtonpost.com'
|
12
|
+
API_BASE = '/pollster/api'
|
13
|
+
|
14
|
+
class << self
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def encode_params(params)
|
19
|
+
params.map { |k, v| "#{k}=#{v}" }.join('&')
|
20
|
+
end
|
21
|
+
|
22
|
+
def build_request_url(path, params={})
|
23
|
+
URI("http://#{API_SERVER}#{API_BASE}/#{path}#{params.size > 0 ? "?#{encode_params(params)}" : ''}")
|
24
|
+
end
|
25
|
+
|
26
|
+
def invoke(path, params={})
|
27
|
+
uri = build_request_url(path, params)
|
28
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
29
|
+
request['Accept-Encoding'] = 'gzip,deflate'
|
30
|
+
response = Net::HTTP.start(uri.host, uri.port) { |http| http.request(request) }
|
31
|
+
body = response.header['Content-Encoding'].eql?('gzip') ?
|
32
|
+
Zlib::GzipReader.new(StringIO.new(response.body)).read() :
|
33
|
+
response.body
|
34
|
+
raise Exception, JSON.parse(body)["errors"].join(', ') if response.code.eql?('400')
|
35
|
+
JSON.parse(body)
|
36
|
+
end
|
37
|
+
|
38
|
+
def hash_keys_to_sym(hash)
|
39
|
+
Hash[*hash.map { |k, v| [k.to_sym, v] }.flatten(1)]
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Pollster
|
2
|
+
|
3
|
+
class Chart < Base
|
4
|
+
|
5
|
+
attr_reader :title, :slug, :poll_count, :last_updated, :url, :estimates, :estimates_by_date, :state, :topic
|
6
|
+
|
7
|
+
def initialize(params={})
|
8
|
+
params.each_pair do |k,v|
|
9
|
+
instance_variable_set("@#{k}", v)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Get a list of polls for this chart.
|
14
|
+
def polls(params={})
|
15
|
+
Poll.where(params.merge({:chart => self.slug}))
|
16
|
+
end
|
17
|
+
|
18
|
+
# Get a list of all charts.
|
19
|
+
def self.all
|
20
|
+
invoke('charts').map { |chart| self.create(chart) }
|
21
|
+
end
|
22
|
+
|
23
|
+
# Get a chart based on its slug.
|
24
|
+
def self.find(slug)
|
25
|
+
self.create invoke("charts/#{slug}")
|
26
|
+
end
|
27
|
+
|
28
|
+
# Get a list of charts based on the given parameters.
|
29
|
+
# See API documentation for acceptable parameters.
|
30
|
+
def self.where(params={})
|
31
|
+
if params.empty?
|
32
|
+
raise "A search parameter is required"
|
33
|
+
end
|
34
|
+
invoke('charts', params).map { |chart| self.create(chart) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
"#{self.class}: #{self.title}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def inspect
|
42
|
+
"<#{self.class}: #{self.title}>"
|
43
|
+
end
|
44
|
+
|
45
|
+
def estimates_by_date
|
46
|
+
@estimates_by_date ||= Pollster::Chart.find(slug).estimates_by_date
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def self.create(data)
|
52
|
+
data = Hash[*data.map { |k, v| [k.to_sym, v] }.flatten(1)]
|
53
|
+
data[:last_updated] = Time.parse(data[:last_updated])
|
54
|
+
data[:estimates].map! { |estimate| {:choice => estimate['choice'], :value => estimate['value']} }
|
55
|
+
if data[:estimates_by_date]
|
56
|
+
data[:estimates_by_date] = data[:estimates_by_date].map do |x|
|
57
|
+
estimate = hash_keys_to_sym(x)
|
58
|
+
estimate[:date] = Date.parse(estimate[:date])
|
59
|
+
estimate[:estimates] = estimate[:estimates].map { |e| hash_keys_to_sym(e) }
|
60
|
+
estimate
|
61
|
+
end
|
62
|
+
end
|
63
|
+
self.new(data)
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Pollster
|
2
|
+
|
3
|
+
class Poll < Base
|
4
|
+
|
5
|
+
attr_reader :start_date, :end_date, :method, :pollster, :url, :source, :questions
|
6
|
+
|
7
|
+
def initialize(params={})
|
8
|
+
params.each_pair do |k,v|
|
9
|
+
instance_variable_set("@#{k}", v)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Get a list of all polls.
|
14
|
+
# Polls are listed in pages of 25.
|
15
|
+
def self.all(params={})
|
16
|
+
page = params[:page] || 1
|
17
|
+
invoke('polls', {:page => page}).map { |poll| self.create(poll) }
|
18
|
+
end
|
19
|
+
|
20
|
+
# Get a list of polls based on the given parameters.
|
21
|
+
# See API documentation for acceptable parameters.
|
22
|
+
def self.where(params={})
|
23
|
+
if params.empty?
|
24
|
+
raise "A search parameter is required"
|
25
|
+
end
|
26
|
+
invoke('polls', params).map { |poll| self.create(poll) }
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def self.create(data)
|
32
|
+
data = hash_keys_to_sym(data)
|
33
|
+
data[:questions] = data[:questions].map { |question| hash_keys_to_sym(question) }
|
34
|
+
data[:questions].each { |question| question[:responses] = question[:responses].map { |response| hash_keys_to_sym(response) } }
|
35
|
+
data[:start_date] = Date.parse(data[:start_date])
|
36
|
+
data[:end_date] = Date.parse(data[:end_date])
|
37
|
+
self.new(data)
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
data/pollster.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require 'pollster/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'pollster'
|
7
|
+
s.version = Pollster::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Jay Boice", "Aaron Bycoffe"]
|
10
|
+
s.email = ["jay.boice@huffingtonpost.com", "bycoffe@huffingtonpost.com"]
|
11
|
+
s.homepage = "http://github.com/huffingtonpost/ruby-pollster"
|
12
|
+
s.summary = "Ruby library for accessing the Pollster API"
|
13
|
+
s.description = "A Ruby library for accessing the Pollster API."
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.require_paths = ['lib']
|
17
|
+
|
18
|
+
s.add_development_dependency "rdoc"
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'pollster'
|
3
|
+
include Pollster
|
4
|
+
|
5
|
+
class PollsterTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_ge_chart
|
8
|
+
assert_equal "US", Chart.find('2012-general-election-romney-vs-obama').state
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_poll_page_size
|
12
|
+
assert_equal 10, Poll.all.size
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_invalid_chart_slug
|
16
|
+
assert_raise(Exception) { Chart.find('invalid-slug') }
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_estimates_by_date
|
20
|
+
assert_block do
|
21
|
+
chart = Chart.all.first
|
22
|
+
chart.estimates_by_date.is_a?(Array)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pollster
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jay Boice
|
9
|
+
- Aaron Bycoffe
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-07-05 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rdoc
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
31
|
+
description: A Ruby library for accessing the Pollster API.
|
32
|
+
email:
|
33
|
+
- jay.boice@huffingtonpost.com
|
34
|
+
- bycoffe@huffingtonpost.com
|
35
|
+
executables: []
|
36
|
+
extensions: []
|
37
|
+
extra_rdoc_files: []
|
38
|
+
files:
|
39
|
+
- .gitignore
|
40
|
+
- Gemfile
|
41
|
+
- Gemfile.lock
|
42
|
+
- LICENSE
|
43
|
+
- README.md
|
44
|
+
- Rakefile
|
45
|
+
- lib/pollster.rb
|
46
|
+
- lib/pollster/base.rb
|
47
|
+
- lib/pollster/chart.rb
|
48
|
+
- lib/pollster/poll.rb
|
49
|
+
- lib/pollster/version.rb
|
50
|
+
- pollster.gemspec
|
51
|
+
- test/test_pollster.rb
|
52
|
+
homepage: http://github.com/huffingtonpost/ruby-pollster
|
53
|
+
licenses: []
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options: []
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
requirements: []
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 1.8.24
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: Ruby library for accessing the Pollster API
|
76
|
+
test_files: []
|
77
|
+
has_rdoc:
|