Jekyll2022-02-26T09:18:43+00:00https://blog.myelin.ch/feed.xmlMyelin BlogA blog for everything myelin related.Announcing Mockiato - A strict, yet friendly mocking library for Rust 20182019-05-24T00:00:00+00:002019-05-24T00:00:00+00:00https://blog.myelin.ch/2019/05/24/mockiato-announcement<p><strong>Update:</strong> Mockiato now works with stable rust.</p>
<blockquote>
<h2 id="️-disclaimer-for-working-with-stable-rust">⚠️ Disclaimer for working with stable rust</h2>
<p>Mockiato relies on the unstable <code class="language-plaintext highlighter-rouge">proc_macro_diagnostics</code> API to print helpful messages
and the unstable <code class="language-plaintext highlighter-rouge">specialization</code> feature to be able to print expected calls.</p>
<p>Mocks work as expected on stable rust, but diagnostics are very limited.<br />
We recommend re-running failing tests using nighly rust in order to pin-point the issue.</p>
</blockquote>
<p>We’re proud to announce <a href="https://github.com/myelin-ai/mockiato">mockiato</a>! For the last few months, we tackled the issue of creating a usable mocking library.
Our primary goals were</p>
<ul>
<li>Ease of use: The mocks are written in idiomatic Rust and don’t rely on custom macro syntax.</li>
<li>Maintainability: The entire code base strives to follow the rules of Clean Code and Clean Architecture as specified by Robert C. Martin.</li>
<li>Strict expectation enforcement: Mockiato catches unexpected behavior as soon as it happens instead of returning default values.</li>
</ul>
<p>Relying on mocks instead of implementations allows you to test components in isolation of their dependencies, providing real unit testing capabilities.</p>
<p>Mockiato enjoys a broad test suite, composed of many unit tests and <a href="https://github.com/myelin-ai/mockiato/tree/master/tests">integration</a> <a href="https://github.com/myelin-ai/mockiato/tree/master/crates/mockiato-compiletest/tests/ui">tests</a>.</p>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#the-basics">The basics</a></li>
<li><a href="#expecting-a-method-call-a-certain-amount-of-times">Expecting a method call a certain amount of times</a></li>
<li><a href="#specifying-return-values">Specifiying return values</a></li>
<li><a href="#limitations">Limitations</a></li>
</ul>
<h2 id="the-basics">The Basics</h2>
<p>Annotating a trait <code class="language-plaintext highlighter-rouge">Greeter</code> with <code class="language-plaintext highlighter-rouge">#[mockable]</code> generates a struct <code class="language-plaintext highlighter-rouge">GreeterMock</code> that implements <code class="language-plaintext highlighter-rouge">Greeter</code>
and provides an <code class="language-plaintext highlighter-rouge">expect_<method_name></code> method for every method in the trait.</p>
<p>Calling these <code class="language-plaintext highlighter-rouge">expect</code> methods sets up expectations which panic when invoking an
unexpected call or when <code class="language-plaintext highlighter-rouge">GreeterMock</code> goes out of scope with unmet expectations.</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[cfg(test)]</span>
<span class="k">use</span> <span class="nn">mockiato</span><span class="p">::</span><span class="n">mockable</span><span class="p">;</span>
<span class="nd">#[cfg_attr(test,</span> <span class="nd">mockable)]</span>
<span class="k">trait</span> <span class="n">Greeter</span> <span class="p">{</span>
<span class="k">fn</span> <span class="nf">greet</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="o">&</span><span class="nb">str</span><span class="p">);</span>
<span class="p">}</span>
<span class="nd">#[cfg(test)]</span>
<span class="k">mod</span> <span class="n">tests</span> <span class="p">{</span>
<span class="k">use</span> <span class="nn">super</span><span class="p">::</span><span class="o">*</span><span class="p">;</span>
<span class="nd">#[test]</span>
<span class="k">fn</span> <span class="nf">greet_the_world</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">greeter</span> <span class="o">=</span> <span class="nn">GreeterMock</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
<span class="n">greeter</span><span class="nf">.expect_greet</span><span class="p">(|</span><span class="n">arg</span><span class="p">|</span> <span class="n">arg</span><span class="nf">.partial_eq</span><span class="p">(</span><span class="s">"world"</span><span class="p">));</span>
<span class="n">greeter</span><span class="nf">.greet</span><span class="p">(</span><span class="s">"world"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="expecting-a-method-call-a-certain-amount-of-times">Expecting a method call a certain amount of times</h2>
<p>By default, each expected method is configured to be called exactly once.</p>
<p>To be able to specify the number of expected calls, the generated <code class="language-plaintext highlighter-rouge">expect_</code> methods return a <code class="language-plaintext highlighter-rouge">MethodCallBuilder</code>, which amongst other methods contains a <code class="language-plaintext highlighter-rouge">times</code> method.</p>
<p>The <code class="language-plaintext highlighter-rouge">times</code> method accepts a usize value or a range. Here is the full list of supported values from the documentation:</p>
<table>
<thead>
<tr>
<th>Description</th>
<th>Type</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td>Exact amount of times</td>
<td><code class="language-plaintext highlighter-rouge">u64</code></td>
<td><code class="language-plaintext highlighter-rouge">3</code></td>
</tr>
<tr>
<td>Any amount of times</td>
<td><code class="language-plaintext highlighter-rouge">RangeFull</code></td>
<td><code class="language-plaintext highlighter-rouge">..</code></td>
</tr>
<tr>
<td>At least</td>
<td><code class="language-plaintext highlighter-rouge">RangeFrom</code></td>
<td><code class="language-plaintext highlighter-rouge">3..</code></td>
</tr>
<tr>
<td>At most (exclusive)</td>
<td><code class="language-plaintext highlighter-rouge">RangeTo</code></td>
<td><code class="language-plaintext highlighter-rouge">..3</code></td>
</tr>
<tr>
<td>At most (inclusive)</td>
<td><code class="language-plaintext highlighter-rouge">RangeToInclusive</code></td>
<td><code class="language-plaintext highlighter-rouge">..=3</code></td>
</tr>
<tr>
<td>Between (exclusive)</td>
<td><code class="language-plaintext highlighter-rouge">Range</code></td>
<td><code class="language-plaintext highlighter-rouge">3..4</code></td>
</tr>
<tr>
<td>Between (inclusive)</td>
<td><code class="language-plaintext highlighter-rouge">RangeInclusive</code></td>
<td><code class="language-plaintext highlighter-rouge">3..=4</code></td>
</tr>
</tbody>
</table>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[cfg(test)]</span>
<span class="k">use</span> <span class="nn">mockiato</span><span class="p">::</span><span class="n">mockable</span><span class="p">;</span>
<span class="nd">#[cfg_attr(test,</span> <span class="nd">mockable)]</span>
<span class="k">trait</span> <span class="n">Greeter</span> <span class="p">{</span>
<span class="k">fn</span> <span class="nf">greet</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="o">&</span><span class="nb">str</span><span class="p">);</span>
<span class="p">}</span>
<span class="nd">#[cfg(test)]</span>
<span class="k">mod</span> <span class="n">tests</span> <span class="p">{</span>
<span class="k">use</span> <span class="nn">super</span><span class="p">::</span><span class="o">*</span><span class="p">;</span>
<span class="nd">#[test]</span>
<span class="k">fn</span> <span class="nf">greet_the_world</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">greeter</span> <span class="o">=</span> <span class="nn">GreeterMock</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
<span class="n">greeter</span>
<span class="nf">.expect_greet</span><span class="p">(|</span><span class="n">arg</span><span class="p">|</span> <span class="n">arg</span><span class="nf">.partial_eq</span><span class="p">(</span><span class="s">"world"</span><span class="p">))</span>
<span class="nf">.times</span><span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="mi">2</span><span class="p">);</span>
<span class="n">greeter</span><span class="nf">.greet</span><span class="p">(</span><span class="s">"world"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="specifying-return-values">Specifying return values</h2>
<p>The <code class="language-plaintext highlighter-rouge">MethodCallBuilder</code> also provides a <code class="language-plaintext highlighter-rouge">returns</code> method.</p>
<p>This <code class="language-plaintext highlighter-rouge">returns</code> method allow you to specify a return value, which is returned when the corresponding mock method is invoked.</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[cfg(test)]</span>
<span class="k">use</span> <span class="nn">mockiato</span><span class="p">::</span><span class="n">mockable</span><span class="p">;</span>
<span class="nd">#[cfg_attr(test,</span> <span class="nd">mockable)]</span>
<span class="k">trait</span> <span class="n">Greeter</span> <span class="p">{</span>
<span class="k">fn</span> <span class="nf">greet</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="o">&</span><span class="nb">str</span><span class="p">)</span> <span class="k">-></span> <span class="nb">String</span><span class="p">;</span>
<span class="p">}</span>
<span class="nd">#[cfg(test)]</span>
<span class="k">mod</span> <span class="n">tests</span> <span class="p">{</span>
<span class="k">use</span> <span class="nn">super</span><span class="p">::</span><span class="o">*</span><span class="p">;</span>
<span class="nd">#[test]</span>
<span class="k">fn</span> <span class="nf">greet_the_world</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">greeter</span> <span class="o">=</span> <span class="nn">GreeterMock</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
<span class="n">greeter</span>
<span class="nf">.expect_greet</span><span class="p">(|</span><span class="n">arg</span><span class="p">|</span> <span class="n">arg</span><span class="nf">.partial_eq</span><span class="p">(</span><span class="s">"world"</span><span class="p">))</span>
<span class="nf">.returns</span><span class="p">(</span><span class="nn">String</span><span class="p">::</span><span class="nf">from</span><span class="p">(</span><span class="s">"Hello world"</span><span class="p">));</span>
<span class="nd">assert_eq!</span><span class="p">(</span><span class="s">"Hello world"</span><span class="p">,</span> <span class="n">greeter</span><span class="nf">.greet</span><span class="p">(</span><span class="s">"world"</span><span class="p">));</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="specifying-different-return-values-for-the-same-call">Specifying different return values for the same call</h3>
<p>For each method of the <code class="language-plaintext highlighter-rouge">Greeter</code> trait a corresponding <code class="language-plaintext highlighter-rouge">expect_<method_name>_calls_in_order</code> method is generated.</p>
<p>Ordered expectations can be used together with <a href="#expecting-a-method-call-a-certain-amount-of-times"><code class="language-plaintext highlighter-rouge">times</code></a>.</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[cfg(test)]</span>
<span class="k">use</span> <span class="nn">mockiato</span><span class="p">::</span><span class="n">mockable</span><span class="p">;</span>
<span class="nd">#[cfg_attr(test,</span> <span class="nd">mockable)]</span>
<span class="k">trait</span> <span class="n">Greeter</span> <span class="p">{</span>
<span class="k">fn</span> <span class="nf">greet</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="o">&</span><span class="nb">str</span><span class="p">)</span> <span class="k">-></span> <span class="nb">String</span><span class="p">;</span>
<span class="p">}</span>
<span class="nd">#[cfg(test)]</span>
<span class="k">mod</span> <span class="n">tests</span> <span class="p">{</span>
<span class="k">use</span> <span class="nn">super</span><span class="p">::</span><span class="o">*</span><span class="p">;</span>
<span class="nd">#[test]</span>
<span class="k">fn</span> <span class="nf">greet_the_world</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">greeter</span> <span class="o">=</span> <span class="nn">GreeterMock</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
<span class="n">greeter</span>
<span class="nf">.expect_greet</span><span class="p">(|</span><span class="n">arg</span><span class="p">|</span> <span class="n">arg</span><span class="nf">.partial_eq</span><span class="p">(</span><span class="s">"world"</span><span class="p">))</span>
<span class="nf">.returns</span><span class="p">(</span><span class="nn">String</span><span class="p">::</span><span class="nf">from</span><span class="p">(</span><span class="s">"Hello world"</span><span class="p">));</span>
<span class="n">greeter</span>
<span class="nf">.expect_greet</span><span class="p">(|</span><span class="n">arg</span><span class="p">|</span> <span class="n">arg</span><span class="nf">.partial_eq</span><span class="p">(</span><span class="s">"world"</span><span class="p">))</span>
<span class="nf">.returns</span><span class="p">(</span><span class="nn">String</span><span class="p">::</span><span class="nf">from</span><span class="p">(</span><span class="s">"Hi world"</span><span class="p">));</span>
<span class="n">greeter</span><span class="nf">.expect_greet_calls_in_order</span><span class="p">();</span>
<span class="nd">assert_eq!</span><span class="p">(</span><span class="s">"Hello world"</span><span class="p">,</span> <span class="n">greeter</span><span class="nf">.greet</span><span class="p">(</span><span class="s">"world"</span><span class="p">));</span>
<span class="nd">assert_eq!</span><span class="p">(</span><span class="s">"Hi world"</span><span class="p">,</span> <span class="n">greeter</span><span class="nf">.greet</span><span class="p">(</span><span class="s">"world"</span><span class="p">));</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="limitations">Limitations</h2>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Description</th>
<th>Tracking Issue</th>
</tr>
</thead>
<tbody>
<tr>
<td><code class="language-plaintext highlighter-rouge">Sync</code> / <code class="language-plaintext highlighter-rouge">Send</code></td>
<td>Mocks are neither sync, nor send.</td>
<td><a href="https://github.com/myelin-ai/mockiato/issues/106">#106</a></td>
</tr>
<tr>
<td>Lifetimes on traits</td>
<td>Lifetimes are supported in the method signature, but not on the trait itself.</td>
<td><a href="https://github.com/myelin-ai/mockiato/issues/117">#117</a></td>
</tr>
<tr>
<td>Reference to generics</td>
<td>References to types containing a generic type are currently not supported due to a limitation in codegen involving lifetimes.</td>
<td><a href="https://github.com/myelin-ai/mockiato/issues/123">#123</a></td>
</tr>
<tr>
<td>Stable support</td>
<td>Mockiato requires nightly because we use the unstable <code class="language-plaintext highlighter-rouge">proc_macro_diagnostics</code> API to print helpful messages. Printing expected calls requires the unstable feature <code class="language-plaintext highlighter-rouge">specialization</code>.</td>
<td><a href="https://github.com/myelin-ai/mockiato/issues/161">#161</a></td>
</tr>
</tbody>
</table>
<h2 id="discussion">Discussion</h2>
<p>If you’d like to discuss or comment on this post, head over to <a href="https://redd.it/bshn0f">reddit</a>!</p>Jeremy, Ruben, Jan, MathiasUpdate: Mockiato now works with stable rust.Script collection - Part 12019-03-22T00:00:00+00:002019-03-22T00:00:00+00:00https://blog.myelin.ch/2019/03/22/script-collection-part-1<h1 id="clone-script">Clone script</h1>
<p>Clone git repositories and automatically set custom configs, such as commit author or gpg settings.</p>
<p><code class="language-plaintext highlighter-rouge">.zshrc</code></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>clone<span class="o">()</span> <span class="o">{</span>
<span class="nv">username</span><span class="o">=</span><span class="nv">$1</span>
<span class="nv">repository</span><span class="o">=</span><span class="nv">$2</span>
<span class="k">if</span> <span class="o">[</span> <span class="nt">-d</span> <span class="s2">"~github/</span><span class="nv">$username</span><span class="s2">/</span><span class="nv">$repository</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
</span><span class="nb">echo</span> <span class="s2">"Repository already exists"</span>
<span class="k">return </span>1<span class="p">;</span>
<span class="k">fi
</span>git clone git@github.com:<span class="nv">$username</span>/<span class="nv">$repository</span>.git ~github/<span class="nv">$username</span>/<span class="nv">$repository</span>
<span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$username</span><span class="s2">"</span> <span class="o">=</span> <span class="s2">"myelin-ai"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
</span><span class="nb">cat</span> ~/.myelin_gitconfig <span class="o">>></span> ~github/<span class="nv">$username</span>/<span class="nv">$repository</span>/.git/config
<span class="k">fi</span>
<span class="o">}</span>
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">.myelin_gitconfig</code></p>
<div class="language-properties highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">[user]</span>
<span class="py">name</span> <span class="p">=</span> <span class="s">Jeremy Stucki</span>
<span class="py">email</span> <span class="p">=</span> <span class="s">jeremy@myelin.ch</span>
<span class="py">signingkey</span> <span class="p">=</span> <span class="s">6FBAAA51EA742855</span>
<span class="err">[commit]</span>
<span class="py">gpgsign</span> <span class="p">=</span> <span class="s">true</span>
</code></pre></div></div>
<h1 id="latex-spell-check">LaTeX spell check</h1>
<p>Spellcheck your documents using a default language and a custom dictionary.</p>
<p>To spellcheck a whole directory you can use <code class="language-plaintext highlighter-rouge">find</code> and <code class="language-plaintext highlighter-rouge">xargs</code> like this:<br />
<code class="language-plaintext highlighter-rouge">find . -type f -name '*.tex' | xargs -L1 spellcheck.sh</code></p>
<p>The script has some issues. <code class="language-plaintext highlighter-rouge">dictionary.txt</code> must not contain empty lines.</p>
<p><code class="language-plaintext highlighter-rouge">spellcheck.sh</code></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">SPELLING_MISTAKES</span><span class="o">=</span><span class="s2">"</span><span class="si">$(</span><span class="nb">cat</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> | aspell list <span class="nt">-t</span> <span class="nt">-d</span> en_US | <span class="nb">grep</span> <span class="nt">-i</span> <span class="nt">-v</span> <span class="nt">-f</span> dictionary.txt<span class="si">)</span><span class="s2">"</span><span class="p">;</span>
<span class="k">if</span> <span class="o">[[</span> <span class="s2">"</span><span class="k">${</span><span class="nv">SPELLING_MISTAKES</span><span class="k">}</span><span class="s2">"</span> <span class="o">!=</span> <span class="s2">""</span> <span class="o">]]</span>
<span class="k">then
</span><span class="nb">echo</span> <span class="s2">"Spelling mistakes found in </span><span class="nv">$1</span><span class="s2">"</span>
<span class="nb">echo</span> <span class="s2">"</span><span class="k">${</span><span class="nv">SPELLING_MISTAKES</span><span class="k">}</span><span class="s2">"</span> | <span class="nb">sed</span> <span class="s2">"s/^/ /g"</span>
<span class="nb">exit </span>1
<span class="k">fi</span>
</code></pre></div></div>
<h1 id="extract-a-directory-from-a-git-repository">Extract a directory from a git repository</h1>
<ol>
<li><code class="language-plaintext highlighter-rouge">git filter-branch --prune-empty --subdirectory-filter <directory> master</code></li>
<li>(Optional) Set yourself as the commiter and re-commit everything using the script below. (If you require signed commits). Then run:<br />
<code class="language-plaintext highlighter-rouge">git filter-branch -f --commit-filter 'git commit-tree -S "$@";' -- --all</code></li>
<li><code class="language-plaintext highlighter-rouge">git remote set-url origin <new repository></code></li>
<li><code class="language-plaintext highlighter-rouge">git push</code></li>
</ol>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git filter-branch <span class="nt">-f</span> <span class="nt">--env-filter</span> <span class="s1">'
NEW_COMMITER_NAME="Jeremy Stucki"
NEW_COMMITER_EMAIL="jeremy@myelin.ch"
if [[ "$GIT_AUTHOR_NAME" != "$NEW_COMMITER_NAME" ]]
then
export GIT_AUTHOR_NAME="$GIT_COMMITTER_NAME"
export GIT_AUTHOR_EMAIL="$GIT_COMMITTER_EMAIL"
export GIT_COMMITTER_NAME="$NEW_COMMITER_NAME"
export GIT_COMMITTER_EMAIL="$NEW_COMMITER_EMAIL"
fi
'</span> <span class="nt">--tag-name-filter</span> <span class="nb">cat</span> <span class="nt">--</span> <span class="nt">--branches</span> <span class="nt">--tags</span>
</code></pre></div></div>
<h1 id="other-random-stuff">Other random stuff</h1>
<h2 id="macos---cleanup-brew-cache">macOS - Cleanup brew cache</h2>
<p>If you just installed or updated a lot of stuff, you should consider running <code class="language-plaintext highlighter-rouge">brew cleanup</code>.<br />
It also runs automatically every 30 days.</p>
<h2 id="rename-a-lot-of-files-quickly">Rename a lot of files quickly</h2>
<p>With <code class="language-plaintext highlighter-rouge">zmv</code> you can quickly rename all the files in a directory.</p>
<p>Example script: <code class="language-plaintext highlighter-rouge">zmv '(*)S(??)E(??)(*).(???)' 'Season $2 - Episode $3.$4'</code></p>
<table>
<thead>
<tr>
<th>Input</th>
<th>Output</th>
</tr>
</thead>
<tbody>
<tr>
<td>Silicon.Valley.S04E05.HDTV.x264-SVA[ettv].mkv</td>
<td>Season 04 - Episode 05.mkv</td>
</tr>
</tbody>
</table>Jeremy Stuckijeremy@myelin.chClone script Clone git repositories and automatically set custom configs, such as commit author or gpg settings.LAN Party2018-12-23T00:00:00+00:002018-12-23T00:00:00+00:00https://blog.myelin.ch/2018/12/23/lan<p>Over the past weekend we had a little LAN party.<br />
Niklas (@Randalf98) and Stefanie (@StefanieJaeger) were also there.</p>
<p><img src="/assets/lan.jpg" alt="LAN" /></p>
<p>Hello, Stefanie here.</p>
<p>Let me tell you a bit about how Jeremy and I experienced the LAN.</p>
<p>The LAN started friday evening and lasted till early monday morning.</p>
<p>Foresighted as we (Jeremy) are, we packed all our stuff 1 day in advance. This included 2 towers, 2 screens, 2 mice, 2 keyboards (1 missing a keycap, thanks to my cat), 2 headphones, some stuff to be comfy, some food and most importantly my pet shark Thoru. All of this was packed into my Mom’s car at 6am. We then headed off to work.
At about 10am, my Mom arrived at Myelin Headquarters and we helped unpack (my workplace is about 2 minutes away by foot). After that, we went back to work.</p>
<p>We both had taken friday afternoon off to go to <a href="https://www.cutandcandy.ch/">Cut and Candy</a> and execute my semi-annual hair dying ritual.
It was a success, I now had purple roots, nicely fading into blue towards the tips.</p>
<p>At about 7pm we arrived at the Myelin Headquarters and started getting our PCs ready. Thanks to Niklas, the others’ PCs had already arrived.</p>
<p>Jeremy and I had planned on playing a bit of Factorio and starting our second ever try at CIV.<br />
Well, we ended up with pretty much only Factorio (What a surprise!).</p>
<p>The others slept most of the nights at the Myelin Headquarters, but we went home for some privacy and a shower.</p>
<p>To bring the Lan-Party to a nice end, we all gathered under the small, plastic christmas tree (decorated with pokemon and tarfis ornaments) and exchanged presents.</p>
<p>All in all, we really enjoyed playing video games with 4 other people in a crowded room for 3 days. ;)<br />
We would do it again in a heartbeat!</p>
<p>Thanks for having me,<br />
Stefi out.</p>Stefanie and JeremyOver the past weekend we had a little LAN party. Niklas (@Randalf98) and Stefanie (@StefanieJaeger) were also there.The zsh named directory hash table2018-12-14T00:00:00+00:002018-12-14T00:00:00+00:00https://blog.myelin.ch/2018/12/14/named-directory-hash-table<p>Like all cool things, it started with <a href="https://www.reddit.com/r/zsh/comments/9eklqu/shortcut_links_in_zsh/">a reddit comment</a>.
Someone recommended to use the zsh directory hash table.
It enabled me to set custom directory replacements like this:
<img src="/assets/named-directory-hash-table/01.png" alt="01" /></p>
<p>This worked nicely, but I was curious about how it worked.<br />
Since is a zsh built-in function, the docs can be accessed with <code class="language-plaintext highlighter-rouge">man zshbuiltins</code>.</p>
<blockquote>
<p>hash can be used to directly modify the contents of the command hash table, and the named directory hash table. Normally one would modify these tables by modifying one’s PATH (for the command hash table) or by creating appropriate shell parameters (for the named directory hash table). The choice of hash table to work on is determined by the -d option; without the option the command hash table is used, and with the option the named directory hash table is used.</p>
</blockquote>
<p>To display the command hash table contents, run <code class="language-plaintext highlighter-rouge">hash</code>. For the directory hash table, run <code class="language-plaintext highlighter-rouge">hash -d</code>.</p>
<p>So the use of <code class="language-plaintext highlighter-rouge">hash -d github=~/Documents/GitHub</code> only added the value to a cache.<br />
I found out that you can also add a static named directory like this:
<img src="/assets/named-directory-hash-table/02.png" alt="02" /></p>
<p>The documentation for this behaviour can be found <a href="http://zsh.sourceforge.net/Doc/Release/Expansion.html#Static-named-directories">here</a>.<br />
So every variable starting with a slash is considered. Also every users home is included automatically.</p>Jeremy Stuckijeremy@myelin.chLike all cool things, it started with a reddit comment. Someone recommended to use the zsh directory hash table. It enabled me to set custom directory replacements like this:Christmas time2018-12-03T00:00:00+00:002018-12-03T00:00:00+00:00https://blog.myelin.ch/2018/12/03/x-mas<p><img src="/assets/x-mas-tree.jpg" alt="Christmas tree" width="500px" /></p>
<p>Today we got this lovely christmas tree from Stefanie (@StefanieJaeger).<br />
She even got us presents for each myelin workday.</p>Jeremy Stuckijeremy@myelin.ch