pennu 0.0.1 → 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|