pcr 0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,24 @@
1
+ token.dat
2
+ main.rb
3
+ *.gem
4
+ *.rbc
5
+ .bundle
6
+ .config
7
+ .yardoc
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
20
+ instructors.txt
21
+ examples.rb
22
+ json_responses.txt
23
+
24
+ *.swp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pcr-ruby.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 parm289
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,160 @@
1
+ # pcr-ruby: A Penn Course Review Ruby API Wrapper #
2
+
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
+
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
+
12
+ ## How to use pcr-ruby #
13
+
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.*
15
+
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
+
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
+
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.
22
+
23
+ To create a Course History (the first step in getting PCR data):
24
+ ```ruby
25
+ require 'pcr-ruby'
26
+ pcr = PCR.new(API_TOKEN)
27
+ course_history = pcr.coursehistory(COURSE_CODE)
28
+ ```
29
+
30
+ All other attributes will auto-populate based on data from the PCR API.
31
+
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)
40
+
41
+ The most useful way to think about a Course History is as a collection of Course objects.
42
+
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.)
46
+
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:
52
+ ```ruby
53
+ require 'pcr-ruby'
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
59
+ ```
60
+
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.
77
+
78
+ ### 'Sections' in pcr-ruby ###
79
+
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.
81
+
82
+ To retrieve a Section:
83
+ ```ruby
84
+ require 'pcr-ruby'
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
89
+ ```
90
+
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 ###
107
+
108
+ (New version of instructors coming soon)
109
+
110
+ ## pcr-ruby Usage Examples ##
111
+
112
+ Here are some (hopefully very simple and intuitive) usage examples for pcr-ruby:
113
+
114
+ ### Get average course quality rating ###
115
+ Let's say we want to find the average course quality rating for Introduction to International Relations, PSCI-150:
116
+
117
+ ```ruby
118
+ require 'pcr-ruby'
119
+ course_code = "PSCI-150"
120
+ pcr = PCR.new(API_TOKEN)
121
+ psci150 = pcr.coursehistory(course_code)
122
+ puts psci150.average("rCourseQuality") #=> 3.041
123
+ ```
124
+
125
+ Or, even more briefly:
126
+
127
+ ```ruby
128
+ require 'pcr-ruby'
129
+ pcr = PCR.new(API_TOKEN)
130
+ puts pcr.coursehistory("PSCI-150").average("rCourseQuality")
131
+ #=> 3.041
132
+ ```
133
+
134
+ ### Get most recent course difficulty rating ###
135
+ Finding the most recent section's course difficulty rating is just as easy:
136
+
137
+ ```ruby
138
+ require 'pcr-ruby'
139
+ course_code = "PSCI-150"
140
+ pcr = PCR.new(API_TOKEN)
141
+ psci150 = pcr.coursehistory(course_code)
142
+ puts psci150.recent("rDifficulty") #=> 2.59
143
+ ```
144
+
145
+ ### Get the course quality rating for a specific course/semester ###
146
+ ```ruby
147
+ require 'pcr-ruby'
148
+ course_code = "PSCI-150"
149
+ pcr = PCR.new(API_TOKEN)
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
154
+ ```
155
+
156
+
157
+ ## TODO ##
158
+ * Implement refactored Instructor object
159
+ * Implement stricter checks on course code arguments
160
+ * 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.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,59 @@
1
+ require 'classes/resource'
2
+ require 'classes/section'
3
+
4
+ module PCR
5
+ class Course
6
+ include Comparable
7
+ include PCR::Resource
8
+ attr_reader :aliases, :credits, :description, :history, :id,
9
+ :name, :path, :reviews, :sections, :semester,
10
+ :retrieved, :valid, :version
11
+
12
+ def initialize(path, semester)
13
+ #TODO: Don't need to pass in semester
14
+ @path, @semester = path, semester
15
+
16
+ # Hit api
17
+ json = PCR.get_json(path)
18
+
19
+ # List of sections
20
+ @sections = json['result']['sections']['values'].map do |section|
21
+ Section.new(section['path'])
22
+ end
23
+
24
+ # Assign attrs
25
+ attrs = %w(aliases credits description history id name reviews
26
+ retrieved valid version)
27
+ set_attrs(attrs, json)
28
+ end
29
+
30
+ def <=>(other)
31
+ #TODO: Throw error if not same course
32
+ return year <=> other.year unless year == other.year
33
+ season <=> other.season
34
+ end
35
+
36
+ def average(metric)
37
+ # Aggregate ratings across all sections
38
+ total, num = 0, 0
39
+ #TODO: inject
40
+ self.sections.each do |section|
41
+ section.reviews.each do |review|
42
+ total += review.send(metric).to_f
43
+ num += 1
44
+ end
45
+ end
46
+
47
+ # Return average value across all sections
48
+ (total / num)
49
+ end
50
+
51
+ def year
52
+ @semester[0..3].to_i
53
+ end
54
+
55
+ def season
56
+ @semester[4]
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,65 @@
1
+ require 'classes/resource'
2
+ require 'classes/course'
3
+
4
+ module PCR
5
+ class CourseHistory
6
+ include PCR::Resource
7
+ attr_reader :course_code, :courses, :id, :path, :retrieved, :valid, :version
8
+
9
+ def initialize(course_code)
10
+ @course_code = course_code
11
+
12
+ # Read JSON from PCR API
13
+ json = PCR.get_json("coursehistories/#{self.course_code}")
14
+
15
+ # List of courses in coursehistory
16
+ @courses = json['result']['courses'].map do |course|
17
+ Course.new(course['path'], course['semester'])
18
+ end
19
+
20
+ # Sort course list by semester
21
+ @courses.sort!
22
+
23
+ # Assign rest of attrs
24
+ attrs = %w(id path reviews retrieved valid version)
25
+ set_attrs(attrs, json)
26
+ end
27
+
28
+ def recent(metric)
29
+ # Select most recent course
30
+ course = @courses[-1]
31
+
32
+ # Aggregate ratings for metric
33
+ total, num = 0, 0
34
+ course.sections.each do |section|
35
+ section.reviews.each do |review|
36
+ total += review.send(metric).to_f
37
+ num += 1
38
+ end
39
+ end
40
+
41
+ # Return average value across most recent sections
42
+ (total / num)
43
+ end
44
+
45
+ def average(metric)
46
+ # Aggregate ratings across all sections
47
+ total, num = 0, 0
48
+ courses.each do |course|
49
+ course.sections.each do |section|
50
+ section.reviews.each do |review|
51
+ total += review.send(metric).to_f
52
+ num += 1
53
+ end
54
+ end
55
+ end
56
+
57
+ # Return average value across all sections
58
+ total / num
59
+ end
60
+
61
+ def name
62
+ self.courses.last.name
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,9 @@
1
+ module PCR
2
+ module Resource
3
+ def set_attrs(attrs, json)
4
+ attrs.each do |attr|
5
+ self.instance_variable_set("@#{attr}", json['result'][attr] || json[attr])
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,27 @@
1
+ require 'classes/resource'
2
+
3
+ module PCR
4
+ class Review
5
+ include PCR::Resource
6
+ attr_reader :instructor, :num_reviewers, :num_students, :retrieved,
7
+ :comments, :id
8
+
9
+ def initialize(path)
10
+ @path = path
11
+
12
+ # Hit api
13
+ json = PCR.get_json(path)
14
+
15
+ # Assign attrs
16
+ attrs = %w(instructor num_reviewers num_students amount_learned comments
17
+ retrieved id)
18
+ set_attrs(attrs, json)
19
+
20
+ # Assign ratings
21
+ json['result']['ratings'].each do |name, val|
22
+ self.instance_variable_set("@#{name}", val)
23
+ self.class.send(:attr_accessor, name)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,29 @@
1
+ require 'classes/resource'
2
+ require 'classes/review'
3
+
4
+ module PCR
5
+ class Section
6
+ include PCR::Resource
7
+ attr_reader :aliases, :course, :group, :id, :instructors,
8
+ :meetingtimes, :name, :path, :reviews,
9
+ :sectionnum, :retrieved, :valid, :version
10
+
11
+ def initialize(path)
12
+ @path = path
13
+
14
+ # Hit api
15
+ json = PCR.get_json(path)
16
+
17
+ # Get reviews
18
+ # Usually one, but may be > 1
19
+ @reviews = json['result']['reviews']['values'].map do |review|
20
+ Review.new(review['path'])
21
+ end
22
+
23
+ # Assign attrs
24
+ attrs = %w(aliases course group id instructors meetingtimes name
25
+ sectionnum retrieved valid version)
26
+ set_attrs(attrs, json)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,50 @@
1
+ require 'json'
2
+ require 'open-uri'
3
+ require 'classes/coursehistory'
4
+
5
+ #PCR class handles token and api url, so both are easily changed
6
+ module PCR
7
+ class Client
8
+ attr_reader :token
9
+
10
+ def initialize(token, api_endpt = "http://api.penncoursereview.com/v1/")
11
+ @token = token
12
+ @api_endpt = api_endpt
13
+ end
14
+
15
+ def get_json(path)
16
+ #TODO: Error handling for bad/no token
17
+ JSON.parse(open("#{@api_endpt + path}?token=#{@token}").read)
18
+ end
19
+
20
+ def coursehistory(course_code)
21
+ CourseHistory.new(course_code)
22
+ end
23
+
24
+ def instructor(id)
25
+ raise NotImplementedError.new("Instructors have not yet been implemented.")
26
+ end
27
+
28
+ def dept(code)
29
+ raise NotImplementedError.new("Departments have not yet been implemented.")
30
+ end
31
+ end
32
+
33
+ class << self
34
+ attr_accessor :token
35
+
36
+ def client
37
+ @client = PCR::Client.new(token) unless @client && token == @client.token
38
+ @client
39
+ end
40
+
41
+ def respond_to_missing?(method_name, include_private=false); client.respond_to?(method_name, include_private); end if RUBY_VERSION >= "1.9"
42
+ def respond_to?(method_name, include_private=false); client.respond_to?(method_name, include_private) || super; end if RUBY_VERSION < "1.9"
43
+
44
+ private
45
+ def method_missing(method_name, *args, &block)
46
+ return super unless client.respond_to?(method_name)
47
+ client.send(method_name, *args, &block)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,5 @@
1
+ module PCR
2
+ module Ruby
3
+ VERSION = "0.5"
4
+ end
5
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/pcr/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = "Matt Parmett, Greg Terrono"
6
+ gem.email = "terronogr@gmail.com"
7
+ gem.description = %q{Ruby wrapper for the Penn Course Review API}
8
+ gem.summary = %q{Ruby wrapper for the Penn Course Review API}
9
+ gem.homepage = "https://github.com/gterrono/pcr-ruby"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "pcr"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = PCR::Ruby::VERSION
17
+
18
+ gem.add_dependency "json"
19
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pcr
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.5'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Matt Parmett, Greg Terrono
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: json
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Ruby wrapper for the Penn Course Review API
31
+ email: terronogr@gmail.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - .gitignore
37
+ - Gemfile
38
+ - LICENSE
39
+ - README.md
40
+ - Rakefile
41
+ - lib/classes/course.rb
42
+ - lib/classes/coursehistory.rb
43
+ - lib/classes/resource.rb
44
+ - lib/classes/review.rb
45
+ - lib/classes/section.rb
46
+ - lib/pcr.rb
47
+ - lib/pcr/version.rb
48
+ - pcr.gemspec
49
+ homepage: https://github.com/gterrono/pcr-ruby
50
+ licenses: []
51
+ post_install_message:
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project:
69
+ rubygems_version: 1.8.23
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: Ruby wrapper for the Penn Course Review API
73
+ test_files: []