rubyuw 0.99.1 → 0.99.2
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/README.md +8 -4
- data/VERSION +1 -1
- data/lib/rubyuw/base.rb +2 -2
- data/lib/rubyuw/connection.rb +4 -4
- data/lib/rubyuw/curriculum_enrollment.rb +3 -3
- data/lib/rubyuw/schedule.rb +1 -1
- data/lib/rubyuw/sln.rb +62 -10
- data/rubyuw.gemspec +1 -1
- data/test/live/sln_test.rb +5 -4
- data/test/mocked/sln_test.rb +37 -0
- data/test/mocked/test_helper.rb +0 -1
- metadata +1 -1
data/README.md
CHANGED
@@ -20,17 +20,21 @@ with. I do not support this.
|
|
20
20
|
|
21
21
|
RubyUW functions by emulating a human in an actual browser. It hunts
|
22
22
|
down buttons to click, fields to fill in, etc. It is programmed
|
23
|
-
using the
|
24
|
-
simulation.
|
23
|
+
using the ruby [mechanize library](http://github.com/tenderlove/mechanize) to achieve
|
24
|
+
this level of human simulation.
|
25
25
|
|
26
26
|
Of course this also means that even minor tweaks to the MyUW layout
|
27
27
|
could potentially "break" the RubyUW library.
|
28
28
|
|
29
29
|
## Installing
|
30
30
|
|
31
|
+
The `rubyuw` gem is hosted on [gemcutter](http://gemcutter.org/). If
|
32
|
+
your rubygems isn't updated to use gemcutter yet, please visit their
|
33
|
+
website to prepare your rubygems installation prior to running the
|
34
|
+
following command. (It takes only a minute)
|
35
|
+
|
31
36
|
# Install the gem
|
32
|
-
sudo gem
|
33
|
-
sudo gem install mitchellh-rubyuw
|
37
|
+
sudo gem install rubyuw
|
34
38
|
|
35
39
|
## Using RubyUW
|
36
40
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.99.
|
1
|
+
0.99.2
|
data/lib/rubyuw/base.rb
CHANGED
@@ -22,8 +22,8 @@ module RubyUW
|
|
22
22
|
# every feature), will require that this authentication is
|
23
23
|
# completed first.
|
24
24
|
#
|
25
|
-
# @param [String] UW NetID
|
26
|
-
# @param [String] Password for the UW NetID
|
25
|
+
# @param [String] netid UW NetID
|
26
|
+
# @param [String] password Password for the UW NetID
|
27
27
|
# @return [nil]
|
28
28
|
def authenticate(netid, password)
|
29
29
|
# Clear pre-existing session information first
|
data/lib/rubyuw/connection.rb
CHANGED
@@ -55,7 +55,7 @@ module RubyUW
|
|
55
55
|
# Flow item: Go to a specific URL. Calling this method will
|
56
56
|
# attach a task to the current flow to go to a specific URL.
|
57
57
|
#
|
58
|
-
# @param [String] URL to go to (must respond to #to_s)
|
58
|
+
# @param [String] url URL to go to (must respond to #to_s)
|
59
59
|
# @return self
|
60
60
|
def goto(url)
|
61
61
|
current_flow.push([:goto, url])
|
@@ -67,8 +67,8 @@ module RubyUW
|
|
67
67
|
# parameters may be given as the second argument to be filled into
|
68
68
|
# the form.
|
69
69
|
#
|
70
|
-
# @param [String] Name of the form.
|
71
|
-
# @param [Hash] Parameters to pass through to the form.
|
70
|
+
# @param [String] name Name of the form.
|
71
|
+
# @param [Hash] parameters Parameters to pass through to the form.
|
72
72
|
# @return self
|
73
73
|
def submit_form(name, parameters={})
|
74
74
|
current_flow.push([:submit_form, name, parameters])
|
@@ -79,7 +79,7 @@ module RubyUW
|
|
79
79
|
# a task to verify that the given XPath string matches at least one
|
80
80
|
# element.
|
81
81
|
#
|
82
|
-
# @param [String] XPath of the element(s) to verify existence of.
|
82
|
+
# @param [String] xpath XPath of the element(s) to verify existence of.
|
83
83
|
# @return self
|
84
84
|
def verify(xpath)
|
85
85
|
current_flow.push([:verify, xpath])
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module RubyUW
|
2
2
|
# RubyUW::CurriculumEnrollment is used to extract SLN information
|
3
|
-
# for an entire "curriculum" of courses (
|
3
|
+
# for an entire "curriculum" of courses (which is how MyUW refers
|
4
4
|
# to it). If you have multiple SLNs within the same curriculum
|
5
5
|
# (chemistry, computer science, history, etc.), it is more efficient
|
6
6
|
# to use the CurriculumEnrollment class rather than SLN.
|
@@ -24,8 +24,8 @@ module RubyUW
|
|
24
24
|
# directly from the MyUW curriculum information page. Authentication
|
25
25
|
# is required prior to use.
|
26
26
|
#
|
27
|
-
# @param [String] Curriculum to search for.
|
28
|
-
# @param [String] The term (quarter) to search in.
|
27
|
+
# @param [String] curriculum Curriculum to search for.
|
28
|
+
# @param [String] term The term (quarter) to search in.
|
29
29
|
def find(curriculum, term)
|
30
30
|
raise Errors::NotLoggedInError.new unless Base.authenticated?
|
31
31
|
|
data/lib/rubyuw/schedule.rb
CHANGED
@@ -21,7 +21,7 @@ module RubyUW
|
|
21
21
|
# * location
|
22
22
|
# * instructor
|
23
23
|
#
|
24
|
-
# To get any more details you have to use the {RubyUW::SLN
|
24
|
+
# To get any more details you have to use the {RubyUW::SLN} find
|
25
25
|
# method.
|
26
26
|
def get
|
27
27
|
raise Errors::NotLoggedInError.new unless Base.authenticated?
|
data/lib/rubyuw/sln.rb
CHANGED
@@ -16,15 +16,14 @@ module RubyUW
|
|
16
16
|
# sln_info = RubyUW::SLN.find("12345", "AUT+2009")
|
17
17
|
class SLN
|
18
18
|
attr_reader :sln
|
19
|
-
attr_reader :data
|
20
19
|
|
21
20
|
# Initialize a new SLN object. This should never be called on its
|
22
21
|
# own, but instead you should use the find method to setup a
|
23
22
|
# sln.
|
24
23
|
#
|
25
|
-
# @param [String] SLN number in string format.
|
26
|
-
# @param [String] Term that the SLN corresponds to.
|
27
|
-
# @param [Hash] Data of key to value.
|
24
|
+
# @param [String] sln SLN number in string format.
|
25
|
+
# @param [String] term Term that the SLN corresponds to.
|
26
|
+
# @param [Hash] data Data of key to value.
|
28
27
|
def initialize(sln, term, data)
|
29
28
|
@sln = sln
|
30
29
|
@term = term
|
@@ -34,17 +33,48 @@ module RubyUW
|
|
34
33
|
# Grab the data of the SLN based on a key. Returns the value of
|
35
34
|
# a field for the SLN, or nil otherwise. Supported fields coming
|
36
35
|
# soon.
|
37
|
-
|
36
|
+
#
|
37
|
+
# == Example:
|
38
|
+
#
|
39
|
+
# # Assuming @sln has an instance of {RubyUW::SLN} already
|
40
|
+
# course_name = @sln[:course]
|
41
|
+
# capacity = @sln[:room_capacity]
|
42
|
+
#
|
43
|
+
# == Supported fields in alphabetical order:
|
44
|
+
# * *course* - The name of the course
|
45
|
+
# * *credits* - The number of credits the course gives
|
46
|
+
# * *current_enrollment* - Number of students currently enrolled.
|
47
|
+
# * *curriculum* - The curriculum which this course is part of. This field's
|
48
|
+
# value can be used to query {RubyUW::CurriculumEnrollment}.
|
49
|
+
# * *limit_enrollment* - The maximum (limit) number of students which can be enrolled.
|
50
|
+
# * *notes* - Often a multi-paragraph block of text from the "notes" section
|
51
|
+
# on the course info page.
|
52
|
+
# * *room_capacity* - The capacity of the classroom.
|
53
|
+
# * *section* - The section of the course. Ex. "A" or "AB"
|
54
|
+
# * *space_available* -
|
55
|
+
# Space available at the moment. Note that there is an important difference
|
56
|
+
# between this and the difference between "limit_enrollment" and
|
57
|
+
# "current_enrollmemnt." This is because sometimes the university closes
|
58
|
+
# registration for a day (to open more slots the next day). So even though
|
59
|
+
# there may be space, there may be no openings for the day. There are other
|
60
|
+
# reasons as well.
|
61
|
+
# * *status* - Text pulled directly from "status" box on course info page.
|
62
|
+
# * *title* - The name of the course, typically in all caps. Ex. "INTRO TO LOGIC"
|
63
|
+
# * *type* - Type of course. Typically "LC" or "QZ" though others exist
|
64
|
+
def [](key)
|
38
65
|
@data[key.to_sym]
|
39
66
|
end
|
40
67
|
|
68
|
+
# Aliased for legacy
|
69
|
+
alias :data :[]
|
70
|
+
|
41
71
|
class <<self
|
42
72
|
# Finds information about a specific SLN. The SLN information
|
43
73
|
# is grabbed from the MyUW time schedule page. Authentication is
|
44
74
|
# required prior to use.
|
45
75
|
#
|
46
|
-
# @param [#to_s] The SLN, which must respond to #to_s
|
47
|
-
# @param [String] The term, as represented in the time schedule URL.
|
76
|
+
# @param [String, #to_s] sln_number The SLN, which must respond to #to_s
|
77
|
+
# @param [String] term The term, as represented in the time schedule URL.
|
48
78
|
# @return [RubyUW::SLN]
|
49
79
|
def find(sln_number, term)
|
50
80
|
raise Errors::NotLoggedInError.new unless Base.authenticated?
|
@@ -81,13 +111,35 @@ module RubyUW
|
|
81
111
|
[[:notes], "//table[@border=1 and @cellpadding=3]//tr[count(td)=1]//preceding-sibling::tr[count(th)=1]//following-sibling::tr//td"]
|
82
112
|
]
|
83
113
|
|
114
|
+
# Extract initial data, straight scraping
|
84
115
|
data = {}
|
85
|
-
extract_data.each
|
86
|
-
|
87
|
-
|
116
|
+
extract_data.each { |keys, xpath| data.merge!(Base.extract(page, xpath, keys)) }
|
117
|
+
|
118
|
+
# Extract other data which must be massaged
|
119
|
+
extract_curriculum(data)
|
88
120
|
|
89
121
|
data
|
90
122
|
end
|
123
|
+
|
124
|
+
# Extracts the "curriculum" from the SLN information. This curriculum
|
125
|
+
# can then be used with {RubyUW::CurriculumEnrollment} to grab multiple
|
126
|
+
# classes within the same curriculum simultaneously.
|
127
|
+
#
|
128
|
+
# The curriculum value used to query the enrollment page appears to
|
129
|
+
# follow the pattern that it is the course category, URL encoded.
|
130
|
+
#
|
131
|
+
# Examples:
|
132
|
+
# * CHEM 102 = "CHEM"
|
133
|
+
# * C LIT 240 = "C LIT"
|
134
|
+
#
|
135
|
+
# Note that this is subject to change at any time but this method is
|
136
|
+
# well unit tested in both mock and live tests, which should signal
|
137
|
+
# any changes quickly.
|
138
|
+
def extract_curriculum(data)
|
139
|
+
data[:course] =~ /^(.+?)(\d+)$/
|
140
|
+
data[:curriculum] = $1.strip
|
141
|
+
data
|
142
|
+
end
|
91
143
|
end
|
92
144
|
end
|
93
145
|
|
data/rubyuw.gemspec
CHANGED
data/test/live/sln_test.rb
CHANGED
@@ -11,12 +11,13 @@ class LiveSLNTest < Test::Unit::TestCase
|
|
11
11
|
:type => "QZ",
|
12
12
|
:credits => "",
|
13
13
|
:title => "INTRO TO LOGIC",
|
14
|
-
:current_enrollment => "
|
14
|
+
:current_enrollment => "22",
|
15
15
|
:limit_enrollment => "25",
|
16
16
|
:room_capacity => "40",
|
17
|
-
:space_available => "",
|
18
|
-
:status => "
|
19
|
-
:notes => "Quiz Section"
|
17
|
+
:space_available => "3",
|
18
|
+
:status => "Open",
|
19
|
+
:notes => "Quiz Section",
|
20
|
+
:curriculum => "PHIL"
|
20
21
|
}
|
21
22
|
}
|
22
23
|
end
|
data/test/mocked/sln_test.rb
CHANGED
@@ -32,6 +32,43 @@ class SLNTest < Test::Unit::TestCase
|
|
32
32
|
assert_equal v, @sln_obj.data(k.to_s)
|
33
33
|
end
|
34
34
|
end
|
35
|
+
|
36
|
+
should "be able to access using []" do
|
37
|
+
@data.each do |k,v|
|
38
|
+
assert_equal v, @sln_obj[k]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "extracting data from SLN page" do
|
44
|
+
setup do
|
45
|
+
mocked_page = RubyUW::Base.connection.get(path_to_html("sln_status"))
|
46
|
+
@data = RubyUW::SLN.extract_data_from_page(mocked_page)
|
47
|
+
end
|
48
|
+
|
49
|
+
context "extracting 'special' data from page" do
|
50
|
+
context "curriculum" do
|
51
|
+
should "strip any surrounding whitespace and trailing number and return curriculum" do
|
52
|
+
result = RubyUW::SLN.extract_curriculum({ :course => @data[:course]})
|
53
|
+
assert_equal "PHIL", result[:curriculum]
|
54
|
+
end
|
55
|
+
|
56
|
+
should "extract multiword curriculums" do
|
57
|
+
result = RubyUW::SLN.extract_curriculum({ :course => "C LIT 240"})
|
58
|
+
assert_equal "C LIT", result[:curriculum]
|
59
|
+
end
|
60
|
+
|
61
|
+
should "modify data in place" do
|
62
|
+
data = { :course => "PHIL 120" }
|
63
|
+
RubyUW::SLN.extract_curriculum(data)
|
64
|
+
assert_equal "PHIL", data[:curriculum]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "extracting typicaly data from page" do
|
70
|
+
# TODO
|
71
|
+
end
|
35
72
|
end
|
36
73
|
|
37
74
|
context "finding an SLN" do
|
data/test/mocked/test_helper.rb
CHANGED