JavaScript OOP
+Telerik Software Academy
+ http://academy.telerik.com +diff --git a/Additional-Resources/README.md b/Additional-Resources/README.md
index d32c7e6..f68a4f5 100755
--- a/Additional-Resources/README.md
+++ b/Additional-Resources/README.md
@@ -9,6 +9,8 @@
- OOP in JavaScript with ES2015
- [Video Course](https://app.pluralsight.com/library/courses/javascript-es6-object-oriented-programming/table-of-contents)
- [Article MDN](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes)
+ - [ES2015 Classes essentials](http://exploringjs.com/es6/ch_classes.html)
+ - [Rich article on when and why you should avoid ES2015 classes](https://github.com/joshburgess/not-awesome-es6-classes)
- Mixins
- [Article MDN] (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes#Mix-ins)
- [Article](http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/)
diff --git a/Practical Exams/academy-online-catalogs/README.md b/Practical Exams/academy-online-catalogs/README.md
index e7d953c..2d1a280 100644
--- a/Practical Exams/academy-online-catalogs/README.md
+++ b/Practical Exams/academy-online-catalogs/README.md
@@ -108,7 +108,7 @@ has the following:
* Each item **must contain** the pattern as substring either in its **name** or in its **description**
* **Returns an empty array**, if **none of the items** contain the pattern
* The `pattern` is a string containing at least 1 character
- * The search is **case insensitive**
+ * The search is **case sensitive**
##`BookCatalog`
has the following:
@@ -157,7 +157,9 @@ has the following:
* The media must sorted by:
* descending by duration
* ascending by id
-
+ * find(options)
+ * Extends find(options) from parent, but adds a key `rating`
+ * i.e. books can be found by `id`, `name` and/or `rating`
##Example:
@@ -168,11 +170,11 @@ has the following:
},
getMedia: function (name, rating, duration, description) {
//return a media instance
- }
+ },
getBookCatalog: function (name) {
//return a book catalog instance
},
getMediaCatalog: function (name) {
//return a media catalog instance
}
- };
\ No newline at end of file
+ };
diff --git a/Practical Exams/academy-online-catalogs/package.json b/Practical Exams/academy-online-catalogs/package.json
index 7e71ad1..66f844e 100644
--- a/Practical Exams/academy-online-catalogs/package.json
+++ b/Practical Exams/academy-online-catalogs/package.json
@@ -1,14 +1,15 @@
{
- "name": "test-driven-hw-mocha",
- "version": "1.0.0",
- "description": "",
- "main": "index.js",
- "scripts": {
- "test": "mocha -R spec tests"
- },
- "author": "",
- "license": "ISC",
- "devDependencies": {
- "chai": "^3.0.0"
- }
-}
+ "name": "test-driven-hw-mocha",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "node_modules/mocha/bin/mocha -R spec tests"
+ },
+ "author": "",
+ "license": "ISC",
+ "devDependencies": {
+ "chai": "^3.0.0",
+ "mocha": "^3.0.2"
+ }
+}
\ No newline at end of file
diff --git a/Practical Exams/academy-online-catalogs/tasks/solution-es2015-classes-cuki.js b/Practical Exams/academy-online-catalogs/tasks/solution-es2015-classes-cuki.js
new file mode 100644
index 0000000..a87ba07
--- /dev/null
+++ b/Practical Exams/academy-online-catalogs/tasks/solution-es2015-classes-cuki.js
@@ -0,0 +1,279 @@
+function solve() {
+ const getId = (function() {
+ let id = 0;
+
+ return function() {
+ id += 1;
+ return id;
+ };
+ }());
+
+ class Item {
+ constructor(description, name) {
+ this.id = getId();
+ this.description = description;
+ this.name = name;
+ }
+
+ get description() {
+ return this._description;
+ }
+ set description(description) {
+ if(typeof description !== 'string') {
+ throw 'Description should be a string';
+ }
+ if(description === '') {
+ throw 'Description should not be empty';
+ }
+ this._description = description;
+ }
+
+ get name() {
+ return this._name;
+ }
+ set name(name) {
+ if(typeof name !== 'string') {
+ throw 'Name should be a string';
+ }
+ if(name.length < 2 || name.length > 40) {
+ throw 'Name length should be between 2 and 40';
+ }
+ this._name = name;
+ }
+ }
+
+ class Book extends Item {
+ constructor(description, name, isbn, genre) {
+ super(description, name);
+ this.isbn = isbn;
+ this.genre = genre;
+ }
+
+ get isbn() {
+ return this._isbn;
+ }
+ set isbn(isbn) {
+ if(typeof isbn !== 'string') {
+ throw 'Isbn should be a string';
+ }
+ if(isbn.length !== 10 && isbn.length !== 13) {
+ throw 'Isbn length should be either 10 or 13';
+ }
+ if(!isbn.match(/^[0-9]*$/)) {
+ throw 'Isbn should be only digits';
+ }
+
+ this._isbn = isbn;
+ }
+
+ get genre() {
+ return this._genre;
+ }
+ set genre(genre) {
+ if(typeof genre !== 'string') {
+ throw 'Genre should be a string';
+ }
+ if(genre.length < 2 || genre.length > 20) {
+ throw 'Genre length should be between 2 and 20';
+ }
+
+ this._genre = genre;
+ }
+ }
+
+ class Media extends Item {
+ constructor(description, name, duration, rating) {
+ super(description, name);
+ this.duration = duration;
+ this.rating = rating;
+ }
+
+ get duration() {
+ return this._duration;
+ }
+ set duration(duration) {
+ if(typeof duration !== 'number') {
+ throw 'Duration should be a number';
+ }
+ if(duration <= 0) {
+ throw 'Duration must be a number greater than 0';
+ }
+
+ this._duration = duration;
+ }
+
+ get rating() {
+ return this._rating;
+ }
+ set rating(rating) {
+ if(typeof rating !== 'number') {
+ throw 'Rating should be a number';
+ }
+ if(rating < 1 || rating > 5) {
+ throw 'Rating must be a number between 1 and 5';
+ }
+
+ this._rating = rating;
+ }
+ }
+
+ class Catalog {
+ constructor(name) {
+ this.id = getId();
+ this.name = name;
+ this.items = [];
+ }
+
+ get name() {
+ return this._name;
+ }
+ set name(name) {
+ if(typeof name !== 'string') {
+ throw 'Name should be a string';
+ }
+ if(name.length < 2 || name.length > 40) {
+ throw 'Name length should be between 2 and 40';
+ }
+ this._name = name;
+ }
+
+ add(...items) {
+ if(Array.isArray(items[0])) {
+ items = items[0];
+ }
+
+ if(items.length === 0) {
+ throw 'No items are added';
+ }
+
+ this.items.push(...items);
+
+ return this;
+ }
+
+ find(x) {
+ if(typeof x === 'number') {
+ for(let item of this.items) {
+ if(item.id === x) {
+ return item;
+ }
+ }
+
+ return null;
+ }
+
+ if(x !== null && typeof x === 'object') {
+ return this.items.filter(function(item) {
+ return Object.keys(x).every(function(prop) {
+ return x[prop] === item[prop];
+ });
+ });
+ }
+
+ throw 'Invalid options or id';
+ }
+
+ search(pattern) {
+ if(typeof pattern !== 'string' || pattern === '') {
+ throw 'Search pattern should be non-empty a string';
+ }
+
+ return this.items.filter(function(item) {
+ return item.name.indexOf(pattern) >= 0
+ || item.description.indexOf(pattern) >= 0;
+ });
+ }
+ }
+
+ class BookCatalog extends Catalog {
+ constructor(name) {
+ super(name);
+ }
+
+ add(...books) {
+ if(Array.isArray(books[0])) {
+ books = books[0];
+ }
+
+ books.forEach(function(x) {
+ if(!(x instanceof Book)) {
+ throw 'Must add only books';
+ }
+ });
+
+ return super.add(...books);
+ }
+
+ getGenres() {
+ let uniq = {};
+ this.items.forEach(x => uniq[x.genre] = true);
+ return Object.keys(uniq);
+ }
+
+ find(x) {
+ return super.find(x);
+ }
+ }
+
+ class MediaCatalog extends Catalog {
+ constructor(name) {
+ super(name);
+ }
+
+ add(...medias) {
+ if(Array.isArray(medias[0])) {
+ medias = medias[0];
+ }
+
+ medias.forEach(function(x) {
+ if(!(x instanceof Media)) {
+ throw 'Must add only medias';
+ }
+ });
+
+ return super.add(...medias);
+ }
+
+ getTop(count) {
+ if(typeof count !== 'number') {
+ throw 'Count should be a number';
+ }
+ if(count < 1) {
+ throw 'Count must be more than 1';
+ }
+
+ return this.items
+ .sort((a, b) => a.rating < b.rating)
+ .filter((_, ind) => ind < count)
+ .map(x => ({id: x.id, name: x.name}));
+ }
+
+ getSortedByDuration() {
+ return this.items
+ .sort((a, b) => {
+ if(a.duration === b.duration) {
+ return a.id < b.id;
+ }
+
+ return a.duration > b.duration;
+ });
+ }
+ }
+
+ return {
+ getBook(name, isbn, genre, description) {
+ return new Book(description, name, isbn, genre);
+ },
+ getMedia(name, rating, duration, description) {
+ return new Media(description, name, duration, rating);
+ },
+ getBookCatalog(name) {
+ return new BookCatalog(name);
+ },
+ getMediaCatalog(name) {
+ return new MediaCatalog(name);
+ }
+ };
+}
+
+module.exports = solve;
diff --git a/Practical Exams/academy-online-catalogs/tasks/solution-es2015-doncho.js b/Practical Exams/academy-online-catalogs/tasks/solution-es2015-doncho.js
new file mode 100644
index 0000000..b12517a
--- /dev/null
+++ b/Practical Exams/academy-online-catalogs/tasks/solution-es2015-doncho.js
@@ -0,0 +1,301 @@
+/* globals module */
+
+function solve() {
+ function* idGenerator() {
+ let lastId = 0,
+ forever = true;
+
+ while (forever) {
+ yield(lastId += 1);
+ }
+ }
+
+ let itemsIdGenerator = idGenerator();
+
+ const validator = {
+ isStringValid(str, min = 1, max = Number.MAX_VALUE) {
+ return (typeof str === "string") &&
+ str.length >= min && str.length <= max;
+ },
+ isNumberValid(n, min = 0, max = Number.MAX_VALUE) {
+ return (typeof n === "number") && min <= n && n <= max;
+ },
+ isNonEmptyArrayWithValidObjects(array, validFunc) {
+ validFunc = validFunc || function() {
+ return true;
+ };
+ return Array.isArray(array) && array.length > 0 &&
+ array.every(validFunc);
+ }
+ };
+
+ const MIN_ITEM_NAME_LENGHT = 2,
+ MAX_ITEM_NAME_LENGHT = 40;
+
+ const ISBN_LENGTH_10 = 10,
+ ISBN_LENGTH_13 = 13;
+
+ const MIN_GENRE_LENGTH = 2,
+ MAX_GENRE_LENGTH = 20;
+
+ const MIN_RATING = 1,
+ MAX_RATING = 5;
+
+ const MIN_CATALOG_NAME_LENGHT = 2,
+ MAX_CATALOG_NAME_LENGTH = 40;
+
+ const MIN_GET_TOP_COUNT = 1,
+ MIN_PATTERN_LENGTH = 1;
+
+ class Item {
+ constructor(name, description) {
+ this.id = itemsIdGenerator.next().value;
+ this.name = name;
+ this.description = description;
+ }
+
+ get name() {
+ return this._name;
+ }
+
+ set name(name) {
+ if (!validator.isStringValid(name, MIN_ITEM_NAME_LENGHT, MAX_ITEM_NAME_LENGHT)) {
+ throw new Error("Invalid name");
+ }
+
+ this._name = name;
+ }
+
+ get description() {
+ return this._description;
+ }
+
+ set description(description) {
+ if (!validator.isStringValid(description)) {
+ throw new Error("Invalid description");
+ }
+
+ this._description = description;
+ }
+ }
+
+ class Book extends Item {
+ constructor(name, isbn, genre, description) {
+ super(name, description);
+ this.isbn = isbn;
+ this.genre = genre;
+ }
+
+ get isbn() {
+ return this._isbn;
+ }
+
+ set isbn(isbn) {
+ if (!validator.isStringValid(isbn, ISBN_LENGTH_10, ISBN_LENGTH_10) &&
+ !validator.isStringValid(isbn, ISBN_LENGTH_13, ISBN_LENGTH_13)) {
+ throw new Error("Invalid ISBN");
+ }
+
+ this._isbn = isbn;
+ }
+
+ get genre() {
+ return this._genre;
+ }
+
+ set genre(genre) {
+ if (!validator.isStringValid(genre, MIN_GENRE_LENGTH, MAX_GENRE_LENGTH)) {
+ throw new Error("Invalid genre");
+ }
+
+ this._genre = genre;
+ }
+ }
+
+ class Media extends Item {
+ constructor(name, rating, duration, description) {
+ super(name, description);
+ this.rating = rating;
+ this.duration = duration;
+ }
+
+ get rating() {
+ return this._rating;
+ }
+
+ set rating(rating) {
+ if (!validator.isNumberValid(rating, MIN_RATING, MAX_RATING)) {
+ throw new Error("Invalid rating");
+ }
+
+ this._rating = rating;
+ }
+
+ get duration() {
+ return this._duration;
+ }
+
+ set duration(duration) {
+ if (!validator.isNumberValid(duration, 1)) {
+ throw new Error("Invalid duration");
+ }
+
+ this._duration = duration;
+ }
+ }
+
+ let catalogsIdGenerator = idGenerator();
+
+ class Catalog {
+ constructor(name) {
+ this.id = catalogsIdGenerator.next().value;
+ this.name = name;
+ this.items = [];
+ }
+
+ get name() {
+ return this._name;
+ }
+
+ set name(name) {
+ if (!validator.isStringValid(name, MIN_CATALOG_NAME_LENGHT, MAX_CATALOG_NAME_LENGTH)) {
+ throw new Error("Invalid Catalog name");
+ }
+
+ this._name = name;
+ }
+
+ add(...items) {
+ if (Array.isArray(items[0])) {
+ items = items[0];
+ }
+
+ if (!validator.isNonEmptyArrayWithValidObjects(items, this._itemLikeObjectValidation)) {
+ throw new Error("Invalid items");
+ }
+
+ this.items.push(...items);
+
+ return this;
+ }
+
+ find(options) {
+ if (typeof options === "undefined") {
+ throw new Error("Invalid find options");
+ }
+
+ let isSingleResult = false;
+ if (typeof options === "number") {
+ options = {
+ id: options
+ };
+ isSingleResult = true;
+ }
+
+ if (typeof options !== "object") {
+ throw new Error("Invalid options");
+ }
+
+ let result = this.items.filter(item => {
+ return Object.keys(options)
+ .every(key => item[key] === options[key]);
+ });
+
+ return (!isSingleResult) ? result : (result.length) ? result[0] : null;
+ }
+
+ search(pattern) {
+ if (!validator.isStringValid(pattern, MIN_PATTERN_LENGTH)) {
+ throw new Error("Invalid pattern");
+ }
+
+ pattern = pattern.toLowerCase();
+
+ return this.items.filter(item =>
+ item.name.toLowerCase().includes(pattern) ||
+ item.description.toLowerCase().includes(pattern));
+ }
+
+ _itemLikeObjectValidation(item) {
+
+ return (item instanceof Item) ||
+ (typeof item.id === "number" &&
+ typeof item.name === "string" &&
+ typeof item.description === "string");
+ }
+ }
+
+ class BookCatalog extends Catalog {
+ constructor(name) {
+ super(name);
+ }
+
+ _itemLikeObjectValidation(item) {
+ return super._itemLikeObjectValidation(item) &&
+ ((item instanceof Book) ||
+ (typeof item.isbn === "string" &&
+ typeof item.genre === "string"));
+ }
+
+ getGenres() {
+ let genres = {};
+ this.items.forEach(item => {
+ genres[item.genre] = true;
+ });
+
+ return Object.keys(genres);
+ }
+ }
+
+ class MediaCatalog extends Catalog {
+ constructor(name) {
+ super(name);
+ }
+
+ getTop(count) {
+ if (typeof count !== "number" || count < MIN_GET_TOP_COUNT) {
+ throw new Error("Invalid count");
+ }
+ return this.items.sort((x, y) => x.rating - y.rating)
+ .slice(0, count)
+ .map(item => {
+ return {
+ id: item.id,
+ name: item.name
+ };
+ });
+ }
+
+ getSortedByDuration() {
+ return [...this.items]
+ .sort((x, y) => (0 === y.duration - x.duration) ? y.duration - x.duration : x.id - y.id);
+ }
+
+ _itemLikeObjectValidation(item) {
+
+ return super._itemLikeObjectValidation(item) &&
+ ((item instanceof Media) ||
+ (typeof item.rating === "number" &&
+ typeof item.duration === "number"));
+ }
+
+ }
+
+ function getBook(name, isbn, genre, description) {
+ return new Book(name, isbn, genre, description);
+ }
+
+ function getMedia(name, rating, duration, description) {
+ return new Media(name, rating, duration, description);
+ }
+
+ function getBookCatalog(name) {
+ return new BookCatalog(name);
+ }
+
+ function getMediaCatalog(name) {
+ return new MediaCatalog(name);
+ }
+ return { getBook, getMedia, getBookCatalog, getMediaCatalog };
+}
+module.exports = solve;
\ No newline at end of file
diff --git a/Practical Exams/academy-online-catalogs/tasks/solution.js b/Practical Exams/academy-online-catalogs/tasks/solution.js
new file mode 100644
index 0000000..e3c1fb8
--- /dev/null
+++ b/Practical Exams/academy-online-catalogs/tasks/solution.js
@@ -0,0 +1,18 @@
+function solve() {
+ return {
+ getBook: function (name, isbn, genre, description) {
+ // return a book instance
+ },
+ getMedia: function (name, rating, duration, description) {
+ // return a media instance
+ },
+ getBookCatalog: function (name) {
+ // return a book catalog instance
+ },
+ getMediaCatalog: function (name) {
+ // return a media catalog instance
+ }
+ };
+}
+
+module.exports = solve;
diff --git a/Practical Exams/academy-online-catalogs/tests/tests-solution.js b/Practical Exams/academy-online-catalogs/tests/tests-solution.js
index 64a6357..2e3efa6 100644
--- a/Practical Exams/academy-online-catalogs/tests/tests-solution.js
+++ b/Practical Exams/academy-online-catalogs/tests/tests-solution.js
@@ -1,9 +1,11 @@
/* globals require, describe, it */
var expect = require('chai').expect,
- result = require('../tasks/solution')();
+ // result = require("../tasks/solution-es2015-doncho")();
+
+ result = require("../tasks/solution-es2015-doncho")();
/* beforeach: start */
-var utils = (function () {
+var utils = (function() {
var CONSTS = {
NAME: {
MIN: 2,
@@ -36,7 +38,7 @@ var utils = (function () {
};
function getRandom(min, max) {
- if (typeof (max) === 'undefined') {
+ if (typeof(max) === 'undefined') {
max = min;
min = 0;
}
@@ -48,84 +50,84 @@ var utils = (function () {
function getRandomString(chars, length) {
return Array.apply(null, {
length: length
- }).map(function () {
+ }).map(function() {
return chars[getRandom(chars.length)];
}).join('');
}
var utils = {
valid: {
- getName: function () {
+ getName: function() {
var length = getRandom(CONSTS.NAME.MIN, CONSTS.NAME.MAX);
return getRandomString(CONSTS.CHARS, length);
},
- getISBN10: function () {
+ getISBN10: function() {
var length = 10;
return getRandomString(CONSTS.DIGIS, length);
},
- getISBN13: function () {
+ getISBN13: function() {
var length = 13;
return getRandomString(CONSTS.DIGIS, length);
},
- getGenre: function () {
+ getGenre: function() {
var length = getRandom(CONSTS.GENRE.MIN, CONSTS.GENRE.MAX);
return getRandomString(CONSTS.CHARS, length);
},
- getDescription: function () {
+ getDescription: function() {
var length = getRandom(CONSTS.DESCRIPTION.MIN, CONSTS.DESCRIPTION.MAX);
return getRandomString(CONSTS.CHARS, length);
},
- getDuration: function () {
+ getDuration: function() {
return getRandom(0, 1000);
},
- getRating: function () {
+ getRating: function() {
return getRandom(1, 5);
}
},
invalid: {
- getShorterName: function () {
+ getShorterName: function() {
var length = getRandom(0, CONSTS.NAME.MIN - 1);
return getRandomString(CONSTS.CHARS, length);
},
- getLongerName: function () {
+ getLongerName: function() {
var length = getRandom(CONSTS.NAME.MAX + 1, CONSTS.NAME.MAX * 2);
return getRandomString(CONSTS.CHARS, length);
},
- getInvalidISBN10WithLetters: function () {
+ getInvalidISBN10WithLetters: function() {
var isbn = utils.valid.getISBN10().split(''),
index = getRandom(isbn.length);
isbn.splice(index, 1, 'a');
return isbn;
},
- getInvalidISBN13WithLetters: function () {
+ getInvalidISBN13WithLetters: function() {
return utils.valid.getISBN13().substring(1);
},
- getInvalidISBNNot10or13: function () {
+ getInvalidISBNNot10or13: function() {
var isbn = utils.valid.getISBN13().split(''),
index = getRandom(isbn.length);
isbn.splice(index, 1, 'a');
return isbn;
},
- getShorterDescription: function () {
+ getShorterDescription: function() {
var length = getRandom(0, CONSTS.DESCRIPTION.MIN - 1);
return getRandomString(CONSTS.CHARS, length);
},
- getLongerDescription: function () {
+ getLongerDescription: function() {
var length = getRandom(CONSTS.DESCRIPTION.MAX + 1, CONSTS.DESCRIPTION.MAX * 2);
return getRandomString(CONSTS.CHARS, length);
},
- getShorterGenre: function () {
+ getShorterGenre: function() {
var length = getRandom(0, CONSTS.GENRE.MIN - 1);
return getRandomString(CONSTS.CHARS, length);
},
- getLongerGenre: function () {
+ getLongerGenre: function() {
var length = getRandom(CONSTS.GENRE.MAX + 1, CONSTS.GENRE.MAX * 2);
return getRandomString(CONSTS.CHARS, length);
},
- getSmallRating: function () {
+ getSmallRating: function() {
return 0;
},
- getLargeRating: function () {
+ getLargeRating: function() {
return getRandom(6, 1000);
}
}
@@ -135,11 +137,11 @@ var utils = (function () {
}());
/* beforeach: end */
-describe('Academy Catalogs', function () {
- describe('Book tests', function () {
- describe('Valid tests', function () {
+describe('Academy Catalogs', function() {
+ describe('Book tests', function() {
+ describe('Valid tests', function() {
// test 1
- it('expect getBook to exist, to be a function and to return object with properties unique id, name, description, isbn and ganre', function () {
+ it('expect getBook to exist, to be a function and to return object with properties unique id, name, description, isbn and genre', function () {
var name,
isbn,
genre,
@@ -184,11 +186,12 @@ describe('Academy Catalogs', function () {
}
});
});
- describe('Invalid tests', function () {
+ describe('Invalid tests', function() {
// test 2
- it('Expect invalid name to throw', function () {
+ it('Expect invalid name to throw', function() {
expect(result.getBook).to.exist;
+
function testName_undefined() {
result.getBook(undefined, utils.valid.getISBN10(), utils.valid.getGenre(), utils.valid.getDescription());
}
@@ -251,7 +254,7 @@ describe('Academy Catalogs', function () {
expect(testNameSetter_Long).to.throw();
});
// test 3
- it('Expect invalid isbn to throw', function () {
+ it('Expect invalid isbn to throw', function() {
function testISBN_undefined() {
result.getBook(utils.valid.getName(), undefined, utils.valid.getGenre(), utils.valid.getDescription());
}
@@ -321,7 +324,7 @@ describe('Academy Catalogs', function () {
expect(testISBNSetter_not10or13).to.throw();
});
// test 4
- it('Expect invalid genre to throw', function () {
+ it('Expect invalid genre to throw', function() {
function testGenre_undefined() {
result.getBook(utils.valid.getName(), utils.valid.getISBN10(), undefined, utils.valid.getDescription());
}
@@ -384,7 +387,7 @@ describe('Academy Catalogs', function () {
expect(testGenreSetter_Long).to.throw();
});
// test 5
- it('Expect invalid description to throw', function () {
+ it('Expect invalid description to throw', function() {
function testDescription_undefined() {
result.getBook(utils.valid.getName(), utils.valid.getISBN10(), utils.valid.getGenre(), undefined);
@@ -424,10 +427,10 @@ describe('Academy Catalogs', function () {
});
});
- describe('Media tests', function () {
- describe('Valid tests', function () {
+ describe('Media tests', function() {
+ describe('Valid tests', function() {
// test 6
- it('expect getMedia to exist, to be a function and to return object with properties unique id, name, description, duration and rating', function () {
+ it('expect getMedia to exist, to be a function and to return object with properties unique id, name, description, duration and rating', function() {
var name,
duration,
rating,
@@ -469,9 +472,9 @@ describe('Academy Catalogs', function () {
}
});
});
- describe('Invalid tests', function () {
+ describe('Invalid tests', function() {
// test 7
- it('Expect invalid name to throw', function () {
+ it('Expect invalid name to throw', function() {
function testName_undefined() {
/*jshint ignore: start */
@@ -574,7 +577,7 @@ describe('Academy Catalogs', function () {
expect(testNameSetter_Long).to.throw();
});
// test 8
- it('Expect invalid description to throw', function () {
+ it('Expect invalid description to throw', function() {
function testDescription_undefined() {
var name = utils.valid.getName();
@@ -636,7 +639,7 @@ describe('Academy Catalogs', function () {
expect(testDescriptionSetter_EmptyString).to.throw();
});
// test 9
- it('Expect invalid rating to throw', function () {
+ it('Expect invalid rating to throw', function() {
function testRating_undefined() {
var name = utils.valid.getName();
@@ -718,7 +721,7 @@ describe('Academy Catalogs', function () {
expect(testRatingSetter_Large).to.throw();
});
// test 10
- it('Expect invalid duration to throw', function () {
+ it('Expect invalid duration to throw', function() {
function testDuration_undefined() {
var name = utils.valid.getName();
@@ -782,14 +785,15 @@ describe('Academy Catalogs', function () {
});
});
- describe('BookCatalog tests', function () {
- describe('Valid tests', function () {
+ describe('BookCatalog tests', function() {
+ describe('Valid tests', function() {
// test 11
beforeEach(function(done) {
- result = require('../tasks/solution')();
+ // result = require("../tasks/solution-es2015-doncho")();
+ result = require("../tasks/solution-es2015-doncho")();
done();
});
- it('expect getBookCatalog to exist, to be a function and to return object with properties name and unique id and methods: add(), find() with 1 param and search() with 1 param', function () {
+ it('expect getBookCatalog to exist, to be a function and to return object with properties name and unique id and methods: add(), find() with 1 param and search() with 1 param', function() {
var name = utils.valid.getName(),
catalog = result.getBookCatalog(name);
@@ -818,7 +822,7 @@ describe('Academy Catalogs', function () {
expect(catalog.getGenres.length).to.equal(0);
});
// test 12
- it('expect bookCatalog.add() to add books only and to work with array or books separated with comma', function () {
+ it('expect bookCatalog.add() to add books only and to work with array or books separated with comma', function() {
var catalog,
name,
description,
@@ -855,7 +859,7 @@ describe('Academy Catalogs', function () {
expect(catalog.items[5]).to.equal(books[2]);
});
// test 13
- it('expect bookCatalog.getGenres() to get unique genres', function () {
+ it('expect bookCatalog.getGenres() to get unique genres', function() {
var catalog,
genre,
book,
@@ -904,10 +908,10 @@ describe('Academy Catalogs', function () {
catalog = result.getBookCatalog(utils.valid.getName());
findResult = catalog.getGenres();
expect(findResult).to.exits;
- expect(findResult.length).to.equal(0);//*/
+ expect(findResult.length).to.equal(0); //*/
});
// test 14
- it('expect bookCatalog.find() by id to find the leftmost book in the items array or return null', function () {
+ it('expect bookCatalog.find() by id to find the leftmost book in the items array or return null', function() {
var catalog,
book,
i,
@@ -974,7 +978,7 @@ describe('Academy Catalogs', function () {
expect(testFindID_string).to.throw();
});
// test 15
- it('expect bookCatalog.find() by options to find an array of book in the items array or return null', function () {
+ it('expect bookCatalog.find() by options to find an array of book in the items array or return null', function() {
var catalog,
book,
findResult,
@@ -990,10 +994,10 @@ describe('Academy Catalogs', function () {
}
expect(testFindById_Undefined).to.throw();
- expect(catalog.find({name: 'nonexistent'})).to.exits;
- expect(Array.isArray(catalog.find({name: 'nonexistent'}))).to.be.true;
- expect(catalog.find({name: 'nonexistent'}).length).to.exits; // it is an array-like object
- expect(catalog.find({name: 'nonexistent'}).length).to.equal(0);
+ expect(catalog.find({ name: 'nonexistent' })).to.exits;
+ expect(Array.isArray(catalog.find({ name: 'nonexistent' }))).to.be.true;
+ expect(catalog.find({ name: 'nonexistent' }).length).to.exits; // it is an array-like object
+ expect(catalog.find({ name: 'nonexistent' }).length).to.equal(0);
// test with one book
book = {
@@ -1004,7 +1008,7 @@ describe('Academy Catalogs', function () {
description: utils.valid.getDescription()
};
catalog.items.push(book);
- findResult = catalog.find({id: id});
+ findResult = catalog.find({ id: id });
expect(findResult).to.exits;
expect(findResult.length).to.equal(1);
expect(findResult[0]).to.equal(book);
@@ -1023,22 +1027,22 @@ describe('Academy Catalogs', function () {
catalog.items.push(book);
}
- findResult = catalog.find({name: 'myName'});
+ findResult = catalog.find({ name: 'myName' });
expect(findResult).to.exits;
expect(findResult.length).to.equal(len);
- findResult = catalog.find({id: 2 + len, name: 'myName'});
+ findResult = catalog.find({ id: 2 + len, name: 'myName' });
expect(findResult).to.exits;
expect(findResult.length).to.equal(1);
expect(findResult[0]).to.equal(books[2]);
// test search by genre
- findResult = catalog.find({genre: 'generic1'});
+ findResult = catalog.find({ genre: 'generic1' });
expect(findResult).to.exits;
expect(findResult.length).to.equal(1);
});
// test 16
- it('expect bookCatalog.search() to return an array of found items or empty array', function () {
+ it('expect bookCatalog.search() to return an array of found items or empty array', function() {
var i,
catalog,
book,
@@ -1073,14 +1077,14 @@ describe('Academy Catalogs', function () {
catalog.items.push(book);
}
pattern = catalog.items[0].name.substr(1, 3);
- var matchingBooks = catalog.items.filter(function (book) {
+ var matchingBooks = catalog.items.filter(function(book) {
return book.name.indexOf(pattern) >= 0 ||
book.description.indexOf(pattern) >= 0;
});
expect(catalog.search(pattern)).to.eql(matchingBooks);
});
// test 17
- it('Expect bookCatalog.search() to return empty array, when no books in catalog and when no books that contain the pattern ', function () {
+ it('Expect bookCatalog.search() to return empty array, when no books in catalog and when no books that contain the pattern ', function() {
var catalog,
i,
pattern,
@@ -1101,13 +1105,13 @@ describe('Academy Catalogs', function () {
expect(catalog.search(pattern)).to.eql([]);
});
});
- describe('Invalid tests', function () {
+ describe('Invalid tests', function() {
// test 18
beforeEach(function(done) {
- result = require('../tasks/solution')();
+ result = require("../tasks/solution-es2015-doncho")();
done();
});
- it('Expect bookCatalog.search() to throw if pattern is undefined, null or empty string ', function () {
+ it('Expect bookCatalog.search() to throw if pattern is undefined, null or empty string ', function() {
var catalog = result.getBookCatalog(utils.valid.getName());
function testSearch_Undefined() {
@@ -1127,7 +1131,7 @@ describe('Academy Catalogs', function () {
expect(testSearch_EmptyString).to.throw();
});
// test 19
- it('expect invalid name to throw', function () {
+ it('expect invalid name to throw', function() {
var catalog,
name,
count,
@@ -1205,7 +1209,7 @@ describe('Academy Catalogs', function () {
expect(testNameSetter_Long).to.throw();
});
// test 20
- it('expect bookCatalog.add() to throw', function () {
+ it('expect bookCatalog.add() to throw', function() {
var duration,
rating,
description,
@@ -1252,14 +1256,14 @@ describe('Academy Catalogs', function () {
});
});
});
- describe('MediaCatalog tests', function () {
- describe('Valid tests', function () {
+ describe('MediaCatalog tests', function() {
+ describe('Valid tests', function() {
// test 21
beforeEach(function(done) {
- result = require('../tasks/solution')();
+ result = require("../tasks/solution-es2015-doncho")();
done();
});
- it('expect getMediaCatalog to exist, to be a function and to return object with properties name and unique id and methods: add(), find() with 1 param and search() with 1 param', function () {
+ it('expect getMediaCatalog to exist, to be a function and to return object with properties name and unique id and methods: add(), find() with 1 param and search() with 1 param', function() {
var name = utils.valid.getName(),
catalog = result.getMediaCatalog(name);
@@ -1292,7 +1296,7 @@ describe('Academy Catalogs', function () {
expect(catalog.getSortedByDuration.length).to.equal(0);
});
// test 22
- it('expect mediaCatalog.add() to add media only and to work with array or media separated with comma', function () {
+ it('expect mediaCatalog.add() to add media only and to work with array or media separated with comma', function() {
var catalog,
name,
description,
@@ -1329,7 +1333,7 @@ describe('Academy Catalogs', function () {
expect(catalog.items[5]).to.equal(medias[2]);
});
// test 23
- it('expect mediaCatalog.getTop() to get unique genres', function () {
+ it('expect mediaCatalog.getTop() to get unique genres', function() {
var catalog,
name,
rating,
@@ -1398,7 +1402,7 @@ describe('Academy Catalogs', function () {
expect(testGetTop_ltOne).to.throw();
});
// test 24
- it('expect mediaCatalog.find() by id to find the leftmost media in the items array or return null', function () {
+ it('expect mediaCatalog.find() by id to find the leftmost media in the items array or return null', function() {
var catalog,
media,
book,
@@ -1458,10 +1462,10 @@ describe('Academy Catalogs', function () {
expect(testFindID_undefined).to.throw();
expect(testFindID_null).to.throw();
- expect(testFindID_string).to.throw();//*/
+ expect(testFindID_string).to.throw(); //*/
});
// test 25
- it('expect mediaCatalog.find() by options to find an array of media in the items array or return null', function () {
+ it('expect mediaCatalog.find() by options to find an array of media in the items array or return null', function() {
var catalog,
media,
findResult,
@@ -1477,10 +1481,10 @@ describe('Academy Catalogs', function () {
}
expect(testFindById_Undefined).to.throw();
- expect(catalog.find({name: 'nonexistent'})).to.exits;
- expect(Array.isArray(catalog.find({name: 'nonexistent'}))).to.be.true;
- expect(catalog.find({name: 'nonexistent'}).length).to.exits; // it is an array-like object
- expect(catalog.find({name: 'nonexistent'}).length).to.equal(0);
+ expect(catalog.find({ name: 'nonexistent' })).to.exits;
+ expect(Array.isArray(catalog.find({ name: 'nonexistent' }))).to.be.true;
+ expect(catalog.find({ name: 'nonexistent' }).length).to.exits; // it is an array-like object
+ expect(catalog.find({ name: 'nonexistent' }).length).to.equal(0);
// test with one book
media = {
@@ -1491,7 +1495,7 @@ describe('Academy Catalogs', function () {
description: utils.valid.getDescription()
};
catalog.items.push(media);
- findResult = catalog.find({id: id});
+ findResult = catalog.find({ id: id });
expect(findResult).to.exits;
expect(findResult.length).to.equal(1);
expect(findResult[0]).to.equal(media);
@@ -1510,22 +1514,22 @@ describe('Academy Catalogs', function () {
catalog.items.push(media);
}
- findResult = catalog.find({name: 'myName'});
+ findResult = catalog.find({ name: 'myName' });
expect(findResult).to.exits;
expect(findResult.length).to.equal(len);
- findResult = catalog.find({id: 2 + len, name: 'myName'});
+ findResult = catalog.find({ id: 2 + len, name: 'myName' });
expect(findResult).to.exits;
expect(findResult.length).to.equal(1);
expect(findResult[0]).to.equal(medias[2]);
// test search by genre
- findResult = catalog.find({rating: 4});
+ findResult = catalog.find({ rating: 4 });
expect(findResult).to.exits;
expect(findResult.length).to.equal(1);
});
// test 26
- it('expect mediaCatalog.search() to return an array of found items or empty array', function () {
+ it('expect mediaCatalog.search() to return an array of found items or empty array', function() {
var i,
catalog,
media,
@@ -1560,14 +1564,14 @@ describe('Academy Catalogs', function () {
catalog.items.push(media);
}
pattern = catalog.items[0].name.substr(1, 3);
- var matchingMedia = catalog.items.filter(function (media) {
+ var matchingMedia = catalog.items.filter(function(media) {
return media.name.indexOf(pattern) >= 0 ||
media.description.indexOf(pattern) >= 0;
});
expect(catalog.search(pattern)).to.eql(matchingMedia);
});
// test 27
- it('Expect mediaCatalog.search() to return empty array, when no media in catalog and when no media that contain the pattern ', function () {
+ it('Expect mediaCatalog.search() to return empty array, when no media in catalog and when no media that contain the pattern ', function() {
var catalog,
i,
pattern,
@@ -1589,13 +1593,13 @@ describe('Academy Catalogs', function () {
expect(catalog.search(pattern)).to.eql([]);
});
});
- describe('Invalid tests', function () {
+ describe('Invalid tests', function() {
// test 28
beforeEach(function(done) {
- result = require('../tasks/solution')();
+ result = require("../tasks/solution-es2015-doncho")();
done();
});
- it('Expect mediaCatalog.search() to throw if pattern is undefined, null or empty string ', function () {
+ it('Expect mediaCatalog.search() to throw if pattern is undefined, null or empty string ', function() {
var catalog = result.getMediaCatalog(utils.valid.getName());
function testSearch_Undefined() {
@@ -1615,7 +1619,7 @@ describe('Academy Catalogs', function () {
expect(testSearch_EmptyString).to.throw();
});
// test 29
- it('expect invalid name to throw', function () {
+ it('expect invalid name to throw', function() {
var catalog,
name,
count,
@@ -1693,7 +1697,7 @@ describe('Academy Catalogs', function () {
expect(testNameSetter_Long).to.throw();
});
// test 30
- it('expect mediaCatalog.add() to throw', function () {
+ it('expect mediaCatalog.add() to throw', function() {
var duration,
rating,
description,
@@ -1740,4 +1744,4 @@ describe('Academy Catalogs', function () {
});
});
});
-});
\ No newline at end of file
+});
diff --git a/Sample Exams/audio-player/package.json b/Sample Exams/audio-player/package.json
index 996938b..71a5702 100644
--- a/Sample Exams/audio-player/package.json
+++ b/Sample Exams/audio-player/package.json
@@ -4,11 +4,12 @@
"description": "",
"main": "index.js",
"scripts": {
- "test": "mocha -R spec tests"
+ "test": "node_modules/mocha/bin/mocha -R spec tests"
},
"author": "",
"license": "ISC",
"devDependencies": {
- "chai": "^3.0.0"
+ "chai": "^3.0.0",
+ "mocha": "^3.0.2"
}
-}
\ No newline at end of file
+}
diff --git a/Sample Exams/audio-player/tests/task-1-tests-playlist.js b/Sample Exams/audio-player/tests/task-1-tests-playlist.js
index b079b0d..22f1c1c 100644
--- a/Sample Exams/audio-player/tests/task-1-tests-playlist.js
+++ b/Sample Exams/audio-player/tests/task-1-tests-playlist.js
@@ -36,7 +36,7 @@ describe('Sample exam tests', function () {
it('expect playlist.addPlayable() to exists, to be a function and to take a single parameter and to enable chaining', function () {
var name = 'Rock and roll',
playlist = result.getPlaylist(name),
- playable = {id: 1, name: 'Banana Rock', author: 'Wombles'};
+ playable = {id: 1, title: 'Banana Rock', author: 'Wombles'};
expect(playlist.addPlayable).to.exist;
expect(playlist.addPlayable).to.be.a('function');
@@ -58,7 +58,7 @@ describe('Sample exam tests', function () {
var returnedPlayable,
name = 'Rock and roll',
playlist = result.getPlaylist(name),
- playable = {id: 1, name: 'Banana Rock', author: 'Wombles'};
+ playable = {id: 1, title: 'Banana Rock', author: 'Wombles'};
returnedPlayable = playlist.addPlayable(playable).getPlayableById(1);
expect(returnedPlayable.id).to.equal(playable.id);
@@ -80,7 +80,7 @@ describe('Sample exam tests', function () {
plName = 'Banana Rock',
plAuthor = 'Wombles',
playlist = result.getPlaylist(name),
- playable = {id: 1, name: plName, author: plAuthor};
+ playable = {id: 1, title: plName, author: plAuthor};
playlist.addPlayable(playable);
playlist.removePlayable(playable);
@@ -110,7 +110,7 @@ describe('Sample exam tests', function () {
playlist = result.getPlaylist(name);
for (i = 0; i < 35; i += 1) {
- playlist.addPlayable({id: (i + 1), name: 'Rock' + (9 - (i % 10))});
+ playlist.addPlayable({id: (i + 1), title: 'Rock' + (9 - (i % 10))});
}
expect(playlist.listPlayables(2, 10).length).to.equal(10);
diff --git a/Topics/01. JavaScript-Transpilers-and-Babel/README.md b/Topics/01. JavaScript-Transpilers-and-Babel/README.md
index 7716e5a..fbfceb0 100644
--- a/Topics/01. JavaScript-Transpilers-and-Babel/README.md
+++ b/Topics/01. JavaScript-Transpilers-and-Babel/README.md
@@ -47,7 +47,7 @@
- `babel-core` - for advanced scenarios
- `babel-cli` - in order to run babel from the command line
-- Separate packages for each EcmaScript2015 feature in Bable6
+- Separate packages for each EcmaScript2015 feature in Babel6
- Turn on individual features **babel-plugin-* **
- _Example_: `babel-plugin-transform-es2015-arrow-functions`
- Or use **babel-presets-* **
diff --git a/Topics/03. Closures-and-Scope/homework/README.md b/Topics/03. Closures-and-Scope/homework/README.md
index 4ae6500..bd186bb 100644
--- a/Topics/03. Closures-and-Scope/homework/README.md
+++ b/Topics/03. Closures-and-Scope/homework/README.md
@@ -16,7 +16,7 @@
- **List all categories**
- Return an array of categories
- Categories are sorted by ID
- - **Each book/catagory has a unique identifier (ID) that is a number greater than 1**
+ - **Each book/category has a unique identifier (ID) that is a number greater than 1**
- When adding a book/category, the ID is generated automatically
- **Add validation everywhere, where possible**
- Book title and category name must be between 2 and 100 characters, including letters, digits and special characters ('!', ',', '.', etc)
diff --git a/Topics/06. Class-Inheritance/demos/demo.js b/Topics/06. Class-Inheritance/demos/demo.js
deleted file mode 100644
index 2c02d83..0000000
--- a/Topics/06. Class-Inheritance/demos/demo.js
+++ /dev/null
@@ -1 +0,0 @@
-console.log('06. Class-Inheritance');
diff --git a/Topics/06. Class-Inheritance/demos/pet-store.js b/Topics/06. Class-Inheritance/demos/pet-store.js
new file mode 100644
index 0000000..658a0da
--- /dev/null
+++ b/Topics/06. Class-Inheritance/demos/pet-store.js
@@ -0,0 +1,109 @@
+const petStore = (function () {
+
+ class Animal {
+ constructor(name, age, sound) {
+ this.name = name;
+ this.age = age;
+ this.sound = sound;
+ }
+
+ get name() {
+ return this._name;
+ }
+
+ set name(value) {
+ if(typeof value !== 'string' || value.length < 2) {
+ throw new Error('Name must be string value with at least 2 symbols!');
+ }
+
+ this._name = value;
+ }
+
+ get age() {
+ return this._age;
+ }
+
+ set age(value) {
+ if(value < 0) {
+ throw new Error('Age cannot be negative number!');
+ }
+
+ this._age = value;
+ }
+
+ get sound() {
+ return this._sound;
+ }
+
+ set sound(value) {
+ if(typeof value !== 'string') {
+ throw new Error('Sound must be string!');
+ }
+
+ this._sound = value;
+ }
+
+ makeSound() {
+ console.log(this.sound);
+ }
+
+ toString() {
+ return `${this.name} is ${this.age} years old`
+ }
+ }
+
+ class Cat extends Animal {
+ constructor(name, age, color) {
+ super(name, age, 'mew');
+
+ this.color = color;
+ }
+
+ toString() {
+ return `${super.toString()} ${this.color} cat`;
+ }
+ }
+
+ class MythicalDragonHydra extends Animal {
+ constructor(name, age, headsCount) {
+ super(name, age, 'RAWRWRWR');
+
+ if(headsCount < 2) {
+ throw new Error('MythicalDragonHydra must have at least 2 heads!');
+ }
+
+ this._headsCount = headsCount;
+ }
+
+ get headsCount() {
+ return this._headsCount;
+ }
+
+ growHead() {
+ this._headsCount += 1;
+ this.makeSound();
+ }
+
+ toString() {
+ return `${super.toString()} and is a mythic dragon hydra with ${this.headsCount} heads!`;
+ }
+ }
+
+ return {
+ getCat: function(name, age, color) {
+ return new Cat(name, age, color);
+ },
+ getHydra: function(name, age, headsCount) {
+ return new MythicalDragonHydra(name, age, headsCount);
+ }
+ };
+} ());
+
+const davinci = petStore.getCat('davinci', 2, 'gray'),
+ petko = petStore.getHydra('petko', 1000, 5);
+
+davinci.makeSound();
+console.log(davinci.toString());
+
+petko.makeSound();
+console.log(petko.toString());
\ No newline at end of file
diff --git a/Topics/07. Mixins/README.md b/Topics/07. Mixins/README.md
index 26fea32..84796c6 100644
--- a/Topics/07. Mixins/README.md
+++ b/Topics/07. Mixins/README.md
@@ -44,7 +44,7 @@
printName() {
console.log(`My name is ${this.name}`);
}
- }
+ };
```
- Create your class:
diff --git a/Topics/08. ES6-Features/README.md b/Topics/08. ES6-Features/README.md
index f6bbfe3..8ba738c 100644
--- a/Topics/08. ES6-Features/README.md
+++ b/Topics/08. ES6-Features/README.md
@@ -1,41 +1,59 @@
-
-
+
+# ES 2015 Features
+## The new cool stuff in JS
+ JavaScript OOP Telerik Software Academy
JavaScript OOP
Telerik Software Academy
- http://academy.telerik.com + http://academy.telerik.com