pennu 0.0.1 → 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -1
- data/README.md +8 -3
- data/lib/classes/day.rb +21 -4
- data/lib/classes/dininghall.rb +31 -43
- data/lib/classes/errors.rb +4 -0
- data/lib/classes/meal.rb +63 -0
- data/lib/pennu/version.rb +1 -1
- metadata +4 -3
- data/lib/classes/menu.rb +0 -35
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
# pennu: Penn students, get fed. #
|
2
2
|
|
3
|
-
pennu is a simple Ruby
|
3
|
+
pennu is a simple Ruby gem that allows you to easily retreive the menus of Penn dining halls.
|
4
|
+
|
5
|
+
## Installation ##
|
6
|
+
|
7
|
+
pennu is hosted on rubygems, so installation is as simple as:
|
8
|
+
|
9
|
+
```gem install pennu```
|
4
10
|
|
5
11
|
## How to use pennu ##
|
6
12
|
|
@@ -32,7 +38,7 @@ Deli: Assorted Breads, Deli Meats and Cheeses made to order
|
|
32
38
|
Good 4 You: Tofu and Red Lentil Risotto, Roasted Eggplant, Balsamic Tomatoes
|
33
39
|
```
|
34
40
|
|
35
|
-
Calling ``` hill.friday.dinner``` will yield a ``` String``` like the output above. The menu items are more accessible as a hash of titles (e.g. ```Kettles``` and items (e.g. ```Mushroom Barley and Chicken Tortilla Soup```). To get the menu as a hash,
|
41
|
+
Calling ``` hill.friday.dinner``` will yield a ``` String``` like the output above. The menu items are more accessible as a hash of titles (e.g. ```Kettles```) and items (e.g. ```Mushroom Barley and Chicken Tortilla Soup```). To get the menu as a hash, simply call ```to_hash```. Running:
|
36
42
|
|
37
43
|
```ruby
|
38
44
|
puts hill.friday.dinner.to_hash.inspect
|
@@ -54,5 +60,4 @@ pennu was written and tested on Windows; some hiccups may result from running pe
|
|
54
60
|
All contributions are welcome via pull request.
|
55
61
|
|
56
62
|
## TODO ##
|
57
|
-
* Create gem
|
58
63
|
* More extensive testing
|
data/lib/classes/day.rb
CHANGED
@@ -1,9 +1,26 @@
|
|
1
1
|
class Day
|
2
|
-
attr_accessor :date, :breakfast, :lunch, :dinner
|
2
|
+
attr_accessor :date, :dining_hall, :breakfast, :lunch, :dinner
|
3
3
|
def initialize(dining_hall, date)
|
4
4
|
@date = date
|
5
|
-
@
|
6
|
-
@lunch = Menu.new(dining_hall, date, 'lunch')
|
7
|
-
@dinner = Menu.new(dining_hall, date, 'dinner')
|
5
|
+
@dining_hall = dining_hall
|
8
6
|
end
|
7
|
+
|
8
|
+
def breakfast()
|
9
|
+
# fetch bfast menu for the date
|
10
|
+
@breakfast = Meal.new(@dining_hall, @date, 'breakfast')
|
11
|
+
@breakfast
|
12
|
+
end
|
13
|
+
|
14
|
+
def lunch()
|
15
|
+
# fetch lunch menu for the date
|
16
|
+
@lunch = Meal.new(@dining_hall, @date, 'lunch')
|
17
|
+
@lunch
|
18
|
+
end
|
19
|
+
|
20
|
+
def dinner()
|
21
|
+
# fetch dinner menu for the date
|
22
|
+
@dinner = Meal.new(@dining_hall, @date, 'dinner')
|
23
|
+
@dinner
|
24
|
+
end
|
25
|
+
|
9
26
|
end
|
data/lib/classes/dininghall.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class DiningHall
|
2
|
-
attr_accessor :name, :urls, :
|
3
|
-
:tuesday, :wednesday, :thursday,
|
4
|
-
:saturday, :sunday
|
2
|
+
attr_accessor :name, :urls, :breakfast_tds, :lunch_tds, :dinner_tds,
|
3
|
+
:dates, :sunday, :monday, :tuesday, :wednesday, :thursday,
|
4
|
+
:friday, :saturday, :sunday
|
5
5
|
|
6
6
|
# Has days, which have meals
|
7
7
|
def initialize(name)
|
@@ -18,63 +18,51 @@ class DiningHall
|
|
18
18
|
end
|
19
19
|
|
20
20
|
@urls = {
|
21
|
-
'
|
21
|
+
'breakfast' => ROOT_URL + dining_hall_path + BREAKFAST_PATH,
|
22
22
|
'lunch' => ROOT_URL + dining_hall_path + LUNCH_PATH,
|
23
23
|
'dinner' => ROOT_URL + dining_hall_path + DINNER_PATH,
|
24
24
|
}
|
25
25
|
|
26
|
-
|
26
|
+
# Get dates for each day in the current week
|
27
|
+
self.get_days()
|
28
|
+
|
29
|
+
# Get the tds for each #{meal} for each day of the week
|
30
|
+
@urls.each { |meal, _| self.get_meal_tds(meal) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_days()
|
34
|
+
@dates = []
|
35
|
+
today = Date.today
|
36
|
+
@dates << today - today.wday # sunday
|
37
|
+
(1..6).each { |n| @dates << @dates[0] + n }
|
38
|
+
|
39
|
+
# Assign dates to days
|
40
|
+
# Each day will contain b, l, and d menus
|
41
|
+
@dates.each do |date|
|
42
|
+
if !(DAYS.index(date.strftime("%A").downcase).nil?)
|
43
|
+
self.instance_variable_set("@#{date.strftime("%A").downcase}", Day.new(self, date))
|
44
|
+
end
|
45
|
+
end
|
27
46
|
end
|
28
47
|
|
29
|
-
def
|
48
|
+
def get_meal_tds(meal)
|
30
49
|
# Get menu table from dining website, use dinner for dates
|
31
50
|
agent = Mechanize.new
|
32
|
-
meal_page = agent.get(self.urls[
|
51
|
+
meal_page = agent.get(self.urls[meal])
|
33
52
|
table = meal_page.search("div.boxbody")
|
34
53
|
|
35
54
|
# Scrape all tds into array
|
36
|
-
|
55
|
+
tds = []
|
37
56
|
table.xpath('//tr/td').to_a.each do |td|
|
38
57
|
td = td.text.lstrip.rstrip
|
39
58
|
tds << td unless (td.gsub(/\s+/, "") == "" or td.gsub(/\s+/, "") == "\u00A0")
|
40
59
|
end
|
41
60
|
|
42
61
|
# Remove dining hall title, which is the first element in tds
|
43
|
-
|
62
|
+
tds.shift
|
44
63
|
|
45
|
-
#
|
46
|
-
|
47
|
-
@dates = @tds.keep_if { |td|
|
48
|
-
begin
|
49
|
-
DateTime.strptime(td, "%A, %B %d, %Y")
|
50
|
-
rescue ArgumentError
|
51
|
-
false
|
52
|
-
else
|
53
|
-
true
|
54
|
-
end
|
55
|
-
}.map { |day_string| DateTime.strptime(day_string, "%A, %B %d, %Y") }
|
56
|
-
|
57
|
-
# Clone tds to preserve for later methods
|
58
|
-
@tds = tds_clone
|
59
|
-
|
60
|
-
# Assign dates to days
|
61
|
-
# Each day will contain b, l, and d menus
|
62
|
-
@dates.each do |date|
|
63
|
-
if date.strftime("%A") == "Sunday"
|
64
|
-
@sunday = Day.new(self, date)
|
65
|
-
elsif date.strftime("%A") == "Monday"
|
66
|
-
@monday = Day.new(self, date)
|
67
|
-
elsif date.strftime("%A") == "Tuesday"
|
68
|
-
@tuesday = Day.new(self, date)
|
69
|
-
elsif date.strftime("%A") == "Wednesday"
|
70
|
-
@wednesday = Day.new(self, date)
|
71
|
-
elsif date.strftime("%A") == "Thursday"
|
72
|
-
@thursday = Day.new(self, date)
|
73
|
-
elsif date.strftime("%A") == "Friday"
|
74
|
-
@friday = Day.new(self, date)
|
75
|
-
elsif date.strftime("%A") == "Saturday"
|
76
|
-
@saturday = Day.new(self, date)
|
77
|
-
end
|
78
|
-
end
|
64
|
+
# Set instance var
|
65
|
+
self.instance_variable_set("@#{meal}_tds", tds)
|
79
66
|
end
|
67
|
+
|
80
68
|
end
|
data/lib/classes/meal.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
class Meal
|
2
|
+
# Scrapes for one dining hall, one day, one meal
|
3
|
+
def initialize(dining_hall, date, meal)
|
4
|
+
@date = date
|
5
|
+
@meal = meal
|
6
|
+
@dining_hall = dining_hall
|
7
|
+
|
8
|
+
@day_items = self.get_day_items(@meal, @date)
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_hash()
|
12
|
+
# Add date key to beginning of hash and
|
13
|
+
# return hash of items and titles
|
14
|
+
{'date' => @date.to_s}.merge @day_items
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s()
|
18
|
+
str = "Menu for #{@meal} at #{@dining_hall.name.titlecase} on #{@date.strftime("%A, %B %d, %Y")}:\n"
|
19
|
+
@day_items.each do |title, item|
|
20
|
+
str += "#{title}: #{item}\n"
|
21
|
+
end
|
22
|
+
str.rstrip
|
23
|
+
end
|
24
|
+
|
25
|
+
def fetch_menu(meal)
|
26
|
+
# Get menu table from dining website, use dinner for dates
|
27
|
+
agent = Mechanize.new
|
28
|
+
meal_page = agent.get(@dining_hall.urls[meal])
|
29
|
+
table = meal_page.search("div.boxbody")
|
30
|
+
|
31
|
+
# Scrape all tds into array
|
32
|
+
@tds = []
|
33
|
+
table.xpath('//tr/td').to_a.each do |td|
|
34
|
+
td = td.text.lstrip.rstrip
|
35
|
+
@tds << td unless (td.gsub(/\s+/, "") == "" or td.gsub(/\s+/, "") == "\u00A0")
|
36
|
+
end
|
37
|
+
|
38
|
+
# Remove dining hall title, which is the first element in tds
|
39
|
+
@tds.shift
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_day_items(meal, date)
|
43
|
+
# Split dining hall tds array by date delimiter
|
44
|
+
# Each child array contains menu titles and items for one day
|
45
|
+
tds = @dining_hall.instance_variable_get("@#{meal}_tds")
|
46
|
+
days_items = tds.split do |td|
|
47
|
+
begin
|
48
|
+
DateTime.strptime(td, "%A, %B %d, %Y")
|
49
|
+
rescue ArgumentError
|
50
|
+
false
|
51
|
+
else
|
52
|
+
true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
begin
|
57
|
+
Hash[*days_items[DAYS.index(date.strftime("%A").downcase) + 1].flatten]
|
58
|
+
rescue NoMethodError => e
|
59
|
+
raise NoDataError, "Menu data unavailable for this meal."
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
data/lib/pennu/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pennu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.1'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-11-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: mechanize
|
@@ -41,7 +41,8 @@ files:
|
|
41
41
|
- lib/classes/array.rb
|
42
42
|
- lib/classes/day.rb
|
43
43
|
- lib/classes/dininghall.rb
|
44
|
-
- lib/classes/
|
44
|
+
- lib/classes/errors.rb
|
45
|
+
- lib/classes/meal.rb
|
45
46
|
- lib/classes/string.rb
|
46
47
|
- lib/pennu.rb
|
47
48
|
- lib/pennu/version.rb
|
data/lib/classes/menu.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
class Menu
|
2
|
-
# Scrapes for one dining hall, one day, one meal
|
3
|
-
def initialize(dining_hall, date, meal)
|
4
|
-
@date = date
|
5
|
-
@meal = meal
|
6
|
-
@dining_hall = dining_hall
|
7
|
-
|
8
|
-
# Split dining hall tds array by date delimiter
|
9
|
-
# Each child array contains menu titles and items for one day
|
10
|
-
days_items = @dining_hall.tds.split do |td|
|
11
|
-
begin
|
12
|
-
DateTime.strptime(td, "%A, %B %d, %Y")
|
13
|
-
rescue ArgumentError
|
14
|
-
false
|
15
|
-
else
|
16
|
-
true
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
@day_items = Hash[*days_items[DAYS.index(date.strftime("%A").downcase)].flatten]
|
21
|
-
end
|
22
|
-
|
23
|
-
def to_hash()
|
24
|
-
# Return hash of items and titles
|
25
|
-
@day_items
|
26
|
-
end
|
27
|
-
|
28
|
-
def to_s()
|
29
|
-
str = "Menu for #{@meal} at #{@dining_hall.name.titlecase} on #{@date.strftime("%A, %B %d, %Y")}:\n"
|
30
|
-
@day_items.each do |title, item|
|
31
|
-
str += "#{title}: #{item}\n"
|
32
|
-
end
|
33
|
-
str.rstrip
|
34
|
-
end
|
35
|
-
end
|