mitchellh-rubyuw 0.6.1 → 0.6.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.markdown +32 -1
- data/Rakefile +0 -5
- data/VERSION +1 -1
- data/lib/myuw/sln.rb +32 -25
- data/rubyuw.gemspec +2 -2
- data/test/mocked/myuw_test.rb +2 -0
- data/test/mocked/sln_test.rb +96 -3
- data/test/mocked/test_helper.rb +6 -0
- metadata +2 -2
data/README.markdown
CHANGED
@@ -46,4 +46,35 @@ The following is a quick and simple example:
|
|
46
46
|
myuw.login("netid", "password") or raise("Login Failed!")
|
47
47
|
|
48
48
|
# Get SLN information
|
49
|
-
sln_info = myuw.sln(14153)
|
49
|
+
sln_info = myuw.sln(14153)
|
50
|
+
|
51
|
+
# Get user course schedule
|
52
|
+
schedule = myuw.schedule.schedule
|
53
|
+
|
54
|
+
## Testing
|
55
|
+
|
56
|
+
RubyUW includes a comprehensive test suite included both live and
|
57
|
+
mocked testing. Mocked testing uses "mocked" HTML pages and a lot
|
58
|
+
of object stubbing to simulate a real environment and to force
|
59
|
+
certain events to occur (such as strange HTML in a request) in order
|
60
|
+
to completely test the library. Mock testing can be run straight
|
61
|
+
"out of the box" via a rake task:
|
62
|
+
|
63
|
+
rake test:run_mock
|
64
|
+
|
65
|
+
RubyUW also includes "live" testing which uses a real UW NetID and
|
66
|
+
password to conduct live tests. To run this, see test/password.rb.sample
|
67
|
+
and modify it to include your credentials, then save it as password.rb.
|
68
|
+
Following this, run another rake task:
|
69
|
+
|
70
|
+
rake test:run_live
|
71
|
+
|
72
|
+
Note: Live testing is very very slow. On my machine with the current
|
73
|
+
suite it takes about a minute to run all the tests (though this is
|
74
|
+
highly dependent on your internet connection).
|
75
|
+
|
76
|
+
Note: Also, live testing DOES NOT test registration since that actually
|
77
|
+
affects your MyUW account in a significant way. To test registration,
|
78
|
+
run the registration test directly:
|
79
|
+
|
80
|
+
cd test/live && ruby registration_test.rb
|
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.6.
|
1
|
+
0.6.2
|
data/lib/myuw/sln.rb
CHANGED
@@ -36,6 +36,9 @@ class MyUW
|
|
36
36
|
# Request the actual page
|
37
37
|
page = get_sln_page
|
38
38
|
|
39
|
+
# Check if the time is not available
|
40
|
+
check_time_schedule_closed page
|
41
|
+
|
39
42
|
# Get the actual course information
|
40
43
|
get_course_info page
|
41
44
|
get_enrollment_info page
|
@@ -72,48 +75,51 @@ class MyUW
|
|
72
75
|
# Gets the basic SLN info (the top table in the
|
73
76
|
# current status page)
|
74
77
|
def get_course_info(page)
|
78
|
+
data_keys = [nil, :course, :section, :type, :credits, :title]
|
75
79
|
info_nodes = page.search("//table[@border=1 and @cellpadding=3]//tr[@rowspan=1]//td")
|
76
|
-
raise InvalidPageError.new(page, "Could not extract course info for SLN.")
|
77
|
-
|
78
|
-
data_order = [nil, :course, :section, :type, :credits, :title]
|
79
|
-
info_nodes.each_with_index do |node, i|
|
80
|
-
if i < data_order.length then
|
81
|
-
data_key = data_order[i]
|
82
|
-
|
83
|
-
unless data_key.nil?
|
84
|
-
@data ||= {}
|
85
|
-
@data[data_key] = node.inner_text.strip.gsub("\302\240", "")
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
80
|
+
raise InvalidPageError.new(page, "Could not extract course info for SLN.") unless extract_info(data_keys, info_nodes)
|
89
81
|
end
|
90
82
|
|
91
83
|
# Gets the enrollment information for an SLN such
|
92
84
|
# as current enrollment, space available, etc.
|
93
85
|
def get_enrollment_info(page)
|
86
|
+
data_keys = [:current_enrollment, :limit_enrollment, :room_capacity, :space_available, :status]
|
94
87
|
info_nodes = page.search("//table[@border=1 and @cellpadding=3]//tr[count(td)=5]//td")
|
95
|
-
raise InvalidPageError.new(page, "Could not extract enrollment info for SLN.")
|
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?
|
96
102
|
|
97
|
-
|
98
|
-
|
99
|
-
if i <
|
100
|
-
data_key =
|
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]
|
101
107
|
|
108
|
+
# If the key is nil, we skip this node
|
102
109
|
unless data_key.nil?
|
103
110
|
@data ||= {}
|
104
111
|
@data[data_key] = node.inner_text.strip.gsub("\302\240", "")
|
105
112
|
end
|
106
113
|
end
|
107
114
|
end
|
115
|
+
|
116
|
+
true
|
108
117
|
end
|
109
118
|
|
110
|
-
#
|
111
|
-
|
112
|
-
|
113
|
-
raise
|
114
|
-
|
115
|
-
@data ||= {}
|
116
|
-
@data[:notes] = info_nodes[0].inner_text.strip
|
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"
|
117
123
|
end
|
118
124
|
end
|
119
125
|
|
@@ -121,4 +127,5 @@ class MyUW
|
|
121
127
|
# Exceptions
|
122
128
|
class InvalidSLNError < StandardError; end
|
123
129
|
class RequestSLNTooSoonError < StandardError; end
|
130
|
+
class TimeScheduleClosedError < StandardError; end
|
124
131
|
end
|
data/rubyuw.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{rubyuw}
|
5
|
-
s.version = "0.6.
|
5
|
+
s.version = "0.6.2"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Mitchell Hashimoto"]
|
9
|
-
s.date = %q{2009-
|
9
|
+
s.date = %q{2009-07-02}
|
10
10
|
s.description = %q{TODO}
|
11
11
|
s.email = %q{mitchell.hashimoto@gmail.com}
|
12
12
|
s.extra_rdoc_files = [
|
data/test/mocked/myuw_test.rb
CHANGED
data/test/mocked/sln_test.rb
CHANGED
@@ -65,25 +65,118 @@ class MockedSlnTest < Test::Unit::TestCase
|
|
65
65
|
should "raise an InvalidPageError if it can't find the course info" do
|
66
66
|
fixture_page = @browser.get(path_to_html("sln_no_course_info"))
|
67
67
|
|
68
|
-
assert_raise MyUW::InvalidPageError do
|
68
|
+
e = assert_raise MyUW::InvalidPageError do
|
69
69
|
@sln.get_course_info(fixture_page)
|
70
70
|
end
|
71
|
+
|
72
|
+
assert !e.page.nil?
|
71
73
|
end
|
72
74
|
|
73
75
|
should "raise an InvalidPageError if it can't find the enrollment info" do
|
74
76
|
fixture_page = @browser.get(path_to_html("sln_no_enrollment_info"))
|
75
77
|
|
76
|
-
assert_raise MyUW::InvalidPageError do
|
78
|
+
e = assert_raise MyUW::InvalidPageError do
|
77
79
|
@sln.get_enrollment_info(fixture_page)
|
78
80
|
end
|
81
|
+
|
82
|
+
assert !e.page.nil?
|
79
83
|
end
|
80
84
|
|
81
85
|
should "raise an InvalidPageError if it can't find the course notes" do
|
82
86
|
fixture_page = @browser.get(path_to_html("sln_no_course_notes"))
|
83
87
|
|
84
|
-
assert_raise MyUW::InvalidPageError do
|
88
|
+
e = assert_raise MyUW::InvalidPageError do
|
85
89
|
@sln.get_course_notes(fixture_page)
|
86
90
|
end
|
91
|
+
|
92
|
+
assert !e.page.nil?
|
93
|
+
end
|
94
|
+
|
95
|
+
should "raise a TimeScheduleClosedError if the time schedule system is closed" do
|
96
|
+
fixture_page = mock()
|
97
|
+
fixture_page.stubs(:uri).returns("http://www.washington.edu/students/timeschd/nots.html")
|
98
|
+
fixture_page.stubs(:body).returns("")
|
99
|
+
@browser.expects(:get).returns(fixture_page)
|
100
|
+
|
101
|
+
assert_raise MyUW::TimeScheduleClosedError do
|
102
|
+
@sln.course
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
should "not raise a TimeScheduleClosedError if the URI doesn't match" do
|
107
|
+
fixture_page = @browser.get(path_to_html("sln_status"))
|
108
|
+
@browser.expects(:get).returns(fixture_page)
|
109
|
+
|
110
|
+
assert_nothing_raised do
|
111
|
+
@sln.course
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "extract info from nodes" do
|
117
|
+
setup do
|
118
|
+
@myuw = MyUW.new
|
119
|
+
@sln = @myuw.sln("123456", "AUT+2009")
|
120
|
+
|
121
|
+
@keys = [:foo, :bar, :baz]
|
122
|
+
@values = [
|
123
|
+
stub(:inner_text => "vfoo"),
|
124
|
+
stub(:inner_text => "vbar"),
|
125
|
+
stub(:inner_text => "vbaz")
|
126
|
+
]
|
127
|
+
|
128
|
+
@long_values = @values.dup
|
129
|
+
@long_values.push(stub(:inner_text => "vbad"))
|
130
|
+
|
131
|
+
@nil_keys = @keys.dup
|
132
|
+
@nil_keys.push(nil)
|
133
|
+
@nil_keys.push(:bang)
|
134
|
+
|
135
|
+
@nil_values = @long_values.dup
|
136
|
+
@nil_values.push(stub(:inner_text => "vbang"))
|
137
|
+
end
|
138
|
+
|
139
|
+
should "return false if there are no nodes" do
|
140
|
+
assert !@sln.extract_info(@keys, [])
|
141
|
+
end
|
142
|
+
|
143
|
+
should "return true if everything is good" do
|
144
|
+
assert @sln.extract_info(@keys, @values)
|
145
|
+
end
|
146
|
+
|
147
|
+
should "only extract as long as there are keys left" do
|
148
|
+
assert @sln.extract_info(@keys, @long_values)
|
149
|
+
assert_equal @keys.length, @sln.data.length
|
150
|
+
|
151
|
+
# It shouldn't get the 4th long value since there are only 3 keys
|
152
|
+
@sln.data.each { |k,v| assert_not_equal @long_values[@keys.length].inner_text, v }
|
153
|
+
end
|
154
|
+
|
155
|
+
should "extract values and associate them with proper keys" do
|
156
|
+
assert @sln.extract_info(@keys, @values)
|
157
|
+
assert_equal @keys.length, @sln.data.length
|
158
|
+
|
159
|
+
@sln.data.each do |k,v|
|
160
|
+
assert @keys.include?(k)
|
161
|
+
assert_equal @values[@keys.index(k)].inner_text, v
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
should "not store values associated with nil keys" do
|
166
|
+
assert @sln.extract_info(@nil_keys, @nil_values)
|
167
|
+
assert_equal (@nil_keys.length - 1), @sln.data.length
|
168
|
+
|
169
|
+
@nil_keys.each_index do |i|
|
170
|
+
key = @nil_keys[i]
|
171
|
+
|
172
|
+
# If the key is nil, it should NOT store the value
|
173
|
+
# at that index, otherwise it should
|
174
|
+
if key.nil?
|
175
|
+
assert !@sln.data.has_value?(@nil_values[i].inner_text)
|
176
|
+
else
|
177
|
+
assert_equal @nil_values[i].inner_text, @sln.data[key]
|
178
|
+
end
|
179
|
+
end
|
87
180
|
end
|
88
181
|
end
|
89
182
|
end
|
data/test/mocked/test_helper.rb
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'myuw')
|
2
|
+
require 'test/unit'
|
3
|
+
require "contest"
|
4
|
+
require "stories"
|
5
|
+
require "mocha"
|
6
|
+
|
1
7
|
class Test::Unit::TestCase
|
2
8
|
def path_to_html(html)
|
3
9
|
"file://" + File.join(File.dirname(__FILE__), 'fixture_pages', "#{html}.html")
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mitchellh-rubyuw
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mitchell Hashimoto
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-07-02 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|