mitchellh-rubyuw 0.7.2 → 0.99.0

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/lib/myuw/schedule.rb DELETED
@@ -1,74 +0,0 @@
1
- class MyUW
2
- # = Synopsis
3
- # The Schdule class is responsible for querying a
4
- # student's currently registered schedule.
5
- class Schedule
6
- attr_accessor :myuw
7
- attr_reader :courses
8
-
9
- def initialize(myuw=nil)
10
- @myuw ||= myuw
11
- @courses = nil
12
- end
13
-
14
- def credits(force=false)
15
- return @credits if @credits && !force
16
- schedule(true)
17
- @credits
18
- end
19
-
20
- def schedule(force=false)
21
- raise NotLoggedInError.new("User must be logged in to fetch SLN data") unless @myuw.logged_in?
22
-
23
- # Return the schedule if we precached it at some point
24
- # unless we're forcing it
25
- return @courses if @courses && !force
26
-
27
- # Grab the schedule page
28
- schedule_page = @myuw.browser.get("https://sdb.admin.washington.edu/students/uwnetid/schedule.asp")
29
-
30
- # Grab the info out of it
31
- get_courses schedule_page
32
-
33
- # Grab the credits
34
- get_credits schedule_page
35
-
36
- # Return the courses
37
- @courses
38
- end
39
-
40
- def get_courses(schedule)
41
- courses = schedule.search("//table[@border=1 and @cellpadding=3]//tr[@bgcolor='#d0d0d0'][2]/following-sibling::*//td[@align='center']/parent::*")
42
- raise InvalidPageError.new(schedule, "No courses were found") if courses.empty?
43
-
44
- data_order = [:sln, :course, :type, :credits, :title, :days, :time, :location, :instructor]
45
-
46
- @courses = []
47
- courses.each do |course|
48
- data = course.search('td')
49
- raise InvalidPageError(schedule, "Something strange happening, found courses but no course data") if data.empty?
50
-
51
- course_info = {}
52
- i = 0
53
- data.each do |datum|
54
- break if data_order[i].nil?
55
-
56
- course_info[data_order[i]] = datum.inner_text.strip.gsub("\302\240", "")
57
- i += 1
58
- end
59
-
60
- @courses.push(course_info)
61
- end
62
- end
63
-
64
- def get_credits(schedule)
65
- credits = schedule.search("//table[@border=1 and @cellpadding=3]//tr[@bgcolor='#d0d0d0'][2]/following-sibling::*//td[@colspan=4]")
66
- raise InvalidPageError.new(schedule, "No credit row was found") if credits.empty?
67
-
68
- credits_text = credits[0].inner_text.strip.gsub("\302\240", "")
69
- raise InvalidPageError.new(schedule, "Credit row in different syntax") unless credits_text =~ /^Total credits: (.+?)$/
70
-
71
- @credits = $1.to_f
72
- end
73
- end
74
- end
data/lib/myuw/session.rb DELETED
@@ -1,91 +0,0 @@
1
- class MyUW
2
- # = Synopsis
3
- # This class encapsulates a MyUW session. It handles
4
- # the login/logout of the MyUW portal.
5
- class Session
6
- attr_accessor :myuw
7
- attr_accessor :email
8
- attr_accessor :password
9
-
10
- def initialize(myuw=nil)
11
- @myuw ||= myuw
12
-
13
- @email = @password = nil
14
- end
15
-
16
- # Checks if a user is logged in. This method is actually
17
- # pretty expensive in terms of time since it actually
18
- # verifies by going to the MyUW homepage and seeing if the
19
- # dashboard loads.
20
- def logged_in?
21
- home = get_bare_login_page
22
- relay_page = home.form_with(:name => 'f').submit()
23
- !relay_page.search("//div[@class='main_search']").empty?
24
- end
25
-
26
- # Logs a user in using the given email and password
27
- def login
28
- # Make sure that email and password are filled out or this is
29
- # useless
30
- if @email.nil? || @password.nil?
31
- raise ArgumentError.new("Email and password weren't specified for MyUW session")
32
- end
33
-
34
- # Log out first
35
- logout
36
-
37
- # Go to the MyUW page and get to the login form
38
- login_page = get_login_page
39
- login_form = login_page.form_with(:name => 'query')
40
- raise InvalidPageError.new(login_page, "Login form was not found on the MyUW page") if login_form.nil?
41
- login_form.user = @email
42
- login_form.pass = @password
43
- relay_page = login_form.submit()
44
-
45
- # Check if the login failed
46
- unless relay_page.form_with(:name => 'query').nil?
47
- return false
48
- end
49
-
50
- # Follow the relay
51
- follow_relay_page(relay_page)
52
- true
53
- end
54
-
55
- # Log out of the MyUW site
56
- def logout
57
- @myuw.browser.cookie_jar.clear!
58
- end
59
-
60
- private
61
-
62
- # Gets the myuw.washington.edu homepage. It raises an error
63
- # if it cannot find the login button (meaning something
64
- # weird is going on)
65
- def get_bare_login_page
66
- home = @myuw.browser.get("http://myuw.washington.edu")
67
-
68
- # Click the login button to get to the forum
69
- entry_button = home.search("//input[@type='submit' and @value='Log in with your UW NetID']")
70
- raise InvalidPageError.new(home, "Failed to find the log in button") if entry_button.empty?
71
-
72
- home
73
- end
74
-
75
- # Gets the actual login page by pressing the "Log In"
76
- # button and following the relay
77
- def get_login_page
78
- home = get_bare_login_page
79
- entry_form = home.form_with(:name => 'f')
80
- relay_page = entry_form.submit()
81
-
82
- return follow_relay_page(relay_page)
83
- end
84
-
85
- # Follows a relay form
86
- def follow_relay_page(relay_page)
87
- relay_form = relay_page.form_with(:name => 'relay')
88
- relay_form.submit()
89
- end
90
- end
91
- end
data/lib/myuw/sln.rb DELETED
@@ -1,131 +0,0 @@
1
- class MyUW
2
- # = Synopsis
3
- # Gets information regarding a specific SLN, returning
4
- # information in a SLN object.
5
- class SLNInfo
6
- attr_reader :term
7
- attr_reader :sln
8
- attr_accessor :myuw
9
- attr_reader :data
10
-
11
- def initialize(myuw)
12
- @myuw = myuw
13
- @term = nil
14
- @data = nil
15
- @sln = nil
16
- end
17
-
18
- # Custom setter for SLN to reset data
19
- def sln=(value)
20
- @sln = value
21
- @data = nil
22
- end
23
-
24
- # Custom setter for term to reset data
25
- def term=(value)
26
- @term = value
27
- @data = nil
28
- end
29
-
30
- # Fetches the information for the given SLN.
31
- def fetch_data
32
- raise ArgumentError.new("SLN not set.") if @sln.nil?
33
- raise ArgumentError.new("Term not set.") if @term.nil?
34
- raise NotLoggedInError.new("User must be logged in to fetch SLN data") unless @myuw.logged_in?
35
-
36
- # Request the actual page
37
- page = get_sln_page
38
-
39
- # Check if the time is not available
40
- check_time_schedule_closed page
41
-
42
- # Get the actual course information
43
- get_course_info page
44
- get_enrollment_info page
45
- get_course_notes page
46
- end
47
-
48
- # The methods to extract various info out of the SLN. While
49
- # I tend to try to avoid metaprogramming, this case seemed
50
- # simple enough. Nothing tricky happening here!
51
- [:course, :section, :type, :credits, :title, :current_enrollment,
52
- :limit_enrollment, :room_capacity, :space_available, :status,
53
- :notes].each do |info|
54
- eval(<<-eomethod)
55
- def #{info}
56
- fetch_data if @data.nil?
57
- @data[:#{info}]
58
- end
59
- eomethod
60
- end
61
-
62
- # Gets the SLN info page for the SLN and term, raising
63
- # an exception if it is requested too soon
64
- def get_sln_page
65
- page = @myuw.browser.get("https://sdb.admin.washington.edu/timeschd/uwnetid/sln.asp?QTRYR=#{@term}&SLN=#{@sln}")
66
- if page.uri.to_s == "http://www.washington.edu/students/timeschd/badrequest.html"
67
- raise RequestSLNTooSoonError.new("Attempted to fetch SLN data too soon.")
68
- elsif page.body.to_s =~ /SLN: #{@sln} does not exist./
69
- raise InvalidSLNError.new("SLN does not exist.")
70
- end
71
-
72
- page
73
- end
74
-
75
- # Gets the basic SLN info (the top table in the
76
- # current status page)
77
- def get_course_info(page)
78
- data_keys = [nil, :course, :section, :type, :credits, :title]
79
- info_nodes = page.search("//table[@border=1 and @cellpadding=3]//tr[@rowspan=1]//td")
80
- raise InvalidPageError.new(page, "Could not extract course info for SLN.") unless extract_info(data_keys, info_nodes)
81
- end
82
-
83
- # Gets the enrollment information for an SLN such
84
- # as current enrollment, space available, etc.
85
- def get_enrollment_info(page)
86
- data_keys = [:current_enrollment, :limit_enrollment, :room_capacity, :space_available, :status]
87
- info_nodes = page.search("//table[@border=1 and @cellpadding=3]//tr[count(td)=5]//td")
88
- raise InvalidPageError.new(page, "Could not extract enrollment info for SLN.") unless extract_info(data_keys, info_nodes)
89
- end
90
-
91
- # Gets the notes for a course
92
- def get_course_notes(page)
93
- data_keys = [:notes]
94
- info_nodes = page.search("//table[@border=1 and @cellpadding=3]//tr[count(td)=1]//preceding-sibling::tr[count(th)=1]//following-sibling::tr//td")
95
- raise InvalidPageError.new(page, "Could not find course notes information.") unless extract_info(data_keys, info_nodes)
96
- end
97
-
98
- # Extracts course information from each node and
99
- # stores it as the proper key in the @data variable
100
- def extract_info(keys, nodes)
101
- return false if nodes.empty?
102
-
103
- nodes.each_with_index do |node, i|
104
- # Make sure we have keys left still
105
- if i < keys.length then
106
- data_key = keys[i]
107
-
108
- # If the key is nil, we skip this node
109
- unless data_key.nil?
110
- @data ||= {}
111
- @data[data_key] = node.inner_text.strip.gsub("\302\240", "")
112
- end
113
- end
114
- end
115
-
116
- true
117
- end
118
-
119
- # Checks if the time schedule system is closed and if
120
- # so, raises an exception
121
- def check_time_schedule_closed(page)
122
- raise TimeScheduleClosedError.new if page.uri.to_s == "http://www.washington.edu/students/timeschd/nots.html"
123
- end
124
- end
125
-
126
- #
127
- # Exceptions
128
- class InvalidSLNError < StandardError; end
129
- class RequestSLNTooSoonError < StandardError; end
130
- class TimeScheduleClosedError < StandardError; end
131
- end
data/rubyuw.gemspec DELETED
@@ -1,102 +0,0 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
- # -*- encoding: utf-8 -*-
5
-
6
- Gem::Specification.new do |s|
7
- s.name = %q{rubyuw}
8
- s.version = "0.7.2"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Mitchell Hashimoto"]
12
- s.date = %q{2009-09-09}
13
- s.description = %q{TODO}
14
- s.email = %q{mitchell.hashimoto@gmail.com}
15
- s.extra_rdoc_files = [
16
- "README.markdown"
17
- ]
18
- s.files = [
19
- ".gitignore",
20
- "README.markdown",
21
- "Rakefile",
22
- "VERSION",
23
- "lib/myuw.rb",
24
- "lib/myuw/curriculum_enrollment.rb",
25
- "lib/myuw/errors.rb",
26
- "lib/myuw/registration.rb",
27
- "lib/myuw/schedule.rb",
28
- "lib/myuw/session.rb",
29
- "lib/myuw/sln.rb",
30
- "rubyuw.gemspec",
31
- "test/live/registration_test.rb",
32
- "test/live/schedule_test.rb",
33
- "test/live/session_test.rb",
34
- "test/live/sln_test.rb",
35
- "test/live/test_helper.rb",
36
- "test/mocked/curriculum_enrollment_test.rb",
37
- "test/mocked/fixture_pages/bad_request.html",
38
- "test/mocked/fixture_pages/curric_courses.html",
39
- "test/mocked/fixture_pages/curric_no_courses.html",
40
- "test/mocked/fixture_pages/curric_no_curric_found.html",
41
- "test/mocked/fixture_pages/logged_in_relay.html",
42
- "test/mocked/fixture_pages/login.html",
43
- "test/mocked/fixture_pages/no_form_login.html",
44
- "test/mocked/fixture_pages/no_login_button.html",
45
- "test/mocked/fixture_pages/not_logged_in_relay.html",
46
- "test/mocked/fixture_pages/registration.html",
47
- "test/mocked/fixture_pages/registration_error.html",
48
- "test/mocked/fixture_pages/registration_error_no_rows.html",
49
- "test/mocked/fixture_pages/registration_no_form.html",
50
- "test/mocked/fixture_pages/registration_success.html",
51
- "test/mocked/fixture_pages/registration_unknown.html",
52
- "test/mocked/fixture_pages/schedule.html",
53
- "test/mocked/fixture_pages/schedule_diff_credit_row.html",
54
- "test/mocked/fixture_pages/schedule_empty.html",
55
- "test/mocked/fixture_pages/schedule_no_credit_row.html",
56
- "test/mocked/fixture_pages/sln_does_not_exist.html",
57
- "test/mocked/fixture_pages/sln_no_course_info.html",
58
- "test/mocked/fixture_pages/sln_no_course_notes.html",
59
- "test/mocked/fixture_pages/sln_no_enrollment_info.html",
60
- "test/mocked/fixture_pages/sln_status.html",
61
- "test/mocked/fixture_pages/welcome.html",
62
- "test/mocked/myuw_test.rb",
63
- "test/mocked/registration_test.rb",
64
- "test/mocked/schedule_test.rb",
65
- "test/mocked/session_test.rb",
66
- "test/mocked/sln_test.rb",
67
- "test/mocked/test_helper.rb",
68
- "test/password.rb.sample"
69
- ]
70
- s.homepage = %q{http://github.com/mitchellh/rubyuw}
71
- s.rdoc_options = ["--charset=UTF-8"]
72
- s.require_paths = ["lib"]
73
- s.rubygems_version = %q{1.3.4}
74
- s.summary = %q{Library which provides a ruby interface to the University of Washington student portal.}
75
- s.test_files = [
76
- "test/live/registration_test.rb",
77
- "test/live/schedule_test.rb",
78
- "test/live/session_test.rb",
79
- "test/live/sln_test.rb",
80
- "test/live/test_helper.rb",
81
- "test/mocked/curriculum_enrollment_test.rb",
82
- "test/mocked/myuw_test.rb",
83
- "test/mocked/registration_test.rb",
84
- "test/mocked/schedule_test.rb",
85
- "test/mocked/session_test.rb",
86
- "test/mocked/sln_test.rb",
87
- "test/mocked/test_helper.rb"
88
- ]
89
-
90
- if s.respond_to? :specification_version then
91
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
92
- s.specification_version = 3
93
-
94
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
95
- s.add_runtime_dependency(%q<tenderlove-mechanize>, [">= 0.9.2.20090428085858"])
96
- else
97
- s.add_dependency(%q<tenderlove-mechanize>, [">= 0.9.2.20090428085858"])
98
- end
99
- else
100
- s.add_dependency(%q<tenderlove-mechanize>, [">= 0.9.2.20090428085858"])
101
- end
102
- end
@@ -1,46 +0,0 @@
1
- if $0 != __FILE__
2
- puts <<-WORDS
3
- Note: Registration tests can only be run by directly
4
- invoking the registration_test.rb file in the
5
- test/live directory.
6
- WORDS
7
- end
8
-
9
- if $0 == __FILE__
10
- # Only run tests in this file if we're executing it
11
- # on its own
12
- require File.join(File.dirname(__FILE__), 'test_helper')
13
-
14
- class LiveRegistrationTest < Test::Unit::TestCase
15
- context "registering for a course" do
16
- setup do
17
- @myuw = MyUW.new
18
- @session = @myuw.session
19
- @session.email = MYUW_ID
20
- @session.password = MYUW_PASSWORD
21
- assert @session.login
22
-
23
- @schedule = @myuw.schedule
24
- @registration = @myuw.registration
25
-
26
- @good_course = "17697"
27
- @bad_courses = ["17778", "17779"]
28
- end
29
-
30
- should "successfully register for a course" do
31
- assert !@schedule.schedule.empty?
32
- @schedule.schedule.each { |course| assert_not_equal @good_course, course[:sln] }
33
-
34
- assert @registration.register([@good_course])
35
-
36
- @schedule.schedule(true)
37
- assert !@schedule.schedule.select { |course| course[:sln].to_i == @good_course.to_i }.empty?
38
- end
39
-
40
- should "successfully read erroneous registration for multiple courses" do
41
- assert !@registration.register(@bad_courses)
42
- assert !@registration.errors["17779"].empty?
43
- end
44
- end
45
- end
46
- end