archief vanuit wiki tech ter info

This commit is contained in:
wgroeneveld 2018-05-03 16:09:41 +02:00
parent 9cd26233fb
commit f9379df59d
11 changed files with 3985 additions and 2 deletions

View File

@ -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 <i class='fa fa-copyright'></i> reserved - sharing is caring. <i class='fa fa-github'></i> <a href='https://github.com/wgroeneveld/brainbaking/'>Hack away</a>! <i class='fa fa-lightbulb-o'></i> <a href='/'>Brain Baking</a>"

View File

@ -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 <iostream>
#include <memory>
using namespace std;
int main(int argc, char **argv)
{
int *i = new int;
auto_ptr<int> x(i);
auto_ptr<int> 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 <iostream>
int main()
{
Simple* simple = new Complexer();
std::cout << simple->guessNumber();
delete simple;
}
```
10. Haal `virtual` weg. 5. <br/><br/>
Definiëer `Complexer` zo:
```c
Complexer* complexer = new Complexer();
```
En het is altijd 10.
## Initialisatie
(Voorbeelden van bovenstaande)
```c
#include "complexer.h"
#include <iostream>
int main()
{
Simple simpleInitialized; // oops, I created something?
// Simple simpleInitialized = NULL; cannot convert from 'int' to 'Simple' (#define NULL 0)
Simple* simplePtr;
std::cout << "<br/>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<Type>(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.
<br/><br/> 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<HICON> getIcon(int resourceId);
static RAIIObject<HICON> 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<HICON>(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 TObject>
class RAIIObject
{
public:
explicit RAIIObject(const TObject& obj) : m_Object(obj) {}
RAIIObject() {}
~RAIIObject() {ReleaseObject();}
RAIIObject<TObject>& operator######(const TObject& obj) {if(&obj ! &m_Object) {ReleaseObject(); m_Object = obj;} return *this;}
RAIIObject<TObject>& operator######(const RAIIObject<TObject>& 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<HICON>::ReleaseObject() {::DestroyIcon(m_Object); m_Object = NULL;}
template<> inline void RAIIObject<CBrush>::ReleaseObject() {m_Object.DeleteObject();}
template<> inline void RAIIObject<CBitmap>::ReleaseObject() {m_Object.DeleteObject();}
template<> inline void RAIIObject<CFont>::ReleaseObject() {m_Object.DeleteObject();}
template<> inline void RAIIObject<CMenu>::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 <WinBase.h>
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 <psapi.h>` 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:<br/>Users<br/>bkwog<br/>Documents<br/>Visual Studio 2012<br/>Projects<br/>structArrayExportTest<br/>Debug<br/>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:<br/>Program Files (x86)<br/>Microsoft Visual Studio 10.0<br/>Common7<br/>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`!

View File

@ -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
<img style='float: left;' src='/img//code/c/testing/screenshot.png|'>
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:<br/>gtest<br/>include<br/>gtest<br/>gtest-printers.h(550): error C2977: 'std::tuple' : too many template arguments
1> b:<br/>program files (x86)<br/>microsoft visual studio 2012<br/>vc<br/>include<br/>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?)

View File

@ -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. <br/><br/>
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:<br/><br/>
`"#{dinges} is a dong".interpolate({dinges: "mijn dingetje"}) ###### "mijn dingetje is a dong"`<br/><br/>
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
}
}
```

File diff suppressed because it is too large Load Diff

View File

@ -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 youre 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**: *Pythons 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}=<br/>"#{v}<br/>""}.join(', ')
end
[:html, :body, :h1].each do |el|
start="<#{el}"
fin="</#{el}>"
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
=> "<body><h1 class<br/>"bold-h1<br/>", id=<br/>"h1_99<br/>">header</h1></body>"
```
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.

View File

@ -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.

85
content/post/scheme.md Normal file
View File

@ -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)

View File

@ -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 <br/>
$(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 <br/>
$(GTEST_DIR)/src/gtest-all.cc
gtest_main.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c <br/>
$(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 <br/>
$(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 $@
```

500
content/post/unix-cmd.md Normal file
View File

@ -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 <http://cyberciti.biz/fb/>
# 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<br/>r"
# send blank line (<br/>r) to make sure we get back to gui
send -- "<br/>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, ... <br/><br/>
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 `<br/>1` gebruiken. Bijvoorbeeld:
```
sed 's/<br/>(.*<br/>)/regel:<br/>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/^<br/>([^=]<br/>)/ *<br/>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 `<br/>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. <br/><br/>
**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; /^<br/>(.*<br/>)<br/>n<br/>1$/!P; D'
```
##### sed gebruiken om álle dubbels eruit te smijten: buffering
```
sed -n 'G; s/<br/>n/&&/; /^<br/>([ -~]*<br/>n<br/>).*<br/>n<br/>1/d; s/<br/>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-<br/>|jira' |
grep -v 'gcl<br/>|lvm' |
sed -e 's/-*//' -e 's/r[0-9]* .*(<br/>(.*<br/>)).*/#####<br/>1/g' -e 's/^<br/>([^=]<br/>)/ *<br/>1/' |
sed -n 'G; s/<br/>n/&&/; /^<br/>([ -~]*<br/>n<br/>).*<br/>n<br/>1/d; s/<br/>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'<br/>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 `<br/>"` - 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=$'<br/>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] {} <br/>;
```
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), `<br/>;` eindigt het exec commando. De puntkomma wordt escaped door die backslash.
:exclamation: - Er moet een **Spatie** tussen `{}` en `<br/>;` 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. <br/><br/>
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) `<br/>|` - voorbeeld zoekt naar hond of kat:
```
cat file | grep 'hond<br/>|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 <br/>; > 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' {} {}<br/>; -print
```
Vergeet niet dat grep ook **andere argumenten** (of volgorde) heeft (eerst flags dan search pattern en file, geen -C option etc)!<br/><br/>
Zie http://www.compuspec.net/reference/os/solaris/find/find_and_execute_with_pipe.shtml <br/><br/>

View File

@ -24,7 +24,13 @@
<h4>
<a href="{{ .RelPermalink }}">{{ .Title }}</a>
</h4>
{{ .Params.subtitle }} <span style="color: lightgrey;"><i class='fa fa-calendar'></i>&nbsp;{{ $.Scratch.Get "subtitle" }}</span>
{{ with .Params.archived }}
<kbd class="item-tag">Archived</kbd>
{{ end }}
{{ .Params.subtitle }}
<span style="color: lightgrey;">
<i class='fa fa-calendar'></i>&nbsp;{{ $.Scratch.Get "subtitle" }}
</span>
</li>
{{ end }}
</ul>