class Rice::Dining::ManifestFetcher

Public Class Methods

new() click to toggle source
# File lib/rice/dining.rb, line 101
def initialize
  @allergen_map = {}
  @allergen_shortcodes = Set.new
end

Public Instance Methods

fetch() click to toggle source
# File lib/rice/dining.rb, line 106
def fetch
  @allergen_map.clear
  @allergen_shortcodes.clear

  # Make the request
  req = Net::HTTP::Get.new Rice::Dining::BASE
  req['User-Agent'.freeze] = Rice::Dining::IDENT
  res = Net::HTTP.start(Rice::Dining::BASE.hostname, Rice::Dining::BASE.port,
                        use_ssl: Rice::Dining::BASE.scheme == 'https'.freeze) {|h| h.request(req)}

  if res.is_a? Net::HTTPSuccess
    doc = Nokogiri::HTML(res.body)

    # find the title
    title_nodes = doc.css('div.alpha h1:contains("Your")'.freeze)
    unless title_nodes.empty?
      title_stuff = title_nodes.first.text
      title_stuff.strip!
      title_match = title_stuff.match /\Ayour\s+(?<title>[a-z]+)/i
      if title_match
        title = title_match[:title]
      else
        title = nil
      end
    else
      title = nil
    end

    # stash allergen references in the "key" section
    doc.css('div#key div.diet'.freeze).each do |allergen_node|
      allergen_reference allergen_node['class'.freeze]
    end

    # build each location
    locations = []
    location_nodes = doc.css('div.item'.freeze)
    raise CreateError, "couldn't find locations".freeze if location_nodes.empty?
    location_nodes.each do |location_node|
      # get the servery name
      name_nodes = location_node.css('div.servery-title h1'.freeze)
      next if name_nodes.empty?
      name = name_nodes.first.text
      name.strip!

      # might be closed
      closed = !location_node.css('div.nothere'.freeze).empty?
      if closed
        locations << Rice::Dining::Location.new(name)
      else
        # grab the items
        items = []
        item_nodes = location_node.css('div.menu-item'.freeze)
        item_nodes.each do |item_node|
          item_allergens, item_name = [], item_node.text
          item_name.strip!
          item_node.parent.css('div.allergen div.diet'.freeze).each do |allergen_node|
            allergen = allergen_reference allergen_node['class'.freeze]
            item_allergens << allergen if allergen
          end

          items << Rice::Dining::Item.new(item_name, *item_allergens.sort)
        end

        locations << Rice::Dining::Location.new(name, *items)
      end
    end

    locations.sort! do |a, b|
      if a.closed? and b.open?
        1
      elsif a.open? and b.closed?
        -1
      else
        a.name <=> b.name
      end
    end

    Rice::Dining::Manifest.new title, locations, @allergen_map.values
  else
    # Problem with the response
    raise CreateError, "got HTTP #{res.code} from #{Rice::Dining::BASE}"
  end
end

Private Instance Methods

allergen_cleanup(allergens) click to toggle source
# File lib/rice/dining.rb, line 216
def allergen_cleanup allergens
  ret = allergens.match(/\Adiet\s+(?<type>[a-z]+)/i)
  return nil if ret.nil?
  ret[:type].downcase.to_sym
end
allergen_reference(allergen_class) click to toggle source
# File lib/rice/dining.rb, line 192
def allergen_reference allergen_class
  # build the allergen key
  key = allergen_cleanup allergen_class
  return nil if key.nil?

  if !@allergen_map.include? key
    # find a unique value for the shortcode
    shortcode = key[0].to_sym
    if @allergen_shortcodes.include? shortcode
      shortcode = shortcode.swapcase

      while @allergen_shortcodes.include? shortcode
        shortcode = shortcode.downcase.succ
      end
    end

    # create the allergen
    allergen = @allergen_map[key] = Rice::Dining::Allergen.new(key, shortcode)
    @allergen_shortcodes << shortcode
  else
    allergen = @allergen_map[key]
  end
end