Election results in the London Borough of Sutton.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

274 lignes
8.8 KiB

  1. require 'data_mapper'
  2. class Poll
  3. include DataMapper::Resource
  4. property :district_id, Integer, :key => true
  5. property :election_id, Integer, :key => true
  6. property :electorate, Integer # The number of people eligible to vote in this district in this election
  7. property :ballot_papers_issued, Integer # The number of ballot papers issued (includes spoiled ballots)
  8. property :seats, Integer, :required => true # The number of seats to be elected in this district in this election
  9. property :rejected_no_official_mark, Integer
  10. property :rejected_too_many_candidates, Integer
  11. property :rejected_identifiable_voter, Integer
  12. property :rejected_blank_or_uncertain, Integer
  13. def turnout_percent
  14. @ballot_papers_issued.to_f / @electorate.to_f * 100.0
  15. end
  16. def total_rejected_ballots
  17. if @rejected_no_official_mark
  18. @rejected_no_official_mark + \
  19. @rejected_too_many_candidates + \
  20. @rejected_identifiable_voter + \
  21. @rejected_blank_or_uncertain
  22. else
  23. nil
  24. end
  25. end
  26. def valid_ballot_papers
  27. self.total_rejected_ballots ? @ballot_papers_issued - self.total_rejected_ballots : nil
  28. end
  29. def successful_candidacies # Candidacies where the candidate was elected
  30. Candidacy.all(:election => @election, :district => @district, :order => [:position], :limit => @seats)
  31. end
  32. # Set candidacy.position for every candidacy in this poll
  33. # Returns array of candidacies, or false if we don't have results for this poll
  34. def set_positions
  35. # Check that every candidacy for this poll has its votes recorded (ie that the election results are known)
  36. return false if Candidacy.count(:conditions => { :district_id => @district_id, :election_id => @election_id, :votes => nil }) > 0
  37. # Get the candidacies for this poll
  38. ccys = Candidacy.all(:conditions => { :district_id => @district_id, :election_id => @election_id }, :order => [:votes.desc])
  39. puts "Found no candidacies for this poll" if ccys.size == 0
  40. position = 1
  41. ccys.each do |ccy|
  42. position <= @seats ? ccy.seats = 1 : ccy.seats = 0
  43. ccy.position = position
  44. ccy.save
  45. position += 1
  46. end
  47. ccys
  48. end
  49. belongs_to :election
  50. belongs_to :district
  51. end
  52. class PollingStation
  53. include DataMapper::Resource
  54. property :id, String, :key => true, :length => 2 # e.g. "KA"
  55. property :name, String, :length => 255#, :required => true
  56. property :address, String, :length => 255#, :required => true
  57. property :postcode, String#, :required => true
  58. property :easting, Float, :required => true
  59. property :northing, Float, :required => true
  60. property :lat, Float, :required => true
  61. property :lng, Float, :required => true
  62. has n, :postcodes
  63. end
  64. class Postcode
  65. include DataMapper::Resource
  66. # Postcode natural key, uppercase with space, eg. "SM1 1EA"
  67. # Column names derived from Ordnance Survey CodePoint Open
  68. property :postcode, String, :key => true
  69. property :positional_quality_indicator, Integer
  70. property :eastings, Integer, :required => true
  71. property :northings, Integer, :required => true
  72. property :country_code, String, :required => true
  73. property :nhs_regional_ha_code, String, :required => true
  74. property :nhs_ha_code, String, :required => true
  75. property :admin_county_code, String # NULL within Greater London
  76. property :admin_district_code, String, :required => true # e.g. London Borough of Sutton
  77. property :admin_ward_code, String, :required => true # e.g. Sutton Central
  78. property :lat, Float, :required => true
  79. property :lng, Float, :required => true
  80. property :ward_id, Integer, :required => true # Sutton Council
  81. property :constituency_id, Integer, :required => false # UK Parliament
  82. property :polling_station_id, String, :length => 2
  83. belongs_to :district, :child_key => [:ward_id]
  84. belongs_to :polling_station
  85. def self.finder(postcode)
  86. postcode = postcode.strip.upcase
  87. if o = self.get(postcode)
  88. return o
  89. end
  90. result = Pat.get(postcode)
  91. unless result.code == 404
  92. # cache API result
  93. self.create(
  94. :postcode => postcode,
  95. :lat => result['geo']['lat'],
  96. :lng => result['geo']['lng'],
  97. :district_name => result['administrative']['district']['title'],
  98. :district_code => result['administrative']['district']['uri'].match(/.+\/(.+)$/)[1],
  99. :ward_name => result['administrative']['ward']['title'],
  100. :ward_code => result['administrative']['ward']['uri'].match(/.+\/(.+)$/)[1]
  101. )
  102. else
  103. # invalid postcode
  104. nil
  105. end
  106. end
  107. end
  108. class Candidate
  109. include DataMapper::Resource
  110. property :id, Serial
  111. property :forenames, String, :required => true
  112. property :surname, String, :required => true, :index => true
  113. has n, :candidacies
  114. def short_name
  115. @forenames.split(' ')[0] + ' ' + @surname
  116. end
  117. def name
  118. @forenames + ' ' + @surname
  119. end
  120. def url
  121. "/candidates/" + @id.to_s
  122. end
  123. end
  124. class DeletedCandidate
  125. include DataMapper::Resource
  126. property :old_candidate_id, Integer, :key => true # ID of candidate that has been merged/deleted
  127. property :candidate_id, Integer, :required => true # ID of candidate that has been kept
  128. end
  129. class Candidacy
  130. include DataMapper::Resource
  131. property :id, Serial
  132. property :election_id, Integer, :required => true
  133. property :candidate_id, Integer, :required => true
  134. property :party_id, Integer
  135. property :district_id, Integer, :required => true
  136. property :votes, Integer
  137. property :address, String, :length => 200
  138. property :postcode, String
  139. property :position, Integer # Position of this candidate in this district. (1..n)
  140. property :seats, Integer # Number of seats won by this candidacy (0 or 1)
  141. property :labcoop, Boolean, :default => false # Candidacy is for joint Labour/Co-op party
  142. belongs_to :election
  143. belongs_to :candidate
  144. belongs_to :party
  145. belongs_to :district
  146. end
  147. class Campaign
  148. include DataMapper::Resource
  149. property :party_id, Integer, :key => true
  150. property :election_id, Integer, :key => true
  151. property :party_url, String, :length => 255
  152. property :manifesto_html_url, String, :length => 255
  153. property :manifesto_pdf_url, String, :length => 255
  154. belongs_to :party
  155. belongs_to :election
  156. end
  157. class Election
  158. include DataMapper::Resource
  159. property :id, Serial
  160. property :body_id, Integer, :required => true
  161. property :d, Date, :required => true, :index => true
  162. property :reason, String, :length => 255
  163. property :kind, String, :length => 255
  164. has n, :candidacies
  165. has n, :polls
  166. belongs_to :body
  167. has n, :campaigns
  168. def self.past
  169. self.all(:d.lt => Time.now.to_s, :order => [ :d.desc ])
  170. end
  171. def self.future
  172. self.all(:d.gte => Time.now.to_s, :order => [ :d.desc ])
  173. end
  174. # electorate and ballot_papers_issued assume there's a Poll object for every district in this election
  175. def electorate
  176. Poll.sum(:electorate, :election => self)
  177. end
  178. def ballot_papers_issued
  179. Poll.sum(:ballot_papers_issued, :election => self)
  180. end
  181. def set_positions
  182. polls.each { |p| p.set_positions }
  183. end
  184. end
  185. class District
  186. include DataMapper::Resource
  187. property :id, Serial
  188. property :body_id, Integer, :required => true
  189. property :name, String, :length => 255, :required => true
  190. property :slug, String
  191. property :ons_district_code, String
  192. belongs_to :body
  193. has n, :postcodes, :child_key => [:ward_id]
  194. has n, :polls
  195. def self.slugify(name)
  196. name.gsub(/[^\w\s-]/, '').gsub(/\s+/, '-').downcase
  197. end
  198. end
  199. class Body
  200. include DataMapper::Resource
  201. property :id, Serial
  202. property :name, String, :length => 255, :required => true
  203. property :district_name, String, :length => 255, :required => true # singular
  204. property :districts_name, String, :length => 255, :required => true # plural
  205. property :slug, String, :length => 255
  206. has n, :elections
  207. has n, :districts
  208. end
  209. class Party
  210. include DataMapper::Resource
  211. property :id, Serial
  212. property :name, String, :required => true
  213. property :colour, String
  214. has n, :candidacies
  215. has n, :campaigns
  216. end
  217. DataMapper.setup(:default, ENV['DATABASE_URL'] || "postgres://postgres@localhost:5432/suttonelections")
  218. DataMapper.auto_upgrade!