class Eaternet::Agencies::Multco

A Multnomah County (Portland area) Oregon data source for restaurant health inspections.

It produces output in the [LIVES 1.0](www.yelp.com/healthscores) open data standard developed by Yelp and the cities of San Francisco and New York.

@deprecated In May, the County stopped publishing data from the source app

which this code relies on. Additionally, the County plans to shut down
the legacy app entirely at some point. We're planning a new version of
this code which will use the County's new information portal.

Public Instance Methods

businesses() click to toggle source
# File lib/eaternet/agencies/multco.rb, line 25
def businesses
  @businesses ||= multco_get_index do |struct|
    Eaternet::Lives_1_0::Business.new do |b|
      b.business_id = struct['orig_key']
      b.address = struct['address']
      b.city = struct['city']
      b.state = 'OR'
      b.name = struct['name']
      b.postal_code = struct['zipcode']
    end
  end
end
feed_info() click to toggle source
# File lib/eaternet/agencies/multco.rb, line 50
def feed_info
  Eaternet::Lives_1_0::FeedInfo.new do |fi|
    fi.feed_date = Date.today
    fi.feed_version = '1.0'
    fi.municipality_name = 'Multnomah County, Oregon'
    fi.municipality_url = 'https://multco.us/services/restaurants'
    fi.contact_email = 'foodsafety@multco.us'
  end
end
inspections() click to toggle source
# File lib/eaternet/agencies/multco.rb, line 38
def inspections
  @violations = []
  import_inspections_and_capture_violations.map { |struct| try_to_create_inspection(struct) }
    .compact
end
violations() click to toggle source
# File lib/eaternet/agencies/multco.rb, line 44
def violations
  inspections if @violations.nil?
  @violations.map { |struct| try_to_create_violation(struct) }
    .compact
end

Private Instance Methods

import_inspection(page, business) click to toggle source
# File lib/eaternet/agencies/multco.rb, line 167
def import_inspection(page, business)
  i = Eaternet::Agencies::MultcoLib::Misc.parse_inspection(page: page)
  return if i.nil?
  {
    business_id: business.business_id,
    score: i['score'],
    date: i['date']
  }
end
import_inspections_and_capture_violations() click to toggle source
# File lib/eaternet/agencies/multco.rb, line 152
def import_inspections_and_capture_violations
  result = []

  businesses.each do |business|
    Eaternet::Agencies::MultcoLib::Misc.inspection_pages(business.business_id).each do |page|
      inspection_struct = import_inspection(page, business)
      next if inspection_struct.nil?
      result << inspection_struct
      @violations += import_violations(page, inspection_struct)
    end
  end

  result
end
import_violations(page, inspection) click to toggle source
# File lib/eaternet/agencies/multco.rb, line 177
def import_violations(page, inspection)
  Eaternet::Agencies::MultcoLib::Misc.parse_violations(page: page).map do |v|
    {
      business_id: inspection[:business_id],
      date: inspection[:date],
      code: v[:code_number],
      description: v[:code_description],
      facts: v[:facts]
    }
  end
end
inspection(struct) click to toggle source
# File lib/eaternet/agencies/multco.rb, line 72
def inspection(struct)
  Eaternet::Lives_1_0::Inspection.new do |i|
    i.business_id = struct[:business_id]
    i.score = struct[:score]
    i.date = struct[:date]
  end
end
multco_get_index() { |d| ... } click to toggle source
# File lib/eaternet/agencies/multco.rb, line 98
def multco_get_index
  result = []
  agent = Mechanize.new
  agent.get('http://www3.multco.us/MCHealthInspect/ListSearch.aspx')
  agent.page.forms[0].click_button
  form        = agent.page.forms[0]
  button_next = form.button_with(id: 'Next')

  until button_next.nil?
    agent.page.search('table#ResultsDataGrid > tr').each do |tr|
      d = multco_parse_business_table_row(tr)
      next if d.nil? || Eaternet::Agencies::MultcoLib::Misc.blacklisted?(name: d['name'])
      result << yield(d)
    end
    # Go to the next page
    form.click_button(button_next)
    form = agent.page.forms[0]
    button_next = form.button_with(id: 'Next')
  end
  result
end
multco_parse_business_table_row(tr) click to toggle source
# File lib/eaternet/agencies/multco.rb, line 120
def multco_parse_business_table_row(tr)
  result = {}

  columns = tr.search('td')
  link    = columns[0].search('a')
  return nil if link.nil?

  link.to_html =~ /id=([^"]+)/
  orig_key = Regexp.last_match(1)
  return nil unless orig_key

  result['name']        = columns[0].inner_text.strip
  result['address']     = columns[1].inner_text.strip
  result['city']        = columns[2].inner_text.strip
  result['zipcode']     = columns[3].inner_text.strip
  result['orig_key']    = orig_key
  result['detail_page'] = link

  return nil if multco_unwanted?(result)
  result
end
multco_unwanted?(business_data) click to toggle source
# File lib/eaternet/agencies/multco.rb, line 142
def multco_unwanted?(business_data)
  # Throw out weird "Surveillance" results
  return true if business_data['name'] =~ /(Surveill|Surlleillance)/i

  # Throw out food carts
  return true if business_data['address'].blank?

  false
end
try_to_create_inspection(struct) click to toggle source
# File lib/eaternet/agencies/multco.rb, line 63
def try_to_create_inspection(struct)
  inspection(struct)
rescue ArgumentError => e
  logger.warn('Multnomah County LIVES adapter') do
    "Could not create a LIVES Inspection from #{struct.inspect}: #{e}"
  end
  nil
end
try_to_create_violation(struct) click to toggle source
# File lib/eaternet/agencies/multco.rb, line 80
def try_to_create_violation(struct)
  violation(struct)
rescue ArgumentError => e
  logger.warn('Multnomah County LIVES adapter') do
    "Could not create a LIVES Violation from #{struct.inspect}: #{e}"
  end
  nil
end
violation(struct) click to toggle source
# File lib/eaternet/agencies/multco.rb, line 89
def violation(struct)
  Eaternet::Lives_1_0::Violation.new do |v|
    v.business_id = struct[:business_id]
    v.date =        struct[:date]
    v.code =        struct[:code]
    v.description = struct[:description]
  end
end