pollster 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ *.swp
2
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,18 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ pollster (0.1.0)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ json (1.7.3)
10
+ rdoc (3.12)
11
+ json (~> 1.4)
12
+
13
+ PLATFORMS
14
+ ruby
15
+
16
+ DEPENDENCIES
17
+ pollster!
18
+ rdoc
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
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc "Run tests"
8
+ task :default => :test
data/lib/pollster.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'pollster/base'
2
+ require 'pollster/chart'
3
+ require 'pollster/poll'
@@ -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
@@ -0,0 +1,3 @@
1
+ module Pollster
2
+ VERSION = '0.1.0'
3
+ 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: