lse_courses 0.0.2 → 0.0.3
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.
- checksums.yaml +4 -4
- data/README.md +19 -2
- data/lib/lse_courses/course.rb +188 -56
- data/lib/lse_courses/version.rb +1 -1
- data/lse_courses.gemspec +0 -1
- metadata +2 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7c9c9889a37a6207cd6532c6c8dd9063848fcc6
|
4
|
+
data.tar.gz: 176a2d786f26fa542c74b811376165016f762e21
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b7dd7f44f21af449cd850f376920ac5ae3e003eabb660f90fb6ecd252fb6bc97bb8373218e5f41747e734d1e616afd5597cc0cfed867875e60ce90bcabcfc26e
|
7
|
+
data.tar.gz: 2002eff56b061d4953db574ff339f3251b3eb13d37794bd667986ae04731b87ebffe358f1d804b1424dcce871c7853fc1d5b1a244dd9656e6be38e6565199681
|
data/README.md
CHANGED
@@ -9,7 +9,12 @@ something along the line of [YalePlus](http://yaleplus.com/)'s Bluebook+.
|
|
9
9
|
|
10
10
|
Add the gem to your Gemfile, then run `bundle install`:
|
11
11
|
|
12
|
-
```
|
12
|
+
```ruby
|
13
|
+
# Install from RubyGems
|
14
|
+
source "http://rubygems.org"
|
15
|
+
gem 'lse_courses', '0.0.3'
|
16
|
+
|
17
|
+
# Install the latest version via Git
|
13
18
|
gem 'lse_courses', git: 'git@github.com:timrogers/lse_courses.git'
|
14
19
|
```
|
15
20
|
|
@@ -19,10 +24,19 @@ dependent on your setup.
|
|
19
24
|
You can retrieve an array with every course offered at LSE:
|
20
25
|
|
21
26
|
```ruby
|
27
|
+
# You can just fetch the most basic information - name, code and type (e.g. undergraduate)
|
22
28
|
courses = LSECourses::Course.all
|
29
|
+
|
30
|
+
# ...or you can grab everything at once - this will take a long time
|
31
|
+
courses = LSECourses::Course.all(preload: true)
|
32
|
+
|
23
33
|
courses.each do |course|
|
24
34
|
puts "#{course.code} - #{course.name}"
|
25
35
|
|
36
|
+
# Fetch a more detailed attribute, and we'll grab all of them for you
|
37
|
+
# and store them if you didn't preload the data originally
|
38
|
+
puts course.department
|
39
|
+
|
26
40
|
# LSE records include surveys on courses - stored in #survey on the object
|
27
41
|
puts "#{course.survey.recommended_by}% of students recommend this cause"
|
28
42
|
end
|
@@ -31,8 +45,11 @@ end
|
|
31
45
|
...or you can fetch a specific course by code:
|
32
46
|
|
33
47
|
```ruby
|
34
|
-
course = LSECourses::Course.
|
48
|
+
course = LSECourses::Course.find("LSE100")
|
35
49
|
puts course.name
|
50
|
+
|
51
|
+
# All the data is loaded straight up, since there's only one course to fetch
|
52
|
+
puts course.department
|
36
53
|
```
|
37
54
|
|
38
55
|
Upcoming features that should be added are some kind of search (e.g. for
|
data/lib/lse_courses/course.rb
CHANGED
@@ -1,16 +1,167 @@
|
|
1
|
-
require 'active_support/core_ext/object/try'
|
2
1
|
require 'nokogiri'
|
3
2
|
|
4
3
|
module LSECourses
|
5
4
|
class Course
|
6
|
-
attr_reader :code, :name, :
|
7
|
-
|
8
|
-
:content, :teaching, :formative_coursework, :reading, :type, :survey
|
5
|
+
attr_reader :code, :name, :type
|
6
|
+
attr_accessor :url
|
9
7
|
|
10
8
|
def initialize(opts = {})
|
11
9
|
opts.each { |k, v| instance_variable_set("@#{k}", v) }
|
12
10
|
end
|
13
11
|
|
12
|
+
def fetch_attributes
|
13
|
+
page = self.class.fetch_and_parse(url)
|
14
|
+
key_facts = page.css('#keyFacts-Content p')
|
15
|
+
|
16
|
+
@survey = if page.css('#survey-Label').any?
|
17
|
+
SurveyResult.new(
|
18
|
+
response_rate: page.css('#survey-Label-2 span').text.gsub("Response rate: ", "").gsub("%", "").to_f,
|
19
|
+
recommended_by: page.css('#survey-Content-Recommend p')[1].text.gsub("%", "").to_f,
|
20
|
+
reading_list: page.css('#survey-Content table tbody td')[1].text.to_f,
|
21
|
+
materials: page.css('#survey-Content table tbody td')[3].text.to_f,
|
22
|
+
satisfied: page.css('#survey-Content table tbody td')[5].text.to_f,
|
23
|
+
lectures: page.css('#survey-Content table tbody td')[7].text.to_f,
|
24
|
+
integration: page.css('#survey-Content table tbody td')[9].text.to_f,
|
25
|
+
contact: page.css('#survey-Content table tbody td')[11].text.to_f,
|
26
|
+
feedback: page.css('#survey-Content table tbody td')[13].text.to_f,
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
@code = page.css('#courseCode').text
|
31
|
+
@name = page.css('span#title').text
|
32
|
+
@department = key_facts[0].text.gsub("Department: ", "")
|
33
|
+
@students = key_facts[1].text.gsub("Total students 2012/13:", "").to_i
|
34
|
+
@average_class_size = key_facts[2].text.gsub("Average class size 2012/13: ", "").to_i
|
35
|
+
@value = key_facts[3].text.gsub("Value: ", "")
|
36
|
+
@assessments = self.class.join_p_tags(page.css('#assessment-Content p'))
|
37
|
+
@teachers = self.class.join_p_tags(page.css('#teacherResponsible-Content p'))
|
38
|
+
@availability = self.class.join_p_tags(page.css('#availability-Content p'))
|
39
|
+
@prerequisites = self.class.join_p_tags(page.css('#preRequisites-Content p'))
|
40
|
+
@content = self.class.join_p_tags(page.css('#courseContent-Content p'))
|
41
|
+
@teaching = self.class.join_p_tags(page.css('#teaching-Content p'))
|
42
|
+
@formative_coursework = self.class.join_p_tags(page.css('#formativeCoursework-Content p'))
|
43
|
+
@reading = self.class.join_p_tags(page.css('#indicativeReading-Content p'))
|
44
|
+
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
def department
|
49
|
+
if @department
|
50
|
+
@department
|
51
|
+
else
|
52
|
+
fetch_attributes
|
53
|
+
@department
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def students
|
58
|
+
if @students
|
59
|
+
@students
|
60
|
+
else
|
61
|
+
fetch_attributes
|
62
|
+
@students
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def average_class_size
|
67
|
+
if @average_class_size
|
68
|
+
@average_class_size
|
69
|
+
else
|
70
|
+
fetch_attributes
|
71
|
+
@average_class_size
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def value
|
76
|
+
if @value
|
77
|
+
@value
|
78
|
+
else
|
79
|
+
fetch_attributes
|
80
|
+
@value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def assessments
|
85
|
+
if @assessments
|
86
|
+
@assessments
|
87
|
+
else
|
88
|
+
fetch_attributes
|
89
|
+
@assessments
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def teachers
|
94
|
+
if @teachers
|
95
|
+
@teachers
|
96
|
+
else
|
97
|
+
fetch_attributes
|
98
|
+
@teachers
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def availability
|
103
|
+
if @availability
|
104
|
+
@availability
|
105
|
+
else
|
106
|
+
fetch_attributes
|
107
|
+
@availability
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def prerequisites
|
112
|
+
if @prerequisites
|
113
|
+
@prerequisites
|
114
|
+
else
|
115
|
+
fetch_attributes
|
116
|
+
@prerequisites
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def content
|
121
|
+
if @content
|
122
|
+
@content
|
123
|
+
else
|
124
|
+
fetch_attributes
|
125
|
+
@content
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def teaching
|
130
|
+
if @teaching
|
131
|
+
@teaching
|
132
|
+
else
|
133
|
+
fetch_attributes
|
134
|
+
@teaching
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def formative_coursework
|
139
|
+
if @formative_coursework
|
140
|
+
@formative_coursework
|
141
|
+
else
|
142
|
+
fetch_attributes
|
143
|
+
@formative_coursework
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def reading
|
148
|
+
if @reading
|
149
|
+
@reading
|
150
|
+
else
|
151
|
+
fetch_attributes
|
152
|
+
@reading
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def survey
|
157
|
+
if @survey
|
158
|
+
@survey
|
159
|
+
else
|
160
|
+
fetch_attributes
|
161
|
+
@survey
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
14
165
|
def undergraduate?
|
15
166
|
type == "Undergraduate"
|
16
167
|
end
|
@@ -25,8 +176,7 @@ module LSECourses
|
|
25
176
|
|
26
177
|
# Checks if this module is available to General Course students
|
27
178
|
def general_course?
|
28
|
-
|
29
|
-
!general_course_list.read.include? code
|
179
|
+
!self.class.general_course_page.include? code
|
30
180
|
end
|
31
181
|
|
32
182
|
def survey?
|
@@ -45,22 +195,31 @@ module LSECourses
|
|
45
195
|
}
|
46
196
|
end
|
47
197
|
|
48
|
-
def self.all
|
198
|
+
def self.all(options = {})
|
199
|
+
defaults = { preload: false }
|
200
|
+
options = defaults.merge(options)
|
201
|
+
|
49
202
|
results = []
|
50
203
|
|
51
204
|
course_lists.each_pair do |type, url|
|
52
205
|
document = fetch_and_parse(url)
|
53
206
|
document.css('table tr td p a').each do |link|
|
54
|
-
|
207
|
+
abstract = link.text.split(" ")
|
55
208
|
|
56
|
-
|
57
|
-
|
58
|
-
|
209
|
+
course_code = abstract.shift
|
210
|
+
name = abstract.join(" ")
|
211
|
+
course_url = URI.join(URI.parse(url), URI.parse(link['href'])).to_s
|
59
212
|
|
60
|
-
results <<
|
213
|
+
results << self.new(
|
214
|
+
url: course_url,
|
215
|
+
name: name,
|
216
|
+
code: course_code,
|
217
|
+
type: type
|
218
|
+
)
|
61
219
|
end
|
62
220
|
end
|
63
221
|
|
222
|
+
results.each(&:fetch_attributes) if options[:preload]
|
64
223
|
results
|
65
224
|
end
|
66
225
|
|
@@ -68,15 +227,19 @@ module LSECourses
|
|
68
227
|
course_lists.each_pair do |type, url|
|
69
228
|
document = fetch_and_parse(url)
|
70
229
|
document.css('table tr td p a').each do |link|
|
71
|
-
|
72
|
-
course_code = title.split(" ").first
|
230
|
+
abstract = link.text.split(" ")
|
73
231
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
)
|
232
|
+
course_code = abstract.shift
|
233
|
+
name = abstract.join(" ")
|
234
|
+
course_url = URI.join(URI.parse(url), URI.parse(link['href'])).to_s
|
78
235
|
|
79
|
-
|
236
|
+
if code == course_code
|
237
|
+
return self.new(
|
238
|
+
url: course_url,
|
239
|
+
name: name,
|
240
|
+
code: course_code,
|
241
|
+
type: type
|
242
|
+
).fetch_attributes
|
80
243
|
end
|
81
244
|
end
|
82
245
|
end
|
@@ -84,49 +247,18 @@ module LSECourses
|
|
84
247
|
nil
|
85
248
|
end
|
86
249
|
|
87
|
-
def self.course_page_to_object(page, type)
|
88
|
-
key_facts = page.css('#keyFacts-Content p')
|
89
|
-
|
90
|
-
survey_result = if page.css('#survey-Label').any?
|
91
|
-
SurveyResult.new(
|
92
|
-
response_rate: page.css('#survey-Label-2 span').text.gsub("Response rate: ", "").gsub("%", "").to_f,
|
93
|
-
recommended_by: page.css('#survey-Content-Recommend p')[1].text.gsub("%", "").to_f,
|
94
|
-
reading_list: page.css('#survey-Content table tbody td')[1].text.to_f,
|
95
|
-
materials: page.css('#survey-Content table tbody td')[3].text.to_f,
|
96
|
-
satisfied: page.css('#survey-Content table tbody td')[5].text.to_f,
|
97
|
-
lectures: page.css('#survey-Content table tbody td')[7].text.to_f,
|
98
|
-
integration: page.css('#survey-Content table tbody td')[9].text.to_f,
|
99
|
-
contact: page.css('#survey-Content table tbody td')[11].text.to_f,
|
100
|
-
feedback: page.css('#survey-Content table tbody td')[13].text.to_f,
|
101
|
-
)
|
102
|
-
end
|
103
|
-
|
104
|
-
self.new(
|
105
|
-
type: type,
|
106
|
-
code: page.css('#courseCode').text,
|
107
|
-
name: page.css('span#title').text,
|
108
|
-
department: key_facts[0].text.gsub("Department: ", ""),
|
109
|
-
students: key_facts[1].text.gsub("Total students 2012/13:", "").to_i,
|
110
|
-
average_class_size: key_facts[2].text.gsub("Average class size 2012/13: ", "").to_i,
|
111
|
-
value: key_facts[3].text.gsub("Value: ", ""),
|
112
|
-
assessments: join_p_tags(page.css('#assessment-Content p')),
|
113
|
-
teachers: join_p_tags(page.css('#teacherResponsible-Content p')),
|
114
|
-
availability: join_p_tags(page.css('#availability-Content p')),
|
115
|
-
prerequisites: join_p_tags(page.css('#preRequisites-Content p')),
|
116
|
-
content: join_p_tags(page.css('#courseContent-Content p')),
|
117
|
-
teaching: join_p_tags(page.css('#teaching-Content p')),
|
118
|
-
formative_coursework: join_p_tags(page.css('#formativeCoursework-Content p')),
|
119
|
-
reading: join_p_tags(page.css('#indicativeReading-Content p')),
|
120
|
-
survey: survey_result
|
121
|
-
)
|
122
|
-
end
|
123
|
-
|
124
250
|
def self.join_p_tags(elements)
|
125
251
|
elements.map(&:text).join("\n").strip
|
126
252
|
end
|
127
253
|
|
254
|
+
def self.general_course_page
|
255
|
+
@general_course_page ||= open("http://www.lse.ac.uk/resources/calendar/GeneralCourse/coursesNotAvailableToGeneralCStudents.htm").read
|
256
|
+
end
|
257
|
+
|
128
258
|
def self.fetch_and_parse(url)
|
129
259
|
Nokogiri::HTML(open(url, &:read), 'UTF-8')
|
130
260
|
end
|
261
|
+
|
262
|
+
self.singleton_class.send(:alias_method, :find, :find_by_code)
|
131
263
|
end
|
132
264
|
end
|
data/lib/lse_courses/version.rb
CHANGED
data/lse_courses.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lse_courses
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Rogers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-01-
|
11
|
+
date: 2014-01-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: activesupport
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - '>='
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - '>='
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
27
|
description: Access to data on courses at the London School of Economics and Political
|
42
28
|
Science (LSE)
|
43
29
|
email:
|