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.
@@ -1,11 +1,67 @@
1
- require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'myuw')
1
+ require 'rubygems'
2
+ $:.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
3
+ require 'rubyuw'
2
4
  require 'test/unit'
3
5
  require "contest"
4
6
  require "stories"
5
7
  require "mocha"
6
8
 
7
9
  class Test::Unit::TestCase
10
+ def setup
11
+ RubyUW::Base.reset_connection!
12
+ RubyUW::Base.connection.follow_meta_refresh = false
13
+ end
14
+
8
15
  def path_to_html(html)
9
16
  "file://" + File.join(File.dirname(__FILE__), 'fixture_pages', "#{html}.html")
10
17
  end
18
+
19
+ def expect_get(return_page, with=nil, expectation_type = :expects)
20
+ return_html = RubyUW::Base.connection.get(path_to_html(return_page))
21
+ expectation_obj = RubyUW::Base.connection.send(expectation_type, :get).returns(return_html)
22
+ expectation_obj.with(with) unless with.nil?
23
+
24
+ return_html
25
+ end
26
+
27
+ def mock_flow(flow)
28
+ flow_seq = sequence('flow')
29
+
30
+ flow.each do |task, params, return_html|
31
+ return_page = RubyUW::Base.connection.get(path_to_html(return_html))
32
+
33
+ relay_form = return_page.form_with(:name => 'relay')
34
+ relay_form.stubs(:submit) if relay_form
35
+
36
+ RubyUW::Base.connection.expects("execute_#{task}!").with(anything, *params).returns(return_page).in_sequence(flow_seq)
37
+ end
38
+ end
39
+ end
40
+
41
+ # Ugly hack. Avoiding using send() since that will not work in
42
+ # Ruby 1.9. Also, since I'm trying to make SINGLETON methods
43
+ # public, I can't do the Class.send(:public, *Class.protected_methods)
44
+ # trick. So this is the ugly hack until I can find a way around it.
45
+ # Anyone?
46
+ class Class
47
+ def publicize_singleton_methods
48
+ class << self
49
+ @_publicize_internals = protected_instance_methods
50
+ public *@_publicize_internals
51
+ end
52
+
53
+ if block_given?
54
+ yield
55
+
56
+ class <<self
57
+ protected *@_publicize_internals
58
+ end
59
+ end
60
+ end
61
+
62
+ def protect_singleton_methods
63
+ class <<self
64
+ protected *@_publicize_internals
65
+ end
66
+ end
11
67
  end
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.7.2
4
+ version: 0.99.0
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-09-09 00:00:00 -07:00
12
+ date: 2009-09-14 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,34 +20,32 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 0.9.2.20090428085858
23
+ version: 0.9.3.20090623142847
24
24
  version:
25
- description: TODO
25
+ description: Library which provides a ruby interface to the University of Washington student portal.
26
26
  email: mitchell.hashimoto@gmail.com
27
27
  executables: []
28
28
 
29
29
  extensions: []
30
30
 
31
31
  extra_rdoc_files:
32
- - README.markdown
32
+ - README.md
33
33
  files:
34
34
  - .gitignore
35
- - README.markdown
35
+ - README.md
36
36
  - Rakefile
37
37
  - VERSION
38
- - lib/myuw.rb
39
- - lib/myuw/curriculum_enrollment.rb
40
- - lib/myuw/errors.rb
41
- - lib/myuw/registration.rb
42
- - lib/myuw/schedule.rb
43
- - lib/myuw/session.rb
44
- - lib/myuw/sln.rb
45
- - rubyuw.gemspec
46
- - test/live/registration_test.rb
47
- - test/live/schedule_test.rb
48
- - test/live/session_test.rb
38
+ - lib/rubyuw.rb
39
+ - lib/rubyuw/base.rb
40
+ - lib/rubyuw/connection.rb
41
+ - lib/rubyuw/curriculum_enrollment.rb
42
+ - lib/rubyuw/errors.rb
43
+ - lib/rubyuw/sln.rb
44
+ - test/live/curriculum_enrollment_test.rb
49
45
  - test/live/sln_test.rb
50
46
  - test/live/test_helper.rb
47
+ - test/mocked/base_test.rb
48
+ - test/mocked/connection_test.rb
51
49
  - test/mocked/curriculum_enrollment_test.rb
52
50
  - test/mocked/fixture_pages/bad_request.html
53
51
  - test/mocked/fixture_pages/curric_courses.html
@@ -74,15 +72,12 @@ files:
74
72
  - test/mocked/fixture_pages/sln_no_enrollment_info.html
75
73
  - test/mocked/fixture_pages/sln_status.html
76
74
  - test/mocked/fixture_pages/welcome.html
77
- - test/mocked/myuw_test.rb
78
- - test/mocked/registration_test.rb
79
- - test/mocked/schedule_test.rb
80
- - test/mocked/session_test.rb
81
75
  - test/mocked/sln_test.rb
82
76
  - test/mocked/test_helper.rb
83
77
  - test/password.rb.sample
84
78
  has_rdoc: false
85
79
  homepage: http://github.com/mitchellh/rubyuw
80
+ licenses:
86
81
  post_install_message:
87
82
  rdoc_options:
88
83
  - --charset=UTF-8
@@ -103,20 +98,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
98
  requirements: []
104
99
 
105
100
  rubyforge_project:
106
- rubygems_version: 1.2.0
101
+ rubygems_version: 1.3.5
107
102
  signing_key:
108
103
  specification_version: 3
109
104
  summary: Library which provides a ruby interface to the University of Washington student portal.
110
105
  test_files:
111
- - test/live/registration_test.rb
112
- - test/live/schedule_test.rb
113
- - test/live/session_test.rb
106
+ - test/live/curriculum_enrollment_test.rb
114
107
  - test/live/sln_test.rb
115
108
  - test/live/test_helper.rb
109
+ - test/mocked/base_test.rb
110
+ - test/mocked/connection_test.rb
116
111
  - test/mocked/curriculum_enrollment_test.rb
117
- - test/mocked/myuw_test.rb
118
- - test/mocked/registration_test.rb
119
- - test/mocked/schedule_test.rb
120
- - test/mocked/session_test.rb
121
112
  - test/mocked/sln_test.rb
122
113
  - test/mocked/test_helper.rb
data/lib/myuw.rb DELETED
@@ -1,67 +0,0 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
-
3
- require 'rubygems'
4
- require 'mechanize'
5
-
6
- require 'myuw/errors'
7
- require 'myuw/session'
8
- require 'myuw/sln'
9
- require 'myuw/schedule'
10
- require 'myuw/registration'
11
- require 'myuw/curriculum_enrollment'
12
-
13
- class MyUW
14
- extend Forwardable
15
-
16
- attr_accessor :browser
17
- attr_accessor :session
18
- attr_accessor :schedule
19
- attr_accessor :registration
20
-
21
- def initialize
22
- # Initialize the browser instance and mascarade
23
- # around as Safari on Mac
24
- @browser = WWW::Mechanize.new do |browser|
25
- browser.user_agent_alias = 'Mac Safari'
26
- browser.follow_meta_refresh = true
27
-
28
- # Workaround to avoid frozen object error SSL pages
29
- browser.keep_alive = false
30
-
31
- # Do not keep any history
32
- browser.max_history = 0
33
- end
34
-
35
- # Initialize other members
36
- @session = Session.new(self)
37
- @schedule = Schedule.new(self)
38
- @registration = Registration.new(self)
39
- end
40
-
41
- # Forward the session methods
42
- def_delegator :session, :logged_in?
43
- def_delegator :session, :logout
44
-
45
- # Log into MyUW with a given username and password
46
- def login(user, pass)
47
- @session.email = user
48
- @session.password = pass
49
- @session.login
50
- end
51
-
52
- # Creates a new SLN object and returns it
53
- def sln(sln_number, term)
54
- sln_obj = SLNInfo.new(self)
55
- sln_obj.sln = sln_number
56
- sln_obj.term = term
57
- return sln_obj
58
- end
59
-
60
- # Creates a new curriculum enrollment object and returns it
61
- def curriculum_enrollment(curric, term)
62
- curric_obj = CurriculumEnrollment.new(self)
63
- curric_obj.curriculum = curric
64
- curric_obj.term = term
65
- return curric_obj
66
- end
67
- end
@@ -1,110 +0,0 @@
1
- class MyUW
2
- # = Synopsis
3
- # Gets information regarding enrollment within a specific
4
- # subject.
5
- class CurriculumEnrollment
6
- attr_reader :term
7
- attr_reader :curriculum
8
- attr_accessor :myuw
9
- attr_reader :data
10
-
11
- def initialize(myuw)
12
- @myuw = myuw
13
- @term = nil
14
- @data = nil
15
- @curriculum = nil
16
- end
17
-
18
- # Custom setter for SLN to reset data
19
- def curriculum=(value)
20
- @curriculum = 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("Curriculum not set.") if @curriculum.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_dept_page
38
-
39
- # Get the actual course information
40
- end
41
-
42
- # Get data for a specific SLN
43
- def data_by_sln(sln, reload = false)
44
- fetch_data if @data.nil? || reload
45
- @data[sln]
46
- end
47
-
48
- # Gets the SLN info page for the SLN and term, raising
49
- # an exception if it is requested too soon
50
- def get_dept_page
51
- page = @myuw.browser.get("https://sdb.admin.washington.edu/timeschd/uwnetid/tsstat.asp?QTRYR=#{@term}&CURRIC=#{@curriculum}")
52
- if page.body.to_s =~ /No sections found for #{@curriculum}./
53
- raise InvalidCurriculumError.new("Curriculum does not exist.")
54
- end
55
-
56
- page
57
- end
58
-
59
- # Gets and stores all course data
60
- def get_all_courses_data(page)
61
- nodes = page.search('//table//tr[count(th)>1 and @bgcolor="#d0d0d0"]//following-sibling::tr')
62
- raise InvalidPageError.new("Couldn't find any courses listed.") if nodes.empty?
63
-
64
- @data = {}
65
- nodes.each do |node|
66
- node_data = get_course_data(node)
67
- @data[node_data[:sln]] = node_data
68
- end
69
- end
70
-
71
- # Gets a single course row's data
72
- def get_course_data(row)
73
- nodes = row.search('td')
74
- raise InvalidPageError.new("Couldn't find course information for a single row.") if nodes.empty?
75
-
76
- data_keys = [:sln, :course, :section, :type, :title, :current_enrollment, :limit_enrollment,
77
- :room_capacity, :space_available, nil, :notes]
78
-
79
- data = extract_info(data_keys, nodes)
80
- raise InvalidPageError.new("Failed to extract data for single row.") if !data
81
-
82
- data
83
- end
84
-
85
- # Extracts course information from each node and
86
- # stores it as the proper key in the @data variable
87
- def extract_info(keys, nodes)
88
- return false if nodes.empty?
89
-
90
- data = {}
91
- nodes.each_with_index do |node, i|
92
- # Make sure we have keys left still
93
- if i < keys.length then
94
- data_key = keys[i]
95
-
96
- # If the key is nil, we skip this node
97
- unless data_key.nil?
98
- data[data_key] = node.inner_text.strip.gsub("\302\240", "")
99
- end
100
- end
101
- end
102
-
103
- data
104
- end
105
- end
106
-
107
- #
108
- # Exceptions
109
- class InvalidCurriculumError < StandardError; end
110
- end
data/lib/myuw/errors.rb DELETED
@@ -1,18 +0,0 @@
1
- # General purpose errors used within MyUW
2
-
3
- class MyUW
4
- class NotLoggedInError < StandardError; end
5
-
6
- # A generic error to capture strange invalid HTML
7
- # results. These errors can typically be used to
8
- # find edge cases of HTML (such as maintenance
9
- # pages and so on) in MyUW
10
- class InvalidPageError < StandardError
11
- attr_reader :page
12
-
13
- def initialize(page, msg=nil)
14
- @page = page
15
- super(msg)
16
- end
17
- end
18
- end
@@ -1,98 +0,0 @@
1
- class MyUW
2
- # = Synopsis
3
- # The Registration class can automate the registration
4
- # process for a user. It does NOT support initial
5
- # setup of the registration process such as verifying
6
- # addresses and such (and doesnt plan to, that is
7
- # an important step that should be done manually)
8
- class Registration
9
- attr_accessor :myuw
10
- attr_reader :errors
11
-
12
- def initialize(myuw=nil)
13
- @myuw ||= myuw
14
- @errors = nil
15
- end
16
-
17
- # Registers for one or more courses. The courses
18
- # parameter should be an Array of strings (the
19
- # SLNs)
20
- def register(courses)
21
- raise NotLoggedInError.new("User must be logged in to register for classes.") unless @myuw.logged_in?
22
-
23
- # Get registration page
24
- register_page = @myuw.browser.get("https://sdb.admin.washington.edu/students/uwnetid/register.asp")
25
- register_form = register_page.form_with(:name => 'regform')
26
- raise InvalidPageError.new(register_page, "Could not verify registration page") if register_form.nil?
27
-
28
- # Fill in the form
29
- fill_registration_form(register_form, courses)
30
-
31
- # Submit it and analyze result
32
- get_registration_result(register_form.submit())
33
- end
34
-
35
- def get_registration_result(result_page)
36
- return true if result_page.body =~ /ALT="OK">Schedule updated\./i
37
- raise InvalidPageError.new(result_page, "Unknown registration result.") unless result_page.body =~ /ALT="ERROR">Schedule not updated\./i
38
-
39
- # Otherwise, get the errors out of the result page
40
- extract_registration_errors(result_page)
41
- false
42
- end
43
-
44
- def extract_registration_errors(result_page)
45
- # //input[@type='hidden' and @name='action4']/following-sibling::input[@type='hidden']/following-sibling::td
46
- registration_form = result_page.form_with(:name => 'regform')
47
- start_index = get_add_section_index(registration_form)
48
- current_index = start_index.to_i
49
-
50
- @errors = {}
51
-
52
- loop do
53
- # Get current SLN, and if its empty, then return out
54
- current_sln = registration_form["sln#{current_index}"]
55
- return if current_sln.nil? || current_sln.empty?
56
-
57
- error_cell = result_page.search("//input[@name='action#{current_index}']/parent::tr//td[5]")
58
- raise InvalidPageError.new(result_page, "Couldn't extract errors (couldn't get data cells)") if error_cell.empty?
59
-
60
- error_text = error_cell[0].inner_text.strip.gsub("\302\240", '')
61
- @errors[current_sln] = error_text
62
-
63
- current_index += 1
64
- end
65
- end
66
-
67
- def fill_registration_form(register_form, courses)
68
- # Determine where to begin adding SLNs (what fields)
69
- start_index = get_add_section_index(register_form)
70
-
71
- current_index = start_index.to_i
72
- courses.each do |course|
73
- register_form["sln#{current_index}"] = course.to_s
74
- current_index += 1
75
- end
76
- end
77
-
78
- # The registration page is one giant form.
79
- # We need to figure out which index fields
80
- # to begin filling in with SLN data. This
81
- # method returns the index.
82
- def get_add_section_index(register_form)
83
- # First way is to add maxadds and maxdrops and
84
- # determine the offset.
85
- maxdrops = register_form["maxdrops"].to_i
86
- index_by_hiddens = maxdrops + 1
87
-
88
- # Verify by inspecting actions
89
- 1.upto(11) do |i|
90
- # Find the version action with an "A" (meaning add)
91
- if register_form["action#{i}"].to_s == "A"
92
- raise InvalidPageError.new(nil, "Couldn't determine add offset.") unless i == index_by_hiddens
93
- return i.to_s
94
- end
95
- end
96
- end
97
- end
98
- end