pcr-ruby 0.2.1 → 0.5

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 CHANGED
@@ -18,4 +18,5 @@ test/tmp
18
18
  test/version_tmp
19
19
  tmp
20
20
  instructors.txt
21
- examples.rb
21
+ examples.rb
22
+ json_responses.txt
data/README.md CHANGED
@@ -15,76 +15,97 @@ gem install pcr-ruby
15
15
 
16
16
  pcr-ruby follows the structure of the PCR API, with a few name changes to make object identities and roles clearer in your code. (Before using pcr-ruby, you should most definitely read the PCR API documentation, the link to which you should recieve upon being granted your API token.)
17
17
 
18
- The PCR API essentially consists of four types of objects: 'Courses', 'Sections', 'Instructors', and 'Course Histories'. pcr-ruby aims to provide intuitive access to the data contained in these four object types while abstracting you and your user from background processing and unnecessary data. To that end, pcr-ruby (thus far) consists of three types of objects: 'Courses', 'Sections', and 'Instructors'.
18
+ The PCR API essentially consists of four types of objects: 'Courses', 'Sections', 'Instructors', and 'Course Histories'. pcr-ruby aims to provide intuitive access to the data contained in these four object types while abstracting you and your user from background processing and unnecessary data. To that end, pcr-ruby (thus far) consists of the same four types of objects: 'Course Histories', 'Courses', 'Sections', and 'Instructors' (coming soon).
19
19
 
20
- ### 'Courses' in pcr-ruby ###
21
-
22
- Course objects in the PCR API are essentially a group of that Course's Sections which were offered in a certain semester. Courses in pcr-ruby are different, and match up most directly with 'Course History' objects of the PCR API. It is my belief that when students think of a "course," they think of the entire history of the course and *not* the course offering for a specific semester. Therefore, pcr-ruby does not associate Courses with specific semesters -- rather, Courses exist across time and represent a single curriculum and course code.
20
+ ### CourseHistories in pcr-ruby ###
21
+ Course Histories represent a course through time, and contain Course objects that represent the course offering in each semester.
23
22
 
24
- To create a Course:
23
+ To create a Course History (the first step in getting PCR data):
25
24
  ```ruby
26
25
  require 'pcr-ruby'
27
- pcr = PCR.new(api_token)
28
- course = pcr.course(course_code)
26
+ pcr = PCR.new(API_TOKEN)
27
+ course_history = pcr.coursehistory(COURSE_CODE)
29
28
  ```
30
- All other instance variables will auto-populate based on data from the PCR API.
31
29
 
32
- pcr-ruby's Course objects have the following instance variables:
33
- * **course_code** -- a string in the format "DEPT-###", where "DEPT" is the four-letter department code and "###" is the three-digit course code.
34
- * **sections** -- an array of Section objects for the Course across all time. Useful for calculating average ratings and other cumulative statistics.
35
- * **id** -- the Course's PCR API id. (Integer)
36
- * **name** -- the Course's plain-English name. (String)
37
- * **path** -- the PCR API sub-path leading to the Course (or, more accurately, the Course History). For example, "/coursehistories/1794/". Or, more generally: "/coursehistories/[id]/". (String)
38
- * **reviews** -- an array of Hashes that contain review data for each of the Course's sections.
30
+ All other attributes will auto-populate based on data from the PCR API.
39
31
 
40
- Courses have the following instance methods:
41
- * **average(metric)** -- returns the average value, across all Sections, of "metric" as a Float. "Metric" must be a recognized rating in the PCR API. (Currently the names of these ratings are not intuitive, so I may provide plain-English access to rating names in the future.)
42
- * **recent(metric)** -- returns the most recent value of "metric" as a Float. "Metric" must be a recognized rating in the PCR API. (Currently the names of these ratings are not intuitive, so I may provide plain-English access to rating names in the future.)
32
+ Course Histories have the following attributes:
33
+ * **course_code** -- the course code entered by the user at initialization (String)
34
+ * **courses** -- an array of Courses associated with the Course History (Array)
35
+ * **id** -- the Course History's PCR API ID (String)
36
+ * **path** -- the Course History's PCR API URL path (String)
37
+ * **retrieved** -- the date the Course History was retreived (String)
38
+ * **valid** -- true/false whether or not the query was valid (String)
39
+ * **version** -- version of the PCR API hit (String)
43
40
 
44
- ### 'Sections' in pcr-ruby ###
41
+ The most useful way to think about a Course History is as a collection of Course objects.
45
42
 
46
- In pcr-ruby, Sections are single offerings of a Course. Each Section is associated with a certain Instructor and semester -- think of a Section as the individual classes under the umbrella of the Course. Sections in the PCR API are treated similarly.
43
+ Course Histories have the following instance methods:
44
+ * **average(metric)** -- returns the average value, across all Courses, of "metric" as a Float. "Metric" must be a recognized rating in the PCR API. (Currently the names of these ratings are not intuitive, so I may provide plain-English access to rating names in the future.)
45
+ * **recent(metric)** -- returns the most recent value of "metric" as a Float. (If there are multiple Sections offered in the most recent semester, the average across those Sections is returned.) "Metric" must be a recognized rating in the PCR API. (Currently the names of these ratings are not intuitive, so I may provide plain-English access to rating names in the future.)
47
46
 
48
- To create a Section:
47
+ ### 'Courses' in pcr-ruby ###
48
+
49
+ Courses in the PCR API represent a collection of Sections of a course code during a given semester, and are treated similarly in pcr-ruby.
50
+
51
+ Courses are accessed from within their "parent" Course History:
49
52
  ```ruby
50
53
  require 'pcr-ruby'
51
- pcr = PCR.new(api_token)
52
- section = pcr.section(id)
54
+ pcr = PCR.new(API_TOKEN)
55
+ course_history = pcr.coursehistory(course_code)
56
+ courses = course_history.courses
57
+ earliest_course = courses.first
58
+ most_recent_course = courses.last
53
59
  ```
54
60
 
55
- Sections have the following instance variables:
56
- * **aliases** -- an array of the Section's course listings. Most of the time, a Section will only have one listing (the course code followed by a section code, like "-001"), but Sections that are cross-listed between departments may have multiple listings.
57
- * **id** -- the Section's PCR API id. (Integer)
58
- * **name** -- the plain-English name of the class. (String)
59
- * **path** -- the PCR API sub-path that leads to the Section. Similar in format to Course.path. (String)
60
- * **semester** -- the semester code for the semester in which the Section was offered. For example: "2011A". Semester codes are in the format "####X", where "####" represents a year and "X" represents a semester (A for Spring, B for Summer, C for Fall). (String)
61
- * **description** -- a string containing the class description, which is written by the Section's Instructor and details the scope and characteristics of the class.
62
- * **comments** -- a string containing PCR's comments about the Section. The comments are the most major part of the written review, and are sourced from student exit surveys.
63
- * **ratings** -- a Hash of metrics and the ratings of the Section for each metric.
64
- * **instructors** an Array of the Section's instructors.
65
- * **reviews** -- a Hash of the Section's review data, in the format {"comments" => @comments, "ratings" => @ratings}.
61
+ pcr-ruby's Course objects have the following instance variables:
62
+ * **aliases** -- an array of crosslistings (Array)
63
+ * **credits** -- the number of credits awarded for the course (String)
64
+ * **description** -- the PCR course description (String)
65
+ * **history** -- the PCR API path to the course's history (String)
66
+ * **id** -- the PCR API ID of the course (String)
67
+ * **name** -- the plain-English name of the course, taken from the most recent Semester (String)
68
+ * **path** -- the PCR API URL path of the course (String)
69
+ * **reviews** -- a hash that usually contains one key, the path to the course's reviews (String)
70
+ * **sections** -- an array of Sections associated with the course (Array)
71
+ * **semester** -- the semester in which the course was offered (String)
72
+ * **retrieved** -- the date/time the course was retrieved (String)
73
+ * **valid** -- true/false if valid/invalid request (String)
74
+ * **version** -- PCR API version (String)
75
+
76
+ The most useful way to think about Courses is as a collection of Section objects.
66
77
 
67
- ### 'Instructors' in pcr-ruby ###
78
+ ### 'Sections' in pcr-ruby ###
68
79
 
69
- Instructors are arguably the most important part of PCR -- many students use PCR as a substitute for RateMyProfessor and base their course decisions on PCR professor ratings. The Instructor object represents a single professor through time. As of now, pcr-ruby allows you to retrieve both the average and most recent ratings of a professor; I may add the ability to look up ratings for specific courses/semesters taught in the future.
80
+ In pcr-ruby, Sections are single offerings of a Course. Each Section is associated with a certain Course -- think of a Section as the individual classes under the umbrella of the Course. Sections in the PCR API are treated similarly.
70
81
 
71
- To create an Instructor:
82
+ To retrieve a Section:
72
83
  ```ruby
73
84
  require 'pcr-ruby'
74
- pcr = PCR.new(api_token)
75
- instructor = pcr.instructor(id)
85
+ pcr = PCR.new(API_TOKEN)
86
+ course_history = pcr.coursehistory(course_code)
87
+ recent_sections = course_history.courses.last.sections
88
+ single_recent_section = recent_sections.first
76
89
  ```
77
90
 
78
- Insctructors have the following instance variables. All variables other than **id**, which is user-specified, will be filled from the PCR API:
79
- * **id** -- the Instructor's PCR id, a String in the form of "ID#-FIRST-M-LAST". The PCR API also accepts a String in the form of "ID#".
80
- * **name** -- the Instructor's name, a String in the form of "FIRST-M-LAST".
81
- * **path** -- the PCR sub-path that leads to the Instructor, a String in the form of "/instructors/id".
82
- * **sections** -- a Hash of sections taught by Instructor.
83
- * **reviews** -- a Hash of reviews of Instructor in JSON.
91
+ Sections have the following instance variables:
92
+ * **aliases** -- crosslistings of the Section (Array)
93
+ * **course** -- a hash containing info of the parent course (Hash)
94
+ * **group** --
95
+ * **id** -- the PCR API ID of the section (String)
96
+ * **instructors** -- a hash of info on each of the section's instructors (Hash)
97
+ * **meetingtimes** -- an array of hashes that contain info on each of the meeting times of the section (Array)
98
+ * **name** -- the plain-English name of the section (String)
99
+ * **path** -- the PCR API URL path of the section (String)
100
+ * **reviews** -- an array of hashes which each contain the review data for the section (usually only one review hash) (Array)
101
+ * **sectionnum** -- the number of the section (e.g. "001") (String)
102
+ * **retrieved** -- date/time retrieved (String)
103
+ * **valid** -- true/false if query valid/invalid (String)
104
+ * **version** -- PCR API version (String)
105
+
106
+ ### 'Instructors' in pcr-ruby ###
84
107
 
85
- Instructors have the following instance methods:
86
- * **average(metric)** -- returns the average value, across all Sections taught by Instructor, of "metric" as a Float. "Metric" must be a recognized rating in the PCR API. (Currently the names of these ratings are not intuitive, so I may provide plain-English access to rating names in the future.)
87
- * **recent(metric)** -- returns the average value of "metric" for the most recent semester in which the Instructor taught as a float. (For example, if the professor taught 3 classes in the most recent semester, this would return the average of "metric" over the three classes.) "Metric" must be a recognized rating in the PCR API. (Currently the names of these ratings are not intuitive, so I may provide plain-English access to rating names in the future.)
108
+ (New version of instructors coming soon)
88
109
 
89
110
  ## pcr-ruby Usage Examples ##
90
111
 
@@ -97,8 +118,8 @@ Let's say we want to find the average course quality rating for Introduction to
97
118
  require 'pcr-ruby'
98
119
  course_code = "PSCI-150"
99
120
  pcr = PCR.new(API_TOKEN)
100
- course = pcr.course(course_code)
101
- puts course.average("rCourseQuality") #=> 3.041
121
+ psci150 = pcr.coursehistory(course_code)
122
+ puts psci150.average("rCourseQuality") #=> 3.041
102
123
  ```
103
124
 
104
125
  Or, even more briefly:
@@ -106,7 +127,7 @@ Or, even more briefly:
106
127
  ```ruby
107
128
  require 'pcr-ruby'
108
129
  pcr = PCR.new(API_TOKEN)
109
- puts pcr.course("PSCI-150").average("rCourseQuality")
130
+ puts pcr.coursehistory("PSCI-150").average("rCourseQuality")
110
131
  #=> 3.041
111
132
  ```
112
133
 
@@ -115,19 +136,26 @@ Finding the most recent section's course difficulty rating is just as easy:
115
136
 
116
137
  ```ruby
117
138
  require 'pcr-ruby'
139
+ course_code = "PSCI-150"
118
140
  pcr = PCR.new(API_TOKEN)
119
- course = pcr.course("PSCI-150")
120
- puts course.recent("rDifficulty") #=> 2.5
141
+ psci150 = pcr.coursehistory(course_code)
142
+ puts psci150.recent("rDifficulty") #=> 2.59
121
143
  ```
122
144
 
123
- ### Get professor's average "ability to stimulate student interest" rating ###
145
+ ### Get the course quality rating for a specific course/semester ###
124
146
  ```ruby
125
147
  require 'pcr-ruby'
148
+ course_code = "PSCI-150"
126
149
  pcr = PCR.new(API_TOKEN)
127
- instructor = pcr.instructor("1090-LINDA-H-ZHAO")
128
- puts instructor.average("rStimulateInterest").round(2) #=> 1.7
150
+ psci150 = pcr.coursehistory(course_code)
151
+ psci150_course = psci150.courses[3]
152
+ puts psci150_course.semester #=> "2003C"
153
+ puts psci150_course.average("rDifficulty") #=> 2.98
129
154
  ```
130
155
 
156
+
131
157
  ## TODO ##
158
+ * Make the coursehistory init quicker
159
+ * Implement refactored Instructor object
132
160
  * Implement stricter checks on course code arguments
133
161
  * Implement search by professor last/first name rather than by ID. ID is unintuitive. Will probably need to see if I can make a lookup method, or simply pull down a database of all instructors and do a search on that database.
@@ -1,79 +1,68 @@
1
1
  class Course < PCR
2
- attr_accessor :course_code, :sections, :id, :name, :path, :reviews
2
+ attr_accessor :aliases, :credits, :description, :history, :id,
3
+ :name, :path, :reviews, :sections, :semester,
4
+ :retrieved, :valid, :version
3
5
 
4
- def initialize(course_code)
5
- if course_code.is_a? String && course_code.isValidCourseCode?
6
- @course_code = course_code
7
-
8
- #Read JSON from the PCR API
9
- api_url = @@api_endpt + "coursehistories/" + self.course_code + "/?token=" + @@token
10
- json = JSON.parse(open(api_url).read)
11
-
12
- #Create array of Section objects
13
- @sections = []
14
- json["result"]["courses"].each { |c| @sections << Section.new(c["id"]) }
15
-
16
- #Set variables according to Course JSON data
17
- @id = json["result"]["id"]
18
- @name = json["result"]["name"]
19
- @path = json["result"]["path"]
20
-
21
- #Get reviews for the Course -- this has to be a separate query
22
- api_url_reviews = @@api_endpt + "coursehistories/" +
23
- self.id.to_s + "/reviews?token=" + @@token
24
- json_reviews = JSON.parse(open(api_url_reviews).read)
25
- @reviews = json_reviews["result"]["values"]
26
- else
27
- raise CourseError, "Invalid course code specified. Use format [DEPT-###]."
6
+ def initialize(path, semester, api_endpt, token)
7
+ @path, @semester = path, semester
8
+ @api_endpt, @token = api_endpt, token
9
+
10
+ # Hit api
11
+ api_url = makeURL(self.path)
12
+ json = JSON.parse(open(api_url).read)
13
+
14
+ # List of sections
15
+ section_list = json['result']['sections']['values']
16
+ @sections = []
17
+ section_list.each do |section|
18
+ @sections << Section.new(section['path'], @api_endpt, @token)
19
+ end
20
+
21
+ # Assign attrs
22
+ attrs = %w(aliases credits description history id name reviews
23
+ retrieved valid version)
24
+ attrs.each do |attr|
25
+ if json['result'][attr]
26
+ self.instance_variable_set("@#{attr}", json['result'][attr])
27
+ else
28
+ self.instance_variable_set("@#{attr}", json[attr])
29
+ end
28
30
  end
29
31
  end
30
32
 
31
- def average(metric)
32
- #Ensure that we know argument type
33
- metric = metric.to_s if metric.is_a? Symbol
34
-
35
- if metric.is_a? String
36
- #Loop vars
37
- total, n = 0, 0
38
-
39
- #For each section, check if ratings include metric arg
40
- #if so, add metric rating to total && increment counting variable
41
- self.reviews.each do |review|
42
- if review["ratings"].include? metric
43
- total = total + review["ratings"][metric].to_f
44
- n = n + 1
45
- else
46
- raise CourseError, "No ratings found for \"#{metric}\" in #{self.name}."
47
- end
33
+ def compareSemester(other)
34
+ year = self.semester[0..3]
35
+ season = self.semester[4]
36
+ compYear = other.semester[0..3]
37
+ compSeason = other.semester[4]
38
+
39
+ if year.to_i > compYear.to_i #Later year
40
+ return 1
41
+ elsif year.to_i < compYear.to_i #Earlier year
42
+ return -1
43
+ elsif year.to_i == compYear.to_i #Same year, so test season
44
+ if season > compSeason #Season is later
45
+ return 1
46
+ elsif season = compSeason #Exact same time
47
+ return 0
48
+ elsif season < compSeason #compSeason is later
49
+ return -1
48
50
  end
49
-
50
- #Return average score as a float
51
- (total / n)
52
- else
53
- raise CourseError, "Invalid metric format. Metric must be a string or symbol."
54
51
  end
55
52
  end
56
53
 
57
- def recent(metric)
58
- #Ensure that we know argument type
59
- metric = metric.to_s if metric.is_a? Symbol
60
-
61
- if metric.is_a? String
62
- #Get the most recent section
63
- section = self.sections[-1]
64
-
65
- #Iterate through all the section reviews, and if the section review id matches
66
- #the id of the most recent section, return that rating
67
- self.reviews.each do |review|
68
- if review["section"]["id"].to_s[0..4].to_i == section.id
69
- return review["ratings"][metric]
70
- end
54
+ def average(metric)
55
+ # Aggregate ratings across all sections
56
+ total, num = 0, 0
57
+ self.sections.each do |section|
58
+ section.reviews.each do |review|
59
+ total += review.send(metric).to_f
60
+ num += 1
71
61
  end
72
-
73
- #Else, metric hasn't been found
74
- raise CourseError, "No ratings found for #{metric} in #{section.semester}."
75
- else
76
- raise CourseError, "Invalid metric format. Metric must be a string or symbol."
77
62
  end
63
+
64
+ # Return average value across all sections
65
+ (total / num)
78
66
  end
67
+
79
68
  end
@@ -0,0 +1,70 @@
1
+ class CourseHistory < PCR
2
+ attr_accessor :course_code, :courses, :id, :path, :retrieved, :valid, :version
3
+
4
+ def initialize(course_code, api_endpt, token)
5
+ @course_code = course_code
6
+ @api_endpt = api_endpt
7
+ @token = token
8
+
9
+ # Read JSON from PCR API
10
+ api_url = makeURL("coursehistories/#{self.course_code}")
11
+ json = JSON.parse(open(api_url).read)
12
+
13
+ # List of courses in coursehistory
14
+ course_list = json['result']['courses']
15
+ @courses = []
16
+ course_list.each do |course|
17
+ @courses << Course.new(course['path'], course['semester'], @api_endpt, @token)
18
+ end
19
+ # Sort course list by semester
20
+ @courses.sort! { |a,b| a.compareSemester(b) }
21
+
22
+ # Assign rest of attrs
23
+ attrs = %w(id path reviews retrieved valid version)
24
+ attrs.each do |attr|
25
+ if json['result'][attr]
26
+ self.instance_variable_set("@#{attr}", json['result'][attr])
27
+ else
28
+ self.instance_variable_set("@#{attr}", json[attr])
29
+ end
30
+ end
31
+ end
32
+
33
+ def recent(metric)
34
+ # Select most recent course
35
+ course = @courses[-1]
36
+
37
+ # Aggregate ratings for metric
38
+ total, num = 0, 0
39
+ course.sections.each do |section|
40
+ section.reviews.each do |review|
41
+ total += review.send(metric).to_f
42
+ num += 1
43
+ end
44
+ end
45
+
46
+ # Return average value across most recent sections
47
+ (total / num)
48
+ end
49
+
50
+ def average(metric)
51
+ # Aggregate ratings across all sections
52
+ total, num = 0, 0
53
+ courses.each do |course|
54
+ course.sections.each do |section|
55
+ section.reviews.each do |review|
56
+ total += review.send(metric).to_f
57
+ num += 1
58
+ end
59
+ end
60
+ end
61
+
62
+ # Return average value across all sections
63
+ (total / num)
64
+ end
65
+
66
+ def name
67
+ self.courses.last.name
68
+ end
69
+
70
+ end
@@ -0,0 +1,16 @@
1
+ #review_new.rb
2
+
3
+ class Review
4
+ #attr_accessor
5
+
6
+ def initialize(review_hash)
7
+ # Assign ratings
8
+ ratings = review_hash['ratings']
9
+ ratings.each do |name, val|
10
+ self.instance_variable_set("@#{name}", val)
11
+ self.class.send(:attr_accessor, name)
12
+ #self.class_eval("def #{name};@#{name};end")
13
+ end
14
+ end
15
+
16
+ end
@@ -1,50 +1,36 @@
1
- #Section is an individual class under the umbrella of a general Course
2
1
  class Section < PCR
3
- attr_accessor :aliases, :id, :name, :path, :semester, :description, :comments, :ratings, :instructors, :reviews
2
+ attr_accessor :aliases, :course, :group, :id, :instructors,
3
+ :meetingtimes, :name, :path, :reviews,
4
+ :sectionnum, :retrieved, :valid, :version
4
5
 
5
- def initialize(id, hit_api = true)
6
- # Set instance vars
7
- @id = id
8
-
9
- # Hit api to fill additional info
10
- self.hit_api unless hit_api == false
11
- end
12
-
13
- def hit_api
14
- data = ["aliases", "name", "path", "semester", "description"]
15
- api_url = @@api_endpt + "courses/" + self.id.to_s + "?token=" + @@token
6
+ def initialize(path, api_endpt, token)
7
+ @path = path
8
+ @api_endpt = api_endpt
9
+ @token = token
10
+
11
+ # Hit api
12
+ api_url = makeURL(self.path)
16
13
  json = JSON.parse(open(api_url).read)
17
- data.each do |d|
18
- case d
19
- when "aliases"
20
- self.instance_variable_set("@#{d}", json["result"]["aliases"])
21
- when "name"
22
- self.instance_variable_set("@#{d}", json["result"]["name"])
23
- when "path"
24
- self.instance_variable_set("@#{d}", json["result"]["path"])
25
- when "semester"
26
- self.instance_variable_set("@#{d}", json["result"]["semester"])
27
- when "description"
28
- self.instance_variable_set("@#{d}", json["result"]["description"])
29
- end
14
+
15
+ # Get reviews
16
+ # Usually one, but may be > 1
17
+ @reviews = []
18
+ reviews_url = makeURL(json['result']['reviews']['path'])
19
+ reviews_json = JSON.parse(open(reviews_url).read)
20
+ reviews_json['result']['values'].each do |review|
21
+ @reviews << Review.new(review)
30
22
  end
31
23
 
32
- # Get review data
33
- self.get_reviews
34
- end
35
-
36
- def get_reviews
37
- api_url = @@api_endpt + "courses/" + self.id.to_s + "/reviews?token=" + @@token
38
- json = JSON.parse(open(api_url).read)
39
- @comments = []
40
- @ratings = []
41
- @instructors = []
42
- json["result"]["values"].each do |a|
43
- @comments << {a["instructor"]["id"] => a["comments"]}
44
- @ratings << {a["instructor"]["id"] => a["ratings"]}
45
- @instructors << a["instructor"]
24
+ # Assign attrs
25
+ attrs = %w(aliases course group id instructors meetingtimes name
26
+ sectionnum retrieved valid version)
27
+ attrs.each do |attr|
28
+ if json['result'][attr]
29
+ self.instance_variable_set("@#{attr}", json['result'][attr])
30
+ else
31
+ self.instance_variable_set("@#{attr}", json[attr])
32
+ end
46
33
  end
47
- @reviews = {"comments" => @comments, "ratings" => @ratings}
48
34
  end
49
-
35
+
50
36
  end
@@ -52,16 +52,16 @@ class ::String
52
52
  compSeason = s[4]
53
53
 
54
54
  if year.to_i > compYear.to_i #Later year
55
- return true
55
+ return 1
56
56
  elsif year.to_i < compYear.to_i #Earlier year
57
- return false
57
+ return -1
58
58
  elsif year.to_i == compYear.to_i #Same year, so test season
59
59
  if season > compSeason #Season is later
60
- return true
60
+ return 1
61
61
  elsif season = compSeason #Exact same time
62
62
  return 0
63
63
  elsif season < compSeason #compSeason is later
64
- return false
64
+ return -1
65
65
  end
66
66
  end
67
67
  end
@@ -1,27 +1,27 @@
1
1
  require 'json'
2
2
  require 'open-uri'
3
- require 'time'
4
- require 'csv'
5
-
6
3
 
7
4
  #PCR class handles token and api url, so both are easily changed
8
5
  class PCR
6
+ attr_accessor :token, :api_endpt
7
+
9
8
  def initialize(token, api_endpt = "http://api.penncoursereview.com/v1/")
10
- @@token = token
11
- @@api_endpt = api_endpt
9
+ @token = token
10
+ @api_endpt = api_endpt
12
11
  end
13
12
 
14
- def course(course_code)
15
- Course.new(course_code)
13
+ def coursehistory(course_code)
14
+ CourseHistory.new(course_code, self.api_endpt, self.token)
16
15
  end
17
16
 
18
- def section(id, hit_api = true)
19
- Section.new(id, hit_api)
20
- end
17
+ # def instructor(id)
18
+ # Instructor.new(id)
19
+ # end
21
20
 
22
- def instructor(id)
23
- Instructor.new(id)
21
+ def makeURL(path)
22
+ "#{self.api_endpt + path}?token=#{self.token}"
24
23
  end
24
+
25
25
  end
26
26
 
27
27
  # Load classes
@@ -1,5 +1,5 @@
1
1
  module Pcr
2
2
  module Ruby
3
- VERSION = "0.2.1"
3
+ VERSION = "0.5"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pcr-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: '0.5'
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-11-07 00:00:00.000000000 Z
12
+ date: 2012-11-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json
@@ -38,10 +38,10 @@ files:
38
38
  - LICENSE
39
39
  - README.md
40
40
  - Rakefile
41
- - lib/classes/array.rb
42
41
  - lib/classes/course.rb
42
+ - lib/classes/coursehistory.rb
43
43
  - lib/classes/errors.rb
44
- - lib/classes/instructor.rb
44
+ - lib/classes/review.rb
45
45
  - lib/classes/section.rb
46
46
  - lib/classes/string.rb
47
47
  - lib/pcr-ruby.rb
@@ -1,18 +0,0 @@
1
- #Add useful array methods
2
- class Array
3
- def binary_search(target)
4
- self.search_iter(0, self.length-1, target)
5
- end
6
-
7
- def search_iter(lower, upper, target)
8
- return -1 if lower > upper
9
- mid = (lower+upper)/2
10
- if (self[mid] == target)
11
- mid
12
- elsif (target < self[mid])
13
- self.search_iter(lower, mid-1, target)
14
- else
15
- self.search_iter(mid+1, upper, target)
16
- end
17
- end
18
- end
@@ -1,116 +0,0 @@
1
- #Instructor is a professor. Instructors are not tied to a course or section, but will have to be referenced from Sections.
2
- class Instructor < PCR
3
- attr_accessor :id, :name, :path, :sections, :reviews
4
-
5
- def initialize(id)
6
- #Assign args
7
- if id.is_a? String
8
- @id = id
9
- else
10
- raise InstructorError("Invalid Instructor ID specified.")
11
- end
12
-
13
- #Hit PCR API to get missing info based on id
14
- self.getInfo
15
- self.getReviews
16
- end
17
-
18
- #Hit the PCR API to get all missing info
19
- def getInfo
20
- api_url = @@api_endpt + "instructors/" + self.id + "?token=" + @@token
21
- json = JSON.parse(open(api_url).read)
22
- @name = json["result"]["name"].downcase.titlecase unless @name
23
- @path = json["result"]["path"] unless @path
24
- @sections = json["result"]["reviews"]["values"] unless @sections #Mislabeled reviews in PCR API
25
- end
26
-
27
- #Separate method for getting review data
28
- def getReviews
29
- api_url = @@api_endpt + "instructors/" + self.id + "/reviews?token=" + @@token
30
- json = JSON.parse(open(api_url).read)
31
- @reviews = json["result"]["values"] #array
32
- end
33
-
34
- #Get average value of a certain rating for Instructor
35
- def average(metric)
36
- #Ensure that we know argument type
37
- metric = metric.to_s if metric.is_a? Symbol
38
-
39
- if metric.is_a? String
40
- #Loop vars
41
- total, n = 0, 0
42
-
43
- #For each section, check if ratings include metric arg
44
- #if so, add metric rating to total and increment counting variable
45
- self.getReviews
46
- self.reviews.each do |review|
47
- if review["ratings"].include? metric
48
- total = total + review["ratings"][metric].to_f
49
- n = n + 1
50
- else
51
- raise CourseError, "No ratings found for \"#{metric}\" for #{self.name}."
52
- end
53
- end
54
-
55
- #Return average score as a float
56
- (total / n)
57
- else
58
- raise CourseError, "Invalid metric format. Metric must be a string or symbol."
59
- end
60
- end
61
-
62
- #Get most recent value of a certain rating for Instructor
63
- def recent(metric)
64
- #Ensure that we know argument type
65
- metric = metric.to_s if metric.is_a? Symbol
66
-
67
- if metric.is_a? String
68
- #Iterate through reviews and create Section for each section reviewed, presented in an array
69
- sections = []
70
- section_ids = []
71
- self.getReviews
72
- self.reviews.each do |review|
73
- if section_ids.index(review["section"]["id"].to_i).nil?
74
- s = PCR::Section.new(review["section"]["id"].to_i, false)
75
- sections << s
76
- section_ids << s.id
77
- end
78
- end
79
-
80
- #Get only most recent Section(s) in the array
81
- sections.reverse! #Newest first
82
- targets = []
83
- sections.each do |s|
84
- s.hit_api
85
- if sections.index(s) == 0
86
- targets << s
87
- elsif s.semester == sections[0].semester && s.id != sections[0].id
88
- targets << s
89
- else
90
- break
91
- end
92
- end
93
-
94
- #Calculate recent rating
95
- total, num = 0, 0
96
- targets.each do |section|
97
- #Make sure we get the rating for the right Instructor
98
- section.ratings.each do |rating|
99
- if rating.key?(self.id)
100
- if rating[self.id][metric].nil?
101
- raise InstructorError, "No ratings found for #{metric} for #{self.name}."
102
- else
103
- total = total + rating[self.id][metric].to_f
104
- num += 1
105
- end
106
- end
107
- end
108
- end
109
-
110
- # Return recent rating
111
- (total / num)
112
- else
113
- raise CourseError, "Invalid metric format. Metric must be a string or symbol."
114
- end
115
- end
116
- end