class Eaternet::Agencies::Nyc

A data source for New York City food service health inspections. It retrieves the latest CSV export from [the official source](data.cityofnewyork.us/Health/DOHMH-New-York-City-Restaurant-Inspection-Results/xx67-kt59) and makes it easy to work with. See our [NYC wiki page](github.com/eaternet/adapters/wiki/Agency:-New-York-City) for details about the data set.

Output is produced in the [LIVES 1.0](www.yelp.com/healthscores) format developed by Yelp and the cities of San Francisco and New York.

The downloaded CSV is cached for twelve hours in a temporary file.

@example Print the names of all the restaurants in New York City

require 'eaternet'
nyc = Eaternet::Nyc.new
puts nyc.businesses.map(&:name)

@example Compute the average inspection score

# The library is optimized for memory use at the expense
# of speed. E.g., each call to #inspections will iterate
# through the raw CSV. So here, we first retrieve the
# inspections into an array.
inspections = nyc.inspections.to_a
sum = inspections
        .map(&:score)
        .reduce(0, :+)
count = inspections.count

puts "Average inspection score: #{sum / count}"

@example See the Instance Method Details for more examples.

@see data.cityofnewyork.us/Health/DOHMH-New-York-City-Restaurant-Inspection-Results/xx67-kt59 NYC health scores official data, hosted on Socrata

Public Class Methods

new(csv_path: nil) click to toggle source

Create an NYC data-source, ready for querying.

@example

nyc = Eaternet::Nyc.new

@param [String] csv_path for unit testing

# File lib/eaternet/agencies/nyc.rb, line 59
def initialize(csv_path: nil)
  @fixture_table_file = csv_path
end

Private Class Methods

csv_url() click to toggle source
# File lib/eaternet/agencies/nyc.rb, line 206
def self.csv_url
  Eaternet::Socrata.csv_url domain: 'data.cityofnewyork.us', dataset: 'xx67-kt59'
end
download_via_url() click to toggle source

Fastest method for downloading all data but may be non-standard for Socrata.

# File lib/eaternet/agencies/nyc.rb, line 202
def self.download_via_url
  Eaternet::Util.download_and_cache(source: csv_url, dest: Tempfile.new('nyc'))
end

Public Instance Methods

business(row) click to toggle source

@private

# File lib/eaternet/agencies/nyc.rb, line 139
def business(row)
  address = "#{row['BUILDING']} #{row['STREET']}"

  Eaternet::Lives_1_0::Business.new do |b|
    b.business_id =  business_id(row)
    b.name =         row['DBA']
    b.address =      address
    b.city =         row['BORO']
    b.postal_code =  row['ZIPCODE']
    b.state =        'NY'
    b.phone_number = row['PHONE']
  end
end
businesses() click to toggle source

@example Print the number of restaurants in New York.

puts nyc.businesses.count

@return [Enumerable<Business>]

# File lib/eaternet/agencies/nyc.rb, line 67
def businesses
  map_csv { |row| try_to_create(:business, from_csv_row: row) }
    .uniq
    .compact
end
feed_info() click to toggle source

@example Print the name & URL of NYC's health agency.

puts nyc.feed_info.municipality_name
puts nyc.feed_info.municipality_url

@return [FeedInfo]

# File lib/eaternet/agencies/nyc.rb, line 104
def feed_info
  # Anyone know a contact email?
  Eaternet::Lives_1_0::FeedInfo.new do |fi|
    fi.feed_date = Date.today
    fi.feed_version = '1.0'
    fi.municipality_name = 'New York City'
    fi.municipality_url = 'http://www.nyc.gov/html/doh/html/services/restaurant-inspection.shtml'
  end
end
inspections() click to toggle source

@example Compute the average inspection score for NYC.

# The library is optimized for memory use at the expense
# of speed. E.g., each call to #inspections will iterate
# through the raw CSV. So here, we first retrieve the
# inspections into an array.
inspections = nyc.inspections.to_a
sum = inspections
        .map(&:score)
        .reduce(0, :+)
count = inspections.count

puts "Average inspection score: #{sum / count}"

@return [Enumerable<Inspection>]

# File lib/eaternet/agencies/nyc.rb, line 87
def inspections
  map_csv { |row| skip_inspection?(row) ? nil : try_to_create(:inspection, from_csv_row: row) }
    .uniq
    .compact
end
legends() click to toggle source

@return [Enumerable<Legend>]

# File lib/eaternet/agencies/nyc.rb, line 115
def legends
  Eaternet::Lives_1_0::LegendGroup.new do |lg|
    lg.legends = [
      Eaternet::Lives_1_0::Legend.new do |l|
        l.minimum_score = 87
        l.maximum_score = 100
        l.description =   'A'
      end,
      Eaternet::Lives_1_0::Legend.new do |l|
        l.minimum_score = 73
        l.maximum_score = 86
        l.description =   'B'
      end,
      Eaternet::Lives_1_0::Legend.new do |l|
        l.minimum_score = 0
        l.maximum_score = 72
        l.description =   'C'
      end
    ]
  end.legends
end
violations() click to toggle source

@return [Enumerable<Violation>]

# File lib/eaternet/agencies/nyc.rb, line 94
def violations
  map_csv { |row| skip_violation?(row) ? nil : violation(row) }
    .compact
end

Private Instance Methods

adapter_name() click to toggle source
# File lib/eaternet/agencies/nyc.rb, line 210
def adapter_name
  'NYC'
end
business_id(row) click to toggle source
# File lib/eaternet/agencies/nyc.rb, line 180
def business_id(row)
  row['CAMIS']
end
inspection(row) click to toggle source
# File lib/eaternet/agencies/nyc.rb, line 164
def inspection(row)
  Eaternet::Lives_1_0::Inspection.new do |i|
    i.business_id = business_id(row)
    i.date =        Date.strptime(row['INSPECTION DATE'], '%m/%d/%Y')
    i.score =       100 - row['SCORE'].to_i
  end
end
skip_inspection?(row) click to toggle source
# File lib/eaternet/agencies/nyc.rb, line 176
def skip_inspection?(row)
  transfat_inspection?(row)
end
skip_violation?(row) click to toggle source
# File lib/eaternet/agencies/nyc.rb, line 172
def skip_violation?(row)
  transfat_inspection?(row) || violation_code(row).nil?
end
table_file() click to toggle source
# File lib/eaternet/agencies/nyc.rb, line 196
def table_file
  @fixture_table_file || Nyc.download_via_url
end
transfat_inspection?(row) click to toggle source
# File lib/eaternet/agencies/nyc.rb, line 188
def transfat_inspection?(row)
  if row['INSPECTION TYPE']
    row['INSPECTION TYPE'].include?('Trans Fat')
  else
    false
  end
end
violation(row) click to toggle source
# File lib/eaternet/agencies/nyc.rb, line 155
def violation(row)
  Eaternet::Lives_1_0::Violation.new do |v|
    v.business_id = business_id(row)
    v.date =        Date.strptime(row['INSPECTION DATE'], '%m/%d/%Y')
    v.code =        violation_code(row)
    v.description = row['VIOLATION DESCRIPTION']
  end
end
violation_code(row) click to toggle source
# File lib/eaternet/agencies/nyc.rb, line 184
def violation_code(row)
  row['VIOLATION CODE']
end