Repo for activities: https://github.ugrad.cs.ubc.ca/CPSC310-2018W-T2/d2_tutorial
Is the process of restructuring existing code without changing its behavior -- Wikipedia
Rename: Renames a variable, method, class, etc.
Extract method: Moves some block of code to a well contained method
Repo for activities: https://github.ugrad.cs.ubc.ca/CPSC310-2018W-T2/d2_tutorial
1. Clone the repo: https://github.ugrad.cs.ubc.ca/CPSC310-2018W-T2/d2_tutorial
2. Make sure you can run the tests (yarn install, yarn build, yarn test)
3. Try using extract method on the switch statement, the factorial loop, or both. Do the tests still pass?
~5-10 min
1. Add and remove a dataset containing information about UBC classrooms
return new Promise(function (fulfill, reject) {
try {
const myZip = new Zip();
if (kind === InsightDatasetKind.Courses) {
// Extract the content
zip = myZip.extract();
for (file in files inside zip) {
try{
contents = file.getContent();
for (section in results) {
// do something
}
} catch (err) {
// do something
}
});
// more code here
} else if (kind === InsightDatasetKind.Rooms) {
// We are just going to copy and paste the code above and generate ourselves a problem
} else {
// keep doing the same strategy until our code is doomed
}
// more code here
// even more code
// ...
} catch (err) {
// do something
}
});
Do we have a problem?
return new Promise(function (fulfill, reject) {
try {
const myZip = new Zip();
if (kind === InsightDatasetKind.Courses) {
// Extract the content
zip = myZip.extract();
for (file in files inside zip) {
try{
contents = file.getContent();
for (section in results) {
// do something
}
} catch (err) {
// do something
}
});
// more code here
} else if (kind === InsightDatasetKind.Rooms) {
// Extract the content
zip = myZip.extract();
for (file in files inside zip) {
try{
contents = file.getContent();
for (section in results) {
// do something
}
} catch (err) {
// do something
}
});
} else {
// keep doing the same strategy until our code is doomed
}
// more code here
// even more code
// ...
} catch (err) {
// do something
}
});
Do we have a problem?
1. Code Readability
2. Code Maintainability
3. Code Testability
return new Promise(function (fulfill, reject) {
try {
const myZip = new Zip();
if (kind === InsightDatasetKind.Courses) {
// Extract the content
zip = myZip.extract();
for (file in files inside zip) {
try{
contents = file.getContent();
for (section in results) {
// do something
}
} catch (err) {
// do something
}
});
// more code here
} else if (kind === InsightDatasetKind.Rooms) {
// Extract the content
zip = myZip.extract();
for (file in files inside zip) {
try{
contents = file.getContent();
for (section in results) {
// do something
}
} catch (err) {
// do something
}
});
else if (kind === InsightDatasetKind.X) {
// Extract the content
zip = myZip.extract();
for (file in files inside zip) {
try{
contents = file.getContent();
for (section in results) {
// do something
}
} catch (err) {
// do something
}
});
// more code here
} else if (kind === InsightDatasetKind.Y) {
// Extract the content
zip = myZip.extract();
for (file in files inside zip) {
try{
contents = file.getContent();
for (section in results) {
// do something
}
} catch (err) {
// do something
}
});
} else if (kind === InsightDatasetKind.Z) {
// Extract the content
zip = myZip.extract();
for (file in files inside zip) {
try{
contents = file.getContent();
for (section in results) {
// do something
}
} catch (err) {
// do something
}
});
} else {
// keep doing the same strategy until our code is doomed
}
// more code here
// even more code
// ...
} catch (err) {
// do something
}
});
Do we have a problem?
1. Code Readability
2. Code Maintainability
3. Code Testability
1. Add and remove a dataset containing information about UBC classrooms
rooms.zip
addDataset(...)
Parse it
Keep data structure in a variable
Save it to disk
Caching
same workflow as courses.zip BUT with different file types
InsightDatasetKind.Rooms
(kind)
addDataset(...)
new code
kind?
existing code
parse courses
parse rooms
Keep data structure in a variable
Save it to disk
Take a few minutes to talk with a partner (ideally your project partner), about where refactoring might be useful to integrate this new addDataset functionality.
You can think about:
2. Answer advanced queries about UBC courses and rooms
Examples:
"what's the average of CPSC 340?"
2. Answer advanced queries about UBC courses and rooms
2. Answer advanced queries about UBC courses (current solution)
{
"WHERE":{
"AND": [
{ "IS":{ "courses_id": "340" } },
{ "IS":{ "courses_dept": "cpsc" }}
]
},
"OPTIONS":{
"COLUMNS":[
"courses_id", "courses_avg"
],
"ORDER":"courses_avg"
}
}
{"result": [
{ "courses_id": "340",
"courses_avg": 68.4 },
{ "courses_id": "340",
"courses_avg": 68.4 },
{ "courses_id": "340",
"courses_avg": 72.65 },
{ "courses_id": "340",
"courses_avg": 72.65 },
{ "courses_id": "340",
"courses_avg": 72.94 },
{ "courses_id": "340",
"courses_avg": 72.94 },
...
]}
{
"WHERE":{
"AND": [
{ "IS":{ "courses_id": "340" } },
{ "IS":{ "courses_dept": "cpsc" }}
]
},
"OPTIONS":{
"COLUMNS":[
"courses_id", "courses_avg"
],
"ORDER":"courses_avg"
}
}
not what we
were looking for
2. Answer advanced queries about UBC courses (current solution)
2. Answer advanced queries about UBC courses (new solution)
{
"result": [
{
"courses_id": "340",
"overallAvg": 75.69
}
]
}
{
"WHERE":{
"AND": [
{ "IS":{ "courses_id": "340" } },
{ "IS":{ "courses_dept": "cpsc" }}
]
},
"OPTIONS":{
"COLUMNS":[
"courses_id", "overallAvg"
]
},
"TRANSFORMATIONS":{
"GROUP":[ "courses_id"],
"APPLY": [
{
"overallAvg": {
"AVG": "courses_avg"
}
}
]
}
}
this is the right result!
2. New EBNF:
QUERY ::='{'BODY ', ' OPTIONS (', ' TRANSFORMATIONS)? '}'
BODY ::= 'WHERE:{' (FILTER)? '}'
OPTIONS ::= 'OPTIONS:{' COLUMNS ', ' (SORT)?'}'
TRANSFORMATIONS ::= 'TRANSFORMATIONS: {' GROUP ', ' APPLY '}'
// ... Old content ...
COLUMNS ::= 'COLUMNS:[' ((key | applykey) ',')* (key | applykey) ']'
SORT ::= 'ORDER: ' ('{ dir:' DIRECTION ', keys: [ ' ORDERKEY (',' ORDERKEY)* ']}') | ORDERKEY
DIRECTION ::= 'UP' | 'DOWN'
ORDERKEY ::= key | applykey
GROUP ::= 'GROUP: [' (key ',')* key ']'
APPLY ::= 'APPLY: [' (APPLYRULE (', ' APPLYRULE )* )? ']'
APPLYRULE ::= '{' applykey ': {' APPLYTOKEN ':' key '}}'
APPLYTOKEN ::= 'MAX' | 'MIN' | 'AVG' | 'COUNT' | 'SUM'
key ::= mkey | skey
mkey ::= idstring '_' mfield
skey ::= idstring '_' sfield
mfield ::= 'avg' | 'pass' | 'fail' | 'audit' | 'year' | 'lat' | 'lon' | 'seats'
sfield ::= 'dept' | 'id' | 'instructor' | 'title' | 'uuid' |
'fullname' | 'shortname' | 'number' | 'name' | 'address' | 'type' | 'furniture' | 'href'
idstring ::= [^_]+ // One or more of any character, except asterisk.
inputstring ::= [^*]* // zero or more of any character except asterisk.
applykey ::= [^_]+ // one or more of any character except underscore.
rooms/
rooms/index.htm
rooms/campus/
rooms/campus/discover/
rooms/campus/discover/buildings-and-classrooms/
rooms/campus/discover/buildings-and-classrooms/AAC
rooms/campus/discover/buildings-and-classrooms/ACEN
rooms/campus/discover/buildings-and-classrooms/ACU
rooms/campus/discover/buildings-and-classrooms/AERL
rooms/campus/discover/buildings-and-classrooms/ALRD
...
<p id="blame-europe" class="popup">By using our site, you agree...</p>
Inspect the html files in the dataset, take a look at them and try to find useful information
tree node for that element
current html element that I'm inspecting
<html>
<body>
<h1>
<p>
My first heading
My first paragraph.
At the top of a file on GitHub, there is a small printout of the file size. With a partner, think about how you might approach finding this using parse5. You may want to:
~10 min
Since the tree is structured as nodes containing arrays of child nodes, any element could be accessed like:
root.childNodes[1].childNodes[5].childNodes[3]...
Not only is this mindnumbingly annoying to write, it is also incredibly prone to breaking. Any new element added to the page could completely break it.
A better approach is to develop a method to search through this tree for your target data
(Also because we may test for it)
GET http://skaha.cs.ubc.ca:11316/api/v1/team666/6245%20Agronomy%20Road%20V6T%201Z4
6245 Agronomy Road V6T 1Z4
6245%20Agronomy%20Road%20V6T%201Z4
status: 200,
body: {"lat":49.26125,"lon":-123.24807}
* Take a look at https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol for a more comprehensive explanation of HTTP
const request = require('request');
request({
method: 'GET',
uri: 'http://cs310.ugrad.cs.ubc.ca:11316/api/v1/
project_<CSID1>_<CSID2>/6245%20Agronomy%20Road%20V6T%201Z4',
gzip: true
}).on('response', function(response) {
console.log("status: " + response.statusCode);
}).on('data', function(data) {
// decompressed data as it is received
console.log('decoded chunk: ' + data)
});
status: 200
decoded chunk: {
"lat":49.26125,
"lon":-123.24807
}
* https://github.com/request/request
* This code will not work in your project ! You are supposed to use the http package instead of request.
Implement the method do_math in the MathWrapper class. You CAN change the method header and the tests in the process of making it work