pcr-ruby 0.2 → 0.2.1

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
@@ -17,4 +17,5 @@ spec/reports
17
17
  test/tmp
18
18
  test/version_tmp
19
19
  tmp
20
- instructors.txt
20
+ instructors.txt
21
+ examples.rb
data/README.md CHANGED
@@ -2,13 +2,20 @@
2
2
 
3
3
  pcr-ruby is a simple, intuitive way to retrieve course data from the Penn Course Review API in Ruby. With pcr-ruby and a valid API token (which you can request [here](https://docs.google.com/spreadsheet/viewform?hl=en_US&formkey=dGZOZkJDaVkxdmc5QURUejAteFdBZGc6MQ#gid=0)), your Ruby project has access to reviews, ratings, and other information for all Penn courses.
4
4
 
5
+ ## Installation ##
6
+
7
+ pcr-ruby is a gem hosted on rubygems, so installation is as simple as:
8
+ ```
9
+ gem install pcr-ruby
10
+ ```
11
+
5
12
  ## How to use pcr-ruby #
6
13
 
7
14
  *This section may change a lot as pcr-ruby is developed. As such, this section may not be fully accurate, but I will try to keep the instructions as current as possible.*
8
15
 
9
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.)
10
17
 
11
- 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 two 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 three types of objects: 'Courses', 'Sections', and 'Instructors'.
12
19
 
13
20
  ### 'Courses' in pcr-ruby ###
14
21
 
@@ -44,7 +51,6 @@ require 'pcr-ruby'
44
51
  pcr = PCR.new(api_token)
45
52
  section = pcr.section(id)
46
53
  ```
47
- Possible instance variables available for setting in the Section initialize method are: aliases, id, name, path, semester.
48
54
 
49
55
  Sections have the following instance variables:
50
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.
@@ -88,7 +94,7 @@ Here are some (hopefully very simple and intuitive) usage examples for pcr-ruby:
88
94
  Let's say we want to find the average course quality rating for Introduction to International Relations, PSCI-150:
89
95
 
90
96
  ```ruby
91
- require 'pcr.rb'
97
+ require 'pcr-ruby'
92
98
  course_code = "PSCI-150"
93
99
  pcr = PCR.new(API_TOKEN)
94
100
  course = pcr.course(course_code)
@@ -98,9 +104,9 @@ puts course.average("rCourseQuality") #=> 3.041
98
104
  Or, even more briefly:
99
105
 
100
106
  ```ruby
101
- require 'pcr.rb'
107
+ require 'pcr-ruby'
102
108
  pcr = PCR.new(API_TOKEN)
103
- puts pcr.course("PSCI-150")course.average("rCourseQuality")
109
+ puts pcr.course("PSCI-150").average("rCourseQuality")
104
110
  #=> 3.041
105
111
  ```
106
112
 
@@ -108,7 +114,7 @@ puts pcr.course("PSCI-150")course.average("rCourseQuality")
108
114
  Finding the most recent section's course difficulty rating is just as easy:
109
115
 
110
116
  ```ruby
111
- require 'pcr.rb'
117
+ require 'pcr-ruby'
112
118
  pcr = PCR.new(API_TOKEN)
113
119
  course = pcr.course("PSCI-150")
114
120
  puts course.recent("rDifficulty") #=> 2.5
@@ -116,7 +122,7 @@ puts course.recent("rDifficulty") #=> 2.5
116
122
 
117
123
  ### Get professor's average "ability to stimulate student interest" rating ###
118
124
  ```ruby
119
- require 'pcr.rb'
125
+ require 'pcr-ruby'
120
126
  pcr = PCR.new(API_TOKEN)
121
127
  instructor = pcr.instructor("1090-LINDA-H-ZHAO")
122
128
  puts instructor.average("rStimulateInterest").round(2) #=> 1.7
@@ -1,32 +1,28 @@
1
- #Course object matches up with the coursehistory request of the pcr api.
2
- #A Course essentially is a signle curriculum and course code, and includes all Sections across time (semesters).
3
1
  class Course < PCR
4
2
  attr_accessor :course_code, :sections, :id, :name, :path, :reviews
5
3
 
6
4
  def initialize(course_code)
7
- if course_code.is_a? String and course_code.isValidCourseCode?
5
+ if course_code.is_a? String && course_code.isValidCourseCode?
8
6
  @course_code = course_code
9
7
 
10
8
  #Read JSON from the PCR API
11
9
  api_url = @@api_endpt + "coursehistories/" + self.course_code + "/?token=" + @@token
12
10
  json = JSON.parse(open(api_url).read)
13
11
 
14
- #Create array of Section objects, containing all Sections found in the API JSON for the Course
12
+ #Create array of Section objects
15
13
  @sections = []
16
- json["result"]["courses"].each do |c|
17
- @sections << Section.new(c["id"])
18
- end
14
+ json["result"]["courses"].each { |c| @sections << Section.new(c["id"]) }
19
15
 
20
16
  #Set variables according to Course JSON data
21
17
  @id = json["result"]["id"]
22
18
  @name = json["result"]["name"]
23
19
  @path = json["result"]["path"]
24
20
 
25
- #Get reviews for the Course -- unfortunately this has to be a separate query
26
- api_url_reviews = @@api_endpt + "coursehistories/" + self.id.to_s + "/reviews?token=" + @@token
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
27
24
  json_reviews = JSON.parse(open(api_url_reviews).read)
28
25
  @reviews = json_reviews["result"]["values"]
29
-
30
26
  else
31
27
  raise CourseError, "Invalid course code specified. Use format [DEPT-###]."
32
28
  end
@@ -34,19 +30,16 @@ class Course < PCR
34
30
 
35
31
  def average(metric)
36
32
  #Ensure that we know argument type
37
- if metric.is_a? Symbol
38
- metric = metric.to_s
39
- end
40
-
33
+ metric = metric.to_s if metric.is_a? Symbol
34
+
41
35
  if metric.is_a? String
42
36
  #Loop vars
43
- total = 0
44
- n = 0
37
+ total, n = 0, 0
45
38
 
46
- #For each section, check if ratings include metric arg -- if so, add metric rating to total and increment counting variable
39
+ #For each section, check if ratings include metric arg
40
+ #if so, add metric rating to total && increment counting variable
47
41
  self.reviews.each do |review|
48
- ratings = review["ratings"]
49
- if ratings.include? metric
42
+ if review["ratings"].include? metric
50
43
  total = total + review["ratings"][metric].to_f
51
44
  n = n + 1
52
45
  else
@@ -55,8 +48,7 @@ class Course < PCR
55
48
  end
56
49
 
57
50
  #Return average score as a float
58
- (total/n)
59
-
51
+ (total / n)
60
52
  else
61
53
  raise CourseError, "Invalid metric format. Metric must be a string or symbol."
62
54
  end
@@ -64,24 +56,22 @@ class Course < PCR
64
56
 
65
57
  def recent(metric)
66
58
  #Ensure that we know argument type
67
- if metric.is_a? Symbol
68
- metric = metric.to_s
69
- end
70
-
59
+ metric = metric.to_s if metric.is_a? Symbol
71
60
 
72
61
  if metric.is_a? String
73
62
  #Get the most recent section
74
63
  section = self.sections[-1]
75
64
 
76
- #Iterate through all the section reviews, and if the section review id matches the id of the most recent section, return that rating
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
77
67
  self.reviews.each do |review|
78
68
  if review["section"]["id"].to_s[0..4].to_i == section.id
79
69
  return review["ratings"][metric]
80
70
  end
81
71
  end
82
72
 
73
+ #Else, metric hasn't been found
83
74
  raise CourseError, "No ratings found for #{metric} in #{section.semester}."
84
-
85
75
  else
86
76
  raise CourseError, "Invalid metric format. Metric must be a string or symbol."
87
77
  end
@@ -3,7 +3,7 @@ class Instructor < PCR
3
3
  attr_accessor :id, :name, :path, :sections, :reviews
4
4
 
5
5
  def initialize(id)
6
- #Assign args. ID is necessary because that's how we look up Instructors in the PCR API.
6
+ #Assign args
7
7
  if id.is_a? String
8
8
  @id = id
9
9
  else
@@ -13,47 +13,38 @@ class Instructor < PCR
13
13
  #Hit PCR API to get missing info based on id
14
14
  self.getInfo
15
15
  self.getReviews
16
-
17
16
  end
18
17
 
19
18
  #Hit the PCR API to get all missing info
20
- #Separate method in case we want to conduct it separately from a class init
21
19
  def getInfo
22
20
  api_url = @@api_endpt + "instructors/" + self.id + "?token=" + @@token
23
21
  json = JSON.parse(open(api_url).read)
24
-
25
22
  @name = json["result"]["name"].downcase.titlecase unless @name
26
23
  @path = json["result"]["path"] unless @path
27
24
  @sections = json["result"]["reviews"]["values"] unless @sections #Mislabeled reviews in PCR API
28
25
  end
29
26
 
30
- #Separate method for getting review data in case we don't want to make an extra API hit each init
27
+ #Separate method for getting review data
31
28
  def getReviews
32
- if not self.reviews #make sure we don't already have reviews
33
- api_url = @@api_endpt + "instructors/" + self.id + "/reviews?token=" + @@token
34
- json = JSON.parse(open(api_url).read)
35
-
36
- @reviews = json["result"]["values"] #gets array
37
- end
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
38
32
  end
39
33
 
40
34
  #Get average value of a certain rating for Instructor
41
35
  def average(metric)
42
36
  #Ensure that we know argument type
43
- if metric.is_a? Symbol
44
- metric = metric.to_s
45
- end
37
+ metric = metric.to_s if metric.is_a? Symbol
46
38
 
47
39
  if metric.is_a? String
48
40
  #Loop vars
49
- total = 0
50
- n = 0
41
+ total, n = 0, 0
51
42
 
52
- #For each section, check if ratings include metric arg -- if so, add metric rating to total and increment counting variable
43
+ #For each section, check if ratings include metric arg
44
+ #if so, add metric rating to total and increment counting variable
53
45
  self.getReviews
54
46
  self.reviews.each do |review|
55
- ratings = review["ratings"]
56
- if ratings.include? metric
47
+ if review["ratings"].include? metric
57
48
  total = total + review["ratings"][metric].to_f
58
49
  n = n + 1
59
50
  else
@@ -62,8 +53,7 @@ class Instructor < PCR
62
53
  end
63
54
 
64
55
  #Return average score as a float
65
- (total/n)
66
-
56
+ (total / n)
67
57
  else
68
58
  raise CourseError, "Invalid metric format. Metric must be a string or symbol."
69
59
  end
@@ -72,9 +62,7 @@ class Instructor < PCR
72
62
  #Get most recent value of a certain rating for Instructor
73
63
  def recent(metric)
74
64
  #Ensure that we know argument type
75
- if metric.is_a? Symbol
76
- metric = metric.to_s
77
- end
65
+ metric = metric.to_s if metric.is_a? Symbol
78
66
 
79
67
  if metric.is_a? String
80
68
  #Iterate through reviews and create Section for each section reviewed, presented in an array
@@ -93,10 +81,10 @@ class Instructor < PCR
93
81
  sections.reverse! #Newest first
94
82
  targets = []
95
83
  sections.each do |s|
96
- s.hit_api(:get_reviews => true)
84
+ s.hit_api
97
85
  if sections.index(s) == 0
98
86
  targets << s
99
- elsif s.semester == sections[0].semester and s.id != sections[0].id
87
+ elsif s.semester == sections[0].semester && s.id != sections[0].id
100
88
  targets << s
101
89
  else
102
90
  break
@@ -104,8 +92,7 @@ class Instructor < PCR
104
92
  end
105
93
 
106
94
  #Calculate recent rating
107
- total = 0
108
- num = 0
95
+ total, num = 0, 0
109
96
  targets.each do |section|
110
97
  #Make sure we get the rating for the right Instructor
111
98
  section.ratings.each do |rating|
@@ -121,8 +108,7 @@ class Instructor < PCR
121
108
  end
122
109
 
123
110
  # Return recent rating
124
- total / num
125
-
111
+ (total / num)
126
112
  else
127
113
  raise CourseError, "Invalid metric format. Metric must be a string or symbol."
128
114
  end
@@ -7,15 +7,13 @@ class Section < PCR
7
7
  @id = id
8
8
 
9
9
  # Hit api to fill additional info
10
- self.hit_api() unless hit_api == false
11
-
10
+ self.hit_api unless hit_api == false
12
11
  end
13
12
 
14
- def hit_api()
13
+ def hit_api
15
14
  data = ["aliases", "name", "path", "semester", "description"]
16
15
  api_url = @@api_endpt + "courses/" + self.id.to_s + "?token=" + @@token
17
16
  json = JSON.parse(open(api_url).read)
18
-
19
17
  data.each do |d|
20
18
  case d
21
19
  when "aliases"
@@ -33,10 +31,9 @@ class Section < PCR
33
31
 
34
32
  # Get review data
35
33
  self.get_reviews
36
-
37
34
  end
38
35
 
39
- def get_reviews()
36
+ def get_reviews
40
37
  api_url = @@api_endpt + "courses/" + self.id.to_s + "/reviews?token=" + @@token
41
38
  json = JSON.parse(open(api_url).read)
42
39
  @comments = []
@@ -1,5 +1,5 @@
1
1
  module Pcr
2
2
  module Ruby
3
- VERSION = "0.2"
3
+ VERSION = "0.2.1"
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'
4
+ version: 0.2.1
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-10-22 00:00:00.000000000 Z
12
+ date: 2012-11-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json