├── config.ru ├── Gemfile ├── web.rb ├── Gemfile.lock ├── spec ├── marilyn_mensen_spec.rb └── mock_1.html └── marilyn_mensen.rb /config.ru: -------------------------------------------------------------------------------- 1 | require './web' 2 | run Sinatra::Application -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'sinatra' 4 | gem 'sinatra-contrib' 5 | gem 'sinatra-cross_origin' 6 | gem 'nokogiri' 7 | 8 | group :test do 9 | gem 'rspec' 10 | end -------------------------------------------------------------------------------- /web.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | require "json" 3 | require "sinatra" 4 | require "sinatra/json" 5 | require "sinatra/cross_origin" 6 | require "nokogiri" 7 | require "open-uri" 8 | require "./marilyn_mensen" 9 | 10 | BASE_URL = "http://menu.mensen.at/index/index/locid/" 11 | 12 | get '/:mensa_id' do 13 | cross_origin 14 | content_type :json 15 | 16 | doc = Nokogiri::HTML(open(BASE_URL + params[:mensa_id])) 17 | result = MarilynMensen.new.parse doc 18 | 19 | result.to_json 20 | end 21 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | backports (3.1.1) 5 | diff-lcs (1.2.1) 6 | eventmachine (1.0.3) 7 | nokogiri (1.5.9) 8 | rack (1.5.2) 9 | rack-protection (1.5.0) 10 | rack 11 | rack-test (0.6.2) 12 | rack (>= 1.0) 13 | rspec (2.13.0) 14 | rspec-core (~> 2.13.0) 15 | rspec-expectations (~> 2.13.0) 16 | rspec-mocks (~> 2.13.0) 17 | rspec-core (2.13.1) 18 | rspec-expectations (2.13.0) 19 | diff-lcs (>= 1.1.3, < 2.0) 20 | rspec-mocks (2.13.0) 21 | sinatra (1.3.6) 22 | rack (~> 1.4) 23 | rack-protection (~> 1.3) 24 | tilt (~> 1.3, >= 1.3.3) 25 | sinatra-contrib (1.3.2) 26 | backports (>= 2.0) 27 | eventmachine 28 | rack-protection 29 | rack-test 30 | sinatra (~> 1.3.0) 31 | tilt (~> 1.3) 32 | sinatra-cross_origin (0.2.0) 33 | tilt (1.3.6) 34 | 35 | PLATFORMS 36 | ruby 37 | 38 | DEPENDENCIES 39 | nokogiri 40 | rspec 41 | sinatra 42 | sinatra-contrib 43 | sinatra-cross_origin 44 | -------------------------------------------------------------------------------- /spec/marilyn_mensen_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | require "./marilyn_mensen" 3 | require "nokogiri" 4 | require "open-uri" 5 | 6 | describe MarilynMensen, "#parse" do 7 | it "parses the specified document" do 8 | doc = Nokogiri::HTML(open("spec/mock_1.html")) 9 | marilyn_mensen = MarilynMensen.new 10 | 11 | result = marilyn_mensen.parse doc 12 | result["description"].should == "JKU Linz Mensa Markt" 13 | 14 | result["Menü Classic 1"].length.should == 5 15 | result["Menü Classic 1"][0]["date"].should == "Mo, 25.03." 16 | result["Menü Classic 1"][0]["text"].should == "Classic #1 geschlossen!" 17 | result["Menü Classic 1"][3]["date"].should == "Do, 28.03." 18 | result["Menü Classic 1"][3]["text"].should == "Knoblauchrahmsuppe Cremespinat mit Rührei und Erdäpfelschmarrn" 19 | 20 | result["Menü Classic 2"].length.should == 5 21 | result["Menü Classic 2"][0]["date"].should == "Mo, 25.03." 22 | result["Menü Classic 2"][0]["text"].should == "Kohlrabicremesuppe mit Erbsen Marokkanisches Rindsragout mit gedörrten Pfirsichen, Vollkornspirelli und Salat" 23 | 24 | result["Choice"].length.should == 20 25 | end 26 | 27 | it "returns nil when the passed document is nil" do 28 | marilyn_mensen = MarilynMensen.new 29 | 30 | result = marilyn_mensen.parse nil 31 | result.should be_nil 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /marilyn_mensen.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | require "nokogiri" 3 | 4 | class MarilynMensen 5 | 6 | def parse(doc) 7 | { 8 | "description" => doc.css("#header span span").first.text.gsub(/\s+/, " ").strip, 9 | "Menü Classic 1" => menu_entries(doc, "Menü Classic 1"), 10 | "Menü Classic 2" => menu_entries(doc, "Menü Classic 2"), 11 | "Choice" => menu_item(doc, "Choice") 12 | } unless doc == nil 13 | end 14 | 15 | private 16 | 17 | def menu_item(doc, menu) 18 | begin 19 | menu_item = doc.xpath("//*[@class = 'menu-item']//h2[text() = '#{menu}']").first 20 | menu_item.parent.text.split("\n").map(&:strip).reject!(&:empty?) 21 | rescue 22 | nil 23 | end 24 | end 25 | 26 | def menu_entries(doc, menu) 27 | result = [] 28 | 29 | weekdays = [] 30 | week = doc.css("#week ul li").each do |weekday| 31 | day = weekday.css(".day").text 32 | date = weekday.text.gsub(day, "") 33 | weekdays.push "#{day}, #{date}" 34 | end 35 | 36 | menu = doc.xpath("//*[@class = 'menu-item']//h2[contains(text(),'#{menu}')]").first.parent 37 | menu.css(".menu-item-text").each_with_index do |menu_on_day, index| 38 | result.push({ 39 | "date" => weekdays[index], 40 | "text" => menu_on_day.content.gsub(/\s+/, " ").strip 41 | }) 42 | end 43 | 44 | result 45 | end 46 | 47 | end 48 | -------------------------------------------------------------------------------- /spec/mock_1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Speiseplan - JKU Linz Mensa Markt 4 | 5 | 6 | 17 | 18 | 19 |
20 | 28 |
29 |
30 |
31 |
32 |
33 |
34 | 42 |
43 |
    44 |
  • 45 | Mensa Logo 46 |
  • 47 |
  • Tel: 0732/2468/8350
    Fax: 0732/2468/9312
  • Altenbergerstraße 69 4040 Linz
    Email: mensa.linz@mensen.at
  • Betriebsleiter: Alexander Schedl
    Küchenchef: Alexander Brandstötter
48 |
49 |
50 |
51 |
52 | 53 | 54 | 55 |
56 |
    57 |
  • Mo
    25.03.

  • 58 |
  • Di
    26.03.

  • 59 |
  • Mi
    27.03.

  • 60 |
  • Do
    28.03.

  • 61 |
  • Fr
    29.03.

  • 62 |
  • Sa
    30.03.

  • 63 |
64 |
65 | 66 | 469 |
470 | Preise in EUR für Studierende / Universitätsbedienstete / Gäste  |  Alle Preise sind Inklusiv-Preise  |  powered by spiessberger-partner 471 |
472 |
473 |
474 | Logo Brainfood Brainfood 475 |
476 |
477 | Logo Vegetarisch Vegetarisch 478 |
479 |
480 | Logo Fisch Fisch 481 |
482 |
483 | AMA Gütesiegel AMA Gütesiegel 484 |
485 | 488 |
489 |
490 | 491 | Logo Mensa-CD 492 | 493 |
494 | 496 |
497 |
498 |
499 | 501 |
502 | 503 | --------------------------------------------------------------------------------