From f9379df59dd87e8bb89c655fbf60359855b70cfc Mon Sep 17 00:00:00 2001 From: wgroeneveld Date: Thu, 3 May 2018 16:09:41 +0200 Subject: [PATCH] archief vanuit wiki tech ter info --- config.toml | 3 +- content/post/cplusplus-basics.md | 682 +++++++++++ content/post/cplusplus-testing.md | 105 ++ content/post/dynamic-languages.md | 374 ++++++ content/post/introduction-to-js.md | 1779 ++++++++++++++++++++++++++++ content/post/python-basics.md | 215 ++++ content/post/ruby-classes.md | 105 ++ content/post/scheme.md | 85 ++ content/post/scons-building.md | 131 ++ content/post/unix-cmd.md | 500 ++++++++ layouts/_default/list.html | 8 +- 11 files changed, 3985 insertions(+), 2 deletions(-) create mode 100644 content/post/cplusplus-basics.md create mode 100644 content/post/cplusplus-testing.md create mode 100644 content/post/dynamic-languages.md create mode 100644 content/post/introduction-to-js.md create mode 100644 content/post/python-basics.md create mode 100644 content/post/ruby-classes.md create mode 100644 content/post/scheme.md create mode 100644 content/post/unix-cmd.md diff --git a/config.toml b/config.toml index 005c0cd9..a02febf7 100644 --- a/config.toml +++ b/config.toml @@ -6,6 +6,7 @@ pygmentsUseClasses = true pygmentCodeFences = true googleAnalytics = "UA-45748221-1" publishDir = "docs" +enableEmoji = true [taxonomies] tag = "tags" @@ -19,7 +20,7 @@ publishDir = "docs" backgroundColor = "white" highlight = true highlightStyle = "paraiso-dark" - highlightLanguages = ["c#", "java", "scala", "javascript"] + highlightLanguages = ["c#", "c", "scheme", "python", "java", "scala", "javascript"] font = "Open Sans" copyright = "No reserved - sharing is caring. Hack away! Brain Baking" diff --git a/content/post/cplusplus-basics.md b/content/post/cplusplus-basics.md new file mode 100644 index 00000000..480c2d14 --- /dev/null +++ b/content/post/cplusplus-basics.md @@ -0,0 +1,682 @@ ++++ +title = "C++ Basics" +subtitle = "C++ basics for a Java developer" +archived = true +draft = false +tags = [ + "c++" +] +date = "2013-10-01" ++++ + +## Scope + +C++ heeft block level scope, net als Java, alleen is het mogelijk om een variabele binnen een for loop dezelfde naam te geven als een die buiten die block gedefiniëerd is, terwijl dat in Java niet gaat: + +```c +int j; +for(int i = 0; i < 10; i++) { + int j = i + 1; // compile fout in java +} +``` + +### Pointer scope + +[auto_ptr](https://en.wikipedia.org/wiki/Auto_ptr) kan gebruikt worden om een pointer automatisch te verwijderen met `delete` wanneer deze scope verliest - alle andere zaken moet je zelf opkuisen. +:exclamation: Dit is deprecated in C++ 11, gebruik [unique_ptr](https://en.wikipedia.org/wiki/Smart_pointer#unique_ptr) + +Voorbeeld van wikipedia: + +```c +#include +#include +using namespace std; + +int main(int argc, char **argv) +{ + int *i = new int; + auto_ptr x(i); + auto_ptr y; + + y = x; + + cout << x.get() << endl; // Print NULL + cout << y.get() << endl; // Print non-NULL address i + + return 0; +} +``` + +## overloading: 'virtual' + +In java wordt by default het diepste gedefiniëerde element opgeroepen, in C++ ben je verplicht `virtual` te gebruiken als "optimalisatie" wordt dit standaard niet gedaan... Voorbeeld: + +```c +class Simple +{ +public: + Simple() : someMember(3) {} + virtual int guessNumber(); + int someMember; +}; +``` + +```c +#include "simplecpp.h" + +int Simple::guessNumber() +{ + return 5; +} +``` + +Als je nu `guessNumber()` wil overschrijven in een subklasse kan dit: + +```c +#include "simplecpp.h" + +class Complexer : public Simple +{ +public: + Complexer() {} + int guessNumber(); +}; +``` + +Merk op, te overschrijven method heropsommen in header file... (??) - hier hoeft geen `virtual` meer bij dan. + +```c +#include "complexer.h" + +int Complexer::guessNumber() +{ + return 10; +} +``` + +Wat is hier de uitkomst van: + +```c + +#include "complexer.h" +#include + +int main() +{ + Simple* simple = new Complexer(); + std::cout << simple->guessNumber(); + delete simple; +} +``` + +10. Haal `virtual` weg. 5.

+Definiëer `Complexer` zo: + +```c +Complexer* complexer = new Complexer(); +``` + +En het is altijd 10. + +## Initialisatie + +(Voorbeelden van bovenstaande) + +```c +#include "complexer.h" +#include + +int main() +{ + Simple simpleInitialized; // oops, I created something? + // Simple simpleInitialized = NULL; cannot convert from 'int' to 'Simple' (#define NULL 0) + + Simple* simplePtr; + + std::cout << "
n initialiezd: " << simplePtr->someMember; + // Run-Time Check Failure #3 - The variable 'simplePtr' is being used without being initialized + + delete simplePtr; +} +``` + +Wat is hier speciaal aan? + + 1. In C++ wordt altijd een object aangemaakt als je ze declareert. In Java niet! + 2. In C++ is `NULL` gedefiniëerd als `#define NULL 0` - je kan dus niet zomaar iets toekennen hieraan. In C++ 11 heb je `nullptr` + 3. Je kan wel een pointer declareren zonder een waarde toe te kennen, en dit geeft dan een run-time fout (zou bvb een `NullPointerException` gooien in java) + +## Typecasting + +Uitgebreide uitleg: zie http://www.cplusplus.com/doc/tutorial/typecasting/ + +In C++ is één impliciete conversie mogelijk door middel van de constructor, bijvoorbeeld: + +```c +class Something +{ + public: + Something(int i) : myVar(i) {} + private: + int myVar; +} + +int getal = 10; +Something something = getal; // use constructor +``` + +Om dit tegen te gaan kan je altijd het `explicit` keyword gebruiken, zodat je dit moet doen: + +```c +Something something = Something(getal); // expliciet oproepen constructor +``` + +Je kan `staic_cast(var)` gebruiken om explicit constructors aan te roepen, zo kunnen ze dan toch nog gecast worden. + +## C++ 11 goodies + +Algemeen: [How C++ 11 helps boost your productivity](http://www.informit.com/articles/article.aspx?p=1910142) + + 1. [Lambdas](http://www.codeproject.com/Articles/277612/Using-lambdas-Cplusplus-vs-Csharp-vs-Cplusplus-CX) zijn mogelijk + 2. `nullptr` + 3. `auto` keyword, zoals `var` in C# - dit is typesafe en door de compiler zelf bepaald. + 4. 100% multithreading support, zie hieronder + +# Linking obj/dlls + +Probleemstelling: verschillende **solutions**, code over solutions heen willen gebruiken. + +Dit compileert by default altijd, maar tijdens het linken van de gecompileerde files loopt het mis. Waarom? Omdat er geen `dllexport` voorzien is. +

Op te lossen: + +```c +#ifndef RESOURCE_UTILS_H +#define RESOURCE_UTILS_H + +#include "Utility.h" + +#ifdef _DLL + #define DllExImport __declspec(dllexport) +#else + #define DllExImport __declspec(dllimport) +#endif + + +class DllExImport ResourceUtils +{ +public: + static RAIIObject getIcon(int resourceId); + static RAIIObject getIcon(HINSTANCE resourceHandleInstance, int resourceId); + +private: + ResourceUtils() {} +}; + +#endif +``` + +in de cpp file hoeft niets speciaal meer te staan. + +#### Functies exposen voor native calls + +Zelfde principe om klassen te exposen met `_ _declspec(dllexport)`. Gebruik eventueel std calls (C# heeft dit nodig): `DllExImport MyStruct* _ _stdcall GetSignals();`. + +#### Properties van solutions + +##### Die de te exporteren code bevat + + 1. Configuration type: Dynamic Libraray (DLL) + 2. Incremental linking: Yes (/INCREMENTAL) + 3. Link Linkage Deps: Yes + 4. Output file: *.dll + +##### Die de code bevat die gebruik maakt van de dll + + 1. Linker; Input: Additional dependencies ../OtherSolution.lib + +### Shared libraries linken in Unix + +`declspec` is Win32 specifiek. Lees alles over GCC Visibility in [GNU GCC Wiki on Visibility](http://gcc.gnu.org/wiki/Visibility). Komt op dit neer: + +```c +#if defined(_MSC_VER) + // Microsoft + #define EXPORT __declspec(dllexport) + #define IMPORT __declspec(dllimport) +#elif defined(_GCC) + // GCC + #define EXPORT __attribute__((visibility("default"))) + #define IMPORT +#else + // do nothing and hope for the best? + #define EXPORT + #define IMPORT + #pragma warning Unknown dynamic link import/export semantics. +#endif +``` + +Zie ook [How to write shared Libraries](http://www.akkadia.org/drepper/dsohowto.pdf) by Ulrich Drepper. + +# MFC + +:exclamation: MFC en AFX [is hetzelfde](http://en.wikipedia.org/wiki/Microsoft_Foundation_Class_Library): + +> One interesting quirk of MFC is the use of "Afx" as the prefix for many functions, macros and the standard precompiled header name "stdafx.h". During early development what became MFC was called "Application Framework Extensions" and abbreviated "Afx". The name Microsoft Foundation Classes (MFC) was adopted too late in the release cycle to change these references + +### Strings in MFC + +Gebruik `CString` - werkt niet op non-win32 omgevingen. + +##### Formatting + +Formatten kan bijvoorbeeld met `string.Format(_T("%s in %d"), otherString, otherDecimal);` + +:exclamation: Om een string te intialiseren en toe te kennen moet je wel de `_T` macro gebruiken + +##### Substringen + +`Find` is hetzelfde als `indexOf` in andere talen. + +```c++ +CString HostServiceProxy::GetCouponFromResponseString(CString response) +{ + CString couponKey ###### _T("Coupon"); + CString couponPart = response.Mid(response.Find(couponKey) + couponKey.GetLength()); + + return couponPart.Left(couponPart.Find(_T(";"))); +} +``` + +### Resource handling + +Icons en images worden opgeslagen in .rc files die als resources in de code gekoppeld kunnen worden aan bijvoorbeeld een `CButton`. Hoe? + +```c + HANDLE hImage = ::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(resourceId), IMAGE_ICON, 16, 15, LR_DEFAULTCOLOR); + if(hImage ###### NULL) + ASSERT(FALSE); + + HICON image = static_cast(hImage); +``` + +`HICON` is van `WinDef.h` en `::LoadImage` zit op `WinUser.h`. Zie [MSDN doc](http://msdn.microsoft.com/en-us/library/windows/desktop/ms648045(v=vs.85).aspx) voor LoadImage. + +#### De juiste resource handle vastkrijgen #### + +Als je een MFC DLL maakt, gaat `AfxGetResourceHandle()` verwijzen naar de resource handle van uw DLL zelf. Als je dus resources wil vastpakken van een andere DLL heb je pech. Als je geen MFC DLL maakt kan je dit aanpassen met ` AFX_MANAGE_STATE(AfxGetStaticModuleState( ))`. **Dit gooit echter linking errors** ( error LNK2005: _DllMain@12 already defined) indien je dit vanuit een MFC DLL aanroept - dan is dit niet nodig. + +Meer uitleg hierover: zie http://support.microsoft.com/kb/161589 + +:exclamation: de Afx resource handle kan **altijd** gewijzigd worden door leuke dingen te doen als: + +```c + HINSTANCE old = AfxGetResourceHandle(); + AfxSetResourceHandle(GetModuleHandle("andereModule")); +``` + +Gebruik daarom best `::GetModuleHandle(char*)` bij `::LoadImage`. + +#### Resources op het juiste moment terug vrijgeven #### + +Resources worden meestal gewrapped in kleine objectjes die bij de constructor de resource alloceren en bij de destructor deze terug vrijgeven in plaats van in `try { ... }` zoiets te moeten doen in Java. Dit pattern is [RAII](http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) of "Resource Acquisition Is Initialization". Voorbeeld: + +```c +template +class RAIIObject +{ +public: + explicit RAIIObject(const TObject& obj) : m_Object(obj) {} + RAIIObject() {} + ~RAIIObject() {ReleaseObject();} + RAIIObject& operator######(const TObject& obj) {if(&obj ! &m_Object) {ReleaseObject(); m_Object = obj;} return *this;} + RAIIObject& operator######(const RAIIObject& obj) {if(&obj ! this) {ReleaseObject(); m_Object = obj;} return *this;} + TObject& GetObject() {return m_Object;} + const TObject& GetObject() const {return m_Object;} + operator TObject&() {return m_Object;} + operator const TObject&() const {return m_Object;} +private: + void ReleaseObject(); + TObject m_Object; +}; + +template<> inline void RAIIObject::ReleaseObject() {::DestroyIcon(m_Object); m_Object = NULL;} +template<> inline void RAIIObject::ReleaseObject() {m_Object.DeleteObject();} +template<> inline void RAIIObject::ReleaseObject() {m_Object.DeleteObject();} +template<> inline void RAIIObject::ReleaseObject() {m_Object.DeleteObject();} +template<> inline void RAIIObject::ReleaseObject() {m_Object.DestroyMenu();} +``` + +# Preprocessing + +## Handige macro's + +##### Exception/Debug informatie expanden + +```c++ +#define _ERROR_STR2(a) #a +#define _ERROR_STR(a) _ERROR_STR2(a) +#define ERROR_INFO(fn) _T(_ERROR_STR(__FILE__" line: "__LINE__" function: "fn)) +``` + +Te gebruiken als `someFn(ERROR_INFO("bla"))`. Merk op dat `__FUNCTION__` of `__FUNC__` ook gebruikt kan worden, afhankelijk van de C++ compiler, maar dit is geen deel van de standaard (vanaf C++ v11). + +De `#a` notatie wordt gebruikt om iets te [stringifyen](http://gcc.gnu.org/onlinedocs/cpp/Stringification.html) in de preprocessor, vandaar de delegate: + +> Sometimes you may want to convert a macro argument into a string constant. Parameters are not replaced inside string constants, but you can use the ‘#’ preprocessing operator instead. When a macro parameter is used with a leading ‘#’, the preprocessor replaces it with the literal text of the actual argument, converted to a string constant. Unlike normal parameter replacement, the argument is not macro-expanded first. This is called stringification. + +# Threading + +Handige links: + + 1. [Thread synchronization for beginners](http://www.codeproject.com/Articles/7953/Thread-Synchronization-for-Beginners) + +## Thread-safe Singleton pattern + +Bijna onmogelijk in C++ < v11 blijkbaar? + +Onderstaand voorbeeld gebruikt Win32 code (`WaitForSingleObject`) en een mutex om te wachten: + +```c++ +#pragma once +#include + +class AddinProcessService +{ + static AddinProcessService *singletonInstance; + AddinProcessService() : m_coupon(_T("")), m_hostServiceAddress(_T("")) {} + + public: + + inline const CString& GetHostServiceAddress() const + { + return m_hostServiceAddress; + } + inline const CString& GetCoupon() const + { + return m_coupon; + } + inline void SetCoupon(CString coupon) + { + m_coupon = coupon; + } + inline void SetHostServiceAddress(CString address) + { + m_hostServiceAddress = address; + } + + static AddinProcessService* getSingletonInstance() + { + static volatile int initialized = 0; + static HANDLE mtx; + + if (!initialized) + { + if (!mtx) + { + HANDLE mymtx; + mymtx = CreateMutex(NULL, 0, NULL); + if (InterlockedCompareExchangePointer(&mtx, mymtx, NULL) != NULL) + CloseHandle(mymtx); + } + + WaitForSingleObject(mtx, 0); + if (!initialized) + { + libInitInternal(); + initialized = 1; + } + ReleaseMutex(mtx); + } + return singletonInstance; + }; + +private: + CString m_hostServiceAddress; + CString m_coupon; + + static void libInitInternal() + { + singletonInstance = new AddinProcessService(); + } +}; + +``` + +:exclamation: Vergeet niet in de cpp file uw singletonInstance pointer te declareren, anders krijg je linker errors: `AddinProcessService* AddinProcessService::singletonInstance;` + +In UNIX kan men [pthreads](https://computing.llnl.gov/tutorials/pthreads/) gebruiken, ongeveer op deze manier: + +```c++ +static Foo &getInst() +{ + static Foo *inst = NULL; + if(inst ###### NULL) + { + pthread_mutex_lock(&mutex); + if(inst ###### NULL) + inst = new Foo(...); + pthread_mutex_unlock(&mutex); + } + return *inst; +} +``` + +Dan kan je `#ifdef WIN32` gebruiken om te switchen tussen beide implementaties. + +#### C++ 11 multithreading + +Vanaf C++ 11 zijn multithreads 100% native supported, dit wil zeggen dat manueel locken met een `mutex` overbodig wordt. Bovenstaande singleton kan gereduceerd worden tot (merk het **static** keyword op, dat is het belangrijkste voor de autolock): + +```c++ +static Singleton& get(){ + static Singleton instance; + return instance; +} +``` + +Voor meer info, zie http://stackoverflow.com/questions/11711920/how-to-implement-multithread-safe-singleton-in-c11-without-using-mutex + +# Win32 API specifics + +#### Get Loaded DLL info from given process + +huidig proces: `GetCurrentProcessId()` - dit is een `HANDLE`. + +```c++ +CString ExceptionHandler::GetLoadedDllInfo() const +{ + CString dlls = _T(""); + HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId()); + if(process ###### NULL) + { + return dlls; + } + + HMODULE hMods[1024]; + DWORD cbNeeded; + BOOL modules = EnumProcessModules(process, hMods, sizeof(hMods), &cbNeeded); + if(!modules) + { + return dlls; + } + + for (int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) + { + TCHAR szModName[MAX_PATH]; + + if (GetModuleFileNameEx(process, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR))) + { + dlls.Format(_T("%s, %s"), dlls, szModName); + } + } + + CloseHandle(process); + return dlls; +} +``` + +Hiervoor moet je `#include ` includen én de psapi.lib file mee linken! Zie [EnumProcessModules MSDN](http://msdn.microsoft.com/en-us/library/windows/desktop/ms682631(v=vs.85).aspx). + +# C++ Native calls uitvoeren + +#### Voorbeeld project + +Wat is het probleem: + + 1. Ik wil Native C++ methods kunnen aanroepen vanuit C#. Dit kan met de `DllImport` attribute. + 2. Ik wil structs kunnen remarshallen die uit de native code komen. Dit kan met `StructLayout` en `PtrToStructrue`. + 3. Ik wil een char* mappen op een C# string: gebruik `[MarshalAsAttribute(UnmanagedType.LPStr)]` in uw C# struct. + 4. Ik wil parameters mee kunnen geven: gebruik de juiste calling method (STD of DECL) instelling, zie `CallingConvention` op `UnmanagedFunctionPointer`. + +```c++ +#pragma once + +#ifdef _DLL +#define DllExImport __declspec(dllexport) +#else +#define DllExImport __declspec(dllimport) +#endif + +struct MyStruct +{ + char* id; + char* description; +}; + +DllExImport MyStruct* __stdcall GetSignals(); +``` + +```c++ +#include "stdafx.h" +#include "TestClass.h" + +DllExImport MyStruct* __stdcall GetSignals() +{ + static MyStruct a[] = + { + { "id1", "desc1" }, + { "id2", "desc2" }, + { "id3", "desc3" } + }; + return a; +} +``` + +```csharp +namespace structArrayImportTest +{ + #region + + using System; + using System.Runtime.InteropServices; + + #endregion + + internal class StructImporter + { + // Charset.Ansi is not needed it seems + [DllImport("kernel32.dll", EntryPoint = "LoadLibrary")] + private static extern IntPtr LoadLibrary( + [MarshalAs(UnmanagedType.LPStr)] string lpLibFileName); + + [DllImport("kernel32.dll", EntryPoint = "GetProcAddress")] + private static extern IntPtr GetProcAddress(IntPtr hModule, + [MarshalAs(UnmanagedType.LPStr)] string lpProcName); + + [DllImport("kernel32", SetLastError ###### true, EntryPoint "GetProcAddress")] + private static extern IntPtr GetProcAddressOrdinal(IntPtr hModule, IntPtr procName); + + [DllImport("kernel32.dll", EntryPoint = "FreeLibrary")] + private static extern bool FreeLibrary(int hModule); + + [StructLayout(LayoutKind.Sequential)] + public class MyStruct + { + [MarshalAsAttribute(UnmanagedType.LPStr)] + public string _id; + [MarshalAsAttribute(UnmanagedType.LPStr)] + public string _description; + } + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + public delegate IntPtr fGetSignals(); + + public fGetSignals GetSignals; + + public void Import() + { + IntPtr lib = LoadLibrary(@"C:
Users
bkwog
Documents
Visual Studio 2012
Projects
structArrayExportTest
Debug
structArrayExportTest.dll"); + // gebruik dumpbin /exports [bla.dll] om ordinal & name van exported functions te bepalen. + IntPtr signalsHandle = GetProcAddressOrdinal(lib, new IntPtr(1)); + GetSignals = (fGetSignals) Marshal.GetDelegateForFunctionPointer(signalsHandle, typeof (fGetSignals)); + IntPtr myStructs = GetSignals(); + + int structSize = Marshal.SizeOf(typeof(MyStruct)); + Console.WriteLine(structSize); + + for (int i = 0; i < 3; ++i) + { + // What's the difference between toInt32 & 64 here? Both work... + IntPtr data = new IntPtr(myStructs.ToInt64() + structSize * i); + MyStruct ms = (MyStruct)Marshal.PtrToStructure(data, typeof(MyStruct)); + + Console.WriteLine("id: " + ms._id + " - descr: " + ms._description ); + } + } + + } +} +``` + +#### Calling convention + +In te stellen via C++ project settings -> advanced -> calling convention, voor alles, of per functie met `__stdcall`. C# werkt hiet default mee. Aanpasbaar in het attribute, zie boven. + +Als de calling convention niet overeen zou komen, krijg je bij het uitvoeren in de C# code de volgende fout: + +> call to PInvoke function 'structArrayImportTest!structArrayImportTest.StructImporter+fGetSignals::Invoke' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature. + +#### dumpbin + +Als je niet met ordinals wenst te werken maar de volledige naam van de functie kan jet met `dumpbin.exe` dit achterhalen: + +``` +C:
Program Files (x86)
Microsoft Visual Studio 10.0
Common7
IDE>dumpbin /exports TfsAdmin.exe structArrayExportTest.dll +Microsoft (R) COFF/PE Dumper Version 10.00.40219.01 +Copyright (C) Microsoft Corporation. All rights reserved. + + +Dump of file TfsAdmin.exe + +File Type: EXECUTABLE IMAGE + +Dump of file structArrayExportTest.dll + +File Type: DLL + + Section contains the following exports for structArrayExportTest.dll + + 00000000 characteristics + 52A888CA time date stamp Wed Dec 11 16:46:18 2013 + 0.00 version + 1 ordinal base + 2 number of functions + 2 number of names + + ordinal hint RVA name + + 1 0 00011113 ?GetSignals@@YAPAUTestStruct@@XZ + 2 1 000110E6 ?GetSize@@YAPAHXZ + + Summary + + 1000 .data + 1000 .idata + 3000 .rdata + 3000 .reloc + 11000 .rsrc + 8000 .text + 10000 .textbss +``` + +Merk op dat de functie `GetSignals` hier niet die naam heeft, maar `?GetSignals@@YAPAUTestStruct@@XZ`! \ No newline at end of file diff --git a/content/post/cplusplus-testing.md b/content/post/cplusplus-testing.md new file mode 100644 index 00000000..98f46c9c --- /dev/null +++ b/content/post/cplusplus-testing.md @@ -0,0 +1,105 @@ ++++ +title = "C++ Basics: unit testing" +subtitle = "C++ Basics: Unit Testing with GTest" +archived = true +draft = false +tags = [ + "c++", + "Unit Testing", + "gtest" +] +date = "2013-10-01" ++++ + +## Using Google Test + +Downloaden op https://code.google.com/p/googletest/downloads/list + +**Waarom**? + + 1. Platform onafhankelijk + 2. Snelheid + 3. Geen gezeik met Managed C++, compatibel met "eender wat" (enige vereiste: `cc` compiler variant) + 4. Wordt veel gebruikt (Chromium, Stack overflow) + +**Waarom niet**? + + 1. slechte of geen integratie met VStudio (zie onder) + 2. wéér een andere syntax dan MS .NET testen + 3. beetje awkward assertions + +#### Assertions schrijven + +```c +#include "../BaseCode/BaseCode.h" + +#include "gtest/gtest.h" + +TEST(MyTestCase, MyTest_Success) +{ + EXPECT_EQ(2, MySum(1, 1)); +} + +TEST(MyTestCase, MyTest_Failure) +{ + EXPECT_EQ(3, MySum(1, 2)); +} +``` + +Waarbij dan `BaseCode` uw system under test zaken bevat (waar `MySum` defined is) + +#### Builden met scons en g++ + +Tested in Cygwin Win7 & OSX 10.9 + +```python +Import('env') +env ###### env.Clone(CPPPATH './:./include') + +env.Append(CXXFLAGS = ['-g', '-Wall', '-Wextra', '-pthread']) +gtest ###### env.Library(target 'gtest', source = ['src/gtest-all.cc', 'src/gtest_main.cc']) + +Return('gtest') +``` + +Zie [Builden met SCons]({{< relref "post/scons-building" >}}) + +#### Builden met Visual Studio + + + +Zie http://leefrancis.org/2010/11/17/google-test-gtest-setup-with-microsoft-visual-studio-2008-c/ + +Er zijn 2 `.sln` files voorzien in de msvc subdir bij de zipfile, één voor statische links en één voor dynamische. Afhankelijk van uw project (.DLL of .LIB gegenereerde uitkomst), ga je één van beiden moeten compileren. Als je van plan bent om `/MDd` te gebruiken (dll + debugging), gebruik dan `gtest-md.sln`. + +Daarna kan je een nieuwe solution maken, package naar executable om de test zelf te runnen (om gtest testen te draaien). Verander deze dingen in het project: + + 1. General > Configuration type = Application (.EXE) + 2. C/C++ > General > Additional Include dirs naar gtest/include verwijzen + 3. C/C++ > Preprocessor > definitions toevoegen `_VARIADIC_MAX=10` + 4. Code generation > Runtime library op `/MDd` of `/MTd` juist zetten (zie boven) + 5. Linker > Additional Library directories > gtest/Debug (staan reeds binaries indien compiled) + 6. Linker > Input > Additional dependencies = gtestd.lib;gtest_maind.lib;(rest) + 7. Linker > System > SubSystem Console `/SYBSYSTEM:CONSOLE` + 8. Linker > Input > Module Definition file leeg (indien van DLL naar EXE veranderd kan hier wat brol in zitten) + +#### Visual Studio 2012 en STD problemen + +Fouten als + +``` +1>a:
gtest
include
gtest
gtest-printers.h(550): error C2977: 'std::tuple' : too many template arguments +1> b:
program files (x86)
microsoft visual studio 2012
vc
include
utility(73) : see declaration of 'std::tuple' +``` + +Op te lossen met een preprocessor macro _VARIADIC_MAX=10, zie http://stackoverflow.com/questions/12558327/google-test-in-visual-studio-2012 + +##### Integratie met Visual Studio 2008/2010 + +[GoogleTestAddin](http://googletestaddin.codeplex.com/documentation) (kopieer 2 files naar C:\Users\bkwog\Documents\Visual Studio 2008\Addins, map misschien nog aanmaken) + +Niet super nuttig, een knopje om testen snel te herdraaien (of één die geselecteerd is), beter dan post-build actie zie boven... + +#### Integratie met Visual Studio 2012 + +[Google Test Adapter](http://visualstudiogallery.msdn.microsoft.com/f00c0f72-ac71-4c80-bf8b-6fe381548031) plugin (1.1 - geen actieve development?) \ No newline at end of file diff --git a/content/post/dynamic-languages.md b/content/post/dynamic-languages.md new file mode 100644 index 00000000..e7df5739 --- /dev/null +++ b/content/post/dynamic-languages.md @@ -0,0 +1,374 @@ ++++ +title = "A look at dynamic languages" +subtitle = "A comparison on some dynamic languages" +archived = true +draft = false +tags = [ + "javascript", + "ruby", + "dynamiclangs" +] +date = "2013-10-01" ++++ +## Dynamic Languages: Constructs vergelijken + +Deze pagina vergelijkt verschillende dynamische talen in een poging om een overzicht te maken tussen de alsmaar groeiende lijst. De meest gebruikte features van zulke talen worden hieronder opgelijst. + +### Het verschil tussen MOPs en Prototypal inheritance + +:exclamation: Javascript heeft géén **Meta Object Protocol** (MOP) dat de taal dynamisch maakt, maar bouwt verder op prototypes. Dat wil zeggen dat het klassieke inheritance systeem niet bestaat in Javascript, maar wel nagebootst kan worden door objecten te laten afleiden van objecten. De vergelijkingstabellen hieronder tonen hoe Javascript zich kan *gedragen* als een klassieke OO taal, dat wil niet automatisch zeggen dat dit de beste manier is om JS te gebruiken! + +De volgende dynamische talen beschikken wel over een MOP: + + 1. Groovy + 2. Python + 3. Ruby + 4. Smalltalk dialecten + 5. LISP dialecten (bvb. Runtime MOPs via `CLOS`) + 6. Perl 6 + 7. OpenC++ (bvb. Compiletime MOPs door C++ te parsen en analyseren) + +[Ruby VS Javascript metaprogramming](http://fingernailsinoatmeal.com/post/292301859/metaprogramming-ruby-vs-javascript): + +> The most interesting thing about the Javascript example is that it is exactly the same as the example of adding a dynamic method to a class. There is no difference because Javascript functions **are** closures. The ubiquity of closures in Javascript is extremely powerful and, makes metaprogramming very easy. + + +# Vergelijkingstabellen + +## Dynamica van de taal: Metaprogramming + +### Methods toevoegen + +#### Op klasse niveau + + +**JavaScript** +```javascript +String.prototype.isTrue = function() { return this == "true"; } +``` + +**Groovy** +```java +String.metaClass.isTrue = { delegate == "true"} +``` + +Javascript bevat enkele *common pitfalls* hierrond, zie JS Inheritance. + +Groovy staat ook toe om *constructors* toe te voegen op deze manier.

+Methods "lenen" gaat ook met de **&.** operator in Groovy om de pointer naar een method vast te krijgen. In JS gewoon de "key" (methodnaam) als referentie gebruiken. + +#### Op instance niveau #### + +**JavaScript** +```javascript +"someString".isTrue = function() { + return this == "true"; +} +``` +**Groovy** +```java +"someString".metaClass.isTrue = { + delegate == "true" +} +``` + +Voor beide talen op exact dezelfde manier dus, op een *instance* zelf.((Groovy 1.6+ heeft dit standaard, anders uw metaClass nog correct aanpassen! Zie http://groovy.codehaus.org/Per-Instance+MetaClass )) + +Als Groovy problemen geeft, kan het zijn doordat `ExpandoMetaClass` niet geconfigureerd staat voor *inheritance*: + +```java +ExpandoMetaClass.enableGlobally() +``` + +#### Methods catchen #### + +Met "catchen" wordt "*decoreren*" bedoeld. van alle calls op van method namen die niet bestaan en doe ermee wat je wilt. + +**JavaScript** + +**niet** mogelijk + +**Groovy** +```java +SomeClass.metaClass.methodMissing = { name, arguments -> + switch(name) { + case "bla": return "blaing eh" + break; + } +} +assert "blaing eh" == new SomeClass().bla() +``` + +Groovy kan ook **alle methods** opvangen, ook de bestaande, door de MOP hook `invokeMethod`, `get/setProperty`, `propertyMissing` etc te overriden - op `Object` of `metaClass` niveau, op deze manier: + +```java +class SomeClass { + def invokeMethod(String name, args) { + switch(name) { + case "bla": return "blaing eh" + break; + default: + // delegate.invokeMethod name, arguments makes an infinite loop! it's a tarp! + delegate.metaClass.getMetaMethod(name, arguments).invoke(delegate, arguments) + } + } +} +``` + +En ja, dat werkt [Ook met static methods in Groovy](http://groovy.codehaus.org/ExpandoMetaClass+-+Overriding+static+invokeMethod)! + +!! Rhino en SpiderMonkey implementaties van JavaScript (Firefox JS parser bijvoorbeeld) ondersteunen wel een magic missing method, genaamd `__noSuchMethod__` en een hele hoop andere nifty dingen zoals `__defineGetter__` en `__lookupSetter__`. Meer informatie in [deze blogpost](http://offthelip.org/?p=101) te vinden. Voorbeeld in Firefox+Firebug: + +```javascript +SomeClass.prototype.__noSuchMethod__ = function(name, arguments) { + console.log("calling method " + name + " with arguments " + arguments); + if(name === "bla") { + return "blaing eh"; + } +} +"blaing eh" == new SomeClass().bla() // true +``` + +Merk op dat in Groovy zoiets niet bestaat, we overriden **ender welke methodCall**, daarom dat in de `default` van het `switch` statement nog altijd een delegate invoke moet gebeuren! + +#### Properties toevoegen #### + +**JavaScript** +```javascript +var gapingHoleInTheGalaxy = function() {} +gapingHoleInTheGalaxy.theSun = "extraHot"; // method 1 +gapingHoleInTheGalaxy['theSun'] = "extraHot"; // method 2 +gapingHoleInTheGalaxy.explode = function() { + console.log("Explosion!") +} +``` + +**Groovy** +```java +def gapingHoleInTheGalaxy = new Expando() +gapingHoleInTheGalaxy.theSun = "extraHot" // method 1 +gapingHoleInTheGalaxy['theSun'] = "extraHot" // method 2 +gapingHoleInTheGalaxy.explode = { + println "Explosion!" +} +``` + +!! Groovy heeft een speciale klasse `Expando` die dynamisch toelaat om eender wat toe te voegen, zowel *closures* als *properties* op dezelfde manier. Enige nadeel: deze code kan niet gemengd worden met Java als byte code. Bij gewone klassen kan dit niet en moet dit via de `metaClass` gaan. Bij Javascript werkt dit omdat op eender welk moment het prototype van een object veranderd kan worden en er geen onderscheid is tussen closures en functions. + +Merk op dat hier de quotes nodig zijn om via de `[]` operator closures aan iets te hangen. + +Het is wél mogelijk om properties via `metaClass` toe te voegen door de methodnaam de javaBean specificatie te laten volgen, bvb `metaClass.getBrol = {}` zodat men `def x inst.brol` kan uitvoeren. + +#### Itereren over methods #### + +**JavaScript** +```javascript +for(propertyName in someInstance) { + var propertyValue = someInstance[propertyName] + if(typeof propertyValue ###### "function") { + var retVal = eval("someInstance." + propertyName + "(args)"); // method 1 + retVal = propertyValue(args) // method 2 + } else { + console.log(propertyName + " property with value " + propertyValue); + } +} +``` + +**Groovy** +```java +String.metaClass.methods.each { + def methodName = it.name // now what? methods are on class level + def retVal = someInstanceOfString."${methodName}" +} +someInstanceOfString.properties.each { + println "${it.key} property with value ${it.value}" +} +``` + +### Variable arguments ### + +#### varargs core #### + +**JavaScript** +```javascript +function bla() { + for(arg in arguments) { console.log(arg); } +} +bla(1, 2, 3); +``` + +**Groovy** +```javadef bla(Object[] args) { // method 1 +def bla(Object... args) { // classic Java 1.5 method 2 + args.each{ println it } +} +bla(1, 2, 3); +} +``` + +Een map meegeven gaat altijd natuurlijk, om argumenten expressiever te maken, zoals configuratie: (Groovy vb.) + +```java +def bla(Map args) { + println args.stuff +} +bla(stuff: "wow", c: 3) +``` + +#### Argument spreading #### + +**JavaScript** +```javascript +function bla(a, b) { + return a + b + 2; +} +var args = [1, 2]; +bla(1, 2) == bla.apply(this, args) // 5 +``` + +**Groovy** +```java +def bla(a, b) { + a + b + 2 +} +def args = [1, 2] +bla(1, 2) == bla(*args) +``` + +#### Fixed arguments #### + +**JavaScript** +```javascript +function bla(a, b, c) { + if(!c) var c = 0; + console.log("a: " + a + ", b: " + b + ", c: " + c); +} +bla(1, 2) // 1, 2, 0 +bla(1, 2, 3); // 1, 2, 3 +``` + +**Groovy** +```java +def bla(a, b, c = 0) { + println "a: $a, b: $b, c: $c" +} +def blaWow = bla.curry(1) +blaWow(2) // 5, 2, 0 +bla(1, 2) // 1, 2, 0 +bla(1, 2, 3) // 1, 2, 3 +``` + +Merk op dat bij JS er gecontroleerd moet worden of een variabele daadwerkelijk is ingevuld of niet. `curry` is niet standaard aanwezig maar kan eenvoudig geïmplementeerd worden, zoals deze snippet van het *Prototype* framework: + +```javascript + function curry() { + if (!arguments.length) return this; + var __method ###### this, args slice.call(arguments, 0); + return function() { + var a = merge(args, arguments); + return __method.apply(this, a); + } + } +``` + +Dit roept in essentie de eigenlijke method op (met `apply`) met een aantal parameters predefined. + +#### String interpolatie #### + +**JavaScript** +**niet** mogelijk + +**Groovy** +```java +def dinges = "mijn dingetje" +"$dinges is a dong" == "mijn dingetje is a dong" +``` + +JS extentie om dit mogelijk te maken: zie [Prototype JS interpolate](http://www.prototypejs.org/api/string/interpolate), bvb:

+`"#{dinges} is a dong".interpolate({dinges: "mijn dingetje"}) ###### "mijn dingetje is a dong"`

+Merk op dat dit eenvoudig een regex door de string laat lopen. + +Merk op dat bij Groovy dit zeer krachtig is en hele expressies in strings kunnen gegoten worden zoals `"bla ${this.method} jong"`. Ook methods aanroepen zoals this."${methodName}" werkt. + +#### Template parsing #### + +Grotere brokken tekst interpoleren werkt via *templates*. In Prototype JS is er een `Template` klasse [aanwezig](http:*www.prototypejs.org/api/template), in Groovy zit een uitgebreide en uitbreidbare [template engine](http:*groovy.codehaus.org/Groovy+Templates): + +**JavaScript** +```javascript +var myTemplate = new Template('The TV show #{title} was created by #{author}.'); +var show = {title: 'The Simpsons', author: 'Matt Groening', network: 'FOX' }; +myTemplate.evaluate(show); +``` +**Groovy** +```java +def string = "The TV Show ${title} was created by ${author}." +def myTemplate = new groovy.text.SimpleTemplateEngine().createTemplate(string) +def show = [ title: "The Simpsons", author: "Matt Groening", network: "FOX" ] +myTemplate.make(show).toString() +``` + + +#### Evaluatie van expressies #### + +**JavaScript** +```javascript +var y = 20; +var X = function() { + this.y = 10; + this.boem = function() { + console.log(eval("10 * this.y")); // 100, without "this" = 200 (window scope) + } +} +new X().boem() +``` + +**Groovy** +```java +class X { + def y = 20 + def boem = { + def y = 10 + println Eval.x(y, "10 * y") // 100 + } +} +new X().boem() +``` + +Groovy voorziet gemakkelijkheidshalve een paar methods op `Eval` zoals `Eval.me` (zonder params), x/xy/xyz. Wanneer iets uitgebreidere evaluatie nodig is gebruiken we `GroovyShell`: + +```java +def binding = new Binding(x: 10, y: 100) +def shell = new GroovyShell(binding) +def retVal = shell.evaluate(''' + def local = "uncatchable" + catchable = x * y + 10 +''') +assert retVal ###### 10 +assert binding.catchable ###### 100 // method 1 +assert binding.getVariable("catchable") ###### 100 // method 2 +``` + +Alles wat geëvalueerd wordt zit binnen een `Script` klasse, daarom dat het `def` keyword niet nodig is, en enkel dient om lokale variabele te instantiëren. Merk op dat het zelfs zo mogelijk is om nieuwe klassen in te laden, of om Groovy code te evalueren met `GroovyShell` binnen Java klassen! + +#### Scope chain aanpassen #### + +Dit is voor beide talen niet 100% hetzelfde: Groovy maakt het mogelijk om objecten te extenden on-the-fly met `use`, terwijl Javascript de lexicale scope chain kan aanpassen met `with`. + +**JavaScript** +```javascript +with(window.screen) { + console.log(width); +} +``` + +**Groovy** +``` +javadir = new File("/tmp") +use(ClassWithEachDirMethod.class) { + dir.eachDir { + println it + } +} +``` diff --git a/content/post/introduction-to-js.md b/content/post/introduction-to-js.md new file mode 100644 index 00000000..e6867b0e --- /dev/null +++ b/content/post/introduction-to-js.md @@ -0,0 +1,1779 @@ ++++ +title = "Introduction to JavaScript" +subtitle = "Writing JS, Pre-ES5 era." +archived = true +draft = false +tags = [ + "javascript" +] +date = "2013-10-01" ++++ +# Javascript Inleiding + +### Primitives + +#### Soorten + +In javascript zijn er slechts 3 primitives: + + 1. `string` (geassocieerd object: `String`) + 2. `boolean` (geassocieerd object: `Boolean`) + 3. `number` (geassocieerd object: `Number`) + +Primitives zijn **immutable**! Toekennen van properties maakt ook een tijdelijk object aan, dus dit heeft geen nut. + +##### Soort afchecken + +Aangezien JS loosely typed is, kunnen we nooit weten wat er nu in `var variabele;` steekt op een bepaald moment in de code.

+Om dit op te lossen kan men `typeof` gebruiken, een functie die een string teruggeeft wat het type van die variabele is. + +Typeof retourneert in het geval van een object, de string `object`, in alle andere gevallen de bovenstaande primitive namen. + +#### Object coercing + +-> *(Lees eerst het stuk over objecten etc aub!)* + +Elk van de primitives worden door Javascript automatisch geconverteerd naar hun object representatie wanneer men properties of functies hierop probeert toe te passen. Bvb: + +```javascript +var someString = "someString"; + +someString.indexOf("String"); // indexOf() wordt op new String("someString") opgeroepen +``` + +Direct nadat dit geëvalueerd wordt schiet de garbage collector aan de gang en wordt het tijdelijk object verwijderd. + +```javascript +var tekst = "dit is tekst jong"; +tekst.length = 3; // -> String object created & garbage-collected +console.log(tekst); // dit is tekst jong (old primitive value) +``` + +Het object dat wordt aangemaakt bijhouden en daar de lengte van afkappen is zelfs gevaarlijk: + +```javascript +var s = new String("ss"); +s.length = 1; + +for(var i = 0; i < s.length; i++) { + console.log(s[i]); // prints only once 's' +} +console.log(s); // prints 'ss'?? +``` + +Als we weten dat een object aangemaakt wordt zodra we een property oproepen, vraagt een mens zich af, hoe zit dat met `number`s? De `.` accessor wordt hier gebruikt om komma's voor te stellen... Wel, aangezien elk object ook values van properties kan retourneren via de `[]` operator (zie later), werkt dit dus wel: + +```javascript +21.54["toFixed"]() // returns 22, way cool! +``` + +Zie [Mozilla MDC Docs: JS Reference: Number](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Number) voor wat mogelijke functies zijn op `Number`. + +### Objecten en Functies + +Douglas Crockford: + +> An object is a dynamic collection of properties. + +As opposed to "*instances of classes*". + +Een *functie* in JS kan net zoals andere waarden toegekend worden aan een variabele. Een functie ís in feite een waarde. Dit is anders in bijvoorbeeld Java, een "functie" (method) is een syntax block code die uitgevoerd kan worden. Wanneer een functie aan een property van een object gekoppeld is spreken we van een method op dat object. + +Een object bevat properties. Een functie is een rij van expressies die één waarde retourneert voor dezelfde input te evalueren. Bekijk een "functie" als zijn mathematische beschrijving: `f(x)`. + +#### Object Literals + +Een object definiëren gaat heel makkelijk: + +```javascript +var Ezel = new Object(); +Ezel.poten = 4; +Ezel.balk = function() { + console.log("iaia met mijn " + this.poten + " poten"); +}; +``` + +Zodra een `Object` gemaakt wordt, kunnen eender welke property keys toegekend worden met eender welke variabele. Dit kan ook op een *associatieve* manier, bijvoorbeeld `Ezel["poten"] = 4;`. + +Bekijk het volgend stukje code: + +```javascript +var Ezel = { + poten: 4, + balk: function() { + console.log("iaia met mijn " + this.poten + " poten"); + } +}; +``` + +Hier wordt een object door middel van een **literal** gedefiniëerd. De correcte manier om de ezel te laten balken is `Ezel.balk()`. Merk op dat `Ezel` een gewoon object met wat simpele properties is, bekijk het als een map. Dit is een instantie van `Object`: `typeof Ezel` retourneert dit. + +##### JSON en Object Literals + +[JSON](http://www.json.org/js.html) ((JavaScript Object Notation)) is een subset van JavaScript, dus door de JS Compiler op te roepen met `eval()` is het heel eenvoudig om JSON Strings te evalueren. Een JSON Object is in feite een JS Object Literal: + +```javascript +var JSONObj = { + "bindings": [ + { "key": "value1", "key2": "value2" }, + { "key": "value3", "key2": "value4" } + ] +} +``` + +Dat object kan via een string opgebouwd worden door `eval()` te gebruiken, maar dit is **gevaarlijk** aangezien van een externe webserver ook JS functies in dat data object kunnen zitten! Gebruik daarvoor altijd een JSON Parser, zoals de built-in `JSON.parse()`. + +Om de omgekeerde weg uit te gaan, van object naar string, gebruik `JSON.stringify()`. Meer uitleg, zie bovenstaande link. + +#### Functie Literals + +Een functie definiëren gaat op drie manieren: + + 1. `function bla() { ... }` - de normale manier, een **function statement**. + 2. `var bla = function() { ...}` - een **function literal**, ofwel een *lambda function* (Lisp referentie). In feite een closure die toevallig toegekend wordt aan variabele `bla`. + 3. `var bla = new Function("", "...")` met als eerste argument de argumenten van de functie, allemaal in `string` vorm. + +De onderstaande code definiëert bijvoorbeeld in lambda-stijl een functie genaamd Ezel: + +```javascript +var Ezel = function() { + this.poten = 4; + this.balk = function() { + console.log("iaia met mijn " + this.poten + " poten"); + } +}; +``` + +Merk de verschillen op met het bovenstaande: + + * `function()` staat voor `{`. + * `this` wordt gebruikt om keys aan te spreken! Waarom? zie scoping. + * De functie bevat gewone statements met `=` en niet met `:`. Dit is geen object maar een functie! + +!! De functie die net aangemaakt is kan nu als constructor dienen. Die werd intern ook aan de Ezel `prototype` property gekoppeld: + +```javascript +Ezel.prototype.constructor +``` + +De correcte manier om de ezel te laten balken is `new Ezel().balk()`.

+Meer info over hoe `new` werkt om de ezel instance de poten en de balk functie toe te kennen: zie inheritance. + +##### Functies zijn objecten + +> Functions are first class Objects! + +Bewijs: (Uitleg: zie inheritance) + +```javascript +Function.prototype.__proto__ == Object.prototype; +(function fn(){}).__proto__ == Function.prototype; +``` + +Dus functies zijn *ook* associatieve maps, dus `(function(){}).bla = 3;` werkt perfect! Zie scoping, deel "Object/Class Member variables". + +##### De kracht van closures + +In Javascript is élke functie een *closure*! In sommige andere talen kan enkel een closure "deep bindings" uitvoeren (= scope chain bijhouden, zie scoping deel), of een functie opnieuw retourneren. In JS is er geen verschil tussen een literal function en een gewone, buiten de notatie - een literal bind een anonieme functie aan een variabele. Zoiets kan dus perfect: + +```javascript +a = function() { + var aGetal = 10; + return function() { + var bGetal = 20; + return function() { + var cGetal = 30; + + return aGetal + bGetal + cGetal; + } + } +} + +a()()() // 60 +``` + +Merk op dat de `()` operator een functie uivoert, en hier alles 3x genest is, maar toch de binnenste functie een referentie naar `aGetal` kan gebruiken, gedefiniëert in de buitenste functie! Lees hierover meer in het scoping gedeelte. + +##### Declaratie van functie literals + +In javascript worden variabelen die met `var` gedeclareerd worden **altijd** vooraan geplaatst, ook impliciet. Dit wil zeggen dat wanneer ik een function literal definieer, eigenlijk het volgende gebeurt: + +```javascript +function x() { + alert("yo"); + var b = function() { }; +} // is for the JS parser equal to: + +function xParsed() { + var b; + alert("yo"); + b = function() { }; +} +``` + +Wanneer je `b()` probeert uit te voeren vóórdat b effectief geïnitialiseerd is, ontploft de boel. Let hier dus op, en gebruik als dit niet mogelijk is geen literal. Bij naamgevingen binnen een scope geldt een volgorde: + + 1. Language-defined (`this`, `arguments`) + 2. Formal-defined (arguments) + 3. Function-defined + 4. Variable-defined + +Dat wil zeggen dat wanneer je twee keer x probeert toe te kennen aan een getal én een functie, heeft de functie voorrang. + +!! Uitzondering: een formeel argument met naam `arguments` heeft voorrang op lang-defined `arguments`. Bad practice... + +##### Itereren over properties van objecten ##### + +Vergeet niet dat in Javascript alle objecten (zowel object literals als instanties van functies) zich gedragen als een {{< wp "Associative array" >}} - en dat we dus ook kunnen lopen over alle keys: + +```javascript +var N = { one: 1, two: 2 }; +for(key in N) { + console.log(key + " represents as value: " + N[key]); +} +``` + +Om de value van een bepaalde key op te halen kan je natuurlijk ook `eval('N.' + key)` gebruiken - alle wegen leiden tot Rome... + +##### Controleren of een key in een object/array beschikbaar is + +Dit kan op enkele manieren: + + 1. `'key' in object` ((Opgelet: `in` kan misleidend effect hebben bij gebruik in combinatie met prototypal inheritance, zie later!)) + 2. `object.hasOwnProperty('key')` -> gaat wel `false` retourneren bij overgenomen keys vanuit prototypes. Zie later. + 3. nogmaals itereren (er zijn betere ideeën, dit is de neiging die veel mensen hebben, te procedureel denken!) + +Wat géén goede manier is: + +```javascript +var Obj = { + x: 'x', + u: null, + un: undefined +}; + +Obj.x === undefined // false, so it must exist as a key, right? +Obj.u == undefined // whoops, true? oplossing: gebruik '#####' +Obj.un == undefined // whoops, still true? value kan ook undefined zijn natuurlijk! +``` + +#####= Varargs #####= + +```javascript +function f() { + return arguments[0] + arguments[1]; +} +f(1, 2) // == 3 +``` + +Indien er geen argumenten gespecifiëerd zijn, zijn ze allemaal *optioneel*! Dit wil zeggen dat een functie aangeroepen kan worden zonder het aantal argumenten 100% te laten overeen komen. + +###### anonymus functions en recursie ###### + +`arguuments` heeft nog een speciale property: `arguments.callee(...)` dat de huidige functie voorstelt, hiermee kan je jezelf aanroepen! + +!! Dit gaat een syntax error geven bij ECMA Script standaard 5 in *strict* mode + +###### verplicht alle argumenten invullen ###### + +```javascript +function f(x, y, z) { + if(arguments.length != arguments.callee.length) { + throw new Error("kapot wabezig"); + } +} +f(1, 2) // == 3 +``` + +Het is natuurlijk makkelijker om `!= 3` hardcoded te plaatsen, maar dit kan extracted worden naar een aparte functie. + +###### Function overloading ###### + +Overloading bestaat niet in JS aangezien de tweede definitie van de functie de eerste overschrijft (de property "functienaam" in het object, zeg maar).

+Het is wel mogelijk om één functie te maken die delegeert, zie http://ejohn.org/blog/javascript-method-overloading/ + +Maak handig gebruik van het feit dat de `.length` property ook op functies opgeroepen kunnen worden! (Telt enkel de gedefiniëerde) + +```javascript +(function x(y, z) {}).length ###### 2; // y and z +``` + +#####= this Keyword #####= + +Zie scoping + +#####= Aspect Oriented Programming in JS #####= + +Via AOP kan men net voor of na een bepaalde functie gedrag toevoegen zonder dat een component dat die functie aanroept daar weet van heeft. Het is zo makkelijk om bijvoorbeeld logging toe te voegen. In Java wordt Spring AOP gedaan via proxy beans die van dezelfde interface afleiden en daarna delegeren, of via AspectJ die rechtstreeks bytecode wijzigt. + +In Javascript kan dat makkelijker, omdat we de referentie naar een functie gewoon kunnen "vast" pakken. Stel dat ik voordat de ezel balkt wil loggen "ik ga balken": + +```javascript +var oldBalkF = Ezel.prototype.balk; // vereist dat balk via `prototype` werd toegevoegd +Ezel.prototype.balk = function() { + console.log("ik ga balken! "); + oldBalkF.call(this); +} +new Ezel().balk(); // print log eerst +``` + +Hier merken we twee dingen op: + + 1. In de nieuwe balk functie kan **niet** zomaar `oldBalkF()` uitgevoerd worden dan is mijn `this` referentie naar de ezel instantie weer weg. + 1. De `window` scope werd vervuild door oldBalkF, die nog steeds toegankelijk is. Hier zijn twee oplossingen voor: + 1. `delete oldBalkF;` na de `call` instructie (extra werk) + 1. Gebruik een anonieme functie die direct uitgevoerd wordt die de scope bewaakt! + +#####= undefined #####= + +Refereren naar een property in een object dat niet bestaat, geeft ons de speciale waarde `undefined`.

+Merk op dat dit *niet hezelfde* is als `null`. Toch zijn ze gerelateerd: + +```javascript +var x = { + one: 1 +}; +if(x.two == null) { + 3; +} +``` + +Dit geeft 3 omdat `x.two ##### undefined` en `null ###### undefined`. Aangezien `null` in een if test by default `true` retourneert, kan de if test korter: `if(x.two) { ... }`. + +Zo is het makkelijk om optionele argumenten van functies na te gaan: + +```javascript +function count(one, two, three) { + if(!two) two = 0; + if(!three) three = 0; + return one + two + three; +} +``` + +!! `undefined` is een window-scope variabele die initiëel de value `undefined` heeft, dit is dus géén keyword, pas op! + +# Async coding in JS + +[Asynchronous programming in JS: APIs interview](http://www.infoq.com/articles/surviving-asynchronous-programming-in-javascript) (infoQ) + +## Het probleem + +Alle events in javascript zijn asynchroon. Dat wil zeggen dat we geen idee hebben wanneer de eigenlijke code uitgevoerd is, en we een **callback closure** moeten meegeven, die verder werkt als de asynchrone code uitgevoerd is. + +Dit is oké voor 1-2 asynchrone calls. Maar stel u voor dat we 4+ async calls moeten maken om werk gedaan te krijgen. Typisch dingen zoals: + + * setTimeouts + * animaties (jQuery ea) + * AJAX calls (REST, naar domein logica, bewaren, opvragen, veranderen, ...) + +### Een integratietest schrijven in JS + +In *Java* kunnen we gewoon wat methods oproepen die data persisteert, daarna de eigenlijke *asserts* schrijven en eventueel in de `@After` met JUnit data cleanup uitvoeren: + +```java +DomainObj obj = new DomainObjPersister() + .withA() + .withLala("lala") + .persist(); + +ChildObj child = new ChildObjPersister() + .withParent(obj) + .persist(); + +assertThat(child.getStuff()).isNotEmpty(); +``` + +Om `child` te kunnen persisteren moeten we `obj` als parent meegeven, dus die call moet eerst uitgevoerd zijn. Alle persisters gaan naar de database. Dit zou in javascript zoiets zijn= + + +```javascript +$.ajax('/domain/obj/store', { + success: function(obj) { + $.ajax('/domain/child/store', { + success: function(child) { + assertThat(child.getStuff()).isNotEmpty(); + }, ... + }); + }, + type: 'PUT', + dataType: 'json', + data: JSON.stringify({ key: 'value', key2: 'value2' }) +}); +``` + +Dus een callback wrappen in een callback wrappen in een callback. + +#### Async event loop hulpjes + +Zie ook [Philip Roberts: Help, I'm stuck in an event-loop](http://vimeo.com/96425312) + + + +Tooltje om event loop te visualiseren zodat je ziet wat er gebeurt. Breaken in chrome helpt natuurlijk ook, gewoon naar de call stack kijken... + +#### Asynchroon testen in Jasmine + +Met **Jasmine** is het (beperkt) mogelijk om te wachten tot dat een stukje werk uitgevoerd is voordat de assertions afgegaan worden.

+Dit kan op de volgende manier: + +```javascript + +it("should be green, right??", function() { + var asyncCallFinished = false; + function callback(someObj) { + asyncCallFinished = true; + } + doAsyncCall(callback); + + waitsFor(function() { + return asyncCallFinished ##### true; + }); + + runs(function() { + expect(stuff).toBeLotsBetter(); + }); + +}); + +``` + +Pitfalls: + + * Ge moet closure scope gebruiken om een variabele bij te houden om te controleren of de async call klaar is in een callback + * Ge moet `waitsFor()` gebruiken, intern pollt Jasmine waarschijnlijk gewoon... + * Ge moet eigenlijke assertions wrappen in `runs()` omdat `waitsFor()` direct retourneert en opzich async is. + +De assertion functiepointers die meegegeven worden met `runs()` worden intern opgeslaan en bijgehouden totdat de closure van `waitsFor()` `true` retourneert. Daarna wordt ook alles pas meegegeven met de Jasmine reporter (logging, output etc). Redelijk omslachtig, aangezien 3+ async calls dan `waitsFor()` moeten wrappen. Geen oplossing. + +##### Asynchroon testen met QUnit ##### + +```javascript +asyncTest("should be green, right??", function() { + var stuff = gogo(); + function callback(obj) { + equal(obj.stuff, 2); + start(); + } + + doAsyncCall(callback); + +}); +``` + +Pitfalls: + + * In de callback van uw async stuk code moeten zoals verwacht uw assertions zitten + * Ge moet een speciale test method gebruiken, `asyncTest()` + * Ge moet na uw assertions `start()` aanroepen (??) + +#####== De oplossing #####== + +https://github.com/willconant/flow-js e.a. (of iets zelfgemaakt in die aard). + +Herneem bovenstaande integratietest code in javascript, maar dan met flow.js geschreven: + +```javascript +flow.exec( + function() { + $.ajax('/domain/obj/store', { + success: this, + type: 'PUT', + dataType: 'json', + data: JSON.stringify({ key: 'value', key2: 'value2' }) + }); + }, + function(obj) { + $.ajax('/domain/child/store', { + success: this, ... + }); + }, + function(child) { + assertThat(child.getStuff()).isNotEmpty(); + } +); +``` + +Pitfalls: + + * Error handling wordt opgefreten - gebruik Firebug's **debug on all errors** knop in de console. (anders mechanisme maken dat ze doorgooit van closure1 naar 2 ea) + * `curry()` gaat niet lukken aangezien de `this` pas in de closure zelf de juiste waarde krijgt. + * `this` moet meegegeven worden als callback, dus te intensief gebruik makend van `this` pointer in eigen code kan BOEM geven. + +flow.js geeft het resultaat van closure1 mee als argument aan closure2 (via `arguments`) en zo maar door, dat is mega handig. + +##### Synchrone code code combineren met asynchrone in flow.js ##### + +Enige minpunt is dat de callback `this()` moet expliciet aangeroepen worden om van closureX naar closureY over te stappen!

+Los dit op met een utility functie: + +```javascript +flow.sync = function(work) { + return function() { + this(work.apply(this, Array.prototype.slice.call(arguments, 0))); + } +} +``` + +Zodat we dit kunnen doen: + +```javascript +flow.exec( + function() { + asyncStuff(this); + }, + flow.sync(function(resultfromPrev) { + console.log("lol"); // no this() required afterwards + }), + function(resultFromSyncStuff) { + doMoreAsyncStuff(this); + } +); +``` + +##### In een asynchrone closure parallel werken ##### + +Gebruik `this.MULTI()` als callback ipv `this` (zie voorbeeld hieronder) + +##### flow.js combineren met Jasmine ##### + +Om de smeerlapperij van `waitsFor()` weg te werken kunnen we ook `flow.exec` gebruiken. + +:exclamation: De laatste stap gaat **altijd** een `runs()` moeten bevatten voor de reporter om aan te duiden dat assertions uitgevoerd worden, aangezien de `exec()` functie direct retourneert. Dus moeten we 1x wachten, totdat de hele "flow" gedaan is. We kunnen dit combineren met BDD en een mini-DSL hierrond schrijven. Resultaat: + +```javascript +function when() { + var flowDone = false; + var slice = Array.prototype.slice; + var argsArray = slice.call(arguments, 0); + var laatsteArgumenten; + + argsArray.push(function() { + laatsteArgumenten = slice.call(arguments, 0); + flowDone = true; + }); + + flow.exec.apply(this, argsArray); + waitsFor(function() { + return flowDone ##### true; + }); + + return { + then: function(assertionsFn) { + runs(function() { + assertionsFn.apply(this, laatsteArgumenten); + }); + } + }; +} +``` + +Voorbeeldcode: + +```javascript + +describe("plaatsen domein", function() { + it("wanneer ik alle plaatsen ophaal, kan ik hier domeinspecifieke functies aan opvragen", function() { + var plaatsen; + when( + function() { + DOMEIN.plaatsRepository.bewaarPlaats(plaats, this.MULTI()); + DOMEIN.plaatsRepository.bewaarPlaats(anderePlaats, this.MULTI()); + }, + function() { + DOMEIN.plaatsRepository.haalPlaatsenOp(this); + } + ).then( + function(opgehaaldePlaatsen) { + opgehaaldePlaatsen.forEach(function(plaats) { + expect(plaats.geefMeting).toBeDefined(); + }); + } + ); + }); +}); +``` + +Merk op dat de closure meegeven in `then()` (slechts 1 mogelijk voor assertions) als **argument** het resultaat van de laatste closure in `when()` meekrijgt! + +#####== jQuery 1.6: Deferred en piping #####== + +Vanaf **jQuery 1.6** is het mogelijk om met `$.Deferred` te werken, dat het mogelijk maakt om een closure uit te voeren op het moment dat "werk" gedaan is. Met werk bedoelen we: + + 1. fx: `.animate` ea + 2. http: `.ajax` ea + 3. custom code die zelf een `$.Deferred` object retourneren + +##### Promising stuff ##### + +Alle async operaties worden aan een *queue* toegevoegd van het jQuery element zelf. Je kan op eender welk moment vragen aan dat queue object, dat wanneer alle items zijn verwerkt er iets speciaals uigevoerd wordt: + +```javascript +$('#blink').fadeOut().promise().done(function() { + console.log('done blinking!'); +}); +``` + +Dit kan dus ook met `$.ajax`. + +##### Zelf Deferred code schrijven ##### + +Maak een deferred object aan door `$.Deferred()` aan te roepen. Op dat moment kan je `done()` hierop zoals in het vorige voorbeeld aanroepen. Bijvoorbeeld: + +```javascript + +function startStuff() { + var df = $.Deferred(); + setTimeout(1000, function() { + console.log('done async call'); + df.resolve(); + }); + return df.promise(); +} + +startStuff().done(function() { + console.log('really really done with "start stuff"!'); +}); +``` + +##### Multiple elements in queue: piping ##### + +Stel dat eerst element #1 animatie triggert, dan #2, en daarna nog logica dient te gebeuren. Dit kan ook met `$.Deferred`, door `.pipe()` te gebruiken om verder te breiden aan de queue. + +```javascript +$("button").bind( "click", function() { + $("p").append( "Started..."); + var div1 ###### $("#div1"), div2 $("#div2"); + + var df = $.Deferred(); + df.pipe(function() { + return div1.fadeOut("slow") + }).pipe(function() { + return div2.fadeOut() + }).done(function() { + $("p").append( " -- DONE"); + }); + df.resolve(); +}); +``` + +:exclamation: Pas op, in de `.pipe()` functie moet een nieuw **promised object** geretourneerd worden! Dat nieuw object wordt als return value van de vorige pipe gebruikt. Op die manier wordt er dus *chaining* toegepast. + +# Javascript Inheritance + +> JavaScript uses prototypal inheritance. This means that Javascript does not distinguish between classes/prototypes and instances and, therefore, we can add our desired behavior directly to the instance. + +## "new" operator + +Zie http://unitstep.net/blog/2008/01/24/javascript-and-inheritance/

+Gegeven de volgende functie: + +```javascript +function X(bla) { + this.x = bla; + console.log("doeiets"); + this.ding = function() { return this.x; }; +} +``` + +Wat gebeurt er bij de klassieke manier van een "klasse" initialiseren? Zo: + +```javascript +new X("argument").ding() +``` + +Omdat geen klassen bestaan, wordt er eigenlijk een "leeg" object aangemaakt en het prototype van het bestaand object aangepast door `call` te gebruiken: + +```javascript +var johnDoe = function(){}; +X.call(johnDoe, "dinges") +johnDoe.ding() +johnDoe.x ###### "dinges" +``` + +Wat gebeurt hier? + + 1. `function(){}` is een *closure*, dus een *function*, zonder inhoud. + 2. de `call` functie roept een functie aan en vervangt de `this` referentie (**context**) door het meegegeven argument + 3. Bijgevolg wordt in `X()`, `this.x = bla` gedaan, dat wil zeggen dat vanaf nu onze anonieme closure de property `x` **bevat**, samen met alle functies die binnen `X` gedefinieerd zijn. + +Merk op dat "bevat" impliceert dat het object johnDoe natuurlijk nu ook geheugen toegekend krijgt om de variabele "x" op te slaan. Dit in contrast met *prototypal inheritance*, zie volgend stuk. + +Eender welke functie heeft een `prototype`. Een "lege" functie bevat een dynamische "constructor" (de functie zelf) met lege body: + +```javascript +(function(){}).prototype +``` + +######= Gewenst gedrag - wat waar plaatsen ######= + + * Indien ik een functie of een variabele heb die anders kan zijn naargelang de implementatie (definiëer de "naamgeving"), plaats deze dan in de **constructor** functie. + * Indien ik een functie of een variabele heb die specifiek voor die functie is en niet gaat veranderen, plaats deze dan **in het concreet object** via `this.`. + * Indien ik een functie of een variabele heb die ik tijdelijk wens te gebruiken, plaats deze dan **in het concreet object** via `var` ((Maak slim gebruik van scope chaining om zaken te encapsuleren!)). + +Typisch bevatten constructor functies ook *geen* return waarden ((dit retourneert dus impliciet `undefined`)) - we gebruiken deze functies toch altijd in combinatie met de `new` operator, dus kennen de nieuwe instantie van het object direct toe aan een variabele. + +############= prototype gebruiken als inheritance ############= + +-> Meer informatie inclusief grafen met uitgebreide uitleg hoe prototype en constructors werken: zie http://joost.zeekat.nl/constructors-considered-mildly-confusing.html + +Aangezien we aan objecten hun functions kunnen via `.prototype`, is het niet moeilijk om een object zich te laten gedragen als zijn "ouder". Neem bijvoorbeeld een dier object, en een concrete ezel implementatie die een extra functie "balk" definiëert. + +```javascript +function Vierpotige() { + this.aantalPoten = 4; + this.eetIets = function() { + console.log("omnomnom"); + } +} + +function Ezel() { + this.balk = function() { + console.log("IEE-AA enzo"); + } +} + +Ezel.prototype = new Vierpotige(); +var ezeltje = new Ezel(); +ezeltje.eetIets(); // aha! outputs 'omnom' en 'als ezel fret ik ook nog gras enzo' +``` + +Wat gebeurt hier precies? + + 1. Vierpotige bevat een property aantalPoten en een functie eetIets. + 2. de constructor functie Vierpotige wordt aangeroepen zodra een Ezel aangemaakt wordt, zodat properties en functies overgenomen worden. + 3. een nieuwe ezel eet iets via een prototype functie van een lege Vierpotige. + +:exclamation: **Opgelet** Vierpotige.prototype bevat enkel de constructor functie zelf en *NIET* "eetIets", daarom dat we Ezel.prototype gelijk stellen aan een nieuwe lege vierpotige. Dit zou niet werken: + +```javascript +Ezel.prototype = Vierpotige.prototype; +new Ezel().eetIets() // kapot +``` + +Tenzij we eetIets definiëren via `Vierpotige.prototype.eetIets = function() { ... }` - *maar* dan kan `aantalPoten` niet meer vanaf een ezel accessed worden. + +Nu de prototype property van Ezel en Vierpotige gelijk zijn, kunnen we het prototype uitbreiden met een functie en die direct op ons nieuw ezeltje toepassen: + +```javascript +Vierpotige.prototype.verteer = function() { + console.log("ist wc bezet??") +} +ezeltje.verteer() +``` + +:exclamation: **Waarschuwing** het prototype van `Vierpotige` aanpassen past ook elke `Ezel` instantie aan, dit is énorm gevaarlijk als er publieke properties zoals `aantalPoten` gedefiniëerd zijn! Want in tegenstelling tot wat velen denken, worden properties **niet** gekopiëerd! Dus dit zou het aantal poten van ALLE ezels aanpassen: + +```javascript +dier = new Vierpotige(); +Ezel.prototype = dier; +new Ezel().aantalPoten ###### 4; // true +dier.aantalPoten = 2; +new Ezel().aantalPoten ###### 4; // false +``` + +######= Properties overriden ######= + +Prototypal inheritance werkt omdat JS bij elke property lookup kijkt in welk object die referentie gedefiniëerd is. Is dat het huidig object, neem dan die waarde. Indien neen, kijk in het `prototype` object. Indien neen, kijk in het `prototype` object van dat object, en zo maar door tot op `Object` niveau. We kunnen zo ook een property van een prototype zelf overriden, door ander gedrag te definiëren, of zelfs de super aan te roepen: + +```javascript +Vierpotige.prototype.eetIets = function() { + console.log("vierpotige eten"); +} +Ezel.prototype.eetIets = function() { + Vierpotige.prototype.eetIets(); // "super" + console.log("als ezel fret ik ook nog gras enzo"); +} +``` + +######= Built-in JS types extenden ######= + +:exclamation: Extend **nooit** `Object.prototype`! Waarom? Omdat Eender welk object een instantie van `Object` is, dus zijn prototype heeft, en met een `for(x in prop)` deze property nu ineens toegankelijk is voor elk object. Een leeg object `{ }` wordt verwacht géén properties te hebben! + +```javascript +Object.prototype.hack = function() {} +for(x in {}) { + console.log(x); // print "hack", zou hier niet in mogen komen +} +``` + +############ Checken op inheritance ############ + +Met Javascript kan men door middel van `typeof` controleren van welk type een variabele is. Dat komt neer op: + + * object (`{}`) + * function (`function() {}`) + * string (`""`) + * number (`-47.2`) + +Het is niet zo interessant om te gebruiken voor eigen inheritance. Daarvoor dient `instanceof`: + +```javascript +ezeltje instanceof Vierpotige ###### true +ezeltje instanceof Ezel ###### true +new Vierpotige() instanceof Ezel ###### false +``` + +######= Zelf inheritance afchecken met prototype ######= + +###### met constructors ###### + +Dit is een zeer beperkte manier dat geen rekening houdt met "inheritance": + +```javascript +function instanceOf(One, Two) { + return One.constructor ###### Two; +} + +instanceOf(Ezel, Vierpotige) // true +``` + +Aangezien elk object een `.constructor` property heeft die afgeleid werd vanuit de constructor functie die aangeroepen werd, kan men op deze manier een simpele check afwegen. Een praktischer voorbeeld is `(typeof (new Date()) ###### object) && (new Date().constructor ###### Date)`. + +###### met __proto__ ###### + +Het `instanceof` keyword kijkt natuurlijk naar de `prototype` properties van beide objecten om te controleren of object a van object b komt. Dit kan men ook zelf doen: + +```javascript +function instanceOf(One, Two) { + return One.prototype.__proto__ ###### Two.prototype; +} + +instanceOf(Ezel, Vierpotige) // true +``` + +Hoe kan dit kloppen? + + 1. Herinner u dit statement: `Ezel.prototype = new Vierpotige();`. Dit stelt de `prototype` van Ezel gelijk aan die van een vierpotige. Het enige wat in de `prototype` van Vierpotige steekt is de `verteer()` functie, de rest werd via de constructor functie overgekopiëerd! + 2. De magic property `_ _proto_ _` wordt intern gezet zodra een prototype wordt toegekend aan een object. Aangezien Ezel zelf ook prototype functies heeft specifiek voor ezels, kunnen we die van Vierpotige niet overriden, maar wel gebruiken. + +:exclamation: Bekijk iets toevoegen via `.property` als iets toevoegen aan het algemeen prototype object, en iets rechtstreeks toevoegen via een key als iets toevoegen op een instance van dat prototype object. In andere dynamische talen stelt `property` de `metaClass` voor, maar JS werkt enkel met functies. + +De betere oplossing: **`isPrototypeOf()`**! Zie magic properties. + +:exclamation: **`_ _proto_ _` is een __instance__ property, `.prototype` een constructor function property** + +###### met properties ###### + +Door `hasOwnProperty()` te gebruiken kan je nagaan of een property overgenomen is of niet. Vanaf JS 1.5. + +############= call als inheritance ############= + +De klassieke inheritance structuur zoals in Java en C++ kan beter benaderd worden door `call` te gebruiken. Herbekijk onze ezels: + +```javascript +function Vierpotige() { + this.aantalPoten = 4; + this.eetIets = function() { + console.log("omnomnom"); + } +} + +function Ezel() { + Vierpotige.call(this); + this.balk = function() { + console.log("IEE-AA enzo"); + } +} + +var ezeltje = new Ezel(); +ezeltje.eetIets(); // aha! outputs omnom +``` + +Door als eerste statement in de constructor functie van `Ezel` een `call` te plaatsen naar onze "parent", *kopiëren* we alle keys en values die daarin gedefiniëerd staan. In tegenstelling tot prototypal inheritance kost dit dus veel meer geheugengebruik, en is dit beperkter om uit te breiden. We linken eigenlijk impliciet twee functies aan elkaar door waarden over te nemen, maar iets aanpassen aan `Vierpotige` gaat de `Ezel` op geen ekele manier doen veranderen. + +############= prototypal inheritance toepassen ############= + +In plaats van `new` overal te gebruiken zonder te weten wat hierachter ligt, kan men `create` ook gebruiken: + +```javascript +if (typeof Object.create !###### 'function') { + Object.create = function (o) { + function F() {} + F.prototype = o; + return new F(); + }; +} +newObject = Object.create(oldObject); +``` + +Zie http://javascript.crockford.com/prototypal.html + +############ Een minder verbose manier om extra properties te definiëren ############ + +Zie http://howtonode.org/prototypical-inheritance - + +```javascript +Object.defineProperty(Object.prototype, "spawn", {value: function (props) { + var defs = {}, key; + for (key in props) { + if (props.hasOwnProperty(key)) { + defs[key] = {value: props[key], enumerable: true}; + } + } + return Object.create(this, defs); +}}); +``` + +Op die manier kan je `BaseObj.spawn({'extraProp': 'extraValue'});` gebruiken, zonder de relatieve verbose manier van extra properties te moeten gebuiken die `Object.create` [handhaaft](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create#Classical_inheritance_with_Object.create). + +############= Prototype JS en Class.create ############= + +Javascript frameworks proberen altijd inheritance makkelijker te maken voor klassieke OO developers door functies te modelleren als klassen. In [Prototype JS](http://www.prototypejs.org/api/class) kan men zoiets doen: + +```javascript + +var Animal = Class.create({ + initialize: function() { + this.something = "wow"; + }, + + speak: function() { + console.log(this.something); + } +}); + +var Snake = Class.create(Animal, { + hiss: function() { + this.speak(); + } +}); +``` + +Snake leidt af van Animal, en de `initialize()` functies stellen de constructor functies voor. Wat gebeurt er dan achter de schermen bij `Class.create({...})`? + + 1. Net zoals hierboven wordt de constructor functie via `apply` aangeroepen (zelfde als call). Enkel wordt als `this` een lege functie toegevoegd. + 1. `Object.extend()` wordt gebruikt om alle keys van de parent te kopiëren naar de nieuwe lege functie. + 1. De `prototype` property van de parent wordt net zoals hierboven gezet op de nieuwe "klasse". + 1. Speciale gevallen zoals een "lege constructor" functie indien nodig, intern bijhouden wat sub- en superklassen van elkaar zijn, etc. + +In essentie komt het neer op "*syntax sugaring*" zodat het klassieke OO model gebruikt kan worden - terwijl er onderliggend iets anders gebeurt.

+Meer info over deze implementatie: http://code.google.com/p/inheritance/ + +############= Multiple inheritance ############= + +Perfect mogelijk, of slechts delen van object A en alles van B voor object C gebruiken (**mixins**!). Simpelweg alles van de ene `prototype` property naar de andere overzetten wat nodig is: + +######= Methode 1 ######= + +```javascript +function A(){}; +A.prototype.a = function() { return "a"; } +A.prototype.c = function() { return "a"; } +function B(){}; +B.prototype.b = function() { return "b"; } + +function C(){}; +for(prop in B.prototype) { + C.prototype[prop] = B.prototype[prop]; +} +C.prototype.a = A.prototype.a; +C.prototype.c = function() { return "c"; } + +var c = new C(); +c.a() ###### "a"; +c.b() ###### "b"; +c.c() ###### "c"; +``` + +######= Methode 2 ######= + +Creeër de illusie om constructor(s) aan te roepen in een constructor functie van een ander object: + +```javascript +function B() { + this.b = function() { return "b"; } +} +function C() { + this.c = function() { return "c"; } +} + +function A() { + this.a = function() { return "a"; } + this.super = B; + this.super2 = C; + this.super(); // kopiëer de b functie in A, maar inherit niet! + this.super2(); +} + + +var a = new A(); +a.a() ###### "a"; +a.b() ###### "b"; +a.c() ###### "c"; +``` + +######= Problemen met mixins ######= + +:exclamation: Dit is géén authentieke multiple inheritance. Hier zijn twee problemen aan gekoppeld: + + 1. Zodra via `B.prototype` een nieuwe functie toegevoegd wordt, zal C deze **niet** overpakken omdat `C.prototype` niet *gelijk* gesteld werd aan die van A of B + 1. En bijgevolg dus ook de `instanceof` operator naar de zak is: + +```javascript +c instanceof C ###### true +(c instanceof B || c instanceof A) ###### false +``` + +Als dit echt nodig is kan men zoiets zelf implementeren door weer te loopen via `for(prop in x.prototype) { ... }` en te checken of alle keys voorkomen in een object. + +Zie Mozilla Dev center: [Details of the Object Model](https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Details_of_the_Object_Model#No_Multiple_Inheritance) + +# Javascript Scoping + +### Toplevel Scope + +Een stuk Javascript in een HTML pagina, zonder eender welke functie te definiëren, werkt altijd op **top-level scope**. Dat stelt het `window` object voor, waar we ook resolutie gegevens en dergelijke kunnen uithalen. Dus simpele variabelen declareren om in HTML te kunnen gebruiken werkt altijd op de globale scope: + +```javascript +var customerEmail = document.getElementById("username") + "@" + document.getElementById("domain") + ".com"; +window.customerEmail // what did I do?? (null@null.com if unknown IDs) +``` + +Om te vermijden dat we alles op het `window` object "dumpen", schrijven we nette functies die zaken zoals tijdelijke variabelen en private stukken code *encapsuleren*. + +#### Variabele declaratie + +Variabelen definiëren gaat met `var` (zoals hierboven), máár *globale* (window-scope) variabelen kunnen gedeclareerd worden zonder dit. Pas hiermee op: + +```javascript +woot = "leet"; +function yo() { + woot = "omg"; // whoops, I changed a global var + meerWoot = "leet"; + var wootwoot = "one!!1"; +} + +yo(); +window.woot ##### "leet" // false +window.meerWoot ##### "leet" // true +window.wootwoot ##### undefined // true +``` + +Dit verklaart de nood om `var` te gebruiken om *lokale* variabelen te definiëren.

+Merk op dat hier `wootwoot` énkel binnen de functie `yo()` leeft, dus via de Javascript *Garbage Collector* weggesmeten wordt zodra die functie volledig geëvalueerd is. + + +#####= Nested en Block scope #####= + +Functies in functies in functies zijn perfect mogelijk, en de binnenste functies hebben toegang tot de scope van alle anderen. + +:exclamation: In tegenstelling tot Java e.a. beschikt JS **niet over block scope**. Dit wil zeggen: + +```javascript +var f1 = 10; +function f() { + console.log(f1); // 10? Nope, undefined! + var f1 = 1; + function z() { + var z1 = 2; + if(f1 ###### 1) { + var z2 = 2; + } + + return z1 + z2; // z2 nog steeds toegankelijk + } +} +``` + +Waarom logt dit `undefined`, terwijl op global scope aan f1 10 toegekend wordt? Omdat een tweede variabele genaamd f1 in de *body* van de functie gedeclareerd wordt, wordt die versie gebruikt, **ook al is deze nog niet toegekend!**. Wow. + +JS Is dus buiten de *lexicale scoping* ook nog eens *function-level scoped*. + +Een duidelijker voorbeeld via http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting: + +```c +#include +int main() { + int x = 1; + printf("%d, ", x); // 1 + if (1) { + int x = 2; + printf("%d, ", x); // 2 + } + printf("%d
n", x); // 1 +} +``` + +Print logischerwijze 1, 2, 1, juist? Doe hetzelfde eens in javascript: + +```javascript +var x = 1; +console.log(x); // 1 +if (true) { + var x = 2; + console.log(x); // 2 +} +console.log(x); // 2 +``` + +*BOOM*.

+Dit komt doordat `if` statements geen nieuwe scope introduceren, enkel `function` definities! Een oplossing is een anonieme functie gebruiken en die direct evalueren: + +```javascript +function foo() { + var x = 1; + if (x) { + (function () { + var x = 2; + // some other code + }()); + } + // x is still 1. +} +``` + +##### Scope chain ##### + +Elke JS Executie context heeft een **scope chain** toegekend. Dit is een lijst van objecten waar de interpreter door gaat om een variabele x op te kunnen zoeken (Dit proces heet *variable name resolution*). Men begint met de huidige context van de functie die opgeroepen wordt. Indien variabele x daar niet gedefiniëerd is, ga een scope hoger, en zo voort. + +In *top-level* JS (op window scope) bevat de scope chain slechts één object, het "globaal" object. (`window`) + +##### Event handler scope chain ##### + +Bij het uitvoeren van events in de DOM Tree zitten er buiten `window` nog enkele andere objecten op de scope chain: het object dat het event zelf triggerde. Het is dus mogelijk om rechtstreeks vanuit een `onclick` event van een `input` tag, een ander `form` element aan te spreken zonder dit eerst te resolven via de klassieke `getElementById()`: + +```html + + + + + + + +``` + +merk op dat `anders.value` mogelijk is doordat het DOM element text mee op de scope chain zit.

+Dit is vanzelfsprekend serieus verwarrend en **bad practice**, Firebug waarschuwt hier ook voor: + +> Element referenced by ID/NAME in the global scope. Use W3C standard document.getElementById() instead. + +Dit kan serieuze problemen met zich mee brengen, zeker wanneer mensen niet goed weten hoe javascript te gebruiken en bijvoorbeeld for loopjes schrijven door variabelen op toplevel scope te introduceren: + +```html + + + + + + +

Javascript event scopechain voorbeeld

+ +
+ Klik hierop aub +
+ + +``` + +##### Scope tijdelijk aanpassen ##### + +```javascript +with(window.screen) { + console.log(width); +} +``` + +Al is `var screen = window.screen; screen.width` natuurlijk even makkelijk. + +#####= Private Member variables #####= + +:exclamation: "Functies en variabelen in objecten zijn overal en altijd toegankelijk". **DIT IS FOUT**! Bekijk het volgende voorbeeld (zie [private members](http://www.crockford.com/javascript/private.html) docs): + +```javascript +function Func(param) { + this.publicMember = param; + var privateMember = 10; + var me = this; + + this.publicFunction = function() { + console.log(this.publicMember); + }; + + // could be function privateFunction() { + var privateFunction = function() { + console.log(privateMember); + console.log(this.publicMember); // BOOM + console.log(me.publicMember); // OK + }; +} + +new Func(10).privateFunction() // BOEM +``` + +Zodra we `this` gebruiken om members in een constructor functie te steken wordt het publiek. Zodra we gewoon variabelen definiëren, ook al zijn het closures zoals `privateFunction`, is dit *niet* toegankelijk voor de buitenwereld! Dit wil zeggen dat het zelfs niet toegankelijk is voor `.prototype`-toegevoegde functies. + +Merk op dat we aan `privateMember` kunnen zonder `this` te gebruiken om naar iets te refereren. Dit komt omdat die members in de context van het object zitten.

+Een probleem dat zich voordoet is dat de `this` pointer binnen private functions natuurlijk weer gereset wordt tot op `window` scope. Om dit op te lossen kunnen we een private variabele voorzien die refereert naar `this`, daarvoor dient `me`. + +###### Private, Public en prototype functies ###### + +Een **private** functie is een functie die in de constructor functie gedefiniëerd is als *member variabele*, en dus geldig is binnen de context van die functie.

+Een **privileged** functie is een functie die in de constructor functie gedefiniëerd is met de *this accessor*. Deze functies kunnen private functies aanroepen omdat ze binnen de context van de constructor functie leven, en zijn ook aanroepbaar van buitenaf.

+Een **public** functie is een functie die in het *prototype* leeft van een object((privileged en public zijn in feite gelijk, onderscheid wordt gemaakt om public variables te scheidden)). Private members zijn hier niet toegankelijk, privileged wel. Een voorbeeld (vervolg): + +```javascript +Func.prototype.publicThing = function() { + alert(this.publicMember); + return this.privateMember; // BOOM +}; +``` + +#####= Object/Class Member variables #####= + +In typische OO talen zoals Java en C++ kunnen ook "statics" gedefiniëerd worden die enkel op klasse niveau leven. Zoiets is heel simpel te realiseren met Javascript, door een property op de constructor functie zelf te steken: + +```javascript +function Const() { + this.c = "const"; + c = "globalConst"; +} + +Const.C = "C"; + + +c ###### "globalConst"; // remember, window scope +new Const().c ###### "const"; +new Const().C != undefined +``` + +Dit noemen we "class" properties, in plaats van "instance" properties. + +#####= Anonieme functies gebruiken om members private te maken #####= + +Probleem: publieke functies die aan een object hangen met `this.functie = function() { ... }` zijn toegankelijk. Ik wil iets groeperen zonder `window` scope te vervuilen. Hoe kan ik één functie opsplitsen zonder de andere te *exposen*?

+Oplossing: + +```javascript +var Stuff = (function() { + + function doeStap1() { + console.log("private things in here"); + return 3; + } + + function doeStap2Met1(een) { + return een * 2; + } + + return { + doeStuff: function() { + return doeStap2Met1(doeStap1()); + } + } + +})() +console.log(Stuff); // outputs Object met "doeStuff" key +console.log(Stuff.doeStuff()); // 6 +``` + +>In JavaScript, as opposed to statically scoped languages, all variables are scoped to the function in which they're defined (not the "block" as defined by curly braces). The above code snippet creates an anonymous function and immediately executes it. This has the effect of creating a scope in which variables can be defined, and anything in the containing scope is still accessible. + +Zie http://trephine.org/t/index.php?title=Aspect_Oriented_JavaScript + +Wat gebeurt er? + + 1. Wrap een lege functie in Stuff, waar x aantal functies in zitten die wat werk doen. + 1. In plaats van dat toe te kennen aan Stuff, evalueer direct de nieuwe functie met `(function() { ... })()`. Wat terugkomt is een closure functie die `doeStuff` definieert, de rest is niet zichtbaar. + +#####= Expliciet objecten binden met call/apply #####= + +Neem als voorbeeld terug de ezel. Die zal bij het balken "iaia met mijn 4 poten" op de console afdrukken. Zodra de balk functie aangeroepen wordt, *bind* Javascript de ezel aan het `this` keyword, zodat poten correct opgezocht kan worden. Stel nu dat ik een spin wil laten balken, zonder de spin de balk functie te laten refereren/mixen vanuit de ezel: + +```javascript +var Spin = function() { + this.poten = 8; +}; +var tarantula = new Spin(); +new Ezel().balk.call(tarantula); // iaia met mijn 8 poten +``` + +Wat gebeurt hier? + + 1. Ik maak een nieuw object aan met ook een poten property + 1. balk gebruikt de poten property maar ik wil mijn spin gebruiken in plaats van de 4 poten van de ezel! + 1. gebruik `call` om balk uit te voeren, en geef als argument mijn spin mee, zodat de balk functie gebind wordt op mijn spin in plaats van de nieuwe ezel instantie + +Het is ook mogelijk om zonder argument `call` uit te voeren: + +```javascript +var poten = 100; +new Ezel().balk.call(); // iaia met mijn 100 poten +``` + +Hoezo 100? `this` wordt dan `window`, de hoogst mogelijke scope, en daar is net toevallig ook een poten variabele op gedefiniëerd. Als dat niet zo was gaf dit als output "iaia met mijn undefined poten". + +##### Impliciete unbound objecten ##### + +Het vorige voorbeeld toont aan hoe je expliciet `this` kan "unbinden". Dit gebeurt ook regelmatig intern impliciet, bijvoorbeeld met `setTimeout` of met events zoals `blabla.onclick`.

+De oplossing hiervoor is **closures** gebruiken. Bekijk dit voorbeeld: + +```javascript +function SomeClass() { + this.message = "hallo"; + + this.startLooping = function() { + setInterval(this.doeBijInterval, 1000); + }; + + this.doeBijInterval = function() { + console.log(this.message); // BOOOEEMM + } +} + +new SomeClass().startLooping(); +``` + +Wat loopt hier mis? ((Buiten het feit dat setInterval niet altijd mag uitgevoerd worden, er moet een guard clause rond, setInterval retourneert een id!))

+doeBijInterval wordt hier om de seconde uitgevoerd, en this.message wordt afgedrukt. `this` verwijst op dat moment *niet* meer naar de instantie van SomeClass! + +De oplossing, een closure meegeven aan `setInterval` die kan werken op de instance: + +```javascript +function SomeClass() { + this.message = "hallo"; + + this.startLooping = function() { + var instance = this; // OK, SomeClass instance + setInterval(function() { + instance.doeBijInterval(); // this = window scope, gebruik de instance var. + }, 1000); + }; + + this.doeBijInterval = function() { + console.log(this.message); // Da werkt ofwa + } +} + +new SomeClass().startLooping(); +``` + +##### loop closures ##### + +Een ander voorbeeld waar het mis kan gaan (ref. http://trephine.org/t/index.php?title=JavaScript_loop_closures !): + +```javascript +var list = [ 'a', 'b', 'c' ]; +for (var i######0, llist.length; i
+Zie AOP hieronder voor meer uitleg over anonieme functies. + +#####= Samenvatting: module pattern #####= + +Wanneer we alle bovenstaande technieken toepassen, krijgen we typisch in Javascript iets zoals dit: + +```javascript +var MyGlobalNewModule = (function(module) { + var privateVar = 3; + function privateFn() { + privateVar += 3; + } + + // decorate or use module here if wanted. + return { + publicProperty: "hello", + publicFn: function() { + return privateFn() - 2; + } + }; +})(GlobalModule); +``` + +Wat zit hier in verwoven? + + 1. private variables en functions zitten in de anonieme functie scope + 1. andere modules zijn toegankelijk via een argument, en *niet* via de directe variabele + 1. publieke functies worden *exposed* via een object dat teruggegeven wordt. + +Zo werken bijvoorbeeld de API en plugins van __jQuery__. + +:exclamation: Anonieme functies declareren en uitvoeren kan op twee manieren in JS: via `(function() { ... })()` en via `(function() { ... }())`. Merk het verschil in **haakjes** op. Het resultaat is exact hetzelfde, er is alleen een semantisch verschil, namelijk dat bij de eerste expressie de haakjes de *functie expressie* vasthoudt, en bij de tweede expressie de *call expressie* (het resultaat van de functie) + +Zie [stackoverflow](http://stackoverflow.com/questions/3783007/is-there-a-difference-between-function-and-function) voor meer uitleg - schematisch: + +``` + + CallExpression + | | + FunctionExpression | + | | + V V + (function() { }()); + ^ ^ + |--PrimaryExpression --| +``` + +VS + +``` + PrimaryExpression + | + FunctionExpression + | + V + (function() { })(); + ^ ^ + |-- CallExpression --| + +``` + +# Testing JS Code + +## Testen schrijven + +### Klassieke Unit testen + +Frameworks gebruiken zoals jQuery's [QUnit](http://docs.jquery.com/Qunit) die het makkelijk maken modulair te testen: + +```javascript +test("dit zou dat moeten doen blabla", function() { + equal(expected, actual); + ok(someThingExpectedToBeTrue); +}); +``` + +Mocking van bijvoorbeeld `$` mogelijk via [MockMe](http://johanneslink.net/projects/mockme.html), een door Mockito geïnspireerde Javascript Object spy API. Iets van: + +```javascript +when(f)('in').thenReturn('out'); +assertEqual('out', f('in')); +``` + +:exclamation: Vereist `Prototype JS`, en `JsUnit` om de `assert` functions te kunnen gebruiken + +### Gedrag testen met Jasmine + +Inspiratie van de *Ruby* community gehaald, met name **RSpec**-based.

+Frameworks gebruiken zoals [Jasmine](http://pivotal.github.com/jasmine/) ((Niet afhankelijk van andere JS Frameworks, vereist geen DOM dus geen Envjs nodig serverside!)): + +```javascript +describe("Rekenmasjien", function() { + it("should add one number", function() { + var calc = new Calc(0); + expect(calc.increase()).toEqual(1); + }); +}); + +``` + +Krachten: + * Schrijf code door *expectations* ([Matchers vbs](https://github.com/pivotal/jasmine/wiki/Matchers)) op te bouwen, in dezelfde trand als `FESTAssert`. + * Bundel expectations in een suite ("beschrijvend") + * Schrijf makkelijk extenties om eigen expectation functions op te bouwen als de standaard API niet volstaat + * `beforeEach()` en `afterEach()` functions binnen suites + * Snel disablen van testen via `xit()` (`@Ignore` zogezegd) + * **mocking** en **spying** heel eenvoudig mogelijk: zie https://github.com/pivotal/jasmine/wiki/Spies + * Plugins voor reporting, custom matching, ... + +Zwakheden: + * Async testen vereist `waitsFor()` ea. Zie onder + * Vereist specRunner.html files, standaard altijd in een browser runnen. **Genereer specRunners**! + +Betere matchers speciaal voor jQuery ea zijn beschikbaar: https://github.com/velesin/jasmine-jquery + +##### Aynschrone code testen + +Zie async stuff + +##### Jasmine integreren met jsTestDriver + +Zie http://skaug.no/ingvald/2010/10/javascript-unit-testing.html + +Er is een **Jasmine adapter** beschikbaar: https://github.com/ibolmo/jasmine-jstd-adapter + +Het kan ook handig zijn om een **Junit XML Reporter** te gebruiken om bijvoorbeeld voor Hudson het makkelijker te maken om de test output files te verwerken. Er zijn reeds enkele reporter plugins zoals deze beschikbaar, hier: https://github.com/larrymyers/jasmine-reporters + +:exclamation: Integratie met Hudson, EnvJS en Rhino ea: zie eigen junit test runner: https://github.com/jefklak/jasmine-junit-runner + +### Andere JS Test frameworks + +Interessante links: + + 1. http://tddjs.com/ + 2. [Stack overflow: Looking for a better Javascript unit test tool](http://stackoverflow.com/questions/300855/looking-for-a-better-javascript-unit-test-tool) + 3. + +## Testen automatiseren + +### Distributed testing in-browser + +#### jsTestDriver + +http://code.google.com/p/js-test-driver/ + +Wat doet dit? + * Een jar dat een **server** opstart die een browser bestuurt en bepaalde __JS__ files (uw testen en uw productiecode) automatisch inlaadt en uitvoert + * Bevat een API met asserts + * Reportgeneratie met plugins voor eclipse om ze JUnit-like te tonen + * Integratie met build etc mogelijk + * Integratie met Jasmine mogelijk: https://github.com/ibolmo/jasmine-jstd-adapter + +**jsTestDriver integreren met Hudson** + +Zie http://cjohansen.no/en/javascript/javascript_continuous_integration_with_hudson_and_jstestdriver + +Het komt eigenlijk hierop neer: maak een nieuw target, voer extern dit commando uit: + +``` +java -jar test/JsTestDriver-1.2.2.jar
+ --config jsTestDriver.conf
+ --server http://localhost:4223 + --tests all --testOutput . --reset +``` + +Dit neemt aan dat de server reeds gestart is, kan met een shell script op de Hudson server bak: `java -jar test/JsTestDriver-1.2.2.jar --port 4223`. + +#### JsUnit Server + +http://www.jsunit.net/documentation/index.html + +Wat doet dit? + * Een jar dat een **Jetty Server** opstart die een browser bestuurt en bepaalde __HTML__ files inlaadt en uitvoert, waar testen in zitten + * Afhankelijk van `Prototype JS` om asserts uit te voeren + * Integratie met ant zeer eenvoudig + +#### TestSwarm + +Zie http:*swarm.jquery.org/ en https:*github.com/jquery/testswarm/wiki + +### Headless testen + +#### Mogelijkheid 1: EnvJS + +*EnvJS* is een *gesimuleerde* browser omgeving geschreven in JS. Zie http://www.envjs.com/ + +__Voordeel__: heel snel + +__Nadeel__: `Java` ofzoiets nodig om JS te evalueren (**Rhino** of **V8** in C++ van Google), plus kan onregelmatigheden vertonen met hevig gebruik maken van UI frameworks -> dit zou moeten werken allemaal, maar het blijft een gesimuleerde omgeving. + +:exclamation: Zie https://github.com/jefklak/jasmine-junit-runner + +Integreren met hudson als extern commando: + +``` +java -cp lib/envjs/js.jar:lib/envjs/jline.jar org.mozilla.javascript.tools.shell.Main -opt -1 -f lib/envjs/envjs.bootstrap.js -f test.js +``` + +`test.js` heeft dan maar 1 regel die naar de juiste specRunner.html gaat met `window.location`. + +#### Mogelijkheid 2: Qt Webkit widget + +*Webkit* is een opensource web renderer, en er is een implementatie in `Qt` beschikbaar (vereist libs geïnstalleerd te hebben). Zie http://trac.webkit.org/wiki/QtWebKit + +__Voordeel__: gedrag volledig in een "echte" website rendered, in plaats van via een omweg. Aangezien het een Qt Widget is, hoeft het niet expliciet op het scherm gerendered te worden (dit pollt gewoon totdat bvb *"Jasmine tests run"* ofzoiets van tekst verschijnt, om dan de HTML te retourneren als resultaat. + +__Nadeel__: Qt libs vereist, nog altijd niet volledig "headless", aparte widget spec runner in de achtergrond die draait. + +Zie http://johnbintz.github.com/jasmine-headless-webkit/ (Implementatie in Ruby met nogal veel nadruk op gems ea... Handig?) + +[Phantom JS](http://www.phantomjs.org/) is een full stack headless browser implementatie gebaseerd op WebKit (C++/Python implementatie). + +# Pitfalls + +:exclamation: Gebruik aub **[JSLint](http://www.jslint.com)** om onderstaande "probleempjes" makkelijker te kunnen tracen en aanpassen. + +[Strict mode](https://developer.mozilla.org/en/JavaScript/Strict_mode) in ECMA5 is ook iets héél handig. + +-> Meer (al dan niet grappige) pitfalls/weetjes: http://www.wtfjs.com/ + +### Objecten + +Javascript gebruikt intern de `toString()` functie wanneer objecten als keys worden toegekend. Dit wil zeggen dat eigenlijk de string representatie als key gebruikt wordt. Bijvoorbeeld: + +```javascript +var obj = {}; +var key1 = new Object(); +var key2 = new Object(); + +obj[key1] = "hi"; +obj[key2] = "yo"; + +console.log(obj[key1]); // ##### yo??? +``` + +#####= arguments #####= + +##### arguments on-the-fly veranderen ##### + +Zonder `use strict` (ES5) kan je een binnenkomend argument ook toekennen aan een andere waarde. Hierdoor verandert de waarde van `arguments[0]`! De `arguments` lijst houdt dus een pointer bij naar de variabele die de value van het argument vasthoudt, en niet naar de value zelf. In strict mode wel. Voorbeeld: + +```javascript +function bla(a) { + a = 5; + console.log(arguments[0]); +} +bla(1); // 5, in strict mode 1 +``` + +##### arguments is geen array ##### + +Snel "effe" lopen over alle argumentjes: + +```javascript +function aha() { + arguments.forEach(function(itm) { // syntax error ??? + console.log(itm); + }); +} +aha(1, 2, 3); +``` + +Inderdaad: `Array.isPrototypeOf(arguments) ##### false`. Dus de `.length` property werkt op een andere manier, en van die hidden `.callee` dingen (die niet werken in strict mode) zitten er ook op... + +Oplossing: + +```javascript +function aha() { + var args = Array.prototype.slice.call(arguments); + args.forEach(function(itm) { + console.log(itm); + }); +} +aha(1, 2, 3); +``` + +#####= Falsey values #####= + +De volgende values evalueren allemaal naar `false` in bvb een `if()` block: + + 1. `null` + 2. `0` als `number` + 3. `""` als `string` + 4. `false` als `boolean` + 5. `undefined` + 6. `NaN` + +Deze dingen lukken ook niet: + +```javascript +if(new Boolean(false)) { + alert("ik ben false jong!"); // oei tis nie waar hé? +} +``` + +Mogelijke Oplossingen: + 1. gebruik altijd `.valueOf()` van de object counterparts van alle primitives! + 2. gebruik `Boolean(false)` (zonder new), zie [Mozilla Boolean Dev docs](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Boolean) + +Lees hier meer over in [The secret life of Javascript Primitives](http:*javascriptweblog.wordpress.com/2010/09/27/the-secret-life-of-javascript-primitives/) en [the value of valueOf](http:*javascriptweblog.wordpress.com/2010/05/03/the-value-of-valueof/). + +#####= Typecasting #####= + +^ code ^ resultaat ^ +| [] + 23 | de string "23" | +| [1, 2] + 23 | de string "1, 223" | +| false + 23 | het getal 23 | +| true + 23 | het getal 24 | +| "kadootje" + 23 | de string "kadootje23" | +| undefined + 23 | NaN | +| null + 23 | het getal 23 | + +#####= Parsing #####= + +`parseInt("08")` neemt automatisch aan dat de waarde naar octal values omgezet moet worden. Dit evalueert naar het getal `0`.

+Oplossing: `parseInt("08", 10)` - het tweede argument geeft de eenheid aan (10 = decimaal). + +#####= de wereld breken (undefined) #####= + +`undefined` is een toplevel variabele die als value de primitive value `undefined` heeft.

+Zodra je `undefined` (de variabele) toekent aan iets anders, is die primitive value weg en is alles naar de zak. Voorbeeld: + +Dit is opgelost in ECMA5 door sommige properties al dan niet writable te maken. `undefined` is daar dus readonly. Check dit in Firefox 4: + +```javascript +var undefinedProps = Object.getOwnPropertyDescriptor(window, "undefined") +undefinedProps.writable ##### false; // locked down! +``` + +#####= Javascript en puntkomma's #####= + +Geen enkele lijn hoeft een `;` te bevatten, javascript voegt deze automatisch toe bij het evalueren. Dit kan ook miserie veroorzaken: + +```javascript +function geefIets() { + return + { + iets: "wow" + }; +} + +geefIets(); // undefined: unreachable code! +``` + +Los dit op door de accolade na de return te plaatsen in plaats van de newline. + +#####= ECMA5: map, forEach, filter: de 3 parameters #####= + +Sinds ECMA5 is het héél handig om bijvoorbeeld voor een array van strings elk element individueel te manipuleren en een nieuwe array terug te geven.

+Stel, ik wil `string`s naar `number`s omvormen: + +```javascript +["1", "2", "3"].map(parseInt); // returns [1, NaN, NaN ] ??? +``` + +Whoops? `parseInt` heeft als tweede variabele de eenheid (decimaal, hexa, ...) en alle array manipulatie functies geven altijd 3 argumenten mee: het element, de index en de array zelf. Conflict! + +Oplossing: closures! + +#####= Arrays zijn "speciale" associatieve objecten #####= + +Dit zegt de [http:*bclary.com/2004/11/07/#a-15.4ECMAScript specificatie](http:*bclary.com/2004/11/07/#a-15.4ECMAScript specificatie): + +> Array objects give special treatment to a certain class of property names. A property name P (in the form of a string value) is an array index if and only if **ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal to 2^32 - 1**. Every Array object has a length property whose value is always a nonnegative integer less than 2^32. The value of the length property is numerically greater than the name of every property whose name is an array index; whenever a property of an Array object is created or changed, other properties are adjusted as necessary to maintain this invariant. Specifically, whenever a property is added whose name is an array index, the length property is changed, if necessary, to be one more than the numeric value of that array index; and whenever the length property is changed, every property whose name is an array index whose value is not smaller than the new length is automatically deleted. This constraint applies only to properties of the Array object itself and is unaffected by length or array index properties that may be inherited from its prototype. + +Dat wil zeggen dat: + + 1. zodra de `.length` property gewijzigd wordt, er verschillende dingen gebeuren: + 1. Indien kleiner wordt: alle properties kleiner dan de lengte worden automatisch verwijderd + 2. Indien groter wordt: allemaal nieuwe elementen met `undefined` als value (*impliciet*!) + 2. Alle "integer" values (zie geweldige formule) zijn "speciale" properties die de `length` property ook aanpassen. + +Wat gebeurt er als ik de `length` property boven het maximum zet? + +```javascript +var arr = [1]; +arr.length = Math.pow(2, 32) - 1; // max allowed +arr.length++; // RangeError: invalid array length (na lang denken van de parser) +``` + +:exclamation: de `length` property wordt gebruikt door utility functies zoals `push`, `concat` etc, dus als deze niet correct werkt zoals hierboven beschreven gebeuren en vreemde dingen! + +Meer info: zie [How to subclass an Array](http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/) \ No newline at end of file diff --git a/content/post/python-basics.md b/content/post/python-basics.md new file mode 100644 index 00000000..2f685ce9 --- /dev/null +++ b/content/post/python-basics.md @@ -0,0 +1,215 @@ ++++ +title = "Python Class structure basics" +subtitle = "A crash course in Python classes" +draft = false +archived = true +tags = [ + "python", + "ruby", + "classes" +] +date = "2013-10-01" ++++ + +Handy links: + + * [special class methods like _ _getattr_ _ and _ _new_ _](http://www.diveintopython.net/object_oriented_framework/special_class_methods2.html) + * [dive into python - native datatypes](http://www.diveintopython3.net/native-datatypes.html#tuples) + * [Inside story on new style classes](http://python-history.blogspot.be/2010/06/inside-story-on-new-style-classes.html) - ter info: Python3 heeft **enkel** "newstyle" classes! + +### Method overriding + +Is **niet mogelijk**. Gebruik default values! + +```python +def func(i, j = 2, k 3): + return i + j + k + +func(1) # 6 +func(1, 1) # 5 +func(1, 1, 1) # 3 +``` + +Wat wel gaat, evt met decorators, zie [Five-minute multimethods in Python](http://www.artima.com/weblogs/viewpost.jsp?thread=101605) - is `__call__` implementeren en dan met metaprogrammeren te loopen over alle methods en te kijken of de argumenten overeen komen met het type dat required is. Fancypancy! + +##### Opgelet met pitfalls + +**Nummer 1**: default variables worden herbruikt: + +> When Python executes a “def” statement, it takes some ready-made pieces (including the compiled code for the function body and the current namespace), and creates a new function object. When it does this, it also evaluates the default values. [...] Another way to reset the defaults is to simply re-execute the same “def” statement. Python will then create a new binding to the code object, evaluate the defaults, and assign the function object to the same variable as before. But again, only do that if you know exactly what you’re doing. + +Default als `arr = []` Gaat de array muteren. Heel handig voor memoization, heel verwarrend anders. Oplossing? `arr None` en dan `arr = [] if arr is None`. + +Zie ook [Default parameter values in Python](http://effbot.org/zone/default-values.htm) voor in-depth uitleg. + +**Nummer 2**: *Python’s nested scopes bind to variables, not object values*. + +```python +for i in range(10): + def callback(): + print "clicked button", i + UI.Button("button %s" % i, callback) +``` + +variabele `i` gaat altijd 9 zijn - wordt niet op value gebind. Oplossing is explicit binding door de functie definitie van `callback():` te veranderen naar `callback(i=i):`. + +### Fields dynamisch definiëren + +`Thing(a=1, b2)` kan op een paar manieren gedefiniëerd worden. + +##### fields expliciet declareren + +```python +class Thing: + def __init__(self, a, b): + self.a, self.b = a, b +``` + +##### dynamisch uw eigen dictionary updaten + +```python +class Thing: + def __init__(self, **kwargs): + self.__dict__.update(kwargs) +``` + +:exclamation: Dit is uiteraard heel gevaarlijk aangezien het al uw method bodies kan vervangen door een param value. BOEM. + +`* *name`(zonder spatie, wiki markup, nvdr) geeft alle argumenten in een [dict](http://docs.python.org/2/library/stdtypes.html#typesmapping) terug. `*name` gaat ook, geeft u een lijst van argumenten terug. Combinatie gaat ook, één ster moet voor de tweede komen. Zoiets is dus mogelijk: `def _ _init_ _(self, arg1, arg2, *allargs, * *allargsasdict)`. + +##### Alles als een message passing systeem zien + +In Ruby is er een andere manier om `def name block end` te schrijven, hoe het geïnterpreteerd wordt: `self.class.send(:name, args) { block }` + +```ruby +def opt_to_s opt={} + opt.empty? ? '' : ' ' + opt.map {|e,v| "#{e}=
"#{v}
""}.join(', ') +end + +[:html, :body, :h1].each do |el| + start="<#{el}" + fin="" + self.class.send(:define_method, el) {|options={}, &blk| start + opt_to_s(options) + '>' + blk.call + fin} +end + +# Now, we can neatly nest tags and content +html do + body do + h1 :class=>"bold-h1", :id>"h1_99" do + "header" + end + end +end + => "

"bold-h1
", id=
"h1_99
">header

" +``` + +Voilà, een DSL in no-time. Holy crap. [Bron: do you understand ruby's objects messages and blocks?](http://rubylearning.com/blog/2010/11/03/do-you-understand-rubys-objects-messages-and-blocks/) + +### Superclassing + +Klassen aanmaken is niet al te moeilijk, maar een call uitvoeren naar de overridden method is iets minder evident: zie [super() in python docs](http://docs.python.org/2/library/functions.html#super) + +Een voorbeeld van een custom http handler: + +```python +class HttpHandler(SimpleHTTPRequestHandler): + def readStatus(self): + return { + "Status": "blabla", + "StartTime": "" + } + + def do_GET(self): + try: + print('serving %s now' % self.path) + if "status.json" in self.path: + self.send_response(200) + self.send_header('Content-type', 'text/json') + self.end_headers() + self.wfile.write(json.dumps(self.readStatus()).encode()) + else: + SimpleHTTPRequestHandler.do_GET(self) + + except IOError: + self.send_error(500, 'internal server error in server python source: %s' % self.path) + +``` + +Wat is hier speciaal aan: + + * `super.do_GET(self)` => `SimpleHTTPRequestHandler.do_GET(self)` + * eigen method aanroepen: `self.readStatus()` met de `self` prefix + +#### Diamond inheritance + +`BaseClass.method()` is impliciet hetzelfde als `super().method()`, behalve dat je met `super` een argument kan meegeven, over welke superklasse het gaat. + +Zie ook [Things to know about Python's super()](http://www.artima.com/weblogs/viewpost.jsp?thread=236275) + +### Closures en lambda's + +functies in functies aanmaken werkt perfect, "closed over" die lexicale scope, net zoals je zou verwachten zoals bijvoorbeeld in javascript: + +```python + def readBuildStatus(self): + html = urllib.request.urlopen("http://bla/lastbuildstatus.htm").read().decode() + def extractVersion(): + versionString = "Version: " + versionIndex = html.find("Version: ") + return html[versionIndex + len(versionString) : versionIndex + len(versionString) + len("YYYY.MM")] + def extractStatus(): + return "Succeeded" if html.find("SUCCESS") != -1 else "Failed" +``` + +de twee andere methods lezen de `html` variabele uit. Hier hoef je geen `self.` prefix te gebruiken, binnen de `readBuildStatus()` functie zelf - hierbuiten zijn de closures verdwenen natuurlijk (out of scope). + +## unittest module + +Spreekt voor zich: + +```python +import unittest +from calculator import Calculator + +class TestCalculator(unittest.TestCase): + + def setUp(self): + self.calc = Calculator().calculate; + + def test_calculateBasicNumberReturnsNumber(self): + self.assertEqual(3, self.calc('3')) + + def test_calculateSimpleMultiplicationReturnsResult(self): + self.assertEqual(10, self.calc('5*2')) + + def test_calculateInvalidStringShouldThrowException(self): + self.assertRaises(ValueError, self.calc, ('blabl')) +``` + +Zie http://docs.python.org/3/library/unittest.html + + * `setUp` wordt automatisch aangeroepen. Beforeclass, aftereach etc etc bestaat ook. + * alle methods met `test_` worden automatisch herkend. + +#### Hoe voer ik dit nu uit? + +Dit stuk onder uw py file plakken: + +```python +if __name__ == '__main__': + unittest.main() +``` + +En dan `python -m unittest -v calculatorTest`. de v flag geeft wat extra output, anders staat er gewoon OK. De test op zich builden in bijvoorbeeld sublime met de main method erin zorgt er ook voor dat deze automatisch uitgevoerd wordt. + +#### automatic test case discovery #### + +`python -m unittest discover` gaat alle unit testen vanaf huidig dir scannen en uitvoeren (instelbaar met params). Moet voldoen aan: + + 1. extenden van `unittest.TestCase` + 2. voldoen aan python module structuur. Testen in files met prefix "test_x.py". + 3. Indien in subfolder "test": vergeet geen "__init__.py" file. + +##### autotest ##### + +Mogelijk met onder andere `autonose` (nose is een alternatief voor unittest) en `sniffer`. Om die te installeren moet je via de pip package manager gaan, en dan gewoon sniffer uitvoeren in uw base directory. \ No newline at end of file diff --git a/content/post/ruby-classes.md b/content/post/ruby-classes.md new file mode 100644 index 00000000..7fcc1b0f --- /dev/null +++ b/content/post/ruby-classes.md @@ -0,0 +1,105 @@ ++++ +title = "Ruby Class structures basics" +subtitle = "A look at ruby's lambda's" +draft = false +archived = true +tags = [ + "ruby", + "classes" +] +date = "2013-10-01" ++++ +# Ruby Classes + +### Closures and lambda's + +Weer 4 verschillende mogelijkheden in Ruby, zie [Proc and Lambda in Ruby](http://techspry.com/ruby_and_rails/proc-and-lambda-in-ruby/) + +##### Native "blocks" aanmaken + +Is niet mogelijk. `a = { puts "hello" }` geeft een Syntax error; dit moet effectief met `Proc.new` gebeuren. + +##### Lambdas aanmaken + +Kan ook weer op twee manieren: + +```ruby +a = lambda { puts "hello" } +b = -> { puts "hello" } +``` + +##### Blocks als argumenten doorgeven + +Wordt slechts één aanvaard, `Proc`s zijn objecten en kan dus op eender welke manier. Een block is eerder deel van de taal als syntax. (zoals bij `do`) + +##### Een lambda is een Proc + +Met twee grote verschillen (zie [What is the difference between a block, a proc and a lambda in ruby?](http://awaxman11.github.io/blog/2013/08/05/what-is-the-difference-between-a-block/)): + + 1. een `lambda` controleert argumenten, een `Proc` kan het niet schelen. + 2. een `return` statement in een `lambda` stopt slechts de closure. In een `Proc` stopt het de hele enclosing method :exclamation: + +```ruby +def proc_test + proc = Proc.new { return } + proc.call + puts "Hello world" +end + +proc_test # calling proc_test prints nothing +``` + +### Class methods + +Zie [Class and instance methods in Ruby](http://www.railstips.org/blog/archives/2009/05/11/class-and-instance-methods-in-ruby/). Er zijn verschillende manieren om een class method te maken in ruby: + +```ruby +# Way 1 +class Foo + def self.bar + puts 'class method' + end +end + +Foo.bar # "class method" + +# Way 2 +class Foo + class << self + def bar + puts 'class method' + end + end +end + +Foo.bar # "class method" + +# Way 3 +class Foo; end +def Foo.bar + puts 'class method' +end + +Foo.bar # "class method" +``` + +Instance methods worden met `def name` gedefiniëerd, zoals men intuïtief zou aannemen (wow). + + +### "Reflectie": Methods accessen + +Dit kan op twee manieren: op een object **instance** of op een **class**, met `.method` of `.static_method`, zie [Ruby Method doc](http://www.ruby-doc.org/core-2.1.1/Method.html). + +```ruby +1.method(:+).call 2 # output: 3 +Fixnum.static_method(:+).bind(1).call 2 # output: 3 +1.method("+").unbind().bind(1).call(2) # output: 3 +``` + +Object Methods zijn al gebind en kan je dus losmaken van hun reference indien gewenst - zelfde effect als de `static_method` call. Je kan blijkbaar zowel een string als een ref meegeven om de naam van de method te resolven. + +##### Ik wil meer + +`1.methods.each{|x| puts x}` + +of `.static_methods` natuurlijk. Enkel public of protected, ook van subklassen. \ No newline at end of file diff --git a/content/post/scheme.md b/content/post/scheme.md new file mode 100644 index 00000000..ebf827c0 --- /dev/null +++ b/content/post/scheme.md @@ -0,0 +1,85 @@ ++++ +title = "Scheme tips and tricks" +subtitle = "Unit testing in Scheme" +archived = true +draft = false +tags = [ + "scheme", + "Unit Testing" +] +date = "2013-10-01" ++++ + +### Variable arguments + +Bron: http://www.cs.utexas.edu/ftp/garbage/cs345/schintro-v14/schintro_68.html + +```scheme +(define (stack . args) + (display args)) + +(define (plus a b) + (stack a b) + (+ a b)) + +(plus 1 2) +``` + +Print in een lijst `(1 2)` af. In scheme is het mogelijk om args op te splitsen, alles dat na de "." komt, wordt samengenomen als een lijst in een speciale variabele die de rest van de argumenten binnen pakt. Je kan dus ook x aantal argumenten "vast" zetten en de rest laten opvangen door een lijst. `display` print alles in lijst vorm af. + +### Conditional Expressions and Predicates + +##### Debugging purposes + + * `(display arg)` print argument in de `*scheme*` buffer af. (pakt een **lijst** binnen: bvb `(display '("bezig met afdrukken van " arg1 arg2))` + * `(newline)` maakt een nieuwe lijn in diezelfde buffer. + +##### de 'undefined' variabele + +Een conditional operator die door alle gevallen heen valt (zoals een switch zonder default), retourneert de variabele **unspecific**. Dit is een reserved keyword: + +```scheme +(load "./test-manager/load.scm") + +(in-test-group conditionals + (define x 0) + (define-test (case-fall-through-returns-undefined) + (assert-equals unspecific + (cond ((< x 0) 1) + ((> x 0) 1))) + )) + +(run-registered-tests) +``` + +Het is niet mogelijk om die variabele te overschrijven met `(define unspecific 8934)`, volgende fout wordt dan gegenereerd: "Premature reference to reserved name: unspecific." + +### Implementaties + + * MIT-Scheme: http://www.gnu.org/s/mit-scheme/ -> ingebouwde emacs evaluator + * Racket: http://racket-lang.org/ + +### Testen schrijven + +Testing framework: Zie http://web.mit.edu/~axch/www/testing-1.2.html + +Inladen test-manager & testen definen en kunnen wrappen in elkaar à-la Jasmine in JS: + +```scheme +(load "./test-manager/load.scm") + +(in-test-group my-first-tests + + (in-test-group getallekes + + (define-test (add-simple-numbers) + (assert-equals (my-add 1 2) 3))) + + (in-test-group meer-getallekes + (define-test (add-more-complex-numbers) + (assert-equals (my-add 3 7) 10)))) + +(run-registered-tests) +``` + +Achteraf altijd **`run-registered-tests`** evalueren, in de default scheme editor wordt dan de test output getoond. (Default editor = **scheme***, gewoon enter drukken bij open doen nieuwe editor) \ No newline at end of file diff --git a/content/post/scons-building.md b/content/post/scons-building.md index 60f3865f..0ccff8e1 100644 --- a/content/post/scons-building.md +++ b/content/post/scons-building.md @@ -148,3 +148,134 @@ Things to note: So where does that leave us? Yes there's still "syntax" to be learned, even if you're a seasoned python developer; you need to know which function to use for what, that's what the excellent [scons doc](http://www.scons.org/doc/2.3.1/HTML/scons-user.html) is for. I know it made my life a lot easier while trying to do something simple and this is only the tip of the iceberg. Scons is relatively popular according to Stack Overflow, the documentation is excellent and if all else fails you can write your own garbage in a full-fledged dynamic language. The only really irritating bit is the python 2.7 dependency, so don't forget to use [virtualenv](https://pypi.python.org/pypi/virtualenv). + +# In practice + +The section below contains practical snippets used by myself in some point in the past, commented in Dutch. Feel free to grab a piece. + + 1. [SCons Wiki Frontpage](http://www.scons.org/wiki/FrontPage) + 2. [Single HTML Manpage](http://www.scons.org/doc/HTML/scons-man.html#lbAF) + 3. [SCons Construction Variables](http://www.scons.org/doc/0.96.90/HTML/scons-user/a3061.html) om bvb de compiler te specifiëren. + +### Opsplitsen SConstruct en SConscript + +Waarom? http://www.scons.org/doc/2.1.0/HTML/scons-user/c3356.html + +Build output definiëren, duplicate source files, etc. Voorbeeld `SConstruct` file: + +```python +SConscript('SConscript', variant_dir######'build', duplicate0) +``` + +Voorbeeld file om Google Test mee te (proberen) builden `SConscript`: + +```python +def Glob( pattern ###### '*.*', dir '.' ): + import os, fnmatch + files = [] + for file in os.listdir( Dir(dir).srcnode().abspath ): + if fnmatch.fnmatch(file, pattern) : + files.append( os.path.join( dir, file ) ) + return files + +# construction variables: http://www.scons.org/doc/0.96.90/HTML/scons-user/a3061.html +env ###### Environment(CXX 'g++', + CPPPATH = '../:./include') + +# add to library search path env.Append(LIBPATH = ['/usr/local/lib/']) +# add to libraries link path env.Append(LIBS = ['SDL_image','GL']) + +env.Append(CPPFLAGS = ['-isystem ./include']) +env.Append(CXXFLAGS = ['-g', '-Wall', '-Wextra', '-pthread']) + +env.SharedLibrary(target ###### 'gtest_main.dll', source ['../src/gtest-all.cc']) + +# after that, we should link with gtest_main +``` + +Poging tot converteren van deze voorbeeld `Makefile` - supplied bij de gtest sources: + +``` +# A sample Makefile for building Google Test and using it in user +# tests. Please tweak it to suit your environment and project. You +# may want to move it to your project's root directory. +# +# SYNOPSIS: +# +# make [all] - makes everything. +# make TARGET - makes the given target. +# make clean - removes all files generated by make. + +# Please tweak the following variable definitions as needed by your +# project, except GTEST_HEADERS, which you can use in your own targets +# but shouldn't modify. + +# Points to the root of Google Test, relative to where this file is. +# Remember to tweak this if you move this file. +GTEST_DIR = .. + +# Where to find user code. +USER_DIR = ../samples + +# Flags passed to the preprocessor. +# Set Google Test's header directory as a system directory, such that +# the compiler doesn't generate warnings in Google Test headers. +CPPFLAGS += -isystem $(GTEST_DIR)/include + +# Flags passed to the C++ compiler. +CXXFLAGS += -g -Wall -Wextra -pthread + +# All tests produced by this Makefile. Remember to add new tests you +# created to the list. +TESTS = sample1_unittest + +# All Google Test headers. Usually you shouldn't change this +# definition. +GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h
+ $(GTEST_DIR)/include/gtest/internal/*.h + +# House-keeping build targets. + +all : $(TESTS) + +clean : + rm -f $(TESTS) gtest.a gtest_main.a *.o + +# Builds gtest.a and gtest_main.a. + +# Usually you shouldn't tweak such internal variables, indicated by a +# trailing _. +GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS) + +# For simplicity and to avoid depending on Google Test's +# implementation details, the dependencies specified below are +# conservative and not optimized. This is fine as Google Test +# compiles fast and for ordinary users its source rarely changes. +gtest-all.o : $(GTEST_SRCS_) + $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c
+ $(GTEST_DIR)/src/gtest-all.cc + +gtest_main.o : $(GTEST_SRCS_) + $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c
+ $(GTEST_DIR)/src/gtest_main.cc + +gtest.a : gtest-all.o + $(AR) $(ARFLAGS) $@ $^ + +gtest_main.a : gtest-all.o gtest_main.o + $(AR) $(ARFLAGS) $@ $^ + +# Builds a sample test. A test should link with either gtest.a or +# gtest_main.a, depending on whether it defines its own main() +# function. + +sample1.o : $(USER_DIR)/sample1.cc $(USER_DIR)/sample1.h $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1.cc + +sample1_unittest.o : $(USER_DIR)/sample1_unittest.cc
+ $(USER_DIR)/sample1.h $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1_unittest.cc + +sample1_unittest : sample1.o sample1_unittest.o gtest_main.a + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ +``` diff --git a/content/post/unix-cmd.md b/content/post/unix-cmd.md new file mode 100644 index 00000000..231d79f1 --- /dev/null +++ b/content/post/unix-cmd.md @@ -0,0 +1,500 @@ ++++ +title = "Heavily used Unix Commands" +subtitle = "Unix Commandline stuff in here!" +draft = false +archived = true +tags = [ + "unix", + "cmd" +] +date = "2013-10-01" ++++ + +### Binaries zoeken + +Kan met `whereis`, **maar** die zoekt blijkbaar niet in "alle" binary dirs - enkel degene die geconfigureerd zijn onder: + +``` +sysctl user.cs_path +# output: user.cs_path = /usr/bin:/bin:/usr/sbin:/sbin +``` + +### Shell automatisation + +Command-line programs *feeden* kan met het `expect` tooltje. Bijvoorbeeld, bij het aanloggen in `ssh` moet je daarna een wachtwoord geven en op enter drukken dat niet als commandline argument meegegeven kan worden. Dit kan je dan zo forceren: + +``` +#!/usr/bin/expect -f +# Expect script to supply root/admin password for remote ssh server +# and execute command. +# This script needs three argument to(s) connect to remote server: +# password = Password of remote UNIX server, for root user. +# ipaddr = IP Addreess of remote UNIX server, no hostname +# scriptname = Path to remote script which will execute on remote server +# For example: +# ./sshlogin.exp password 192.168.1.11 who +# ------------------------------------------------------------------------ +# Copyright (c) 2004 nixCraft project +# This script is licensed under GNU GPL version 2.0 or above +# ------------------------------------------------------------------------- +# This script is part of nixCraft shell script collection (NSSC) +# Visit http://bash.cyberciti.biz/ for more information. +# ---------------------------------------------------------------------- +# set Variables +set password [lrange $argv 0 0] +set ipaddr [lrange $argv 1 1] +set username [lrange $argv 2 2] +set timeout -1 +# now connect to remote UNIX box (ipaddr) with given script to execute +spawn ssh $username@$ipaddr +match_max 100000 +# Look for passwod prompt +expect "*?assword:*" +# Send password aka $password +send -- "$password
r" +# send blank line (
r) to make sure we get back to gui +send -- "
r" +expect eof +``` + +([bron](http://nixcraft.com/shell-scripting/4489-ssh-passing-unix-login-passwords-through-shell-scripts.html)) - voor meer uitleg zie {{< wp "Expect" >}} wiki. + +### Synchronizing/backupping/file copying + +Gebruik het `rsync` commando om incrementeel een kopie te nemen van een directory en alle subdirs van plaats1 naar plaats2. Dit kan lokaal, naar een externe HDD of zelfs via een server. `rsync` heeft ook een daemon mode die je aan kan zetten met `--daemon` - Zie [rsync man](http://www.samba.org/ftp/rsync/rsync.html). Het belangrijkste commando is zonder twijfel: + +``` +$ rsync -auv -E -W --del [src] [dest] +``` + +Opties: + + * `-a`: archive mode: auto-enable een hoop andere opties (keep timestamps etc) + * `-u`: update (incremental mode) + * `-v`: verbose + * `-E`: preserve executability (niet nodig onder windows) + * `--del`: delete files die in de source verdwijnen ook in de destination. + +Een extra optie `-z` kan ook compressie over netwerk toevoegen. Verwijder dan best `-W`. + +Je kan periodiek dit commando uit voeren om de destination dir up-to-date te houden. Vergeet niet dat rsync ook een `daemon` mode heeft, met nog veel meer opties! + +### User rechten geven om root te worden + +Probleem bij `su` commando: *su: Sorry for normal user account.* + +Vergeten toe te voegen aan de `wheel` user group, zo doen: + +```pw user mod vivek -G wheel``` + +### Shell editing mode + +Zie http://www.catonmat.net/blog/bash-vi-editing-mode-cheat-sheet/ + +``` +$ set -o vi +``` + +Best opslaan in uw `.bashrc` (of whateverrc) + +-> Tof om te weten: `CTRL+L` **cleart het scherm** van een **terminal** (dit werkt ook voor Cygwin!) + +### Command History + +voorbeeld: + +``` +dir $ history + 1 ls -la + 2 cd ~ + 3 rm somedir +dir $ !2 +~ $ !! +``` + +waarbij ![getal] laatste x commando uitvoert en !! het laatste. Zie `man history` voor geavanceerde voorbeelden. + +### Copy and auto-create dir structure + +Bewaar dit shell script naar cpi.sh: + +```bash +#!/bin/bash +if [ ! -d "$2" ]; then + mkdir -p "$2" +fi +cp -R "$1" "$2" +``` + +`chmod +x cpi.sh` en dan in uw `.bashrc` een link leggen om `cpi` te gebruiken. + +### xargs + +Het bovenstaande kan ook uitgevoerd worden met `xargs` en piping. Bijvoorbeeld bepaalde bestanden (niet-recursief) kopiëren naar "tmp": + +``` +ls | grep .php | xargs -i cp {} ./tmp +``` + +Andere interessante opties van xargs: + + * `-ix`: gebruik `{}` (of `x` karakters indien specified) om lijn per lijn de input te vervangen. Het kan zijn dat dit escaped moet worden met backslashen voor de shell! + * `-0`: gebruik in combinatie met `-print0` en `find` om het verschil tussen spaties en newlines duidelijk te maken + * `-p`: confirm elke actie, interessant bij verwijderen van crutiale files + * `-lx`: gebruik maximum x lijnen input per command line. + * `-nx`: gebruik maximum x argumenten per command line. + * `-t`: verbose mode (`--verbose` werkt ook) + +### sed + +Gebruik `sed` om snel replaces te doen door middel van regex, of door lines te nummeren, ...

+Het is ook mogelijk om regex partities te *groeperen*, vergeet niet de haakjes zelf te escapen! Om de gegroepeerde waarde in het "replace" geteelde te gebruiken, moeten we niet `$1` maar `
1` gebruiken. Bijvoorbeeld: + +``` +sed 's/
(.*
)/regel:
1/g' log.tmp >> $logfile +``` + +Resultaat: + + 1. Replace x door y via `s/regex/replace/` + 2. Replace alle gevonden instanties (`g` na expressie) + 3. Groepeer alles door te zoeken op `.*` en er haakjes rond te plaatsen + 4. Vervang alles door 'regel:' + alles van de groep + +Dus prepend elke regel met 'regel:'. + +-> Groeperen in sed vereist escaped parentheses, anders matchen we exact `(` in de zoekstring zelf! + +##### chainen + +Een keer sed aanroepen en in een sequentie meerdere replaces doen gaat met het `-e` argument (script mode): + +``` +cat file | sed -e 's/replace/by/g' -e 's/other/new/g' +``` + +##### Aan begin van lijnen prependen + +Gebruik het symbool '^' om het begin van een lijn te matchen, en '$' om het einde van een lijn te matchen: + +``` +cat file | sed 's/^
([^=]
)/ *
1/' +``` + +Hier wordt in het begin van elke lijn spatie spatie ster toegevoegd behalve als de lijn begint met het gelijkheidsteken. Omdat we anders het eerste karakter vervangen moeten we die ook capturen! + +-> Zoals in eclipse een getal matchen met `
d` werkt niet, daarvoor moet je `[0-9]` gebruiken. + +### uniq + +Vergelijkt een lijn met de volgende en gooit dubbels eruit. Instelbaar met een beperkt aantal parameters.

+**adjacent matching lines**, meer kan dit ding niet! + +##### sed gebruiken om uniq te emuleren + +Zie http://www.catonmat.net/blog/sed-one-liners-explained-part-three/ voor volledige uitleg + +``` +sed '$!N; /^
(.*
)
n
1$/!P; D' +``` + +##### sed gebruiken om álle dubbels eruit te smijten: buffering + +``` +sed -n 'G; s/
n/&&/; /^
([ -~]*
n
).*
n
1/d; s/
n//; h; P' +``` + +### cut + +Een utility command dat meestal gebruikt wordt om lijnen op te splitsen afhankelijk van een __delimiter__. Bijvoorbeeld: + +``` +cat test.txt | cut -d '|' -f 3 +``` + +meest gebruikte opties: + + * `-d` verplicht, geef delimiter op + * `-f` selecteer enkel deze kolommen + +### Combinatievoorbeeld + +Onderstaand script zoekt in de svn log entries met 'jira' of 'hel' (case insensitive, `-i` grep operator) behalve 'gcl' of 'lvm', print context 1 lijn above en 2 lijnen below, filtert dubbels, haalt de derde kolom eruit gesplitst door '|' (datum), vervangt eender welke hoeveelheid '-' door niets en wrap datums beginnende met 2011 met twee = tekens. + +```bash +#!/bin/sh +datefrom=2011-02-28 +dateto=2011-03-12 +logfile=/cygdrive/c/opt/wamp/www/wiki/data/wiki/helena/svnlog.txt + +pushd /cygdrive/c/opt/hudson/jobs/Helena_build/workspace/burgerlijkestand +echo "### Svn log Helena Trunk " > $logfile +echo ":exclamation: periode **[$datefrom - $dateto]**" >> $logfile +echo "#### Helena Jira's via svn log" >> $logfile +svn --username######cp8tsc --passwordq3Sp8Phu log -r{$datefrom}:{$dateto} | + grep -B 2 -A 1 -i 'HEL-
|jira' | + grep -v 'gcl
|lvm' | + sed -e 's/-*//' -e 's/r[0-9]* .*(
(.*
)).*/#####
1/g' -e 's/^
([^=]
)/ *
1/' | + sed -n 'G; s/
n/&&/; /^
([ -~]*
n
).*
n
1/d; s/
n//; h; P' >> $logfile +popd +``` + + +# Random commands + + * `seq 1 10` print in een sequence getalletjes. + * `head` werkt ook in plaats van `tail`, maar zelfs van een lijst - ge kunt `head 1` van een stream dus gebruiken als pop voor een stack. + * `ftp -i -n [host] << FTP_SCRIPT` newline, een hoop commands, en `FTP_SCRIPT` op het laatste = in 1 regel wat op een ftp server doen. + * `mail -a [attach]` = in 1 regel als attach iets mailen naar iemand (zie `man`) + * `wc` = wordcount; -e enkel lijnen + +## Video converting/concatenating etc + +Met behulp van `ffmpeg` . + +#### Concatting + +Alle files die eindigen op mp4: + +``` +ffmpeg -f concat -i <(printf "file '%s'
n" ./*.mp4) -c copy output.mp4 +``` + +Gaat ook met `mplayer` en de tool `mencoder`: + +``` +mencoder -oac pcm -ovc copy -idx -o all.mp4 1.mp4 2.mp4 3.mp4 4.mp4 5.mp4 +``` + +#### Resizing (compressing) + +Ook met `ffmpeg` - bijvoorbeeld reduceren naar "medium" quality. Neem alle mp4s in folder: + +``` +for i in *.mp4 ; do ffmpeg -i "$i" -c:a copy -preset medium "${i%.*}_medium.${i##*.}"; done +``` + +Voor meer presets zoals "medium", zie http://trac.ffmpeg.org/wiki/x264EncodingGuide + +# Bash Scripting + + +#### Rerun last command + +``` +!! +``` + +Joink. + +#### bash opties uit een shell script halen + +Gepikt van http://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash + +```bash +#!/bin/bash +for i in $* +do +case $i in + -p######*|--prefix*) + PREFIX######`echo $i | sed 's/[-a-zA-Z0-9]*//'` + + ;; + -s######*|--searchpath*) + SEARCHPATH######`echo $i | sed 's/[-a-zA-Z0-9]*//'` + ;; + -l######*|--lib*) + DIR######`echo $i | sed 's/[-a-zA-Z0-9]*//'` + ;; + --default) + DEFAULT=YES + ;; + *) + # unknown option + ;; +esac +done +echo PREFIX = ${PREFIX} +echo SEARCH PATH = ${SEARCHPATH} +echo DIRS = ${DIR} +``` + +Makkelijker dan `getopts()`? + +#### Pipen en multiple lines in shell scripts + +Dit is legale shell code: + +```bash +#!/bin/sh +cat dinges.log | + cut -d ' ' -f 3 + grep 'Exception' | + uniq +``` + +De pipe aan het begin van een nieuwe lijn alleszins niet. Ook `>>` of `>` kan niet het begin zijn van een nieuwe lijn, dan wordt een spatie gepiped naar de outputstream. + +#### array loops + +```bash +names=( Jennifer Tonya Anna Sadie ) +for name in ${names[@]} +do + echo $name + # other stuff on $name +done +``` + +Ook mogelijk om bvb een counter bij te houden met `for (( i = 0 ; i < ${#names[@]} ; i++ ))`. Array waarde accessen met `${names[$i]}`. + +Inline arrays "maken" en over lopen gaat met `for VAR in 'a' 'b' 'c' do ... done`. + +##### argumenten samen rapen in een variabele + +```bash +DIR_EXCLUDES=(eclipsecompiled test bin target) +FILE_EXCLUDES=(messages errors) + +SEARCH="" + +for FILE_EXCLUDE in ${FILE_EXCLUDES[@]} +do + SEARCH="${SEARCH} -not -name *${FILE_EXCLUDE}*" +done +for DIR_EXCLUDE in ${DIR_EXCLUDES[@]} +do + SEARCH="${SEARCH} -not -path *${DIR_EXCLUDE}*" +done +``` + +:exclamation: dit werkt **niet** als er een dubbele quote bij komt kijken in de vorm van `
"` - vreemd? uit te zoeken... + +#### Controleren of een string in een variabele steekt + +Zie http://stackoverflow.com/questions/229551/string-contains-in-bash - makkelijkste manieren zijn + +##### met grep + +```bash +if grep -q '|' <<<$line; then + echo "jup" +fi +``` + +##### met regexp + +```bash +if [[ "$line" =~ "|" ]]; then + echo "jup" +fi +``` + +#### Loopen over alle lijnen van bepaalde output voor verdere processing + +```bash +`cat somefile` | while read line +do + echo "lijn $line" +done +``` + +Dit kan ook maar dan moet je de separator variabele voor `for` aanpassen: + +```bash +IFS=$'
n' +for line in `cat somefile` +do + echo "lijn $line" +done +``` + +:exclamation: By default splitst for **op spaties** + +# Find command + +-> Zie http://northredoubt.com/n/2009/12/30/linuxunixcygwin-find-command/ voor enorm veel uitleg over basics van `find`. + +### Finding stuff + +``` +find / -name "*.ext" -type f -exec [command with args] {}
; +``` + +Bovenstaande lijn zoekt in root directory voor alle .ext bestanden (-type f is standaard, `d` staat voor directory etc, zie manual) en pipet alle resultaten naar een bepaald commando achter `-exec`. `{}` Stelt het gevonden bestand voor (full path), `
;` eindigt het exec commando. De puntkomma wordt escaped door die backslash. + +:exclamation: - Er moet een **Spatie** tussen `{}` en `
;` komen, anders krijgt men een foutmelding: + +> find: missing argument to '-exec' + +### Includen en excluden: filters + +Ik zoek *.properties behalve die en die file en overal behalve in die en die directory: + +``` +find . -name "*.properties" -not -path "*dir*" -not -name "ugly.properties" +``` + +`-not` is te combineren met eender wat én te chainen, bijvoorbeeld met `-size` enzo. + +# Greppin' away + +#### Surrounding lines while greppin' + +Dit heet **lines in context** in *man grep*. + +``` +grep -B 3 -A 2 foo README.txt +``` + +Verklaring: Zoek foo in readme.txt met 3 lijnen boven en 2 lijnen onderaan.

+Indien aantal lijnen gelijk, gebruik simpelweg `-C [x]`. + +#### Inverse grepping + +##### In file contents + +Om te zoeken naar bijvoorbeeld 'hond', maar niet 'kat', moet je inverse zoeken voor kat: + +``` +cat file | grep 'hond' | grep -v 'kat' +``` + +#### Finding pattern a OR b + +Combineren gaat met het pipe character (escaped) `
|` - voorbeeld zoekt naar hond of kat: + +``` +cat file | grep 'hond
|kat' +``` + +:exclamation: Normale manier is `egrep pattern1|pattern2` gebruiken of `grep -E pattern1|pattern2`. + +#### Toon meer info bij context + +``` +grep 'zoekstring' file.bla -n -H +``` + +Print ook line numbers & filename, vooral handig wanneer dit van een `-exec` commando komt van een search, bijvoorbeeld: + +``` +find . -name "*.php" -exec grep 'backlink' {} -C 2 -n -H
; > find_backlinks.txt +``` + + 1. Zoek alle .php files vanaf de current directory + 2. Zoek in alle gevonden files naar 'backlink' + 3. Print 2 bovenste en onderste context lijnen af + 4. Print lijn nummer en prefix met bestandsnaam + 5. Output alles naar find_backlinks.txt + +De `-print` flag bij find print de filename af voor elke gevonden file die naar de `-exec` doorgegeven wordt. + +:exclamation: Onder Solaris een commando uitvoeren met `-exec` moet dit ook nog gewrapped worden met een shell executable, zo: + +``` +find . -name "*.php" -exec sh -c 'grep -n "backlink" $1' {} {}
; -print +``` + +Vergeet niet dat grep ook **andere argumenten** (of volgorde) heeft (eerst flags dan search pattern en file, geen -C option etc)!

+Zie http://www.compuspec.net/reference/os/solaris/find/find_and_execute_with_pipe.shtml

diff --git a/layouts/_default/list.html b/layouts/_default/list.html index d84c3506..03939e54 100644 --- a/layouts/_default/list.html +++ b/layouts/_default/list.html @@ -24,7 +24,13 @@

{{ .Title }}

- {{ .Params.subtitle }}  {{ $.Scratch.Get "subtitle" }} + {{ with .Params.archived }} + Archived + {{ end }} + {{ .Params.subtitle }} + +  {{ $.Scratch.Get "subtitle" }} + {{ end }}