pollster 0.2.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +1 -1
  3. data/README.md +68 -111
  4. data/example.rb +128 -0
  5. data/lib/pollster.rb +46 -4
  6. data/lib/pollster/api.rb +655 -0
  7. data/lib/pollster/api_client.rb +400 -0
  8. data/lib/pollster/api_error.rb +26 -0
  9. data/lib/pollster/configuration.rb +184 -0
  10. data/lib/pollster/models/chart.rb +239 -0
  11. data/lib/pollster/models/chart_estimate.rb +226 -0
  12. data/lib/pollster/models/chart_estimate_lowess_parameters.rb +197 -0
  13. data/lib/pollster/models/chart_pollster_estimate_summary.rb +217 -0
  14. data/lib/pollster/models/chart_pollster_trendlines.rb +41 -0
  15. data/lib/pollster/models/inline_response_200.rb +208 -0
  16. data/lib/pollster/models/inline_response_200_3.rb +206 -0
  17. data/lib/pollster/models/inline_response_200_4.rb +208 -0
  18. data/lib/pollster/models/poll.rb +279 -0
  19. data/lib/pollster/models/poll_question.rb +198 -0
  20. data/lib/pollster/models/poll_question_responses.rb +197 -0
  21. data/lib/pollster/models/poll_question_sample_subpopulations.rb +209 -0
  22. data/lib/pollster/models/pollster_chart_poll_questions.rb +92 -0
  23. data/lib/pollster/models/question.rb +253 -0
  24. data/lib/pollster/models/question_poll_responses_clean.rb +93 -0
  25. data/lib/pollster/models/question_poll_responses_raw.rb +86 -0
  26. data/lib/pollster/models/question_responses.rb +207 -0
  27. data/lib/pollster/models/tag.rb +207 -0
  28. data/lib/pollster/version.rb +1 -1
  29. data/pollster.gemspec +17 -16
  30. metadata +85 -65
  31. data/.gitignore +0 -2
  32. data/Gemfile +0 -3
  33. data/Gemfile.lock +0 -19
  34. data/Rakefile +0 -8
  35. data/lib/pollster/base.rb +0 -45
  36. data/lib/pollster/chart.rb +0 -69
  37. data/lib/pollster/poll.rb +0 -47
  38. data/lib/pollster/question.rb +0 -19
  39. data/test/test_pollster.rb +0 -26
@@ -0,0 +1,197 @@
1
+ require 'date'
2
+
3
+ module Pollster
4
+
5
+ class PollQuestionResponses
6
+ # Prompt the survey house presented to the respondent. For instance: `Hillary Clinton, the Democrat`
7
+ attr_accessor :text
8
+
9
+ # One of `poll_question.question.responses[*].label`: a label chosen by Pollster editors. Often, two `text` entries will have the same `pollster_label`. Rarely, the `pollster_label` may be `null`.
10
+ attr_accessor :pollster_label
11
+
12
+ # Value reported by the survey house, out of 100. Survey houses typically weight respondents, meaning this you cannot guess the number of respondents from this value.
13
+ attr_accessor :value
14
+
15
+
16
+ # Attribute mapping from ruby-style variable name to JSON key.
17
+ def self.attribute_map
18
+ {
19
+ :'text' => :'text',
20
+ :'pollster_label' => :'pollster_label',
21
+ :'value' => :'value'
22
+ }
23
+ end
24
+
25
+ # Attribute type mapping.
26
+ def self.swagger_types
27
+ {
28
+ :'text' => :'String',
29
+ :'pollster_label' => :'String',
30
+ :'value' => :'Float'
31
+ }
32
+ end
33
+
34
+ # Initializes the object
35
+ # @param [Hash] attributes Model attributes in the form of hash
36
+ def initialize(attributes = {})
37
+ return unless attributes.is_a?(Hash)
38
+
39
+ # convert string to symbol for hash key
40
+ attributes = attributes.each_with_object({}){|(k,v), h| h[k.to_sym] = v}
41
+
42
+ if attributes.has_key?(:'text')
43
+ self.text = attributes[:'text']
44
+ end
45
+
46
+ if attributes.has_key?(:'pollster_label')
47
+ self.pollster_label = attributes[:'pollster_label']
48
+ end
49
+
50
+ if attributes.has_key?(:'value')
51
+ self.value = attributes[:'value']
52
+ end
53
+
54
+ end
55
+
56
+ # Show invalid properties with the reasons. Usually used together with valid?
57
+ # @return Array for valid properies with the reasons
58
+ def list_invalid_properties
59
+ invalid_properties = Array.new
60
+ return invalid_properties
61
+ end
62
+
63
+ # Check to see if the all the properties in the model are valid
64
+ # @return true if the model is valid
65
+ def valid?
66
+ return true
67
+ end
68
+
69
+ # Checks equality by comparing each attribute.
70
+ # @param [Object] Object to be compared
71
+ def ==(o)
72
+ return true if self.equal?(o)
73
+ self.class == o.class &&
74
+ text == o.text &&
75
+ pollster_label == o.pollster_label &&
76
+ value == o.value
77
+ end
78
+
79
+ # @see the `==` method
80
+ # @param [Object] Object to be compared
81
+ def eql?(o)
82
+ self == o
83
+ end
84
+
85
+ # Calculates hash code according to all attributes.
86
+ # @return [Fixnum] Hash code
87
+ def hash
88
+ [text, pollster_label, value].hash
89
+ end
90
+
91
+ # Builds the object from hash
92
+ # @param [Hash] attributes Model attributes in the form of hash
93
+ # @return [Object] Returns the model itself
94
+ def build_from_hash(attributes)
95
+ return nil unless attributes.is_a?(Hash)
96
+ self.class.swagger_types.each_pair do |key, type|
97
+ if type =~ /\AArray<(.*)>/i
98
+ # check to ensure the input is an array given that the the attribute
99
+ # is documented as an array but the input is not
100
+ if attributes[self.class.attribute_map[key]].is_a?(Array)
101
+ self.send("#{key}=", attributes[self.class.attribute_map[key]].map{ |v| _deserialize($1, v) } )
102
+ end
103
+ elsif !attributes[self.class.attribute_map[key]].nil?
104
+ self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]]))
105
+ end # or else data not found in attributes(hash), not an issue as the data can be optional
106
+ end
107
+
108
+ self
109
+ end
110
+
111
+ # Deserializes the data based on type
112
+ # @param string type Data type
113
+ # @param string value Value to be deserialized
114
+ # @return [Object] Deserialized data
115
+ def _deserialize(type, value)
116
+ case type.to_sym
117
+ when :DateTime
118
+ DateTime.parse(value)
119
+ when :Date
120
+ Date.parse(value)
121
+ when :String
122
+ value.to_s
123
+ when :Integer
124
+ value.to_i
125
+ when :Float
126
+ value.to_f
127
+ when :BOOLEAN
128
+ if value.to_s =~ /\A(true|t|yes|y|1)\z/i
129
+ true
130
+ else
131
+ false
132
+ end
133
+ when :Object
134
+ # generic object (usually a Hash), return directly
135
+ value
136
+ when /\AArray<(?<inner_type>.+)>\z/
137
+ inner_type = Regexp.last_match[:inner_type]
138
+ value.map { |v| _deserialize(inner_type, v) }
139
+ when /\AHash<(?<k_type>.+?), (?<v_type>.+)>\z/
140
+ k_type = Regexp.last_match[:k_type]
141
+ v_type = Regexp.last_match[:v_type]
142
+ {}.tap do |hash|
143
+ value.each do |k, v|
144
+ hash[_deserialize(k_type, k)] = _deserialize(v_type, v)
145
+ end
146
+ end
147
+ else # model
148
+ temp_model = Pollster.const_get(type).new
149
+ temp_model.build_from_hash(value)
150
+ end
151
+ end
152
+
153
+ # Returns the string representation of the object
154
+ # @return [String] String presentation of the object
155
+ def to_s
156
+ to_hash.to_s
157
+ end
158
+
159
+ # to_body is an alias to to_hash (backward compatibility)
160
+ # @return [Hash] Returns the object in the form of hash
161
+ def to_body
162
+ to_hash
163
+ end
164
+
165
+ # Returns the object in the form of hash
166
+ # @return [Hash] Returns the object in the form of hash
167
+ def to_hash
168
+ hash = {}
169
+ self.class.attribute_map.each_pair do |attr, param|
170
+ value = self.send(attr)
171
+ next if value.nil?
172
+ hash[param] = _to_hash(value)
173
+ end
174
+ hash
175
+ end
176
+
177
+ # Outputs non-array value in the form of hash
178
+ # For object, use to_hash. Otherwise, just return the value
179
+ # @param [Object] value Any valid value
180
+ # @return [Hash] Returns the value in the form of hash
181
+ def _to_hash(value)
182
+ if value.is_a?(Array)
183
+ value.compact.map{ |v| _to_hash(v) }
184
+ elsif value.is_a?(Hash)
185
+ {}.tap do |hash|
186
+ value.each { |k, v| hash[k] = _to_hash(v) }
187
+ end
188
+ elsif value.respond_to? :to_hash
189
+ value.to_hash
190
+ else
191
+ value
192
+ end
193
+ end
194
+
195
+ end
196
+
197
+ end
@@ -0,0 +1,209 @@
1
+ require 'date'
2
+
3
+ module Pollster
4
+
5
+ class PollQuestionSampleSubpopulations
6
+ # Number of people in this subpopulation who responded to this question, or `null` if the survey house did not report a number.
7
+ attr_accessor :observations
8
+
9
+ # One of: Adults, Adults - Democrat, Adults - Republican, Adults - independent, Registered Voters, Registered Voters - Democrat, Registered Voters - Republican, Registered Voters - independent, Likely Voters, Likely Voters - Democrat, Likely Voters - Republican, Likely Voters - independent. `Likely Voters` is editorially important during election seasons; sometimes Pollster editors will skip all other subpopulations.
10
+ attr_accessor :name
11
+
12
+ # Margin of error for this subpopulation, or `null` if the survey house did not report a number.
13
+ attr_accessor :margin_of_error
14
+
15
+ # Options the survey house provided to respondents, and respondents' answers. These are ordered randomly.
16
+ attr_accessor :responses
17
+
18
+
19
+ # Attribute mapping from ruby-style variable name to JSON key.
20
+ def self.attribute_map
21
+ {
22
+ :'observations' => :'observations',
23
+ :'name' => :'name',
24
+ :'margin_of_error' => :'margin_of_error',
25
+ :'responses' => :'responses'
26
+ }
27
+ end
28
+
29
+ # Attribute type mapping.
30
+ def self.swagger_types
31
+ {
32
+ :'observations' => :'Integer',
33
+ :'name' => :'String',
34
+ :'margin_of_error' => :'Float',
35
+ :'responses' => :'Array<PollQuestionResponses>'
36
+ }
37
+ end
38
+
39
+ # Initializes the object
40
+ # @param [Hash] attributes Model attributes in the form of hash
41
+ def initialize(attributes = {})
42
+ return unless attributes.is_a?(Hash)
43
+
44
+ # convert string to symbol for hash key
45
+ attributes = attributes.each_with_object({}){|(k,v), h| h[k.to_sym] = v}
46
+
47
+ if attributes.has_key?(:'observations')
48
+ self.observations = attributes[:'observations']
49
+ end
50
+
51
+ if attributes.has_key?(:'name')
52
+ self.name = attributes[:'name']
53
+ end
54
+
55
+ if attributes.has_key?(:'margin_of_error')
56
+ self.margin_of_error = attributes[:'margin_of_error']
57
+ end
58
+
59
+ if attributes.has_key?(:'responses')
60
+ if (value = attributes[:'responses']).is_a?(Array)
61
+ self.responses = value
62
+ end
63
+ end
64
+
65
+ end
66
+
67
+ # Show invalid properties with the reasons. Usually used together with valid?
68
+ # @return Array for valid properies with the reasons
69
+ def list_invalid_properties
70
+ invalid_properties = Array.new
71
+ return invalid_properties
72
+ end
73
+
74
+ # Check to see if the all the properties in the model are valid
75
+ # @return true if the model is valid
76
+ def valid?
77
+ return true
78
+ end
79
+
80
+ # Checks equality by comparing each attribute.
81
+ # @param [Object] Object to be compared
82
+ def ==(o)
83
+ return true if self.equal?(o)
84
+ self.class == o.class &&
85
+ observations == o.observations &&
86
+ name == o.name &&
87
+ margin_of_error == o.margin_of_error &&
88
+ responses == o.responses
89
+ end
90
+
91
+ # @see the `==` method
92
+ # @param [Object] Object to be compared
93
+ def eql?(o)
94
+ self == o
95
+ end
96
+
97
+ # Calculates hash code according to all attributes.
98
+ # @return [Fixnum] Hash code
99
+ def hash
100
+ [observations, name, margin_of_error, responses].hash
101
+ end
102
+
103
+ # Builds the object from hash
104
+ # @param [Hash] attributes Model attributes in the form of hash
105
+ # @return [Object] Returns the model itself
106
+ def build_from_hash(attributes)
107
+ return nil unless attributes.is_a?(Hash)
108
+ self.class.swagger_types.each_pair do |key, type|
109
+ if type =~ /\AArray<(.*)>/i
110
+ # check to ensure the input is an array given that the the attribute
111
+ # is documented as an array but the input is not
112
+ if attributes[self.class.attribute_map[key]].is_a?(Array)
113
+ self.send("#{key}=", attributes[self.class.attribute_map[key]].map{ |v| _deserialize($1, v) } )
114
+ end
115
+ elsif !attributes[self.class.attribute_map[key]].nil?
116
+ self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]]))
117
+ end # or else data not found in attributes(hash), not an issue as the data can be optional
118
+ end
119
+
120
+ self
121
+ end
122
+
123
+ # Deserializes the data based on type
124
+ # @param string type Data type
125
+ # @param string value Value to be deserialized
126
+ # @return [Object] Deserialized data
127
+ def _deserialize(type, value)
128
+ case type.to_sym
129
+ when :DateTime
130
+ DateTime.parse(value)
131
+ when :Date
132
+ Date.parse(value)
133
+ when :String
134
+ value.to_s
135
+ when :Integer
136
+ value.to_i
137
+ when :Float
138
+ value.to_f
139
+ when :BOOLEAN
140
+ if value.to_s =~ /\A(true|t|yes|y|1)\z/i
141
+ true
142
+ else
143
+ false
144
+ end
145
+ when :Object
146
+ # generic object (usually a Hash), return directly
147
+ value
148
+ when /\AArray<(?<inner_type>.+)>\z/
149
+ inner_type = Regexp.last_match[:inner_type]
150
+ value.map { |v| _deserialize(inner_type, v) }
151
+ when /\AHash<(?<k_type>.+?), (?<v_type>.+)>\z/
152
+ k_type = Regexp.last_match[:k_type]
153
+ v_type = Regexp.last_match[:v_type]
154
+ {}.tap do |hash|
155
+ value.each do |k, v|
156
+ hash[_deserialize(k_type, k)] = _deserialize(v_type, v)
157
+ end
158
+ end
159
+ else # model
160
+ temp_model = Pollster.const_get(type).new
161
+ temp_model.build_from_hash(value)
162
+ end
163
+ end
164
+
165
+ # Returns the string representation of the object
166
+ # @return [String] String presentation of the object
167
+ def to_s
168
+ to_hash.to_s
169
+ end
170
+
171
+ # to_body is an alias to to_hash (backward compatibility)
172
+ # @return [Hash] Returns the object in the form of hash
173
+ def to_body
174
+ to_hash
175
+ end
176
+
177
+ # Returns the object in the form of hash
178
+ # @return [Hash] Returns the object in the form of hash
179
+ def to_hash
180
+ hash = {}
181
+ self.class.attribute_map.each_pair do |attr, param|
182
+ value = self.send(attr)
183
+ next if value.nil?
184
+ hash[param] = _to_hash(value)
185
+ end
186
+ hash
187
+ end
188
+
189
+ # Outputs non-array value in the form of hash
190
+ # For object, use to_hash. Otherwise, just return the value
191
+ # @param [Object] value Any valid value
192
+ # @return [Hash] Returns the value in the form of hash
193
+ def _to_hash(value)
194
+ if value.is_a?(Array)
195
+ value.compact.map{ |v| _to_hash(v) }
196
+ elsif value.is_a?(Hash)
197
+ {}.tap do |hash|
198
+ value.each { |k, v| hash[k] = _to_hash(v) }
199
+ end
200
+ elsif value.respond_to? :to_hash
201
+ value.to_hash
202
+ else
203
+ value
204
+ end
205
+ end
206
+
207
+ end
208
+
209
+ end
@@ -0,0 +1,92 @@
1
+ require 'ruby-immutable-struct'
2
+
3
+ module Pollster
4
+ PollsterChartPollQuestion = RubyImmutableStruct.new(
5
+ :responses,
6
+ :poll_slug,
7
+ :survey_house,
8
+ :start_date,
9
+ :end_date,
10
+ :question_text,
11
+ :sample_subpopulation,
12
+ :observations,
13
+ :margin_of_error,
14
+ :mode,
15
+ :partisanship,
16
+ :partisan_affiliation
17
+ ) do
18
+ def self.from_tsv_line_with_labels(tsv_line, labels)
19
+ if m = PollsterChartPollQuestion::TsvLineRegex.match(tsv_line)
20
+ # split(..., -1) avoids omitting trailing blanks
21
+ values = m[:values].split(/\t/, -1).map{ |v| v.empty? ? nil : v.to_f }
22
+
23
+ if values.length != labels.length
24
+ raise ArgumentError.new("TSV line `#{tsv_line}` has #{values.length} values for #{labels.length} labels")
25
+ end
26
+
27
+ responses = {}
28
+ for i in 0...(labels.length)
29
+ responses[labels[i]] = values[i]
30
+ end
31
+
32
+ PollsterChartPollQuestion.new(
33
+ responses,
34
+ m[:poll_slug],
35
+ m[:survey_house],
36
+ Date.parse(m[:start_date]),
37
+ Date.parse(m[:end_date]),
38
+ m[:question_text],
39
+ m[:sample_subpopulation],
40
+ m[:observations].empty? ? nil : m[:observations].to_i,
41
+ m[:margin_of_error].empty? ? nil : m[:margin_of_error].to_f,
42
+ m[:mode],
43
+ m[:partisanship],
44
+ m[:partisan_affiliation]
45
+ )
46
+ else
47
+ raise ArgumentError.new("TSV line `#{tsv_line}` is not a valid PollsterChartPollQuestion line")
48
+ end
49
+ end
50
+ end
51
+ PollsterChartPollQuestion::TsvLineRegex = %r{
52
+ \A
53
+ (?<values>(?:\d+(?:\.\d+)?)?(?:\t(?:\d+(?:\.\d+)?)?)*)\t
54
+ (?<poll_slug>[^\t]+)\t
55
+ (?<survey_house>[^\t]+)\t
56
+ (?<start_date>\d\d\d\d-\d\d-\d\d)\t
57
+ (?<end_date>\d\d\d\d-\d\d-\d\d)\t
58
+ (?<question_text>[^\t]*)\t
59
+ (?<sample_subpopulation>[^\t]+)\t
60
+ (?<observations>\d*)\t
61
+ (?<margin_of_error>(?:\d+(?:\.\d+)?)?)\t
62
+ (?<mode>[^\t]+)\t
63
+ (?<partisanship>[^\t]+)\t
64
+ (?<partisan_affiliation>[^\t]+)\b
65
+ # No \Z ... Pollster's API doesn't guarantee it won't add columns
66
+ }x
67
+
68
+ class PollsterChartPollQuestions
69
+ HeaderLineRegex = /\A(?<labels>[^\t]+(?:\t[^\t]+)*)\tpoll_slug\tsurvey_house\tstart_date\tend_date\tquestion_text\tsample_subpopulation\tobservations\tmargin_of_error\tmode\tpartisanship\tpartisan_affiliation\b/
70
+
71
+ include Enumerable
72
+
73
+ def initialize(array)
74
+ @array = array
75
+ end
76
+
77
+ def each(&block)
78
+ @array.each(&block)
79
+ end
80
+
81
+ def self.from_tsv(tsv)
82
+ lines = tsv.split(/(?:\r?\n)+/).reject(&:empty?)
83
+ if m = HeaderLineRegex.match(lines[0])
84
+ labels = m[:labels].split(/\t/)
85
+ rows = lines[1..-1].map { |tsv_line| PollsterChartPollQuestion.from_tsv_line_with_labels(tsv_line, labels) }
86
+ PollsterChartPollQuestions.new(rows)
87
+ else
88
+ raise ArgumentError.new("First line of TSV is `#{lines[0]}`, which does not match Pollster::PollsterChartPollQuestions::HeaderLineRegex")
89
+ end
90
+ end
91
+ end
92
+ end