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 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: