For people who like abstract art, the Miro museum is a real treasure. For people who like sports there is the Olympic stadium. And for the people who like nature there are beautiful gardens. All on Montjuice.
Readers who are asking why i change to English, that is because my Spanish isn't good enough to make a decent article.
Like The Netherlands who seem to learn everyone dutch, Spain is making everyone talk Spanish. For some reason it seems more mandatory than France, Germany or the UK with their language.
But i don't fear the task, i welcome it. The more I know the more i can use.
After my siësta i went to Badalona to eat by the sea but i couldn't find the place with the right vibe so I folded back to my favorite Barcelona quarter, Passeige de Garcia. Met an American in my favorite tapas bar. Are all the Americans named Bill, or just the ones that come oversea?
Anyway it was a pleasant conversation.
Then i searched for a good place to get a night cap, so I found a terras an went into the place. Asked for a good rum, ron in Spanish, and just sat at the bar.
Some guy came inside, asked if they spoke English, No habla of course. And the real insult was they looked for another bar. Try that in any bar anywhere in the wold and they send you in the wrong direction. But the people were correct and that is for me a good indication how people from Barcelona act with visitors. It's such a visited place they accept stupid behavior from tourists.
These two days where the weekend for people from Barcelona, so I guess they also mingled with the tourists. Lets see who tomorrow goes. Mondays are always a good way to see people in their day to day rhythm.
Zoals mozes van de berg kwam met de tien geboden, ging ik het avontuur aan om van mijn hotel naar het strand te gaan.
Het eerste wat me opviel is dar Barcelona overal goed geregeld is. Er is veel groen zodat je geen benauwd gevoel heb die je krijgt in steden met voor het merendeel steen en glas. Daarnaast vind je ook overal afvalcontainers. In de Barelona versie van linkeroever staan die op straat en bij de chiquere wijken zijn ze ondergonds. Maar ze staan wel overal en dit heeft volgens mij het effect dat je geen zwerfvuil ziet. Bij ons zijn gewone vuilbakken veel te klein maar zelfs glascontainers worden met moeite leeg gemaakt.
Het strand vinden in een stad waar de bergen uitlopen tot de zee is niet zo gemakkelijk. Ik dacht naar beneden blijven gaan en eens je beneden bent zal het strand wel niet ver af zijn. Barcelona lachte in zijn vuistje.
Na ik tegen een grote bouwplaats uitkwam die in mijn weg stond kon ik oversteken op een voetgangersbrug. Maar het desolate van de bouwwerf was een voorproefje van een parking die in Belgïe gewoon niet kan bestaan omdat de plaats ervoor niet bestaat. Eens ik van de parkeerplaats af was kwam ik de busstelplaats tegen. Ik was dus in de industriële wijk van barcelona beland. En tussen al die magazijen zag ik het volgende.
After being exited about the way the ES6 changes allows me to write cleaner code, it was time i actually wrote some.
There are probably more options but traceur, 6to5 and typescript are the most common.
Typescript isn't an option I explored because next to ES6 syntax it adds its own. For example it has static typing, hence the name.
I tried traceur but the dealbreaker was the need of a runtime for the ES5 code.
So I will use 6to5. For modules you need to add requirejs but that is something I can live with.
I'm going to make a ES6 version of the livevalidation library because it is complex enough to go from babysteps to running.
The library usage needs ES6 syntax, this means the tests also need to be written in ES6.
Node supports ES6 using the --harmony flag, but it doesn't support all the 6to5 features.
The solution
This makes it easy to version the code.
Of course there is a node_modules directory, but which javascript project hasn't one these days.
After npm init
I run npm install 6to5 mocha should --save-dev
{ | |
"name": "livevalidation-es6", | |
"version": "0.0.0", | |
"description": "es6 version of livevalidation", | |
"main": "index.js", | |
"scripts": { | |
"test": "node_modules/.bin/6to5 src -d test/out && node_modules/.bin/6to5 test-es6 -d test && mocha" | |
}, | |
"author": "", | |
"license": "ISC", | |
"devDependencies": { | |
"should": "^4.4.1", | |
"mocha": "^2.0.1", | |
"6to5": "^1.15.0" | |
} | |
} |
On line 7 you see the commands that transpiles the library and test code and starts the testrunner.
The base of the validation library is the validate class that holds the checks you need to determine the form is valid or not.
The most used check Presence has following tests:
import validate from '../test/out/validate'; | |
var should = require('should'); | |
describe('Validate', () => { | |
describe('Presence', () => { | |
it('should return true', () => { | |
validate.Presence('test').should.be.true; | |
}) | |
it('should return error', () => { | |
try{ | |
validate.Presence('').should.be.an.instanceof(validate.Error); | |
}catch(err){ | |
err.name.should.equal('ValidationError'); | |
err.message.should.eql("Can't be empty!") | |
} | |
}) | |
it('should return custom error', () => { | |
try{ | |
validate.Presence('', { errMsg: 'Add a value'}).should.be.an.instanceof(validate.Error); | |
}catch(err){ | |
err.message.should.eql("Add a value") | |
} | |
}) | |
}) | |
// other tests ... | |
}); |
For the people who aren't familiar with mocha and should I will explain them briefly.
Should extends variables, functions and objects with a should namespace and in that namespace there are assertions that need to be met for the test to pass.
Mocha is a test runner that goes through all the files in the test directory and executes all describe function calls. The it function calls contain the actual tests.
As you can see above the there is one positive test and two negative tests.
You may have noticed I'm using the ES6 (fat) arrow function syntax. Why should I write function(){ when I can use less characters.
Line 1 is the ES6 module syntax.
The rest of the code must look familiar for people that used livevalidation and/or mocha-should before.
Now lets write the code to pass the tests.
class Validate { | |
static Presence(value, paramsObj = { errMsg: "Can't be empty!"}) { | |
if(value === '' || value === null || value === undefined){ Validate.fail(paramsObj.errMsg); } | |
return true; | |
} | |
// other methods ... | |
} | |
export default Validate |
I'm going to add the original code as a reference.
var Validate = { | |
Presence: function(value, paramsObj){ | |
var paramsObj = paramsObj || {}; | |
var message = paramsObj.failureMessage || "Can't be empty!"; | |
if(value === '' || value === null || value === undefined) Validate.fail(message); | |
return true; | |
} | |
} |
As you can see instead of using an object expression to create the class, the ES6 code uses the keyword class.
Another thing you might notice it uses a functioncreatelike syntax instead of a jsonlike syntax. The keyword static looks very recognisable for people who have used object-oriented languages.
The last ES6 syntax related code of the Presence method is the default value for the paramsObj.
As you can see the class method only contains the actual code, which makes it easier to read than the original code.
The last line of the class file is the ES6 syntax for modules. Each module can have multiple exports
, but it can only have one export default
.
Now that I have written code you can find in all the ES6 tutorials let's go a step further with the Numericality method.
Numericality: function(value, paramsObj){ | |
var suppliedValue = value; | |
var value = Number(value); | |
var paramsObj = paramsObj || {}; | |
var minimum = ((paramsObj.minimum) || (paramsObj.minimum == 0)) ? paramsObj.minimum : null;; | |
var maximum = ((paramsObj.maximum) || (paramsObj.maximum == 0)) ? paramsObj.maximum : null; | |
var is = ((paramsObj.is) || (paramsObj.is == 0)) ? paramsObj.is : null; | |
var notANumberMessage = paramsObj.notANumberMessage || "Must be a number!"; | |
var notAnIntegerMessage = paramsObj.notAnIntegerMessage || "Must be an integer!"; | |
var wrongNumberMessage = paramsObj.wrongNumberMessage || "Must be " + is + "!"; | |
var tooLowMessage = paramsObj.tooLowMessage || "Must not be less than " + minimum + "!"; | |
var tooHighMessage = paramsObj.tooHighMessage || "Must not be more than " + maximum + "!"; | |
if (!isFinite(value)) Validate.fail(notANumberMessage); | |
if (paramsObj.onlyInteger && (/\.0+$|\.$/.test(String(suppliedValue)) || value != parseInt(value)) ) Validate.fail(notAnIntegerMessage); | |
switch(true){ | |
case (is !== null): | |
if( value != Number(is) ) Validate.fail(wrongNumberMessage); | |
break; | |
case (minimum !== null && maximum !== null): | |
Validate.Numericality(value, {tooLowMessage: tooLowMessage, minimum: minimum}); | |
Validate.Numericality(value, {tooHighMessage: tooHighMessage, maximum: maximum}); | |
break; | |
case (minimum !== null): | |
if( value < Number(minimum) ) Validate.fail(tooLowMessage); | |
break; | |
case (maximum !== null): | |
if( value > Number(maximum) ) Validate.fail(tooHighMessage); | |
break; | |
} | |
return true; | |
} |
ES6 has the default parameters, but because it is a single parameter it will not keep the default values once you add an object in the function call.
To keep the defaults there needs to be a method that merges them with the object in the function call. A simple method for this is:
static mergeObj(out, replacements = null){
if(!replacements){ return out; }
for(let attr in out){
if(replacements.hasOwnProperty(attr)){
out[attr] = replacements[attr];
}
}
return out;
}
This allows me to create a NumericalityConfig method which contains the defaults object and calls the mergeObj code.
Now I can write my tests.
describe('Numericality', () => { | |
it('should be true', () => { | |
validate.Numericality(2).should.be.true; | |
validate.Numericality('2').should.be.true; | |
validate.Numericality(0).should.be.true; | |
validate.Numericality(-2).should.be.true; | |
validate.Numericality(2.5).should.be.true; | |
validate.Numericality(2, validate.NumericalityConfig({isInteger: true})).should.be.true; | |
validate.Numericality(1.123e3, validate.NumericalityConfig({isInteger: true})).should.be.true; | |
validate.Numericality('1.123e3', validate.NumericalityConfig({isInteger: true})).should.be.true; | |
validate.Numericality(0, validate.NumericalityConfig({isInteger: true})).should.be.true; | |
validate.Numericality(9, validate.NumericalityConfig({exactNr : 9})).should.be.true; | |
validate.Numericality(9, validate.NumericalityConfig({minimum: 9})).should.be.true; | |
validate.Numericality(10, validate.NumericalityConfig({minimum: 9})).should.be.true; | |
validate.Numericality(9, validate.NumericalityConfig({maximum: 10})).should.be.true; | |
validate.Numericality(10, validate.NumericalityConfig({maximum: 10})).should.be.true; | |
validate.Numericality(9, validate.NumericalityConfig({minimum: 9, maximum: 10})).should.be.true; | |
validate.Numericality(10, validate.NumericalityConfig({minimum: 9, maximum: 10})).should.be.true; | |
}) | |
it('should return a number error', () => { | |
try{ | |
validate.Numericality('a').should.be.an.instanceof(validate.Error); | |
}catch(err){ | |
err.name.should.equal('ValidationError'); | |
err.message.should.eql('Must be a number!'); | |
} | |
}) | |
it('should return a custom number error', () => { | |
try{ | |
validate.Numericality('a', validate.NumericalityConfig({notNrErrMsg: 'Not a number!'})).should.be.an.instanceof(validate.Error); | |
}catch(err){ | |
err.message.should.eql('Not a number!'); | |
} | |
}) | |
it('should return an integer error', () => { | |
try{ | |
validate.Numericality(1.5, validate.NumericalityConfig({isInteger: true})).should.be.an.instanceof(validate.Error); | |
}catch(err){ | |
err.message.should.eql('Must be an integer!'); | |
} | |
}) | |
it('should return a custom integer error', () => { | |
try{ | |
validate.Numericality(1.5, validate.NumericalityConfig({isInteger: true, notIntErrMsg: 'Not an integer!'})).should.be.an.instanceof(validate.Error); | |
}catch(err){ | |
err.message.should.eql('Not an integer!'); | |
} | |
}) | |
it('should return an exact number error', () => { | |
try{ | |
validate.Numericality(1.5, validate.NumericalityConfig({exactNr: 1})).should.be.an.instanceof(validate.Error); | |
}catch(err){ | |
err.message.should.eql('Must be 1!'); | |
} | |
}) | |
it('should return a custom exact number error', () => { | |
try{ | |
validate.Numericality(1.5, validate.NumericalityConfig({exactNr: 1, wrongNrErrMsg: (exact) => `The number must be ${exact}!`})).should.be.an.instanceof(validate.Error); | |
}catch(err){ | |
err.message.should.eql('The number must be 1!'); | |
} | |
}) | |
it('should return a minimum error', () => { | |
try{ | |
validate.Numericality(1.5, validate.NumericalityConfig({minimum: 2})).should.be.an.instanceof(validate.Error); | |
}catch(err){ | |
err.message.should.eql('Must not be less than 2!'); | |
} | |
}) | |
it('should return a custom minimum error', () => { | |
try{ | |
validate.Numericality(1.5, validate.NumericalityConfig({minimum: 2, tooLowErrMsg: (min) => `${min} or higher!`})).should.be.an.instanceof(validate.Error); | |
}catch(err){ | |
err.message.should.eql('2 or higher!'); | |
} | |
}) | |
it('should return a maximum error', () => { | |
try{ | |
validate.Numericality(1.5, validate.NumericalityConfig({maximum: 1})).should.be.an.instanceof(validate.Error); | |
}catch(err){ | |
err.message.should.eql('Must not be more than 1!'); | |
} | |
}) | |
it('should return a custom maximum error', () => { | |
try{ | |
validate.Numericality(1.5, validate.NumericalityConfig({maximum: 1, tooHighErrMsg: (max) => `${max} or lower!`})).should.be.an.instanceof(validate.Error); | |
}catch(err){ | |
err.message.should.eql('1 or lower!'); | |
} | |
}) | |
it('should return a range error', () => { | |
try{ | |
validate.Numericality(1.5, validate.NumericalityConfig({minimum: 1, maximum: 1})).should.be.an.instanceof(validate.Error); | |
}catch(err){ | |
err.message.should.eql('Must be not less than 1 and not more than 1!'); | |
} | |
}) | |
it('should return a custom range error', () => { | |
try{ | |
validate.Numericality(1.5, validate.NumericalityConfig({minimum: 1, maximum: 1, notInRangeErrMsg: (min, max) => `Must be in the ${min}-${max} range!`})).should.be.an.instanceof(validate.Error); | |
}catch(err){ | |
err.message.should.eql('Must be in the 1-1 range!'); | |
} | |
}) | |
}); |
There is only one positive test because the output of all the assertions is the same and there are 12 negative tests.
The ES6 syntax you can see in these test is a template string. Instead of writing "My name is " + name
you can write `My name is ${name}`
. It gives more context to the variable. Because a template string is executed directly you need to wrap it in a function to defer the execution.
Lets look at the code of NumericalityConfig and Numericality.
static NumericalityConfig(config = null) { | |
var defaults = { notNrErrMsg: "Must be a number!", | |
isInteger: false, notIntErrMsg: "Must be an integer!", | |
minimum: null, tooLowErrMsg: (min) => `Must not be less than ${min}!`, | |
maximum: null, tooHighErrMsg: (max) => `Must not be more than ${max}!`, | |
notInRangeErrMsg: (min, max) => `Must be not less than ${min} and not more than ${max}!`, | |
exactNr: null, wrongNrErrMsg: (exact) => `Must be ${exact}!` | |
}; | |
return Validate.mergeObj(defaults, config); | |
} | |
static Numericality(value, paramsObj = { notNrErrMsg: "Must be a number!", | |
isInteger: false, notIntErrMsg: "Must be an integer!", | |
minimum: null, tooLowErrMsg: (min) => `Must not be less than ${min}!`, | |
maximum: null, tooHighErrMsg: (max) => `Must not be more than ${max}!`, | |
notInRangeErrMsg: (min, max) => `Must be not less than ${min} and not more than ${max}!`, | |
exactNr: null, wrongNrErrMsg: (exact) => `Must be ${exact}!` | |
}) { | |
var val = Number(value); | |
if(isNaN(val)){ Validate.fail(paramsObj.notNrErrMsg); } | |
if (paramsObj.isInteger && (/\.0+$|\.$/.test(String(value)) || val != parseInt(val)) ){ Validate.fail(paramsObj.notIntErrMsg); } | |
if(paramsObj.exactNr){ | |
var exactNr = Number(paramsObj.exactNr); | |
if(isNaN(exactNr)){ throw Error('exactNr is not a number!'); } | |
if(val !== exactNr){ Validate.fail(paramsObj.wrongNrErrMsg(paramsObj.exactNr)); } | |
} | |
if(paramsObj.minimum && paramsObj.maximum){ | |
let minimum = Number(paramsObj.minimum); | |
let maximum = Number(paramsObj.maximum); | |
if(isNaN(minimum)){ throw Error('minimum is not a number!'); } | |
if(isNaN(maximum)){ throw Error('maximum is not a number!'); } | |
if(val < minimum || val > maximum){ Validate.fail(paramsObj.notInRangeErrMsg(minimum, maximum)); } | |
} | |
if(paramsObj.minimum){ | |
let minimum = Number(paramsObj.minimum); | |
if(isNaN(minimum)){ throw Error('minimum is not a number!'); } | |
if(val < minimum){ Validate.fail(paramsObj.tooLowErrMsg(minimum)); } | |
} | |
if(paramsObj.maximum){ | |
let maximum = Number(paramsObj.maximum); | |
if(isNaN(maximum)){ throw Error('maximum is not a number!'); } | |
if(val > maximum){ Validate.fail(paramsObj.tooHighErrMsg(maximum)); } | |
} | |
return true; | |
} |
Again you see the method only contains the code needed to do the checks.
You also see that the error messages with a template string get called with the value(s) that are needed in the string.
If you would copy all the code and run the tests it would would fail. This is because I haven't shown you the error code of the validate class.
static fail(errorMessage) { | |
throw new Validate.Error(errorMessage); | |
} | |
static Error(errorMessage) { | |
this.message = errorMessage; | |
this.name = 'ValidationError'; | |
} |
It already has been a lot to take in so I'm going to end it here. Later posts will show the other parts where ES6 improves the code.
Velen denken dat er al te ver gegaan wordt met de fitnesstrackers en smartwatches, maar dit is maar een klein deeltje van wat er gemaakt wordt om gedragen te worden.
Laten we beginnen met de voeten. Hang eens iets aan je schoen om je prestaties bij te houden en je routes te onthouden.
Ben je niet zo sportief. Doe dan een paar rolschaatsen aan met elektrische aandrijving.
Wil je weten hoe de andere delen van je lichaam bewegen, hang een bewegingssensor waar je wil.
Er is zoveel plaats aan je rok of broekrand om dingen aan te hangen, waarom geen thermometer of uv meter en waarom geen lucht kwaliteits meter.
Om jewat meer zichtbaarheid te geven, doe eens een led lamp riem aan.
Fitnesstrackers zijn maar eenzijdig, dus waarom geen fitnesstracker met noodalarm. Nu het over veiligheid gaat geef me dan ineens maar een wachtwoord vervangende armband. Omdat je op je handen loopt doe eens een wandel houding verbeteraar armband aan.
Vergeet het uurwerk niet, maar waarom een smartwatch als je een zonnepaneel annex uurwerk.
Je smartphone vasthouden dat is niet meer van deze tijd, dus draag je de smartphone band.
Voor je vingers ga je low tech met pen/stylus ring en high tech met de smartring.
Waarom zou je handshoenen alleen maar aan doen bij koud weer als ze je muziek kunnen aansturen.
Waarom zouden halskettingen alleen maar mooi mogen zijn. Hang er eens een camera aan. En zorg voor je nek met nektracker.
Omdat google glas creepy is draag je beter een zonneklep.
Als je alles filmt wat voor je gebeurd waarom ook niet alles wat achter je gebeurd.