<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Eray Erdin's Programming Blog]]></title><description><![CDATA[dev doing stuff]]></description><link>https://erayerdin.com</link><generator>RSS for Node</generator><lastBuildDate>Sun, 07 Jun 2026 19:32:34 GMT</lastBuildDate><atom:link href="https://erayerdin.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Dockerize A React + Vite + Appwrite App]]></title><description><![CDATA[Again, this is another quick note.
Instead of using Firebase, AWS and their confusing services, I wanted to use my own VPS for my app. Of course, in order to NOT deal with backend stuff (which is coming from a former backend dev), I wanted to set up ...]]></description><link>https://erayerdin.com/dockerize-a-react-vite-appwrite-app</link><guid isPermaLink="true">https://erayerdin.com/dockerize-a-react-vite-appwrite-app</guid><category><![CDATA[vite]]></category><category><![CDATA[React]]></category><category><![CDATA[Appwrite]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Sat, 18 Oct 2025 19:36:29 GMT</pubDate><content:encoded><![CDATA[<p>Again, this is another quick note.</p>
<p>Instead of using Firebase, AWS and their confusing services, I wanted to use my own VPS for my app. Of course, in order to NOT deal with backend stuff (which is coming from a former backend dev), I wanted to set up <a target="_blank" href="https://appwrite.io/">Appwrite</a>, which is a self-hosted BaaS (backend-as-a-service). Basically a Firebase alternative that you can set up on your own server.</p>
<p>What I like about it is:</p>
<ul>
<li><p>It is almost the perfect BaaS. Covers tons of cases from Functions to Messaging to multiple projects.</p>
</li>
<li><p>It is relatively mature compared to other solutions.</p>
</li>
</ul>
<p>So, let’s get started.</p>
<blockquote>
<p>This post already assumes you have created a fresh new Vite+React project.</p>
</blockquote>
<h1 id="heading-step-1-dockerizing-our-project">Step 1: Dockerizing Our Project</h1>
<p>We need a multi-stage <code>Dockerfile</code> to build and then serve our Vite project. Here it is:</p>
<pre><code class="lang-dockerfile"><span class="hljs-comment"># Stage 1: Build</span>

<span class="hljs-keyword">FROM</span> node:<span class="hljs-number">20</span>-alpine AS build <span class="hljs-comment"># Define "build" stage</span>

<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app <span class="hljs-comment"># set working dir</span></span>

<span class="hljs-keyword">COPY</span><span class="bash"> package.json package-lock.json ./ <span class="hljs-comment"># copy dep files</span></span>
<span class="hljs-keyword">RUN</span><span class="bash"> corepack <span class="hljs-built_in">enable</span> &amp;&amp; npm i <span class="hljs-comment"># install deps</span></span>

<span class="hljs-keyword">COPY</span><span class="bash"> . . <span class="hljs-comment"># copy everything else</span></span>

<span class="hljs-keyword">ENV</span> NODE_ENV=production <span class="hljs-comment"># set env to production</span>

<span class="hljs-keyword">RUN</span><span class="bash"> npm build <span class="hljs-comment"># start building</span></span>

<span class="hljs-comment"># Stage 2: Run</span>

<span class="hljs-keyword">FROM</span> nginx:alpine <span class="hljs-comment"># Define "run" stage</span>

<span class="hljs-keyword">COPY</span><span class="bash"> --from=build /app/dist /usr/share/nginx/html <span class="hljs-comment"># Copy transpiled files from "build" stage to this container</span></span>

<span class="hljs-keyword">COPY</span><span class="bash"> ./nginx.conf /etc/nginx/conf.d/default.conf <span class="hljs-comment"># add our custom nginx config</span></span>

<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">80</span> <span class="hljs-comment"># expose port 8*</span>

<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"nginx"</span>, <span class="hljs-string">"-g"</span>, <span class="hljs-string">"daemon off;"</span>] <span class="hljs-comment"># define run script</span></span>
</code></pre>
<p>So, we also need to create two more things. The first one is defined in <code>Dockerfile</code>, it is our custom <code>nginx.conf</code> file.</p>
<pre><code class="lang-nginx"><span class="hljs-section">server</span> {
    <span class="hljs-attribute">listen</span> <span class="hljs-number">80</span>;
    <span class="hljs-attribute">server_name</span> localhost;
    <span class="hljs-attribute">root</span> /usr/share/nginx/html;
    <span class="hljs-attribute">index</span> index.html;

    <span class="hljs-comment"># SPA support - redirect all routes to index.html</span>
    <span class="hljs-attribute">location</span> / {
        <span class="hljs-attribute">try_files</span> <span class="hljs-variable">$uri</span> <span class="hljs-variable">$uri</span>/ /index.html;
    }

    <span class="hljs-comment"># Cache static assets</span>
    <span class="hljs-attribute">location</span> <span class="hljs-regexp">~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$</span> {
        <span class="hljs-attribute">expires</span> <span class="hljs-number">1y</span>;
        <span class="hljs-attribute">add_header</span> Cache-Control <span class="hljs-string">"public, immutable"</span>;
    }

    <span class="hljs-comment"># Security headers</span>
    <span class="hljs-attribute">add_header</span> X-Frame-Options <span class="hljs-string">"SAMEORIGIN"</span> always;
    <span class="hljs-attribute">add_header</span> X-XSS-Protection <span class="hljs-string">"1; mode=block"</span> always;
    <span class="hljs-attribute">add_header</span> X-Content-Type-Options <span class="hljs-string">"nosniff"</span> always;
}
</code></pre>
<p>And also we need to ignore some files for Docker. Create a <code>.dockerignore</code> with this content:</p>
<pre><code class="lang-plaintext">node_modules
npm-debug.log
.git
.gitignore
README.md
.eslintrc
.prettierrc
Dockerfile
.dockerignore
</code></pre>
<p>And run with:</p>
<pre><code class="lang-bash">docker build -t ourprojectname .
</code></pre>
<p>If it runs successfully, that is fine.</p>
<h1 id="heading-step-2-connecting-it-altogether-with-appwrite">Step 2: Connecting It Altogether with Appwrite</h1>
<p>Now, we need to connect our app to Appwrite, which we will define with Docker Compose. Here is my <code>docker-compose.yml</code> file:</p>
<pre><code class="lang-bash">version: <span class="hljs-string">"3.8"</span>

services:
  ourprojectname: <span class="hljs-comment"># change this</span>
    build:
      context: .
      args:
        - VITE_APPWRITE_ENDPOINT=<span class="hljs-variable">${VITE_APPWRITE_ENDPOINT}</span>
        - VITE_APPWRITE_PROJECT=<span class="hljs-variable">${VITE_APPWRITE_PROJECT}</span>
    ports:
      - <span class="hljs-string">"80:80"</span>
    depends_on:
      - appwrite
    environment:
      - VITE_APPWRITE_ENDPOINT=<span class="hljs-variable">${VITE_APPWRITE_ENDPOINT}</span>
      - VITE_APPWRITE_PROJECT=<span class="hljs-variable">${VITE_APPWRITE_PROJECT}</span>
    networks:
      - appwrite-network
    env_file:
      - .env.app <span class="hljs-comment"># we will create this file</span>

  <span class="hljs-comment"># AppWrite services</span>
  appwrite:
    image: appwrite/appwrite:latest
    depends_on:
      - mariadb <span class="hljs-comment"># for appwrite to store data</span>
      - redis <span class="hljs-comment"># for appwrite to cache data</span>
    ports:
      - <span class="hljs-string">"1900:80"</span> <span class="hljs-comment"># host machine port is 1900 because our app uses 80</span>
    volumes: <span class="hljs-comment"># define volumes on host machine to store data somewhere</span>
        <span class="hljs-comment"># change "ourprojectname"</span>
      - ourprojectname-appwrite-uploads:/storage/uploads
      - ourprojectname-appwrite-cache:/storage/cache
      - ourprojectname-appwrite-config:/storage/config
      - ourprojectname-appwrite-certificates:/storage/certificates
      - ourprojectname-appwrite-functions:/storage/<span class="hljs-built_in">functions</span>
    networks:
      - appwrite-network
    env_file:
      - .env.appwrite <span class="hljs-comment"># we will create this file</span>

  mariadb:
    image: mariadb:12
    volumes: <span class="hljs-comment"># define volumes on host machine to store data somewhere</span>
        <span class="hljs-comment"># change "ourprojectname"</span>
      - ourprojectname-mariadb-data:/var/lib/mysql
    networks:
      - appwrite-network
    env_file:
      - .env.mariadb <span class="hljs-comment"># we will create this file</span>

  redis:
    image: redis:8
    volumes: <span class="hljs-comment"># define volumes on host machine to store data somewhere</span>
        <span class="hljs-comment"># change "ourprojectname"</span>
      - ourprojectname-redis-data:/data
    networks:
      - appwrite-network

volumes:
  <span class="hljs-comment"># all our volumes</span>
  ourprojectname-appwrite-uploads:
  ourprojectname-appwrite-cache:
  ourprojectname-appwrite-config:
  ourprojectname-appwrite-certificates:
  ourprojectname-appwrite-functions:
  ourprojectname-mariadb-data:
  ourprojectname-redis-data:

networks:
  appwrite-network:
    driver: bridge
</code></pre>
<p>So, what this does is, it sets up Appwrite container, and then Redis and MariaDB containers because Appwrite needs them to store some data.</p>
<p>However, as you can see, we need to define a lot of <code>.env</code> files. Of course, these <code>.env</code> files will contain sensitive data, so I will ignore them in <code>.gitignore</code> like this:</p>
<pre><code class="lang-plaintext"># ... other entries ...

.env
.env.*
!.env*example
</code></pre>
<p>You might have noticed, I excluded <code>.env.*.example</code> files, because we will use them as template. So, let’s create them:</p>
<pre><code class="lang-plaintext"># .env.app.example file
VITE_APPWRITE_ENDPOINT=http://localhost/v1
VITE_APPWRITE_PROJECT=band9buddy

# .env.appwrite.example file
_APP_ENV=production
_APP_OPENSSL_KEY_V1=your-very-secure-encryption-key-here
_APP_DOMAIN=localhost
_APP_REDIS_HOST=redis
_APP_DB_HOST=mariadb
_APP_DB_USER=appwrite-user
_APP_DB_PASS=super-secure-password-456
_APP_DB_SCHEMA=appwrite
_APP_STORAGE_DEVICE=local
_APP_STORAGE_ANTIVIRUS=clamav

# .env.mariadb.example file
MYSQL_ROOT_PASSWORD=rootpassword
MYSQL_DATABASE=appwrite
MYSQL_USER=user
MYSQL_PASSWORD=password
</code></pre>
<p>And copy and paste them and remove <code>.example</code> part from the filename. These examples will stay as a template in our repo for setting it up later on the server.</p>
<p>Now, if we run:</p>
<pre><code class="lang-bash">docker compose up <span class="hljs-comment"># -d for detaching</span>
</code></pre>
<p>We will see it runs just fine.</p>
]]></content:encoded></item><item><title><![CDATA[Importing TOML in React Native]]></title><description><![CDATA[This is a no bullshit quick note that I also can use in the future.
I love to use TOML in i18next because I also comment the translations to give them context. The problem is, there’s no standard way to simply import TOML files in a React Native proj...]]></description><link>https://erayerdin.com/importing-toml-in-react-native</link><guid isPermaLink="true">https://erayerdin.com/importing-toml-in-react-native</guid><category><![CDATA[React]]></category><category><![CDATA[React Native]]></category><category><![CDATA[Metro Bundler]]></category><category><![CDATA[Babel]]></category><category><![CDATA[TOML]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Sun, 12 Oct 2025 18:26:55 GMT</pubDate><content:encoded><![CDATA[<p>This is a no bullshit quick note that I also can use in the future.</p>
<p>I love to use TOML in <code>i18next</code> because I also comment the translations to give them context. The problem is, there’s no standard way to simply import TOML files in a React Native project.</p>
<p>Metro is the bundler for React Native projects. In our case, it has a very useful feature: Transforming source codes.</p>
<p>Transforming is basically taking in a source code that is not native to JS (like TOML, YAML etc.), and converting it into native JS type. Of course, this is oversimplified.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760292989939/16e1043f-0fe7-40e5-95bd-44635cb765ca.png" alt class="image--center mx-auto" /></p>
<p>So, when you do <code>import enTranslation from “@/assets/translations/en.toml”</code>, Metro will parse TOML and convert it into native JS.</p>
<p>We also need a parser for TOML, and I think <a target="_blank" href="https://www.npmjs.com/package/smol-toml">smol-toml</a> is the most maintained one at the time I am writing this.</p>
<p>So, let’s first create <code>metro.transformer.js</code> and add this code:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// import transformer</span>
<span class="hljs-keyword">const</span> upstreamTransformer = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@expo/metro-config/babel-transformer"</span>);
<span class="hljs-comment">// import parser</span>
<span class="hljs-keyword">const</span> { parse } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"smol-toml"</span>);

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-comment">// export custom transform function</span>
  <span class="hljs-attr">transform</span>: <span class="hljs-function">(<span class="hljs-params">config</span>) =&gt;</span> {
    <span class="hljs-comment">// spread config, we need individual vars</span>
    <span class="hljs-keyword">const</span> { src, filename, options } = config;

    <span class="hljs-comment">// if file is toml</span>
    <span class="hljs-keyword">if</span> (filename.endsWith(<span class="hljs-string">".toml"</span>)) {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// parse it</span>
        <span class="hljs-keyword">const</span> parsedData = parse(src);
        <span class="hljs-comment">// act like it's a JS module and export the data</span>
        <span class="hljs-keyword">const</span> code = <span class="hljs-string">`module.exports = <span class="hljs-subst">${<span class="hljs-built_in">JSON</span>.stringify(parsedData, <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>)}</span>;`</span>;

        <span class="hljs-comment">// transform the result</span>
        <span class="hljs-keyword">return</span> upstreamTransformer.transform({
          <span class="hljs-attr">src</span>: code,
          filename,
          options,
        });
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-comment">// if there's error, do not compile</span>
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(
          <span class="hljs-string">`Error parsing TOML file <span class="hljs-subst">${filename}</span>: <span class="hljs-subst">${error.message}</span>`</span>
        );
      }
    }

    <span class="hljs-comment">// Use default transformer for other files</span>
    <span class="hljs-keyword">return</span> upstreamTransformer.transform(config);
  },
};
</code></pre>
<p>This is not where it ends, though. We also need to add it to <code>metro.config.js</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { getDefaultConfig } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"expo/metro-config"</span>);

<span class="hljs-comment">// get default config</span>
<span class="hljs-keyword">const</span> config = getDefaultConfig(__dirname);

<span class="hljs-comment">// introduce transformer into default config</span>
config.transformer = {
  ...config.transformer,
  <span class="hljs-comment">// define transformer path here</span>
  <span class="hljs-attr">babelTransformerPath</span>: <span class="hljs-built_in">require</span>.resolve(<span class="hljs-string">"./metro.transformer.js"</span>),
};

<span class="hljs-comment">// introduce resolver, without this, import will not recognize toml imports</span>
config.resolver = {
  ...config.resolver,
  <span class="hljs-attr">sourceExts</span>: [...config.resolver.sourceExts, <span class="hljs-string">"toml"</span>],
};

<span class="hljs-built_in">module</span>.exports = config;
</code></pre>
<p>After this, you can safely import TOML files:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> enTranslations <span class="hljs-keyword">from</span> <span class="hljs-string">"@/assets/translations/en.toml"</span>;
</code></pre>
<p>Of course, you will see some problems about Typescript being unable to define types. Create <code>toml.d.ts</code> at root of your project and define type:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">module</span> "*.toml" {
  <span class="hljs-keyword">const</span> value: Record&lt;<span class="hljs-built_in">string</span>, unknown&gt;;
  <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> value;
}
</code></pre>
<p>And add it to your <code>tsconfig.json</code>.</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"extends"</span>: <span class="hljs-string">"expo/tsconfig.base"</span>,
  <span class="hljs-attr">"compilerOptions"</span>: {
    <span class="hljs-attr">"strict"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">"paths"</span>: {
      <span class="hljs-attr">"@/*"</span>: [<span class="hljs-string">"./src/*"</span>]
    }
  },
  <span class="hljs-attr">"include"</span>: [
    <span class="hljs-string">"**/*.ts"</span>,
    <span class="hljs-string">"**/*.tsx"</span>,
    <span class="hljs-string">".expo/types/**/*.ts"</span>,
    <span class="hljs-string">"expo-env.d.ts"</span>,
    <span class="hljs-string">"nativewind-env.d.ts"</span>,
    <span class="hljs-string">"toml.d.ts"</span>, <span class="hljs-comment">// add type definition file here</span>
  ]
}
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Making Video in React/Remotion: Slide and Reveal]]></title><description><![CDATA[This is how it looks like.
https://youtu.be/ttIb8WWxPLg
 
The "Create of the Week" text and the badges on the bottom use this component. Here's the component:
import { translateY } from "@remotion/animation-utils";
import { Children, CSSProperties, R...]]></description><link>https://erayerdin.com/making-video-in-reactremotion-slide-and-reveal</link><guid isPermaLink="true">https://erayerdin.com/making-video-in-reactremotion-slide-and-reveal</guid><category><![CDATA[React]]></category><category><![CDATA[Remotion]]></category><category><![CDATA[animation]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Fri, 05 Jul 2024 21:59:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720216712818/89353bd2-0c6a-49c7-a57f-d76d5216bee8.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is how it looks like.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/ttIb8WWxPLg">https://youtu.be/ttIb8WWxPLg</a></div>
<p> </p>
<p>The "Create of the Week" text and the badges on the bottom use this component. Here's the component:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { translateY } <span class="hljs-keyword">from</span> <span class="hljs-string">"@remotion/animation-utils"</span>;
<span class="hljs-keyword">import</span> { Children, CSSProperties, ReactNode } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { Easing, interpolate, useCurrentFrame } <span class="hljs-keyword">from</span> <span class="hljs-string">"remotion"</span>;

<span class="hljs-keyword">type</span> SlideRevealProps = {
  className?: <span class="hljs-built_in">string</span>,
  style?: CSSProperties,
  speedFrame?: <span class="hljs-built_in">number</span>,
  direction?: <span class="hljs-string">"up"</span> | <span class="hljs-string">"down"</span>,
  children: ReactNode,
}

<span class="hljs-keyword">const</span> SlideReveal = <span class="hljs-function">(<span class="hljs-params">{ className: classNames, style, speedFrame = <span class="hljs-number">15</span>, direction = <span class="hljs-string">"down"</span>, children }: SlideRevealProps</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> containerClassNames = classNames ? <span class="hljs-string">`flex gap-4 <span class="hljs-subst">${classNames}</span>`</span> : <span class="hljs-string">"flex gap-4"</span>;
  <span class="hljs-keyword">const</span> frame = useCurrentFrame();

  <span class="hljs-keyword">return</span> (
    &lt;div className={containerClassNames} style={style}&gt;
      {
        Children.map(children, <span class="hljs-function">(<span class="hljs-params">child, index</span>) =&gt;</span> {
          <span class="hljs-keyword">const</span> startFrame = index * speedFrame; <span class="hljs-comment">// Each child starts animating 15 frames apart</span>
          <span class="hljs-keyword">const</span> opacity = interpolate(
            frame,
            [startFrame, startFrame + speedFrame], <span class="hljs-comment">// Animate opacity over 15 frames</span>
            [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>],
            { easing: Easing.out(Easing.ease), extrapolateLeft: <span class="hljs-string">'clamp'</span>, extrapolateRight: <span class="hljs-string">'clamp'</span> }
          );
          <span class="hljs-keyword">const</span> trY = interpolate(
            frame,
            [startFrame, startFrame + speedFrame], <span class="hljs-comment">// Animate translateY over 15 frames</span>
            [direction === <span class="hljs-string">'down'</span> ? <span class="hljs-number">-20</span> : <span class="hljs-number">20</span>, <span class="hljs-number">0</span>],
            { easing: Easing.out(Easing.ease), extrapolateLeft: <span class="hljs-string">'clamp'</span>, extrapolateRight: <span class="hljs-string">'clamp'</span> }
          );

          <span class="hljs-keyword">return</span> (
            &lt;div key={index} style={{ opacity, transform: translateY(trY) }}&gt;
              {child}
            &lt;/div&gt;
          );
        })
      }
    &lt;/div&gt;
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> SlideReveal
</code></pre>
<p>Basically, what this component does is:</p>
<ul>
<li><p>Iterate over each <code>children</code> with their <code>index</code>.</p>
</li>
<li><p>Interpolate on <code>translateY</code> and <code>opacity</code> based on their <code>index</code> and <code>frame</code>.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[No, I ain't paying for full-text search | Implementing Full-Text Search in Firestore]]></title><description><![CDATA[It's been a long time since I haven't posted anything here. The life, the work, the hustle, everything's been going hard on me these days. I've switched my mother tongue to Satirish™. This is not my best piece of writing, so viewer discretion is a mu...]]></description><link>https://erayerdin.com/no-i-aint-paying-for-full-text-search-implementing-full-text-search-in-firestore</link><guid isPermaLink="true">https://erayerdin.com/no-i-aint-paying-for-full-text-search-implementing-full-text-search-in-firestore</guid><category><![CDATA[Firebase]]></category><category><![CDATA[React]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[full text search]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Fri, 29 Dec 2023 19:00:33 GMT</pubDate><content:encoded><![CDATA[<blockquote>
<p>It's been a long time since I haven't posted anything here. The life, the work, the hustle, everything's been going hard on me these days. I've switched my mother tongue to Satirish™. This is not my best piece of writing, so viewer discretion is a must.</p>
</blockquote>
<p>My last endeavor, a website where ELT teachers can share their resources, has stuck in a phase where I needed to implement a feature that the users can search for resources with a simple search bar. It kinda looks like Google's home page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703869777823/a529e218-cbbb-434e-8b8b-502c52695b50.png" alt="home page of my new project" class="image--center mx-auto" /></p>
<p>The problem is this: The simpler things are for the end user, the more complex it gets to implement for the developer.</p>
<p>The model looks like this (in Typescript):</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Resource = {
  createdAt: <span class="hljs-built_in">number</span>,
  uid: <span class="hljs-built_in">string</span>,
  title: <span class="hljs-built_in">string</span>,
  shortDescription: <span class="hljs-built_in">string</span>,
  longDescription: <span class="hljs-built_in">string</span>,
  files: <span class="hljs-built_in">string</span>[],
  tags: <span class="hljs-built_in">string</span>[],
} &amp; Model; <span class="hljs-comment">// model is another type that has "id" field</span>
</code></pre>
<p>So, the search I need to implement has to do these things:</p>
<ul>
<li><p>Check if <code>title</code> contains any token in the query.</p>
</li>
<li><p>Check if <code>shortDescription</code> contains any token in the query.</p>
</li>
<li><p>Check if <code>longDescription</code> contains any token in the query.</p>
</li>
<li><p>Check if <code>tags</code> contain any token in the query.</p>
</li>
</ul>
<p>This is a rather complex query, and Google, being a billion dollar company, has limited functionality on Firestore. Mainly:</p>
<ul>
<li><p>You can compound 30 filters at most in a single query.</p>
</li>
<li><p>There's nothing like <code>LIKE</code> like in relational databases in Firestore (are you confused yet? <em>double snap on your face</em>). So, you can't search a substring in a string field in Firestore.</p>
</li>
</ul>
<p>So, <a target="_blank" href="https://firebase.google.com/docs/firestore/solutions/search?provider=algolia">Firebase docs</a> says they can't handle a complex query (despite being owned by a multibillion peak engineering company) and suggest me to use another third-party company (<em>multimillion</em> this time).</p>
<p>Don't get me wrong. Full-text search solutions are great because they can solve fuzzy searches just like in my case.</p>
<p>I've checked all the solutions provided. Algolia seemed the best fit since it allowed me to do 10k searches free every month. On the other hand, I duplicate my data, sending it to Algolia just for some fancy search functionality. And the more data I store, the costlier it gets. Also, integrating another service makes testing challenging.</p>
<p>Another thing is, the integration with Firebase extensions takes 2 cents every month for Algolia, which is not an expensive amount, but I have a big problem: <em>I live in the third world</em>.</p>
<p>I live in the third world and people tend to vote for demagogues here, which, as a result, makes life more expensive every second.</p>
<p>So, as an economically-challenged personality who cannot afford a satire attitude towards life but does it anyway, my brainmeats been overheating for the last week to make it as free and functional as possible.</p>
<h1 id="heading-free-full-text-search-in-firebase-not-rly-lets-call-it-semi-text-search">FREE FULL-TEXT SEARCH IN FIREBASE (not rly, let's call it semi-text search)</h1>
<p>Remember the <code>Resource</code> model? Let's throw a <code>searchQueries: string[]</code> field in there:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Resource = {
  createdAt: <span class="hljs-built_in">number</span>,
  uid: <span class="hljs-built_in">string</span>,
  title: <span class="hljs-built_in">string</span>,
  shortDescription: <span class="hljs-built_in">string</span>,
  longDescription: <span class="hljs-built_in">string</span>,
  files: <span class="hljs-built_in">string</span>[],
  tags: <span class="hljs-built_in">string</span>[],
  searchQueries: <span class="hljs-built_in">string</span>[], <span class="hljs-comment">// you're here</span>
} &amp; Model;
</code></pre>
<p>You might be asking: What are we gonna do with this? We gon <code>trim</code>, <code>split</code> and <code>toLowercase</code> every field we want searchable into it. Here's a sample <code>createResource</code> Firebase function:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> createResource = functions.https.onCall(<span class="hljs-keyword">async</span> (raw: AddResourceSchemaType, context) =&gt; {
  <span class="hljs-keyword">if</span> (context.auth?.uid === <span class="hljs-literal">undefined</span>) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"anon user call"</span>);
    <span class="hljs-keyword">return</span>;
  }

  <span class="hljs-comment">// i validate and parse the data</span>
  <span class="hljs-keyword">const</span> data = AddResourceSchema.parse(raw);

  <span class="hljs-keyword">const</span> searchQueries = [
    <span class="hljs-comment">// make title field searchable</span>
    ...data.title.trim().split(<span class="hljs-string">" "</span>).map(<span class="hljs-function"><span class="hljs-params">s</span> =&gt;</span> s.toLowerCase()),
    <span class="hljs-comment">// make tags field searchable</span>
    ...data.tags.map(<span class="hljs-function"><span class="hljs-params">s</span> =&gt;</span> s.toLowerCase()),
  ];

  <span class="hljs-keyword">await</span> firestore.collection(<span class="hljs-string">"resources"</span>).add({
    <span class="hljs-comment">// ... other fields ...</span>
    searchQueries,
  } <span class="hljs-keyword">as</span> Omit&lt;Resource, <span class="hljs-string">"id"</span>&gt;);
});
</code></pre>
<p>Now that we have <code>Resource.searchQueries</code> field, we can filter the resources with <a target="_blank" href="https://firebase.google.com/docs/firestore/query-data/queries#array-contains-any">array-contains-any</a> operator. (Thank god we have this operator at least).</p>
<p>There's only one problem, though: As the docs for <code>array-contains-any</code> states:</p>
<blockquote>
<p>Use the <code>array-contains-any</code> operator to combine <a target="_blank" href="https://firebase.google.com/docs/firestore/query-data/queries#in_not-in_array-contains-any_limits">up to 30</a> <code>array-contains</code> clauses on the same field with a logical <code>OR</code>.</p>
</blockquote>
<p>I can live with that, my users can live with that as well. As a matter of fact, anyone who is searching a 30-word query on the website? I call'em crazy.</p>
<center><iframe src="https://giphy.com/embed/ynyZeravv9GknILElo" width="480" height="270" class="giphy-embed"></iframe></center>

<p>That's why, my custom <code>useSearch</code> hook implementation looks like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> useSearch = (): <span class="hljs-function"><span class="hljs-params">UseSearchReturnType</span> =&gt;</span> {
  <span class="hljs-comment">// other states and contexts</span>

  <span class="hljs-keyword">const</span> [ searchParams, ] = useSearchParams();

  <span class="hljs-keyword">const</span> params = {
    uid: searchParams.get(<span class="hljs-string">'uid'</span>),
    q: searchParams.get(<span class="hljs-string">'q'</span>), <span class="hljs-comment">// this is what i use</span>
    tags: searchParams.get(<span class="hljs-string">'tags'</span>),
  }

  <span class="hljs-comment">// create a `(QueryFieldFilterConstraint | QueryLimitConstraint)[]` to use it with firestore later on</span>
  <span class="hljs-keyword">const</span> filters = [
    ...(
      params.uid === <span class="hljs-literal">null</span>
        ? []
        : [where(<span class="hljs-string">'uid'</span>, <span class="hljs-string">'=='</span>, params.uid)]
    ),
    ...(
      params.q === <span class="hljs-literal">null</span>
        ? []
        : [
          <span class="hljs-comment">// here i use the filter on searchQueries</span>
          where(
            <span class="hljs-string">'searchQueries'</span>,
            <span class="hljs-string">'array-contains-any'</span>,
            params.q.split(<span class="hljs-string">'|'</span>).slice(<span class="hljs-number">0</span>, <span class="hljs-number">20</span>), <span class="hljs-comment">// firestore limit is 30, 20 to be safe</span>
          )
        ]
    ),
    ...(
      params.tags === <span class="hljs-literal">null</span>
        ? []
        : [
          where(
            <span class="hljs-string">'tags'</span>,
            <span class="hljs-string">'array-contains-any'</span>,
            params.tags.split(<span class="hljs-string">'|'</span>).slice(<span class="hljs-number">0</span>, <span class="hljs-number">5</span>), <span class="hljs-comment">// max 5 tags, cuz why not?</span>
          )
        ]
    ),
    limit(<span class="hljs-number">100</span>),
  ].filter(<span class="hljs-function">(<span class="hljs-params">f</span>) =&gt;</span> f !== <span class="hljs-literal">null</span>).map(<span class="hljs-function"><span class="hljs-params">f</span> =&gt;</span> f!);

  <span class="hljs-comment">// return a widget or smn</span>
}
</code></pre>
<p>And tell you what?</p>
<center><iframe src="https://giphy.com/embed/MGsgibl5SOtLNXNQRO" width="480" height="270" class="giphy-embed"></iframe></center>]]></content:encoded></item><item><title><![CDATA[A Practical Introduction to Derive Macros in Rust]]></title><description><![CDATA[https://youtu.be/XY0yR6IPbhw]]></description><link>https://erayerdin.com/a-practical-introduction-to-derive-macros-in-rust</link><guid isPermaLink="true">https://erayerdin.com/a-practical-introduction-to-derive-macros-in-rust</guid><category><![CDATA[Rust]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Sat, 06 May 2023 07:48:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1683359240832/bbe47501-3e07-4c76-87c2-c6bb4d2ef838.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/XY0yR6IPbhw">https://youtu.be/XY0yR6IPbhw</a></div>
]]></content:encoded></item><item><title><![CDATA[A Practical Introduction to Declarative Macros in Rust]]></title><description><![CDATA[https://youtu.be/dHv8FhcAl5U]]></description><link>https://erayerdin.com/a-practical-introduction-to-declarative-macros-in-rust</link><guid isPermaLink="true">https://erayerdin.com/a-practical-introduction-to-declarative-macros-in-rust</guid><category><![CDATA[Rust]]></category><category><![CDATA[Metaprogramming ]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Fri, 21 Apr 2023 07:23:55 GMT</pubDate><content:encoded><![CDATA[<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/dHv8FhcAl5U">https://youtu.be/dHv8FhcAl5U</a></div>
]]></content:encoded></item><item><title><![CDATA[Mastering Testing in Rust Using Rstest]]></title><description><![CDATA[https://www.youtube.com/watch?v=w10ndWcuflo]]></description><link>https://erayerdin.com/mastering-testing-in-rust-using-rstest</link><guid isPermaLink="true">https://erayerdin.com/mastering-testing-in-rust-using-rstest</guid><category><![CDATA[Rust]]></category><category><![CDATA[Testing]]></category><category><![CDATA[rstest]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Fri, 31 Mar 2023 17:32:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1680284021415/44cf486c-88a8-4b2a-b2ab-1654ea1d1def.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=w10ndWcuflo">https://www.youtube.com/watch?v=w10ndWcuflo</a></div>
]]></content:encoded></item><item><title><![CDATA[Integrating Dart's Build Runner with VSCode]]></title><description><![CDATA[There are cases that you need to generate code in Dart to be relieved from writing a lot of boilerplate codes. Some 3rd party libraries utilize it. freezed requires it to generate code to have compile-time errors for union classes. json_serializable ...]]></description><link>https://erayerdin.com/integrating-darts-build-runner-with-vscode</link><guid isPermaLink="true">https://erayerdin.com/integrating-darts-build-runner-with-vscode</guid><category><![CDATA[Dart]]></category><category><![CDATA[Flutter]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Fri, 15 Apr 2022 12:28:59 GMT</pubDate><content:encoded><![CDATA[<p>There are cases that you need to generate code in Dart to be relieved from writing a lot of boilerplate codes. Some 3rd party libraries utilize it. <a target="_blank" href="https://pub.dev/packages/freezed">freezed</a> requires it to generate code to have compile-time errors for union classes. <a target="_blank" href="https://pub.dev/packages/json_serializable">json_serializable</a> requires it to generate necessary methods for serializing into and deserializing from JSON data type. <a target="_blank" href="https://pub.dev/packages/auto_route">auto_route</a> generates code for type-safe routing in Flutter.</p>
<p>Some of you might think "Why do not we get these functionalities at runtime?". For example, I can annotate a class just like in Python, I get autocomplete and call it a day. While this is out of the scope of this post, the most basic reason is <strong>Dart checks code at compile time and removes the unused ones</strong>. This process is called <strong>tree-shaking</strong> and runtime interpretation of a language puts too much work on runtime, which sacrifices a great deal from the performance on device.</p>
<p>Given the scope of the 3rd party libraries of above and the reason why we need to generate code in Dart, we can safely assume that you will have to use <a target="_blank" href="https://pub.dev/packages/build_runner">build_runner</a> one day, one way or another.</p>
<h2 id="heading-launching-build-runner">Launching Build Runner</h2>
<p>There are two ways to launch build runner:</p>
<ul>
<li><p>Build launch</p>
</li>
<li><p>Watch launch</p>
</li>
</ul>
<p>Build launch is a one-off process. It simply analyzes the project directory, checks out if we ever need to generate some code, generates it and exits. You can launch a build as below:</p>
<pre><code class="lang-bash">flutter pub run build_runner build
</code></pre>
<p>Watch launch is just like build but with event loop. It runs forever, hence the name "watch". It triggers a new code generation task when it realizes a file has changed in the project directory. You can launch a watch as below:</p>
<pre><code class="lang-bash">flutter pub run build_runner watch
</code></pre>
<p>While these are simple expressions, I usually add some args that I find useful.</p>
<pre><code class="lang-bash">flutter pub run build_runner build lib/ --delete-conflicting-outputs
<span class="hljs-comment"># or</span>
flutter pub run build_runner watch lib/ --delete-conflicting-outputs
</code></pre>
<p>Here, I add <code>lib/</code> to tell build runner to only check <code>lib</code> directory. The other directories, especially in Flutter, are cluttered with configurations. They are not usually Dart files and even if so, I found out that they won't need any code generation. Giving <code>lib</code> directory makes it faster because now build runner has a narrow scope of file list to look for.</p>
<p>One strange behavior of build runner is that when it finds an already-generated file and needs to generate it again, it asks the user to confirm, which is an odd behavior. If I have changed the source file, I'd like the target file to be generated accordingly. That's why <code>--delete-conflicting-output</code> flag is needed. It automatically answers "Yes" to replace the generated files.</p>
<p>This is how I use build runner, yet build runner is sometimes a problematic beast. You need to constantly check its output to know if it failed or not. So, launching it on an external terminal or integrated terminal in VSCode requires a lot of mouse actions (which all devs agree it is not desirable). That's why I came up with a solution to integrate it with VSCode seamlessly so that I do not have to worry about the generated code.</p>
<blockquote>
<p>🗒 <strong>Note</strong></p>
<p>Before you mention, I have already tried <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=GaetSchwartz.build-runner">Build Runner</a> extension for VSCode. It only provides a way to launch it with either status bar or a keyboard shortcut and also it seems to be buggy on Linux. I've got a better solution.</p>
</blockquote>
<h2 id="heading-writing-task-for-build-runner">Writing Task for Build Runner</h2>
<p>VSCode has a feature called "Tasks". It lets you launch dev tools (without the debugger injected, so it is naturally faster).</p>
<p>So, create <code>.vscode/tasks.json</code> file in your project root and add these:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"version"</span>: <span class="hljs-string">"2.0.0"</span>,
    <span class="hljs-attr">"tasks"</span>: [
        <span class="hljs-comment">// build runner's build task</span>
        {
            <span class="hljs-attr">"label"</span>: <span class="hljs-string">"build_runner-build"</span>, <span class="hljs-comment">// this label will be useful later</span>
            <span class="hljs-attr">"type"</span>: <span class="hljs-string">"flutter"</span>,
            <span class="hljs-attr">"command"</span>: <span class="hljs-string">"flutter"</span>,
            <span class="hljs-attr">"args"</span>: [
                <span class="hljs-string">"pub"</span>,
                <span class="hljs-string">"run"</span>,
                <span class="hljs-string">"build_runner"</span>,
                <span class="hljs-string">"build"</span>,
                <span class="hljs-string">"lib/"</span>, <span class="hljs-comment">// only scan lib dir</span>
                <span class="hljs-string">"--delete-conflicting-outputs"</span>, <span class="hljs-comment">// do not ask to delete conflicting files</span>
            ],
            <span class="hljs-attr">"presentation"</span>: {
                <span class="hljs-attr">"echo"</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// write logs</span>
                <span class="hljs-attr">"reveal"</span>: <span class="hljs-string">"silent"</span>, <span class="hljs-comment">// i don't wanna see the terminal window</span>
                <span class="hljs-attr">"focus"</span>: <span class="hljs-literal">false</span>,
                <span class="hljs-attr">"panel"</span>: <span class="hljs-string">"shared"</span>,
                <span class="hljs-attr">"showReuseMessage"</span>: <span class="hljs-literal">true</span>,
                <span class="hljs-attr">"clear"</span>: <span class="hljs-literal">false</span> <span class="hljs-comment">// i wanna see logs when I want</span>
            },
            <span class="hljs-attr">"problemMatcher"</span>: [
                <span class="hljs-string">"$dart-build_runner"</span>
            ],
            <span class="hljs-attr">"group"</span>: <span class="hljs-string">"build"</span>,
            <span class="hljs-attr">"detail"</span>: <span class="hljs-string">""</span>
        },
        <span class="hljs-comment">// build runner's watch task</span>
        {
            <span class="hljs-attr">"label"</span>: <span class="hljs-string">"build_runner-watch"</span>,
            <span class="hljs-attr">"type"</span>: <span class="hljs-string">"flutter"</span>,
            <span class="hljs-attr">"command"</span>: <span class="hljs-string">"flutter"</span>,
            <span class="hljs-attr">"args"</span>: [
                <span class="hljs-string">"pub"</span>,
                <span class="hljs-string">"run"</span>,
                <span class="hljs-string">"build_runner"</span>,
                <span class="hljs-string">"watch"</span>, <span class="hljs-comment">// the same stuff but watching this time</span>
                <span class="hljs-string">"lib/"</span>,
                <span class="hljs-string">"--delete-conflicting-outputs"</span>,
            ],
            <span class="hljs-attr">"presentation"</span>: {
                <span class="hljs-attr">"echo"</span>: <span class="hljs-literal">true</span>,
                <span class="hljs-attr">"reveal"</span>: <span class="hljs-string">"always"</span>, <span class="hljs-comment">// show output for watch tasks</span>
                <span class="hljs-attr">"focus"</span>: <span class="hljs-literal">false</span>,
                <span class="hljs-attr">"panel"</span>: <span class="hljs-string">"shared"</span>,
                <span class="hljs-attr">"showReuseMessage"</span>: <span class="hljs-literal">true</span>,
                <span class="hljs-attr">"clear"</span>: <span class="hljs-literal">false</span>
            },
            <span class="hljs-attr">"problemMatcher"</span>: [
                <span class="hljs-string">"$dart-build_runner"</span>
            ],
            <span class="hljs-attr">"group"</span>: <span class="hljs-string">"build"</span>,
            <span class="hljs-attr">"detail"</span>: <span class="hljs-string">""</span>
        },
    ]
}
</code></pre>
<p>Now, you can <kbd>CTRL</kbd>+<kbd>SHIFT</kbd>+<kbd>P</kbd>, search "Tasks: Run Task" and select what you need to run.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://vimeo.com/699760533">https://vimeo.com/699760533</a></div>
<p>This is cool and all, yet you need to either run build each time you change something in a <em>generative</em> file or you need to spawn a watch process. Each has their own things.</p>
<p>As I've said, <code>build_runner build</code> is a one-off process. It reads, analyzes, generates and exits. This means there won't be any background process that will hog your computer's resources. This also means <code>build_runner build</code> is going to start from the very beginning each time it gets spawned.</p>
<p>On the other hand, <code>build_runner watch</code> initializes build runner and waits. It is especially good if you are frequently generating codes because you won't initialize it over and over again. The subsequent generations will be faster but, at the same time, it will constantly use resources since it is a never-ending process.</p>
<p>What about we run <code>build_runner build</code> after we save a, say, Dart file? That would be conveinent and also not resource draining solution.</p>
<h2 id="heading-running-a-task-after-file-save">Running a Task After File Save</h2>
<p>There is a VSCode extension called <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.triggertaskonsave">Trigger Task on Save</a>. Hence the name, it will run a task after a file is saved.</p>
<p>After installing it, you have to add a couple of lines to <code>.vscode/settings.json</code> file.</p>
<pre><code class="lang-json">{
  <span class="hljs-comment">// other settings</span>
  <span class="hljs-attr">"triggerTaskOnSave.tasks"</span>: {
    <span class="hljs-comment">// run the task with label `build_runner-build`</span>
    <span class="hljs-attr">"build_runner-build"</span>: [
      <span class="hljs-string">"lib/**/*.dart"</span>, <span class="hljs-comment">// if file is a dart file and under lib directory</span>
    ],
  },
  <span class="hljs-attr">"triggerTaskOnSave.resultIndicator"</span>: <span class="hljs-string">"statusBar.background"</span>, <span class="hljs-comment">// change status bar bg color</span>
  <span class="hljs-attr">"triggerTaskOnSave.failureColour"</span>: <span class="hljs-string">"#c62828"</span>, <span class="hljs-comment">// success color</span>
  <span class="hljs-attr">"triggerTaskOnSave.successColour"</span>: <span class="hljs-string">"#2e7d32"</span>, <span class="hljs-comment">// failure color</span>
  <span class="hljs-attr">"triggerTaskOnSave.showNotifications"</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// show notification if fails or succeeds</span>
  <span class="hljs-attr">"workbench.colorCustomizations"</span>: {},
}
</code></pre>
<p>After this, whenever you save a Dart file, it will launch the task labeled <code>build_runner-build</code>, which will inform you with notifications <em>and</em> change the color of status bar to green or red depending on success.</p>
<p>With this method, you don't even have to touch the build runner again. It will do the work for you.</p>
]]></content:encoded></item><item><title><![CDATA[Checking Unused Dependencies in a Rust Project with Github Actions]]></title><description><![CDATA[TL;DR
Below is the .github/workflows/udeps.yaml file I have come up with:
name: udeps

on: [push, pull_request]

jobs:
  Test:
    strategy:
      matrix:
        os: [ubuntu-latest]
        # udeps requires nightly
        rust: [nightly]

    runs-...]]></description><link>https://erayerdin.com/checking-unused-dependencies-in-a-rust-project-with-github-actions</link><guid isPermaLink="true">https://erayerdin.com/checking-unused-dependencies-in-a-rust-project-with-github-actions</guid><category><![CDATA[Rust]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[github-actions]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Tue, 30 Nov 2021 13:00:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1638277077352/7SVePDJj-y.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-tldr">TL;DR</h2>
<p>Below is the <code>.github/workflows/udeps.yaml</code> file I have come up with:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">udeps</span>

<span class="hljs-attr">on:</span> [<span class="hljs-string">push</span>, <span class="hljs-string">pull_request</span>]

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">Test:</span>
    <span class="hljs-attr">strategy:</span>
      <span class="hljs-attr">matrix:</span>
        <span class="hljs-attr">os:</span> [<span class="hljs-string">ubuntu-latest</span>]
        <span class="hljs-comment"># udeps requires nightly</span>
        <span class="hljs-attr">rust:</span> [<span class="hljs-string">nightly</span>]

    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.os</span> <span class="hljs-string">}}</span>

    <span class="hljs-attr">steps:</span>
      <span class="hljs-comment"># get the code</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v1</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">"Repository Checkout"</span>
      <span class="hljs-comment"># set up rust environment</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions-rs/toolchain@v1</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">"Rust Toolchain Setup"</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">profile:</span> <span class="hljs-string">minimal</span>
          <span class="hljs-attr">toolchain:</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.rust</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">override:</span> <span class="hljs-literal">true</span>
      <span class="hljs-comment"># cache build to wait shorter on next builds</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/cache@v2</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">"Cache Setup"</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">path:</span> <span class="hljs-string">|
            ~/.cargo/registry
            ~/.cargo/git
            target
</span>          <span class="hljs-attr">key:</span> <span class="hljs-string">${{</span> <span class="hljs-string">runner.os</span> <span class="hljs-string">}}-cargo-${{</span> <span class="hljs-string">hashFiles('**/Cargo.lock')</span> <span class="hljs-string">}}</span>
      <span class="hljs-comment"># install cargo-udeps</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions-rs/cargo@v1</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">"Udeps Installation"</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">command:</span> <span class="hljs-string">install</span>
          <span class="hljs-attr">args:</span> <span class="hljs-string">cargo-udeps</span> <span class="hljs-string">--locked</span>
      <span class="hljs-comment"># use cargo-udeps</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions-rs/cargo@v1</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">"Unused Dependency Check"</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">command:</span> <span class="hljs-string">udeps</span>
</code></pre>
<hr />
<h2 id="heading-too-short-gotta-read">Too Short; Gotta Read</h2>
<p>cargo-udeps is an amazing project that helps you analyze unused dependencies on your Rust codebase. You can simply do <code>cargo install cargo-udeps</code> to install it. The only problem with it, however, is that it runs on nightly.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/est31/cargo-udeps">https://github.com/est31/cargo-udeps</a></div>
<p>On the other hand, there's no easier way to automatize it. Currently ,there is an issue on actions-rs/meta that proposes to implement udeps, but it is open since 2019 and there's no clear indication that it will be resolved in the near future.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/actions-rs/meta/issues/11">https://github.com/actions-rs/meta/issues/11</a></div>
<p>That does not mean there is no way, though. Create a new workflow named <code>.github/workflows/udeps.yaml</code> and give some initial content:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">udeps</span> <span class="hljs-comment"># change to whatever you want</span>

<span class="hljs-attr">on:</span> [<span class="hljs-string">push</span>, <span class="hljs-string">pull_request</span>] <span class="hljs-comment"># run on push and pull requests</span>
</code></pre>
<p>We need to set up <code>jobs</code> so that it runs on Ubuntu and Rust Nightly as below:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">Test:</span>
    <span class="hljs-attr">strategy:</span>
      <span class="hljs-attr">matrix:</span>
        <span class="hljs-attr">os:</span> [<span class="hljs-string">ubuntu-latest</span>]
        <span class="hljs-attr">rust:</span> [<span class="hljs-string">nightly</span>] <span class="hljs-comment"># this is where we define to use rust nightly</span>

    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.os</span> <span class="hljs-string">}}</span>
</code></pre>
<p>And, of course, we have to define some steps</p>
<pre><code class="lang-yaml">    <span class="hljs-attr">steps:</span>
      <span class="hljs-comment"># check out the code</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v1</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">"Repository Checkout"</span>
      <span class="hljs-comment"># get the minimal requirements to compile rust</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions-rs/toolchain@v1</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">"Rust Toolchain Setup"</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">profile:</span> <span class="hljs-string">minimal</span>
          <span class="hljs-attr">toolchain:</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.rust</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">override:</span> <span class="hljs-literal">true</span>
</code></pre>
<p>We need to install cargo-udeps in order to use it. To do that:</p>
<pre><code class="lang-yaml">      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions-rs/cargo@v1</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">"Udeps Installation"</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">command:</span> <span class="hljs-string">install</span>
          <span class="hljs-attr">args:</span> <span class="hljs-string">cargo-udeps</span> <span class="hljs-string">--locked</span>
</code></pre>
<p>And, finally, we need to run it:</p>
<pre><code class="lang-yaml">      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions-rs/cargo@v1</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">"Unused Dependency Check"</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">command:</span> <span class="hljs-string">udeps</span>
          <span class="hljs-comment"># same as `cargo udeps`</span>
          <span class="hljs-comment"># we don't need `cargo +nightly udeps`</span>
          <span class="hljs-comment"># because we are already in nightly env</span>
</code></pre>
<p>Of course, you can also add some caching configuration on it. TL;DR section on top already covers it for you.</p>
<p>Save, commit and push. When there's an unused dependency, this workflow will fail since cargo-udeps exits with exit-code 0.</p>
]]></content:encoded></item><item><title><![CDATA[Complete Guide to Setup SSH Keys for Github (in Linux)]]></title><description><![CDATA[I use 2FA wherever I can. One of them is Github. However, the problem with 2FA, at least for Github, is that you have to get and use your personal access token for pushing to your repository on Github instead of your password. Well, this makes sense ...]]></description><link>https://erayerdin.com/complete-guide-to-setup-ssh-keys-for-github-in-linux</link><guid isPermaLink="true">https://erayerdin.com/complete-guide-to-setup-ssh-keys-for-github-in-linux</guid><category><![CDATA[Linux]]></category><category><![CDATA[ssh]]></category><category><![CDATA[Git]]></category><category><![CDATA[GitHub]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Tue, 18 May 2021 08:57:58 GMT</pubDate><content:encoded><![CDATA[<p>I use 2FA wherever I can. One of them is Github. However, the problem with 2FA, at least for Github, is that you have to get and use your personal access token for pushing to your repository on Github instead of your password. Well, this makes sense since the ability to access, read and write to your repository must have a security level to a similar extent to simply logging in Github website, yet personal access token is just <em>too long</em>, you can't memorize it and you need to take a note somewhere so that you can copy and paste each time. However, HTTPS is not the only way you can push to your repository. SSH is one of them and it is safer to use.</p>
<p>SSH keys are located in your computer, which means your computer is the <em>key</em> to push to or pull from your repository. That also means any other machine will not be able to push to your repository. This is a great scenario for companies where they require access to the repository only on company machines. Instead of providing each employee credentials, you set it up on your company machines.</p>
<p>SSH keys also can be passwordless unless you define one. You do not have to write your password each time you push to the repository.</p>
<p>As to how to set it up, there are many great documentations, StackExchange answers or blog posts out there. In this post, I will try to provide a complete guide to set up SSH keys for your Github account.</p>
<h1 id="step-1-generating-ssh-key">Step 1: Generating SSH Key</h1>
<p>This step can be also followed  <a target="_blank" href="https://docs.github.com/en/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent">on Github's own documentation</a>. The documentation itself tells you what to do but does not go into details as to why. I will explain it.</p>
<p>Firstly, you should create a new SSH key by doing below:</p>
<pre><code class="lang-bash">ssh-keygen -t ed25519 -C <span class="hljs-string">"your_email@example.com"</span>
</code></pre>
<p>Change your email with your own email. The email you have used to register to Github is probably the best, otherwise you may have permission problems. Also, in this command, I use <code>ed25519</code> as a public key cryptography algorithm. There are also other algorithms as well such as RSA, but since Github recommends to use it, we better use it as well.</p>
<p>When you run this command, you will get an interactive session, asking you:</p>
<pre><code class="lang-plain">Enter a file in which to save the key (/home/you/.ssh/id_ed25519):
</code></pre>
<p>This part is important and is up to your choice. If you leave it as is, it will automatically find the key and use it when you try to log in with your SSH to Github (which is every <code>git push</code>), which is convenient for maybe some of us.</p>
<p>However, having different keys for different hosts also makes sense. If you use (or will use) SSH on a different service, then creating and grouping with different names under <code>~/.ssh</code> is a good idea. Using the same key for different services is similar to using the same key for your all houses. If the key gets somehow stolen, then all your stuff gets gone for sure. The catch is, if you rename your key, it will not be automatically discovered by SSH. So you will have to add your key to your agent each time you log in, which I will discuss later on.</p>
<p>If you have chosen the name, also you should be aware of the fact that you need to enter <em>full path</em> to the question. If you enter only the file name, then it gets created on the current working directory.</p>
<h1 id="step-2-setting-up-ssh-agent">Step 2: Setting Up SSH Agent</h1>
<p>We need to start <code>ssh-agent</code> and register our key in there <em>so that</em> whenever we <code>git push</code>, Git will be able to know to use SSH key.</p>
<p>In the Github's documentation above, it tells you to spawn <code>ssh-agent</code> process, yet the problem is that this process only lasts as long as your computer runs. When you restart, you need to start <code>ssh-agent</code> again.</p>
<p>However, in Linux, we have <code>systemctl</code>, a service manager that will spawn processes on boot <em>or</em> login. Luckily, our hero <a target="_blank" href="https://unix.stackexchange.com/users/249856/lightsing">lightsing</a> provides us <a target="_blank" href="https://unix.stackexchange.com/a/390631/73035">a way to register ssh-agent as systemctl service</a> so it can run on each log in automatically.</p>
<p>Firstly, you should know that SSH service is user-scoped. We have our keys under our home directory, so it is reasonable to register this service as user, which will run when we log in to our user (not when we boot up). In order to do that, we need to create the config directory for systemctl as seen below:</p>
<pre><code class="lang-bash">mkdir -p ~/.config/systemd/user/
</code></pre>
<p>Then, we will create <code>ssh-agent.service</code> file in there to spawn <code>ssh-agent</code> process when we log in. In this step, you can use whatever text editor you'd like, or create it with the default one like below:</p>
<pre><code class="lang-bash">touch ~/.config/systemd/user/ssh-agent.service
xdg-open ~/.config/systemd/user/ssh-agent.service
</code></pre>
<p>Paste below, save and close:</p>
<pre><code class="lang-service">[Unit]
Description=SSH key agent

[Service]
Type=simple
Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket
ExecStart=/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK

[Install]
WantedBy=default.target
</code></pre>
<p>This is basically a service file which describes to spawn <code>ssh-agent</code> and use socket file to communicate with other processes like Git in this case.</p>
<p>However, if you recognize in the service file, we also have <code>SSH_AUTH_SOCK</code> environment variable so we need to set it up so that <code>ssh-agent</code> can recognize it when it launches. In order to do that:</p>
<pre><code class="lang-bash">touch ~/.pam_environment
xdg-open ~/.pam_environment
</code></pre>
<p>And define the variable in that file, save and close:</p>
<pre><code class="lang-bash">SSH_AUTH_SOCK DEFAULT=<span class="hljs-string">"<span class="hljs-variable">${XDG_RUNTIME_DIR}</span>/ssh-agent.socket"</span>
</code></pre>
<p>Now we need to activate <code>ssh-agent</code> on boot is to enable it on systemctl and start it:</p>
<pre><code class="lang-bash">systemctl --user <span class="hljs-built_in">enable</span> ssh-agent
systemctl --user start ssh-agent
</code></pre>
<p><code>--user</code> flag tells this is a user-scoped service, which will spawn when your user logs in in your machine. <code>enable</code> is a subcommand telling "Start this service whenever I log in." and <code>start</code> is a subcommand telling "Start this service right away.".</p>
<p>You can check the status of your service by doing:</p>
<pre><code class="lang-bash">systemctl --user status ssh-agent
</code></pre>
<p>This should say "active (running)".</p>
<p>The next thing we should do is to tell <code>ssh-agent</code> to use our keys when we use Git. To do that, we need to add some line to <code>~/.ssh/config</code> file. Luckily, we can do it in one line in terminal:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">'AddKeysToAgent  yes'</span> &gt;&gt; ~/.ssh/config
</code></pre>
<p>Also, we better set the permissions for <code>~/.ssh/config</code> file to tell that <em>my user owns that file</em>. To do that:</p>
<pre><code class="lang-bash">chmod 600 ~/.ssh/config
</code></pre>
<h1 id="step-3-setting-up-github-to-use-ssh-key">Step 3: Setting Up Github to Use SSH Key</h1>
<p>Github's documentation also <a target="_blank" href="https://docs.github.com/en/github/authenticating-to-github/adding-a-new-ssh-key-to-your-github-account">has this already covered</a>. I will try to explain even further.</p>
<p>First, you should login to your Github account and head to settings page:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621327306006/mYwbw1epk.png" alt="click your profile image and click settings" /></p>
<p>Then, you should go to "SSH and GPG Keys" page:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621327426708/yDVpoBhRT.png" alt="click SSH and GPG keys button on the left" /></p>
<p>Then you click "New SSH Key" button:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621327515215/XC0fjYcsK.png" alt="click new ssh key button" /></p>
<p>You should see a form as below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621327555906/L-RtBac_3.png" alt="new ssh key form" /></p>
<p>In this form, name can be whatever you'd like, and can be human-readable. Since my SSH key is <code>github_homemachine</code>, I will call it "Github Home Machine" in here.</p>
<p>In the Key input, you should paste the content of your public key you have created under <code>~/.shh</code> directory. Remember, though, you should paste your public key, which ends with <code>pub</code> extension. Then hit save.</p>
<h1 id="step-4-testing-ssh-key">Step 4: Testing SSH Key</h1>
<p>You can test if you are authenticated on <code>github.com</code> without actually pushing or pulling with Git. All you need to do is:</p>
<pre><code class="lang-bash">ssh git@github.com -v
</code></pre>
<p>Almost near the end, you should see "Hi erayerdin! You've successfully authenticated, but GitHub does not provide shell access.", which is a good sign.</p>
<h1 id="step-5-using-ssh-key">Step 5: Using SSH Key</h1>
<p>When you complete this setup, SSH URL will be the default in Github when you click "Code" button on any repository's home page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621327785249/SUBcNG2Jz.png" alt="it is the default as you can see" /></p>
<p>You should use this in your projects.</p>
<h2 id="how-to-use-on-a-new-project">How to Use On a New Project</h2>
<p>You should copy the SSH link provided by "Code" button on repository's home page. <code>cd</code> into your local repository and add it as such:</p>
<pre><code class="lang-bash">git remote add origin git@github.com:username/reponame.git
</code></pre>
<h2 id="how-to-change-existing-repository-to-ssh-key">How to Change Existing Repository to SSH Key</h2>
<p>First, you need to remove <code>origin</code> from your local repository. <code>cd</code> into there and do:</p>
<pre><code class="lang-bash">git remote remove origin
</code></pre>
<p>Then, just like a new project, add your SSH URL:</p>
<pre><code><span class="hljs-attribute">git</span> remote add origin git<span class="hljs-variable">@github</span>.com:username/reponame.git
</code></pre><hr />
<p>This is how you setup SSH with your Github account, which is a safer way and will make it easier to access a repository at the end of the day. Hope this post also helped you.</p>
<hr />
<h1 id="troubleshooting">Troubleshooting</h1>
<h2 id="it-was-working-but-now-it-says-permission-denied-when-i-try-to-push-my-code">It was working, but now it says "Permission denied" when I try to push my code.</h2>
<p>The problem is probably your key's name being not one of defaults. There are two solutions to this: (i) either rename your key to one of SSH defaults so it can be detected automatically (ii) or add your key to the agent each time you restart your computer (yes, the problem was you restarted your computer so your SSH agent got reset).</p>
<p>To apply the first solution, just go into <code>~/.ssh</code> and rename your private and public key to <code>id_ed25519</code> and <code>id_25519.pub</code>. This solution is convenient if you have only one SSH service and that is Github. Or you can use the same key multiple times but this arises security concerns.</p>
<p>To apply the second solution, just do <code>ssh-add ~/.ssh/my_key_name</code> each time you log in or restart your machine. With this solution, you can use different keys under different names with different services using SSH, which is more secure than the first solution but, as I've said, requires this extra step on each time you reboot your machine.</p>
]]></content:encoded></item><item><title><![CDATA[Quick Note: Changing Testing Database in Laravel]]></title><description><![CDATA[By default, Laravel uses in-memory SQLite database to run your tests doing database operations. You can confirm this by checking phpunit.xml in the root of your Laravel project.
<!-- ... -->
<php>
    <!-- ... -->
    <server name="CACHE_DRIVER" valu...]]></description><link>https://erayerdin.com/quick-note-changing-testing-database-in-laravel</link><guid isPermaLink="true">https://erayerdin.com/quick-note-changing-testing-database-in-laravel</guid><category><![CDATA[PHP]]></category><category><![CDATA[Laravel]]></category><category><![CDATA[PHPUnit]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Fri, 22 May 2020 12:53:17 GMT</pubDate><content:encoded><![CDATA[<p>By default, Laravel uses in-memory SQLite database to run your tests doing database operations. You can confirm this by checking <code>phpunit.xml</code> in the root of your Laravel project.</p>
<pre><code class="lang-xml"><span class="hljs-comment">&lt;!-- ... --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">php</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- ... --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">server</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"CACHE_DRIVER"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"array"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">server</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"DB_CONNECTION"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"sqlite"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">server</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"DB_DATABASE"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">":memory:"</span>/&gt;</span>
    <span class="hljs-comment">&lt;!-- ... --&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">php</span>&gt;</span>
<span class="hljs-comment">&lt;!-- ... --&gt;</span>
</code></pre>
<p>Laravel does this because it is much much faster to run tests in-memory SQLite. Considering we have two tests called <code>TestFoo</code> and <code>TestBar</code>, the lifecycle of database testing is similar to below:</p>
<ol>
<li>Run all migrations before all tests.</li>
<li>Run each <code>TestFoo</code> tests.</li>
<li>Clear database after each <code>TestFoo</code> tests if <code>RefreshDatabase</code> trait is <code>use</code>d.</li>
<li>Run <code>TestBar</code>.</li>
<li>Clear database after each <code>TestBar</code> tests if <code>RefreshDatabase</code> trait is <code>use</code>d.</li>
<li>Rollback all migrations.</li>
</ol>
<p>Migration process and clearing all tables in a database is quite costly. That&#39;s why it is a viable choice for Laravel to use in-memory SQLite databases by default. However, SQLite might not have all the features you&#39;d like to use as MariaDB/MySQL. In my particular case, I have wanted to use <a target='_blank' rel='noopener noreferrer'  href="https://mariadb.com/kb/en/generated-columns/">stored columns</a>. There aren&#39;t any stored columns in SQLite. Thus, it is essential to use MariaDB as testing database. However, please note that running tests on a database not running on a memory just like SQLite will run the tests significantly slower.</p>
<h1 id="creating-a-testing-database">Creating A Testing Database</h1>
<p>In my case, I will use MariaDB. You need to create a separate testing database instead of a database you target in your machine. It&#39;s mainly because you might have factories and seeders which affect your main database. They will be affected (probably your records will get deleted) due to being used on tests. That&#39;s why we need a separate one.</p>
<p>So I login my MariaDB as root:</p>
<pre><code class="lang-bash">sudo mysql -u root
</code></pre>
<p>And then set up my testing database:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">DATABASE</span> myapp_testing; <span class="hljs-comment">-- replace "myapp" with whatever you'd like</span>
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">USER</span> <span class="hljs-string">'tester'</span>@<span class="hljs-string">'localhost'</span> <span class="hljs-keyword">identified</span> <span class="hljs-keyword">by</span> <span class="hljs-string">'111111'</span>; <span class="hljs-comment">-- change your username and password with what you'd like</span>
<span class="hljs-keyword">GRANT</span> ALL <span class="hljs-keyword">ON</span> myapp_testing.* <span class="hljs-keyword">TO</span> <span class="hljs-string">'tester'</span>@<span class="hljs-string">'localhost'</span>; <span class="hljs-comment">-- grant all privileges of user "tester" on "myapp_testing" database</span>
<span class="hljs-keyword">FLUSH</span> <span class="hljs-keyword">PRIVILEGES</span>; <span class="hljs-comment">-- refresh privilege cache</span>
</code></pre>
<p>You can replace these with whatever you&#39;d like.</p>
<h1 id="configuring-phpunit-accordingly">Configuring PHPUnit Accordingly</h1>
<p>First thing you notice might be that I create a new user. You might ask &quot;Why create a new user since I can use my own user on my development machine?&quot;. It&#39;s because you put your database credentials to <code>.env</code> file, which is in <code>.gitignore</code> file and will not be pushed to a git repository. On the other hand, we will add these to <code>phpunit.xml</code>, which is not listed in <code>.gitignore</code> (clearly because it&#39;s needed to be pushed in order to work in other machines) and thus will be pushd to a git repository. While you might not choose to create a new user, you definitely should do it for security reasons. We all have our usernames and passwords that we use in our local development server in our minds. We should not let people know that.</p>
<p>After we do this, we can change our <code>phpunit.xml</code> accordingly:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">server</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"DB_CONNECTION"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"mysql"</span>/&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">server</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"DB_DATABASE"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"myapp_testing"</span>/&gt;</span>
<span class="hljs-comment">&lt;!-- The lines below are new --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">server</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"DB_USERNAME"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"tester"</span>/&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">server</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"DB_PASSWORD"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"111111"</span>/&gt;</span>
</code></pre>
<hr>
<p>And next time we run <code>php artisan test</code>, you will realize it will use MariaDB mainly because it is significantly slower. As stated above, migration and refreshing the database take more time on a database that&#39;s on disk rather than in a memory like SQLite.</p>
]]></content:encoded></item><item><title><![CDATA[Setting Up A Switching Camera for Top-Down RPG Games in Godot]]></title><description><![CDATA[End Result
The end result is demonstrated below.
  
Introduction
I will talk about how you implement a camera in a top-down RPG game in Godot. Before going through, however, you need to check that you satisfy some requirements and environments listed...]]></description><link>https://erayerdin.com/setting-up-a-switching-camera-for-top-down-rpg-games-in-godot</link><guid isPermaLink="true">https://erayerdin.com/setting-up-a-switching-camera-for-top-down-rpg-games-in-godot</guid><category><![CDATA[C#]]></category><category><![CDATA[Game Development]]></category><category><![CDATA[Godot]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Thu, 30 Apr 2020 23:54:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1588290851615/b9ClHmETK.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="end-result">End Result</h1>
<p>The end result is demonstrated below.</p>
<p> <a target='_blank' rel='noopener noreferrer'  href="https://youtu.be/1MtWdU3fjA4"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1588285704775/9t_A4ylsp.png" alt="end result video"></a> </p>
<h1 id="introduction">Introduction</h1>
<p>I will talk about how you implement a camera in a top-down RPG game in Godot. Before going through, however, you need to check that you satisfy some requirements and environments listed below:</p>
<ul>
<li><strong>Godot 3.2</strong>: Alright, this is not strictly required but it&#39;s the latest stable version of Godot 3. This tutorial covers Godot 3. If you&#39;ve got version 2, there might be some huge differences.</li>
<li><strong>C#</strong>: This tutorial mainly uses the new C# feature of Godot, which is still to be considered experimental at this point. If you use GDScript, it still should click how you implement a similar logic in that domain.</li>
</ul>
<p>Also, this method has drawbacks as well as benefits, which is to be discussed at the end of this article.</p>
<h1 id="the-premise">The Premise</h1>
<p>It&#39;s actually a bit hard to setup the camera for Godot and it really depends on your needs. My first goal was to implement a camera that will collide with boundaries but that complicated things a lot. Then something clicked. Basically, my game could be divided by section, which utilizes the resolution of the game as constant. To visualize what I&#39;m saying, see the image below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1588286707053/SADHfqkME.png" alt="sections of the whole world"></p>
<p>In this image, I split my world into two sections, which are marked with blue rectangle (and pointed at with blue arrows if you cannot see it). These sections are only <em>as large as</em> the resolution of the game. So the logic is simple, when the player collides with one section, switch the camera to that section.</p>
<h1 id="setting-up-components">Setting Up Components</h1>
<p>The main tip for Godot is to save everything as scene for reusability purposes. Some <em>scenes</em> <em>are not meant to be launched directly</em>. I call these scenes <strong>components</strong>. These are meant to be injected into a scene and used.</p>
<p>In this case, I need two exact components:</p>
<ul>
<li>An <a target='_blank' rel='noopener noreferrer'  href="https://docs.godotengine.org/en/stable/classes/class_area2d.html">Area2D</a> component called <strong>Section</strong>.</li>
<li>A <a target='_blank' rel='noopener noreferrer'  href="https://docs.godotengine.org/en/stable/classes/class_camera2d.html">Camera2D</a> component called <strong>Camera</strong>.</li>
</ul>
<p>Whenever the player collides with Section, it will emit two <a target='_blank' rel='noopener noreferrer'  href="https://docs.godotengine.org/en/stable/classes/class_area2d.html#signals">signals for Area2D</a>, named <code>body_entered</code> and <code>body_exited</code>. In <code>body_entered</code> signal, we will invoke a method that loads Camera component on runtime, add it to the tree as a child and <a target='_blank' rel='noopener noreferrer'  href="https://docs.godotengine.org/en/stable/classes/class_camera2d.html#class-camera2d-property-current">set it as the current camera</a>. In <code>body_exited</code> signal, we will do the reverse.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1588287764021/IupKzglLK.png" alt="section component scene"></p>
<p>This is how <strong>Section</strong> component looks like. The scene tree is formed as below:</p>
<pre><code><span class="hljs-deletion">- section: Area2D</span>
<span class="hljs-deletion">-- collision: CollisionShape2D(visible=false)</span>
</code></pre><p>Notice how <code>collision</code> node&#39;s <code>visible</code> property is set to <code>false</code> by default. That&#39;s because it would cover entire game world with a blue mask while we develop the game and make it quite harder to see and manipulate the world. Also, <code>collision</code>&#39;s boundaries are set exactly to the game resolution as it&#39;s seen by the green rectangle above.</p>
<p><code>section</code> emits two signals on itself:</p>
<ul>
<li><code>body_entered</code> to <code>_InitCameraSignal()</code> on <strong>Section</strong> component, which means on itself</li>
<li><code>body_exited</code> to <code>_UninitCameraSignal()</code> on <strong>Section</strong> component, which means on itself</li>
</ul>
<p>On the other hand, <strong>Camera</strong> component is actually a very simple scene, containing only a <code>Camera2D</code> node named <code>camera</code> as root. See below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1588288494154/_wWhxsKl0.png" alt="camera component scene"></p>
<p>The things you need to be sure is to set <strong>Anchor Mode</strong> to &quot;Fixed TopLeft&quot; so that the camera&#39;s origin should be at top-left, which makes it easy to place on game world, and <strong>Current</strong> to &quot;On&quot; to immediately focus on that camera when the game loads.</p>
<h1 id="the-code">The Code</h1>
<p><strong>Section</strong> component will deal with setting the camera when player collides. Let&#39;s start from scratch.</p>
<pre><code class="lang-c#">using Godot;
using System;

public class Section : Area2D
{
    private PackedScene cameraScene;
    private Camera2D camera;

    public override void _Ready()
    {
        // to be implemented
    }

    private void _InitCameraSignal(Node body)
    {
        // to be implemented
    }

    private void _UninitCameraSignal(Node body)
    {
        // to be implemented
    }
}
</code></pre>
<p><code>cameraScene</code> property will be used to load <strong>Camera</strong> component on the fly and <code>camera</code> property will be used to mutate its properties, such as <code>current</code> property of <code>Camera2D</code>.</p>
<p>Whenever a scene loads a section, it will call <code>_Ready</code> method, let&#39;s see how that goes.</p>
<pre><code class="lang-c#">public override void _Ready()
{
    GD.Print(String.Format(&quot;Preparing section: {0}&quot;, Name));
    // load Camera component
    cameraScene = (PackedScene)ResourceLoader.Load(&quot;res://components/Camera.tscn&quot;);
}
</code></pre>
<p>When <strong>Section</strong> is ready, it will load <strong>Camera</strong> scene once so that it will never do that again. Loading a resource, especially in software types like games where you need to compute and render every pixel on the screen based on user input and do that probably 60 times per second, can be quite resource-draining. That&#39;s why we need to load it once and reuse it when in need. Now it&#39;s time to write <code>body_entered</code>  emitter, <code>_InitCameraSignal</code> method:</p>
<pre><code class="lang-c#">private void _InitCameraSignal(Node body)
{
    GD.Print(String.Format("Invoking camera enter signal for area named {0}...", Name));
    // if the body that entered is player and camera is null
    if (body.Name == "player" &amp;&amp; camera == null)
    {
        // instantiate camera
        camera = (Camera2D)cameraScene.Instance();
        // add it as child to Section component
        AddChild(camera);
        // set it as current so that Godot will use that camera
        camera.Current = true;
    }
}
</code></pre>
<p>Checking for the name of body is vital here because we&#39;d like to filter the others out. The thing to be careful here is that our player must be named <code>player</code> in the tree so that this method can actually work.</p>
<p>And let it run only when the camera is null. Setting the camera <code>null</code> will make more sense with <code>_UnintCameraSignal</code> method below:</p>
<pre><code class="lang-c#">private void _UninitCameraSignal(Node body)
{
    GD.Print(String.Format("Invoking camera exit signal for area named {0}...", Name));
    // if the body that exited is player and camera is not null
    if (body.Name == "player" &amp;&amp; camera != null)
    {
        // it's not the current camera anymore
        camera.Current = false;
        // remove it from the section
        RemoveChild(camera);
        // set the camera to null
        camera = null;
    }
}
</code></pre>
<p>Here we also set the <code>camera</code> to <code>null</code> because we would not like to have more than one camera at a time in our scene. Setting it to <code>null</code> will also result the camera to be freed from the memory after some time.</p>
<p>The final code can be viewed below:</p>
<pre><code class="lang-c#">using Godot;
using System;

public class Section : Area2D
{
    private PackedScene cameraScene;
    private Camera2D camera;

    public override void _Ready()
    {
        GD.Print(String.Format("Preparing section: {0}", Name));
        cameraScene = (PackedScene)ResourceLoader.Load("res://components/Camera.tscn");
    }

    private void _InitCameraSignal(Node body)
    {
        GD.Print(String.Format("Invoking camera enter signal for area named {0}...", Name));
        if (body.Name == "player" &amp;&amp; camera == null)
        {
            camera = (Camera2D)cameraScene.Instance();
            AddChild(camera);
            camera.Current = true;
        }
    }

    private void _UninitCameraSignal(Node body)
    {
        GD.Print(String.Format("Invoking camera exit signal for area named {0}...", Name));
        if (body.Name == "player" &amp;&amp; camera != null)
        {
            camera.Current = false;
            RemoveChild(camera);
            camera = null;
        }
    }
}
</code></pre>
<h1 id="adding-sections-in-the-world">Adding Sections in the World</h1>
<p>Now the only thing left is to add <strong>Section</strong> components to our game world.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1588289805175/Ubmk8lMuD.png" alt="injecting section to the game world at compile time"></p>
<p>We will repeat this many times until we cover all the game world. After adjusting the position of the sections, it will look like below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1588290039767/kTbGKyqaD.png" alt="sections in the scene tree and the 2d view"></p>
<p>And it will change the camera to the other section as we collide with another section.</p>
<h1 id="final-words-and-discussions">Final Words and Discussions</h1>
<p>This provides a camera that is locked in a particular section. This way, you will not need to deal with the boundaries of the world and how the camera will interact with that. That caused me a lot of headache, so instead of doing that, I thought this method is simpler and more useful in terms of reusability.</p>
<p>This method, however, also brings some considerations and drawbacks as well. One that comes to mind is that we constantly initialize a <code>Camera2D</code> and remove reference (setting it null) as we switch sections, which might be okay for small to middle sized worlds but as the world gets bigger, initializing constantly will bring a resource cost to the table. Also, in big worlds, cameras that are nullified, that have lost reference, will be cleaned after some time by the garbage collector, which will lead to some peaks as GC starts working that will result in frame skips as the player moves on.</p>
<p>This method also does not consider how the entities on unseen sections will react. So, if your game has enemies that has player detection, they might follow player from out of camera. I wanted to keep this as simple as possible, so I did not want to also cover that. Possibly the simples solution for your most basic demo game would be to design the game world with that&#39;s in mind. For instance, keeping enemies far from where the player will enter the Section and keep player detection radius as narrow as possible.</p>
<p>That&#39;s all. Eray&#39;s out.</p>
]]></content:encoded></item><item><title><![CDATA[NuShell: Shell Redefined]]></title><description><![CDATA[NuShell is an alternative shell. It has many features that are pretty useful such as table as output, filtering the columns and rows or searching them. That's why it is safe to say that it's not Bash compatible but being quite useful for what it curr...]]></description><link>https://erayerdin.com/nushell-shell-redefined</link><guid isPermaLink="true">https://erayerdin.com/nushell-shell-redefined</guid><category><![CDATA[shell]]></category><category><![CDATA[terminal]]></category><category><![CDATA[command line]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Sun, 26 Apr 2020 00:36:03 GMT</pubDate><content:encoded><![CDATA[<p><a target='_blank' rel='noopener noreferrer'  href="https://www.nushell.sh/">NuShell</a> is an alternative shell. It has many features that are pretty useful such as table as output, filtering the columns and rows or searching them. That&#39;s why it is safe to say that it&#39;s not Bash compatible but being quite useful for what it currently is. It is actually written in Rust, which is a technology that I am interested in. I tried to give it a try a couple of days ago and wanted to introduce it to you.</p>
<p>NuShell is cross-platform, you can install and use it in your Windows, Linux or Mac machine. In Linux, you can use your package system to install it. In other operating systems, you can <a target='_blank' rel='noopener noreferrer'  href="https://www.nushell.sh/installation.html">see their installation page</a> to see how to install it in your machine.</p>
<hr>
<h1 id="features">Features</h1>
<p>I would first like to give you a brief introduction to its key features.</p>
<h2 id="data-oriented-output-and-output-as-table">Data Oriented Output and Output as Table</h2>
<p>In NuShell, output as data is first-class citizen. The best way to represent data in a terminal is to show it as a table. For instance, doing <code>ls</code> will print the current directory as a table.</p>
<pre><code> &gt; <span class="hljs-selector-tag">ls</span>
───┬─────────┬──────┬──────┬─────────────
 # │ <span class="hljs-selector-tag">name</span>    │ <span class="hljs-selector-tag">type</span> │ <span class="hljs-selector-tag">size</span> │ <span class="hljs-selector-tag">modified</span> 
───┼─────────┼──────┼──────┼─────────────
 0 │ <span class="hljs-selector-tag">bar</span><span class="hljs-selector-class">.png</span> │ <span class="hljs-selector-tag">File</span> │  0 <span class="hljs-selector-tag">B</span> │ 4 <span class="hljs-selector-tag">secs</span> <span class="hljs-selector-tag">ago</span> 
 1 │ <span class="hljs-selector-tag">baz</span><span class="hljs-selector-class">.txt</span> │ <span class="hljs-selector-tag">File</span> │  0 <span class="hljs-selector-tag">B</span> │ 1 <span class="hljs-selector-tag">sec</span> <span class="hljs-selector-tag">ago</span> 
 2 │ <span class="hljs-selector-tag">foo</span>     │ <span class="hljs-selector-tag">Dir</span>  │      │ 12 <span class="hljs-selector-tag">secs</span> <span class="hljs-selector-tag">ago</span> 
───┴─────────┴──────┴──────┴─────────────
</code></pre><p>And pretty much many commands output as table like this one.</p>
<p>NuShell is also <em>kind of</em> object oriented. You can access embedded objects inside other objects. For example, see what <code>sys</code> does:</p>
<pre><code> &gt; <span class="hljs-selector-tag">sys</span>
───────┬─────────────────────────────────────────
 <span class="hljs-selector-tag">host</span>  │ <span class="hljs-selector-attr">[row 7 columns]</span> 
 <span class="hljs-selector-tag">cpu</span>   │ <span class="hljs-selector-attr">[row cores current ghz max ghz min ghz]</span> 
 <span class="hljs-selector-tag">disks</span> │ <span class="hljs-selector-attr">[table 6 rows]</span> 
 <span class="hljs-selector-tag">mem</span>   │ <span class="hljs-selector-attr">[row free swap free swap total total]</span> 
 <span class="hljs-selector-tag">temp</span>  │ <span class="hljs-selector-attr">[table 4 rows]</span> 
 <span class="hljs-selector-tag">net</span>   │ <span class="hljs-selector-attr">[table 2 rows]</span> 
───────┴─────────────────────────────────────────
</code></pre><p><code>sys</code> is an internal command and returns an object that is viewed as a table. You can access its internal properties with <code>get</code>. See below:</p>
<pre><code> &gt; sys | <span class="hljs-keyword">get</span> host
──────────┬─────────────────────────────────────
 name     │ Linux 
 release  │ <span class="hljs-number">4.19</span><span class="hljs-number">.117</span><span class="hljs-number">-1</span>-MANJARO 
 version  │ <span class="hljs-meta">#1 SMP Tue Apr 21 12:19:11 UTC 2020 </span>
 hostname │ eray-pc 
 arch     │ x86_64 
 uptime   │ <span class="hljs-number">6</span>:<span class="hljs-number">53</span>:<span class="hljs-number">59</span> 
 sessions │ [table <span class="hljs-number">3</span> rows] 
──────────┴─────────────────────────────────────
</code></pre><p>You can also get deeper:</p>
<pre><code> &gt; sys | <span class="hljs-keyword">get</span> host.release
 <span class="hljs-number">4.19</span>.117-<span class="hljs-number">1</span>-MANJARO
</code></pre><h2 id="pipeline-and-sort-filter">Pipeline and Sort &amp; Filter</h2>
<p>As a Bash user, using pipes (<code>|</code> character) is vital part of a development workflow and often used to process the output, whether it is to filter them, search them or redirect them. Since NuShell is data oriented, you can pretty much do these with its internal commands combining with pipes. For instance, say we only care about <code>name</code> and <code>type</code>, we can do:</p>
<pre><code> &gt; ls | pick name <span class="hljs-keyword">type</span>
───┬─────────┬──────
 # │ name    │ <span class="hljs-keyword">type</span> 
───┼─────────┼──────
 <span class="hljs-number">0</span> │ bar.png │ File 
 <span class="hljs-number">1</span> │ baz.txt │ File 
 <span class="hljs-number">2</span> │ foo     │ Dir 
───┴─────────┴──────
</code></pre><p>Assuming it is a long output, we can define it to get only to an extent as below:</p>
<pre><code> &gt; ls | first <span class="hljs-number">2</span>
───┬─────────┬──────┬──────┬────────────
 # │ name    │ <span class="hljs-keyword">type</span> │ size │ modified 
───┼─────────┼──────┼──────┼────────────
 <span class="hljs-number">0</span> │ bar.png │ File │  <span class="hljs-number">0</span> B │ <span class="hljs-number">4</span> mins ago 
 <span class="hljs-number">1</span> │ baz.txt │ File │  <span class="hljs-number">0</span> B │ <span class="hljs-number">4</span> mins ago 
───┴─────────┴──────┴──────┴────────────
</code></pre><p>Examples until now may not probably seem quite functional to you. NuShell has more. You can sort it by any column you&#39;d like as below:</p>
<pre><code> &gt; ls | sort-<span class="hljs-keyword">by</span> modified
───┬─────────┬──────┬──────┬────────────
 <span class="hljs-comment"># │ name    │ type │ size │ modified </span>
───┼─────────┼──────┼──────┼────────────
 <span class="hljs-number">0</span> │ foo     │ Dir  │      │ <span class="hljs-number">5</span> mins ago 
 <span class="hljs-number">1</span> │ bar.png │ File │  <span class="hljs-number">0</span> B │ <span class="hljs-number">5</span> mins ago 
 <span class="hljs-number">2</span> │ baz.txt │ File │  <span class="hljs-number">0</span> B │ <span class="hljs-number">5</span> mins ago 
───┴─────────┴──────┴──────┴────────────
</code></pre><p>You can filter by column:</p>
<pre><code> &gt; ls | <span class="hljs-built_in">where</span> <span class="hljs-built_in">type</span> == File
───┬─────────┬──────┬──────┬────────────
 <span class="hljs-comment"># │ name    │ type │ size │ modified </span>
───┼─────────┼──────┼──────┼────────────
 0 │ bar.png │ File │  0 B │ 7 mins ago 
 1 │ baz.txt │ File │  0 B │ 7 mins ago 
───┴─────────┴──────┴──────┴────────────
</code></pre><h2 id="useful-io-operations">Useful IO Operations</h2>
<p>NuShell provides useful internal commands while reading from the disk <em>or</em> from the network. One of them is <code>open</code>. This is like <code>cat</code> but better.</p>
<pre><code> &gt; <span class="hljs-keyword">open</span> baz.txt
 lorem ipsum
</code></pre><p>This is a simple text file. However, it gets even more useful when reading a data file we are probably familiar with, such as JSON, TOML or YAML files. For instance, see below for a JSON file:</p>
<pre><code> &gt; <span class="hljs-selector-tag">open</span> <span class="hljs-selector-tag">me</span><span class="hljs-selector-class">.json</span>
──────────┬────────────────
 <span class="hljs-selector-tag">name</span>     │ <span class="hljs-selector-tag">Eray</span> 
 <span class="hljs-selector-tag">surname</span>  │ <span class="hljs-selector-tag">Erdin</span> 
 <span class="hljs-selector-tag">contacts</span> │ <span class="hljs-selector-attr">[table 2 rows]</span> 
──────────┴────────────────
</code></pre><p>This is a JSON file, containing <code>name</code>, <code>surname</code> and <code>contacts</code> keys. <code>name</code> and <code>surname</code> are strings and <code>contacts</code> is an array of two objects. You can combine these with what you&#39;ve seen above, such as:</p>
<pre><code> &gt; <span class="hljs-keyword">open</span> me.json | <span class="hljs-keyword">get</span> contacts
───┬────────┬──────────
 # │ name   │ surname 
───┼────────┼──────────
 <span class="hljs-number">0</span> │ Ruslan │ Hasanov 
 <span class="hljs-number">1</span> │ Melih  │ Yıldırım 
───┴────────┴──────────

 &gt; <span class="hljs-keyword">open</span> me.json | <span class="hljs-keyword">get</span> contacts | sort-<span class="hljs-keyword">by</span> name
───┬────────┬──────────
 # │ name   │ surname 
───┼────────┼──────────
 <span class="hljs-number">0</span> │ Melih  │ Yıldırım 
 <span class="hljs-number">1</span> │ Ruslan │ Hasanov 
───┴────────┴──────────
</code></pre><p><code>open</code> allows you to work with your local operations. And there is also <code>fetch</code>, where you can do pretty much the same things with an API. For instance:</p>
<pre><code> &gt; fetch <span class="hljs-string">"https://jsonplaceholder.typicode.com/posts/1"</span>
────────┬────────────────────────────────────────────────────────────────────────────
 userId │ <span class="hljs-number">1</span> 
 <span class="hljs-keyword">id</span>     │ <span class="hljs-number">1</span> 
 title  │ sunt aut facere repellat provident occaecati excepturi optio reprehenderit 
 body   │ quia et suscipit 
        │ suscipit recusandae consequuntur expedita et cum 
        │ reprehenderit molestiae ut ut quas totam 
        │ nostrum rerum est autem sunt rem eveniet architecto 
────────┴────────────────────────────────────────────────────────────────────────────
</code></pre><p>And use many commands with pipes:</p>
<pre><code> &gt; fetch <span class="hljs-string">"https://jsonplaceholder.typicode.com/posts"</span> | <span class="hljs-built_in">where</span> userId == 1 | pick id title
───┬────┬────────────────────────────────────────────────────────────────────────────
 <span class="hljs-comment"># │ id │ title </span>
───┼────┼────────────────────────────────────────────────────────────────────────────
 0 │  1 │ sunt aut facere repellat provident occaecati excepturi optio reprehenderit 
 1 │  2 │ qui est esse 
───┴────┴────────────────────────────────────────────────────────────────────────────
</code></pre><p>Maybe your data type is not a well-known one and you&#39;d like to quickly parse it and see it readable on your terminal. NuShell solves this problem. Consider we have a text file with content as below:</p>
<pre><code><span class="hljs-attribute">Eray</span> <span class="hljs-comment"># Erdin</span>
Ruslan <span class="hljs-comment"># Hasanov</span>
Melih <span class="hljs-comment"># Yıldırım</span>
</code></pre><p>This contains names and surnames, line by line, oddly delimited by pound sign (<code>#</code> sign). We can quickly parse it on NuShell. First, split it to lines:</p>
<pre><code> &gt; open file.txt | lines
───┬──────────────────
 <span class="hljs-meta"># │ <span class="hljs-meta-string">&lt;value&gt;</span> </span>
───┼──────────────────
 <span class="hljs-number">0</span> │ Eray <span class="hljs-meta"># Erdin </span>
 <span class="hljs-number">1</span> │ Ruslan <span class="hljs-meta"># Hasanov </span>
 <span class="hljs-number">2</span> │ Melih <span class="hljs-meta"># Yıldırım </span>
───┴──────────────────
</code></pre><p>Then do <code>split-column</code>:</p>
<pre><code> &gt; <span class="hljs-keyword">open</span> file.txt | lines | <span class="hljs-keyword">split</span>-column <span class="hljs-string">" # "</span>
───┬─────────┬──────────
 <span class="hljs-comment"># │ Column1 │ Column2 </span>
───┼─────────┼──────────
 <span class="hljs-number">0</span> │ Eray    │ Erdin 
 <span class="hljs-number">1</span> │ Ruslan  │ Hasanov 
 <span class="hljs-number">2</span> │ Melih   │ Yıldırı<span class="hljs-keyword">m</span> 
───┴─────────┴──────────
</code></pre><p>We can also finally name our columns:</p>
<pre><code> &gt; <span class="hljs-keyword">open</span> file.txt | lines | <span class="hljs-keyword">split</span>-column <span class="hljs-string">" # "</span> name surname
───┬────────┬──────────
 <span class="hljs-comment"># │ name   │ surname </span>
───┼────────┼──────────
 <span class="hljs-number">0</span> │ Eray   │ Erdin 
 <span class="hljs-number">1</span> │ Ruslan │ Hasanov 
 <span class="hljs-number">2</span> │ Melih  │ Yıldırı<span class="hljs-keyword">m</span> 
───┴────────┴──────────
</code></pre><p>So you can also quickly parse an unknown file like this one.</p>
<h2 id="small-features">Small Features</h2>
<p>You can do math operations on it:</p>
<pre><code> &gt; = 2 + 3
5
</code></pre><p>You can quickly copy the output string with <code>clip</code>:</p>
<pre><code> &gt; <span class="hljs-keyword">open</span> textfile.txt | clip
</code></pre><p>You can convert output table to known table types such as CSV, TSV, HTML, Markdown, JSON, TOML, YAML, URL parameters and even SQLite. Assuming you have that unknown typed file with some data inside, just like before and we&#39;ve done the same thing as before:</p>
<pre><code> &gt; <span class="hljs-keyword">open</span> file.txt | lines | <span class="hljs-keyword">split</span>-column <span class="hljs-string">" # "</span> name surname
───┬────────┬──────────
 <span class="hljs-comment"># │ name   │ surname </span>
───┼────────┼──────────
 <span class="hljs-number">0</span> │ Eray   │ Erdin 
 <span class="hljs-number">1</span> │ Ruslan │ Hasanov 
 <span class="hljs-number">2</span> │ Melih  │ Yıldırı<span class="hljs-keyword">m</span> 
───┴────────┴──────────
</code></pre><p>You can convert it as such:</p>
<pre><code> &gt; open file.txt | lines | split-column " # " name surname | to-csv
name,surname
Eray,"Erdin"
Ruslan,"Hasanov"
Melih,Yıldırım
 &gt; open file.txt | lines | split-column " # " name surname | to-html
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">table</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>name<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>surname<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Eray<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Erdin
<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Ruslan<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Hasanov
<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Melih<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Yıldırım<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
 &gt; open file.txt | lines | split-column " # " name surname | to-json
[{"name":"Eray","surname":"Erdin"},{"name":"Ruslan","surname":"Hasanov"},{"name":"Melih","surname":"Yıldırım"}]
</code></pre><h1 id="drawbacks">Drawbacks</h1>
<p>NuShell is very useful, but there are some things to consider before using it. Despite being a minimum viable product, it is <em>still</em> a very young one. I will talk about the ones I know of. These might not be problem for you, or these might not be a problem if this article is old enough, might have been resolved.</p>
<p>One of these problems (for me) is that the configurations are persistent. NuShell does not have a solid concept of variables <em>in terms of Bash</em> yet. It has the logic of <em>configuration</em> and it persists from session to session. That&#39;s why it is not yet possible to set a temporary variable to be used.</p>
<p>Another one is that you cannot really <code>source</code> in your current scope, which renders it impossible to port some of your Bash scripts yet. One example comes to mind is Python&#39;s virtualenv. virtualenv uses <code>source</code> heavily in order to set its environment and it&#39;s not usable in a NuShell environment yet.</p>
<p>These problems also mean that your development toolkit might not quite integrate well with NuShell very well.</p>
<hr>
<p>NuShell is an exciting alternative shell. It redefines how a shell should behave from ground up. While it has some considerable drawbacks, I think the benefits outweigh it. That&#39;s why today I use NuShell as my default. Yes, Bash has quite much scripts but I can switch to it quickly typing <code>bash</code> anyway.</p>
]]></content:encoded></item><item><title><![CDATA[Quick Note: Implementing Running for Character in Godot]]></title><description><![CDATA[Forewords
Before beginning, I'd like to announce there's a new top-down action RPG tutorial  here  by  HeartBeast. It's the most up-to-date tutorial for Godot in Youtube right now, which is version 3.2. As of I'm writing this, he's already 11 episode...]]></description><link>https://erayerdin.com/quick-note-implementing-running-for-character-in-godot</link><guid isPermaLink="true">https://erayerdin.com/quick-note-implementing-running-for-character-in-godot</guid><category><![CDATA[Game Development]]></category><category><![CDATA[C#]]></category><category><![CDATA[Godot]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Sun, 05 Apr 2020 11:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1586046410274/114nxGR3u.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="forewords">Forewords</h2>
<p>Before beginning, I&#39;d like to announce there&#39;s a new top-down action RPG tutorial  <a target='_blank' rel='noopener noreferrer'  href="https://www.youtube.com/playlist?list=PL9FzW-m48fn2SlrW0KoLT4n5egNdX-W9a">here</a>  by  <a target='_blank' rel='noopener noreferrer'  href="https://www.youtube.com/user/uheartbeast">HeartBeast</a>. It&#39;s the most up-to-date tutorial for Godot in Youtube right now, which is version 3.2. As of I&#39;m writing this, he&#39;s already 11 episodes in. Go and show your love.</p>
<p>By the way, I&#39;m trying out C# in Godot, but the tutorial series above uses GDScript, so mine is going to be a bit different. I also need to state that I&#39;ve never coded in C# before, what I had in mind before I started C# was that C# was kinda like Java, which helped me understand it a lot but, if you see any quirky code, like violation of style guides or common practices in C#, let me know or simply ignore them.</p>
<p>This post also follows the logic of HeartBeast&#39;s tutorial, so I strongly recommend you check it out, at least 4 episodes in.</p>
<h2 id="movement-101">Movement 101</h2>
<p>Firstly, we need to understand that there are three parts for a smooth movement:</p>
<ul>
<li><strong>Acceleration</strong> is how fast a <em>player</em> starts moving.</li>
<li><strong>Friction</strong> is how fast a <em>player</em> stops moving.</li>
<li>Of course when a player <em>accelerates</em>, you need to define a peek value, which is the limit of how fast it can accelerate. This is called <strong>maximum speed</strong>.</li>
</ul>
<p>When you imagine it in a graph, it starts increasing as soon as the player receives an input and it starts decreasing back to zero when it stops receiving the input. See below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1586045757205/nQmt6v0xD.png" alt="graph about the speed of a player"></p>
<p>(I know this is not the most beautiful graph you&#39;ve ever seen but bear with me please.)</p>
<p>Knowing this, we can assume a player&#39;s code (assuming the player is a <code>KinematicBody2D</code>) is going to be as such:</p>
<pre><code class="lang-c#">using Godot;
using System;

public class Player : KinematicBody2D
{
    private const int ACCELERATION = 500;
    private const int MAX_SPEED = 60;
    private const int FRICTION = 500;

    private Vector2 velocity;

    public override void _PhysicsProcess(float delta)  // compute next frame
    {
        // let&#39;s create a vector for user input, defining which coordinates the vector is targeting to
        var input_vector = Vector2.Zero;  // equivalent to `new Vector2()`, I use it for shorthand sometimes
        input_vector.x = Input.GetActionStrength(&quot;ui_right&quot;) - Input.GetActionStrength(&quot;ui_left&quot;);  // assign *if it is left or right* to input vector
        input_vector.y = Input.GetActionStrength(&quot;ui_down&quot;) - Input.GetActionStrength(&quot;ui_up&quot;);  // assign *if it is up or down* to input vector
        input_vector = input_vector.Normalized();  // see heartbeast for this, he explains better

        if (input_vector == Vector2.Zero)  // if we do not receive any input
        {
            velocity = velocity.MoveToward(Vector2.Zero, FRICTION * delta);
        }
        else  // if we receive any input
        {
            velocity = velocity.MoveToward(input_vector * MAX_SPEED, ACCELERATION * delta);
        }

        velocity = MoveAndSlide(velocity);  // move to target and new assign target coordinates to velocity
    }
}
</code></pre>
<p>This is a basic movement which has a constant speed. You can play with <code>ACCELERATION</code>, <code>MAX_SPEED</code> and <code>FRICTION</code> constants to change the feel of your movement.</p>
<h2 id="how-to-run">How to Run</h2>
<p>Let&#39;s assume we&#39;d like to bump our speed when we, say, press <code>SHIFT</code> key. In order to do that, we first need to define an input. You can do that by clicking &quot;Project &gt; Project Settings&quot; menu...</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1586043594923/yHT2t8D6d.png" alt="project settings menu entry"></p>
<p>...and going into &quot;Input Map&quot; tab.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1586043718826/dHxfjzuef.png" alt="input map tab"></p>
<p>As you can see, the ones such as <code>ui_up</code> and <code>ui_down</code> in the code are defined here along with the keys they target. So, as in the image, we need to add a new action and mapping it to a key by first defining a name for our new action and clicking the &quot;Add&quot; button.</p>
<p>Then we need to add a key for our new <code>accelerate</code> action...</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1586044148811/YfHW7n7a4.png" alt="adding a key"></p>
<p>...and define a key for it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1586044155499/wHZKlJGaC.png" alt="defining a key"></p>
<p>When you do that, you can now check if <code>accelerate</code> action is received by writing a code like below in C#:</p>
<pre><code class="lang-c#">bool is_accelerating = Input.IsActionPressed(&quot;accelerate&quot;);
</code></pre>
<p>Now we need to refactor our code a little bit. I wanted to do this with as little change to the code as possible. Our target is <code>ACCELERATION</code>, <code>MAX_SPEED</code> and <code>FRICTION</code> constants.</p>
<p>The problem is these are constants, which are not meant to be mutated on the runtime. However, we&#39;d like to change the values of these depending on if we receive <code>accelerate</code> action or not. So, we change these to static.</p>
<pre><code class="lang-c#">private static int ACCELERATION = 500;
private static int MAX_SPEED = 60;
private static int FRICTION = 500;
</code></pre>
<p>There is also a very nice feature in C#. Just like Kotlin (for the sake of giving an example from JVM-based languages), we can write getters (and also setters) in property line. So, my code changes to:</p>
<pre><code class="lang-c#">private static int ACCELERATION
{
    get
    {
        var value = 500;
        if (Input.IsActionPressed(&quot;accelerate&quot;))
        {
            value = 700;
        }
        return value;
    }
}
private static int MAX_SPEED
{
    get
    {
        var value = 60;
        if (Input.IsActionPressed(&quot;accelerate&quot;))
        {
            value = 90;
        }
        return value;
    }
}
private static int FRICTION
{
    get
    {
        var value = 500;
        if (Input.IsActionPressed(&quot;accelerate&quot;))
        {
            value = 700;
        }
        return value;
    }
}
</code></pre>
<p>We define default values with <code>value</code> variable and change it if we receive <code>accelerate</code> action. The code above results in the table below:</p>
<table>
<thead>
<tr>
<td></td><td><strong>Normal</strong></td><td><strong>While <code>accelerate</code></strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>ACCELERATION</strong></td><td>500</td><td>700</td></tr>
<tr>
<td><strong>MAX_SPEED</strong></td><td>60</td><td>90</td></tr>
<tr>
<td><strong>FRICTION</strong></td><td>500</td><td>700</td></tr>
</tbody>
</table>
<p>You can, again, change the values as your needs. Some values feel like you are controlling a rock while others feel like the ground is ice.</p>
<h2 id="final-words">Final Words</h2>
<p>As I&#39;ve said in the beginning, be sure to check HeartBeast&#39;s <a target='_blank' rel='noopener noreferrer'  href="https://www.youtube.com/playlist?list=PL9FzW-m48fn2SlrW0KoLT4n5egNdX-W9a">Godot RPG series</a>. It&#39;s the hottest thing in Godot tutorials right now. See you in the next post.</p>
]]></content:encoded></item><item><title><![CDATA[How to Make Selenium Load Faster with Firefox in Python]]></title><description><![CDATA[Foreword
This article was first published in my Tumblr blog in 2015. Yes, the devblogging concept was not wide-spread those days and I was looking for a nice solution and Tumblr was a good choice. Now, however, we have many blogging solutions for dev...]]></description><link>https://erayerdin.com/how-to-make-selenium-load-faster-with-firefox-in-python</link><guid isPermaLink="true">https://erayerdin.com/how-to-make-selenium-load-faster-with-firefox-in-python</guid><category><![CDATA[selenium]]></category><category><![CDATA[Python]]></category><category><![CDATA[Firefox]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Wed, 11 Mar 2020 13:16:07 GMT</pubDate><content:encoded><![CDATA[<h2 id="foreword">Foreword</h2>
<p><a target='_blank' rel='noopener noreferrer'  href="https://alreadycoded.tumblr.com/post/132794826752/how-to-make-firefox-of-selenium-load-faster-in">This article was first published in my Tumblr blog in 2015</a>. Yes, the devblogging concept was not wide-spread those days and I was looking for a nice solution and Tumblr was a good choice. Now, however, we have many blogging solutions for developers. That&#39;s why I migrate the article here.</p>
<p>There are some things to be aware of, though. This article was published in 2015. Things were quite different back then.</p>
<ul>
<li><strong>There was no concept of headless browsing</strong>, a browser that runs as a service and not providing a GUI. In those days, there was a project called PhantomJS, which is pretty much abandoned today and does not receive updates. Today, however, major browsers provide a headless option. If you see some mumbling about PhantomJS, ignore it.</li>
<li><strong>The part about QuickJava extension configuration is removed in this version of article.</strong> The extension was removed from Firefox extension registry and does not exist today. It was basically an extension to disable some <em>things</em>, like Flash, Silverlight, Javascript etc. Today, Firefox provides configurations to disable them, but...</li>
<li><strong>Standard Firefox configurations are kept as is in this article.</strong> That&#39;s because (i) I am lazy, (ii) I want to persist my technical past and (iii) I&#39;ve actually linked this in a Stackoverflow question that still gets reactions today. That&#39;s why disabling CSS is not included in this article (which was done by QuickJava). You should figure it out.</li>
</ul>
<p>I&#39;ve got to say, however, I will return to this article one day and edit it out properly. Until then, though, I present you &quot;me&quot; in 2015.</p>
<h2 id="article">Article</h2>
<p>It is good to run a browser then manipulate the DOM elements on a page and scrap data. However, it might be a nightmare testing on a personal  computer. There are a couple of solutions for headless browser in  Python, but in Selenium, there’s one choice and <a target='_blank' rel='noopener noreferrer'  href="https://stackoverflow.com/questions/33587734/python-selenium-phantomjs-returns-empty-source-after-clicking-an-element">it seems to be buggy</a> while manipulating DOM elements. So there’s another choice, which is built-in widely in the most of Linux distributions: <em>Firefox</em>!</p>
<p>You might find it too slow. However, there are a couple of <code>about:config</code> tricks and extension for increasing the rendering speed. First, create a Firefox profile instance:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> selenium <span class="hljs-keyword">import</span> webdriver
profile = webdriver.FirefoxProfile()
</code></pre>
<p>And these are the built-in configuration of Firefox:</p>
<pre><code class="lang-python">profile.set_preference(<span class="hljs-string">"network.http.pipelining"</span>, <span class="hljs-keyword">True</span>)
profile.set_preference(<span class="hljs-string">"network.http.proxy.pipelining"</span>, <span class="hljs-keyword">True</span>)
profile.set_preference(<span class="hljs-string">"network.http.pipelining.maxrequests"</span>, <span class="hljs-number">8</span>)
profile.set_preference(<span class="hljs-string">"content.notify.interval"</span>, <span class="hljs-number">500000</span>)
profile.set_preference(<span class="hljs-string">"content.notify.ontimer"</span>, <span class="hljs-keyword">True</span>)
profile.set_preference(<span class="hljs-string">"content.switch.threshold"</span>, <span class="hljs-number">250000</span>)
profile.set_preference(<span class="hljs-string">"browser.cache.memory.capacity"</span>, <span class="hljs-number">65536</span>) <span class="hljs-comment"># Increase the cache capacity.</span>
profile.set_preference(<span class="hljs-string">"browser.startup.homepage"</span>, <span class="hljs-string">"about:blank"</span>)
profile.set_preference(<span class="hljs-string">"reader.parse-on-load.enabled"</span>, <span class="hljs-keyword">False</span>) <span class="hljs-comment"># Disable reader, we won't need that.</span>
profile.set_preference(<span class="hljs-string">"browser.pocket.enabled"</span>, <span class="hljs-keyword">False</span>) <span class="hljs-comment"># Duck pocket too!</span>
profile.set_preference(<span class="hljs-string">"loop.enabled"</span>, <span class="hljs-keyword">False</span>)
profile.set_preference(<span class="hljs-string">"browser.chrome.toolbar_style"</span>, <span class="hljs-number">1</span>) <span class="hljs-comment"># Text on Toolbar instead of icons</span>
profile.set_preference(<span class="hljs-string">"browser.display.show_image_placeholders"</span>, <span class="hljs-keyword">False</span>) <span class="hljs-comment"># Don't show thumbnails on not loaded images.</span>
profile.set_preference(<span class="hljs-string">"browser.display.use_document_colors"</span>, <span class="hljs-keyword">False</span>) <span class="hljs-comment"># Don't show document colors.</span>
profile.set_preference(<span class="hljs-string">"browser.display.use_document_fonts"</span>, <span class="hljs-number">0</span>) <span class="hljs-comment"># Don't load document fonts.</span>
profile.set_preference(<span class="hljs-string">"browser.display.use_system_colors"</span>, <span class="hljs-keyword">True</span>) <span class="hljs-comment"># Use system colors.</span>
profile.set_preference(<span class="hljs-string">"browser.formfill.enable"</span>, <span class="hljs-keyword">False</span>) <span class="hljs-comment"># Autofill on forms disabled.</span>
profile.set_preference(<span class="hljs-string">"browser.helperApps.deleteTempFileOnExit"</span>, <span class="hljs-keyword">True</span>) <span class="hljs-comment"># Delete temprorary files.</span>
profile.set_preference(<span class="hljs-string">"browser.shell.checkDefaultBrowser"</span>, <span class="hljs-keyword">False</span>)
profile.set_preference(<span class="hljs-string">"browser.startup.homepage"</span>, <span class="hljs-string">"about:blank"</span>)
profile.set_preference(<span class="hljs-string">"browser.startup.page"</span>, <span class="hljs-number">0</span>) <span class="hljs-comment"># blank</span>
profile.set_preference(<span class="hljs-string">"browser.tabs.forceHide"</span>, <span class="hljs-keyword">True</span>) <span class="hljs-comment"># Disable tabs, We won't need that.</span>
profile.set_preference(<span class="hljs-string">"browser.urlbar.autoFill"</span>, <span class="hljs-keyword">False</span>) <span class="hljs-comment"># Disable autofill on URL bar.</span>
profile.set_preference(<span class="hljs-string">"browser.urlbar.autocomplete.enabled"</span>, <span class="hljs-keyword">False</span>) <span class="hljs-comment"># Disable autocomplete on URL bar.</span>
profile.set_preference(<span class="hljs-string">"browser.urlbar.showPopup"</span>, <span class="hljs-keyword">False</span>) <span class="hljs-comment"># Disable list of URLs when typing on URL bar.</span>
profile.set_preference(<span class="hljs-string">"browser.urlbar.showSearch"</span>, <span class="hljs-keyword">False</span>) <span class="hljs-comment"># Disable search bar.</span>
profile.set_preference(<span class="hljs-string">"extensions.checkCompatibility"</span>, <span class="hljs-keyword">False</span>) <span class="hljs-comment"># Addon update disabled</span>
profile.set_preference(<span class="hljs-string">"extensions.checkUpdateSecurity"</span>, <span class="hljs-keyword">False</span>)
profile.set_preference(<span class="hljs-string">"extensions.update.autoUpdateEnabled"</span>, <span class="hljs-keyword">False</span>)
profile.set_preference(<span class="hljs-string">"extensions.update.enabled"</span>, <span class="hljs-keyword">False</span>)
profile.set_preference(<span class="hljs-string">"general.startup.browser"</span>, <span class="hljs-keyword">False</span>)
profile.set_preference(<span class="hljs-string">"plugin.default_plugin_disabled"</span>, <span class="hljs-keyword">False</span>)
profile.set_preference(<span class="hljs-string">"permissions.default.image"</span>, <span class="hljs-number">2</span>) <span class="hljs-comment"># Image load disabled again</span>
</code></pre>
<p>Those will make your browser load and render the page faster. Thanks  for reading.</p>
]]></content:encoded></item><item><title><![CDATA[Quick Note: Default Value for JSON in Laravel]]></title><description><![CDATA[Many RDBMS today have json data type implemented. MySQL has it since 5.7.8 and PostgreSQL since 9.3. MariaDB, a MySQL-like RDBMS solution, has  json as an alias to longtext , that means while MySQL and PostgreSQL can search and validate JSON data, Ma...]]></description><link>https://erayerdin.com/quick-note-default-value-for-json-in-laravel</link><guid isPermaLink="true">https://erayerdin.com/quick-note-default-value-for-json-in-laravel</guid><category><![CDATA[PHP]]></category><category><![CDATA[Laravel]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Mon, 09 Mar 2020 20:15:50 GMT</pubDate><content:encoded><![CDATA[<p>Many RDBMS today have <code>json</code> data type implemented. MySQL has it since 5.7.8 and PostgreSQL since 9.3. MariaDB, a MySQL-like RDBMS solution, has  <a target='_blank' rel='noopener noreferrer'  href="https://mariadb.com/kb/en/json-data-type/"><code>json</code> as an alias to <code>longtext</code></a> , that means while MySQL and PostgreSQL can search and validate JSON data, MariaDB does not.</p>
<p>Laravel also supports JSON columns since 5.x. They do not, however, sometimes work as you expect it to be. I ran across a problem about setting a default value for a JSON column and, in this article, I would like to present you how I&#39;ve solved the issue.</p>
<h2 id="how-to-do-it">How to Do It</h2>
<p>After starting a new Laravel project with <code>laravel new whatever</code>, we need to create an example model with its migrations that we can work on.</p>
<pre><code class="lang-bash">php artisan make:model Article -m
</code></pre>
<p>This will both generate the model and migration file for us.</p>
<p>Then we write our migration as such:</p>
<pre><code class="lang-php">$table-&gt;text(<span class="hljs-string">"content"</span>);  <span class="hljs-comment">// for the sake of example</span>
$table-&gt;json(<span class="hljs-string">"tags"</span>)-&gt;default(<span class="hljs-string">"[]"</span>);
</code></pre>
<p>The column <code>tags</code> here is a <code>json</code> typed column but here is the catch: It might not work (tested in PostgreSQL). In such cases, you can use a pre-create (creating) hook to set the default value before saving. To do that, we need to open up our model, <code>app/Article.php</code> in this case, and override built-in static <code>booted</code> method of the model:</p>
<pre><code class="lang-php"> <span class="hljs-keyword">protected</span> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">booted</span><span class="hljs-params">()</span> </span>{
     <span class="hljs-comment">// when the model is loaded</span>
 }
</code></pre>
<p>Here we can define any event in lifetime of our model. You can see a list <a target='_blank' rel='noopener noreferrer'  href="https://laravel.com/docs/7.x/eloquent#events">here</a>. In our case, we need to define a <code>creating</code> event as such:</p>
<pre><code class="lang-php"> <span class="hljs-keyword">protected</span> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">booted</span><span class="hljs-params">()</span> </span>{
     <span class="hljs-keyword">static</span>::creating(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">($article)</span> </span>{
         <span class="hljs-keyword">if</span> ($article-&gt;tags === <span class="hljs-keyword">null</span>) {
             <span class="hljs-comment">// if tags are not provided on creation</span>
             $article-&gt;tags = <span class="hljs-string">"[]"</span>;  <span class="hljs-comment">// set empty json array</span>
         }
     });
 }
</code></pre>
<p>Note that we actually check if <code>tags</code> property is <code>null</code>. We need it to be set to empty JSON array <em>only</em> in case we have not provided values by hand on creation.</p>
<p>Also another note is that, on <code>creating</code> event, we do not call any <code>save</code> method or something alike (which is querying the database). It&#39;s because we are literally <em>injecting</em> a value to <code>$article</code> instance, which is not yet saved. Laravel will save it after <code>creating</code> event runs.</p>
<p>After this, it will set default value to empty JSON array in database. Thanks for reading.</p>
]]></content:encoded></item><item><title><![CDATA[Quick Note: Setting Up Pytest Model Factory Fixtures for Django]]></title><description><![CDATA[Update: 01.03.2021
Recently, I've found out this can be easily implemented using factoryboy and pytest-factoryboy.
For each model registered, pytest-factoryboy dynamically generates an instance fixture and a factory fixture. Let's say you have a mode...]]></description><link>https://erayerdin.com/quick-note-setting-up-pytest-model-factory-fixtures-for-django</link><guid isPermaLink="true">https://erayerdin.com/quick-note-setting-up-pytest-model-factory-fixtures-for-django</guid><category><![CDATA[Python]]></category><category><![CDATA[Django]]></category><category><![CDATA[Testing]]></category><category><![CDATA[pytest]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Tue, 18 Feb 2020 14:25:17 GMT</pubDate><content:encoded><![CDATA[<h1 id="update-01032021">Update: 01.03.2021</h1>
<p>Recently, I've found out this can be easily implemented using <a target="_blank" href="https://factoryboy.readthedocs.io/en/stable/">factoryboy</a> and <a target="_blank" href="https://github.com/pytest-dev/pytest-factoryboy">pytest-factoryboy</a>.</p>
<p>For each model registered, pytest-factoryboy dynamically generates an instance fixture and a factory fixture. Let's say you have a model called <code>User</code> and you registered it to pytest-factoryboy, you can simply call <code>user</code> fixture to get an instance or <code>user_factory</code> fixture to generate it on the test. You can also <a target="_blank" href="https://github.com/pytest-dev/pytest-factoryboy#attributes-are-fixtures">use parameters</a> on instance fixtures to have cleaner tests.</p>
<p>Below is just a way to implement the same behavior without factoryboy and pytest-factoryboy. I wasn't aware these existed back then.</p>
<hr />
<p>Generating model instances in Django test is vital and it needs to be done quick and in a painless way. In this article, I'd like to present a common pattern that I've figured out.</p>
<h2 id="requirements">Requirements</h2>
<p>The methods below are tested in the relevant environment below:</p>
<ul>
<li>Python &gt;= 3.5</li>
<li>Django &gt;= 2.2</li>
<li>pytest-django</li>
</ul>
<p>So I assume you have these same dependencies in your enironment.</p>
<h2 id="factory-fixtures">Factory Fixtures</h2>
<p>I'd like to first discuss about factory fixtures. These are fixtures that simply return functions. To give an example:</p>
<pre><code class="lang-python"><span class="hljs-meta">@pytest.fixture</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">foo_factory</span>():</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">factory</span>(<span class="hljs-params">number</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">"foo{}"</span>.format(number)
    <span class="hljs-keyword">return</span> factory
</code></pre>
<p>This way we can simply inject them into our tests and invoke them on the fly.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_foo</span>(<span class="hljs-params">foo_factory</span>):</span>
    <span class="hljs-keyword">assert</span> foo_factory(<span class="hljs-number">1</span>) == <span class="hljs-string">"foo1"</span>
</code></pre>
<p>This is useful when you'd like to generate instances based on some context and especially useful when creating model instances.</p>
<h2 id="model-instance-factories">Model Instance Factories</h2>
<p>Assuming we have a model as below:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span>(<span class="hljs-params">models.Model</span>):</span>
    name = models.CharField(max_length=<span class="hljs-number">128</span>)
    surname = models.CharField(max_length=<span class="hljs-number">128</span>)
</code></pre>
<p>We can construct a factory fixture as below:</p>
<pre><code class="lang-python"><span class="hljs-meta">@pytest.fixture</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">person_factory</span>(<span class="hljs-params">db</span>):</span>  <span class="hljs-comment"># mind "db"</span>
    <span class="hljs-comment"># db is a fixture of pytest-django</span>
    <span class="hljs-comment"># it is used to activate testing in database in a django environment</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">factory</span>(<span class="hljs-params">**kwargs</span>):</span>
        <span class="hljs-keyword">return</span> Person.objects.create(**kwargs)
    <span class="hljs-keyword">return</span> factory
</code></pre>
<p>So now we can create many instances as we need in a test:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_person</span>(<span class="hljs-params">person_factory</span>):</span>
    person = person_factory(name=<span class="hljs-string">"Eray"</span>, surname=<span class="hljs-string">"Erdin"</span>)
    <span class="hljs-keyword">assert</span> (person.name, person.surname) == (<span class="hljs-string">"Eray"</span>, <span class="hljs-string">"Erdin"</span>)
</code></pre>
<p>While this might seem good, it is not still perfect. We would probably like to create an instance quickly, without providing any data such as:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_person</span>(<span class="hljs-params">person_factory</span>):</span>
    person = person_factory()  <span class="hljs-comment"># what we'd like to do</span>
    <span class="hljs-keyword">assert</span> (person.name, person.surname) == (<span class="hljs-string">"Eray"</span>, <span class="hljs-string">"Erdin"</span>)
</code></pre>
<p>This will probably fail because <code>name</code> and <code>surname</code> fields are implicitly <code>NOT NULL</code>.</p>
<pre><code>IntegrityError: <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">constraint</span> failed: app_person.name
</code></pre><h2 id="setting-defaults">Setting Defaults</h2>
<p>What we'd like to do is to write our fixture in such a way that it will provide a default value to the field that's not provided. We provide the values with <code>kwargs</code> and it's a <code>dict</code> of <a target="_blank" href="https://www.python.org/dev/peps/pep-3102/">keyword-only arguments</a>. Since it is a plain <code>dict</code>, there is a helper method called <a target="_blank" href="https://docs.python.org/3/library/stdtypes.html#dict.setdefault">setdefault</a> for <code>dict</code>. This method adds the key and value <em>if</em> the key does not exist. With this lore, see the example below:</p>
<pre><code class="lang-python"><span class="hljs-meta">@pytest.fixture</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">person_factory</span>(<span class="hljs-params">db</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">factory</span>(<span class="hljs-params">**kwargs</span>):</span>
        kwargs.setdefault(<span class="hljs-string">"name"</span>, <span class="hljs-string">"Eray"</span>)
        kwargs.setdefault(<span class="hljs-string">"surname"</span>, <span class="hljs-string">"Erdin"</span>)
        <span class="hljs-keyword">return</span> Person.objects.create(**kwargs)
    <span class="hljs-keyword">return</span> factory
</code></pre>
<p>So <code>name</code> and <code>surname</code> will have a default value and will not needed to be provided.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_person</span>(<span class="hljs-params">person_factory</span>):</span>
    person = person_factory(name=<span class="hljs-string">"Şenay"</span>)  <span class="hljs-comment"># now this won't error</span>
    <span class="hljs-keyword">assert</span> (person.name, person.surname) == (<span class="hljs-string">"Şenay"</span>, <span class="hljs-string">"Erdin"</span>)  <span class="hljs-comment"># `surname` defaults to `"Erdin"` in this case</span>
</code></pre>
<h2 id="unique-constraint">Unique Constraint</h2>
<p>However, this is not the end yet. In this case, neither <code>name</code> nor <code>surname</code> fields have unique constraints. Let's add a field with <code>unique</code> to our model.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span>(<span class="hljs-params">models.Model</span>):</span>
    name = models.CharField(max_length=<span class="hljs-number">128</span>)
    surname = models.CharField(max_length=<span class="hljs-number">128</span>)
    phone = models.CharField(max_length=<span class="hljs-number">128</span>, unique=<span class="hljs-literal">True</span>)  <span class="hljs-comment"># new field</span>
</code></pre>
<blockquote>
<h4 id="warning">⚠️ Warning</h4>
<p>In this example, I do not really care about the formatting and validation of <code>phone</code> field. It's added only for the sake of example. I will count "1", "2", "3" and such values as valid.</p>
</blockquote>
<p>And we should update our related factory fixture accordingly:</p>
<pre><code class="lang-python"><span class="hljs-meta">@pytest.fixture</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">person_factory</span>(<span class="hljs-params">db</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">factory</span>(<span class="hljs-params">**kwargs</span>):</span>
        kwargs.setdefault(<span class="hljs-string">"name"</span>, <span class="hljs-string">"Eray"</span>)
        kwargs.setdefault(<span class="hljs-string">"surname"</span>, <span class="hljs-string">"Erdin"</span>)
        kwargs.phone(<span class="hljs-string">"phone"</span>, <span class="hljs-string">"1"</span>)  <span class="hljs-comment"># See warning above.</span>
        <span class="hljs-keyword">return</span> Person.objects.create(**kwargs)
    <span class="hljs-keyword">return</span> factory
</code></pre>
<p>This is okay with one instance in a test, however will immediately fail at the initialization of the second instance.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_person</span>(<span class="hljs-params">person_factory</span>):</span>
    person1 = person_factory()
    person2 = person_factory()  <span class="hljs-comment"># will fail here</span>
    <span class="hljs-keyword">assert</span> (person1.name, person1.surname) == (<span class="hljs-string">"Eray"</span>, <span class="hljs-string">"Erdin"</span>)
    <span class="hljs-keyword">assert</span> (person2.name, person2.surname) == (<span class="hljs-string">"Eray"</span>, <span class="hljs-string">"Erdin"</span>)
</code></pre>
<p>This will fail saying:</p>
<pre><code><span class="hljs-selector-tag">django</span><span class="hljs-selector-class">.db</span><span class="hljs-selector-class">.utils</span><span class="hljs-selector-class">.IntegrityError</span>: <span class="hljs-selector-tag">UNIQUE</span> <span class="hljs-selector-tag">constraint</span> <span class="hljs-selector-tag">failed</span>: <span class="hljs-selector-tag">app_person</span><span class="hljs-selector-class">.phone</span>
</code></pre><p>This is because the first time the factory is invoked the phone is <code>"1"</code> and the second time it is the same, yet we explicitly defined <code>phone</code> field to be <em>unique</em>.</p>
<p>These kind of errors usually require different solutions but the foundation is the same. We need to set unique field to a different value each time its factory fixture is invoked. In this example, I will use the count of <code>Person</code> instances and use them to set the <code>phone</code> field.</p>
<pre><code class="lang-python"><span class="hljs-meta">@pytest.fixture</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">person_factory</span>(<span class="hljs-params">db</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">factory</span>(<span class="hljs-params">**kwargs</span>):</span>
        kwargs.setdefault(<span class="hljs-string">"name"</span>, <span class="hljs-string">"Eray"</span>)
        kwargs.setdefault(<span class="hljs-string">"surname"</span>, <span class="hljs-string">"Erdin"</span>)
        kwargs.setdefault(<span class="hljs-string">"phone"</span>, str(Person.objects.count()))  <span class="hljs-comment"># person instance count as phone</span>
        <span class="hljs-keyword">return</span> Person.objects.create(**kwargs)
    <span class="hljs-keyword">return</span> factory
</code></pre>
<blockquote>
<h4 id="tip">ℹ️ Tip</h4>
<p>You can also format strings as below:</p>
<pre><code class="lang-python"><span class="hljs-string">"foo{}"</span>.format(bar)
</code></pre>
<p>This is what I usually use with <code>CharField</code>s and alikes.</p>
</blockquote>
<p>Now we will not get those <code>IntegrityError</code>s because the <code>phone</code> will be different in each invocation.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_person</span>(<span class="hljs-params">person_factory</span>):</span>
    person1 = person_factory()  <span class="hljs-comment"># phone: "0"</span>
    person2 = person_factory()  <span class="hljs-comment"># phone: "1"</span>
    <span class="hljs-keyword">assert</span> (person1.name, person1.surname) == (<span class="hljs-string">"Eray"</span>, <span class="hljs-string">"Erdin"</span>)
    <span class="hljs-keyword">assert</span> (person2.name, person2.surname) == (<span class="hljs-string">"Eray"</span>, <span class="hljs-string">"Erdin"</span>)
</code></pre>
<h2 id="relations">Relations</h2>
<p>This pattern also lets us create instances with relations pretty easily. This time, let's use a different kind of example with two models where they are bound by a <code>ForeignKey</code>.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Category</span>(<span class="hljs-params">models.Model</span>):</span>
    name = models.CharField(max_length=<span class="hljs-number">128</span>)
    <span class="hljs-comment"># other fields if necessary ...</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Product</span>(<span class="hljs-params">models.Model</span>):</span>
    price = models.DecimalField()
    category = models.ForeignKey(Category, models.CASCADE, <span class="hljs-string">"products"</span>)
    <span class="hljs-comment"># other fields if needed ...</span>
</code></pre>
<blockquote>
<h4 id="warning">⚠️ Warning</h4>
<p>In this example, I assume that each <code>Product</code> will have <em>only one</em> <code>Category</code> and a <code>Category</code> is <em>required</em>.</p>
</blockquote>
<p>In this case, if I'd like to create a <code>Product</code> instance, I will definitely need a <code>Category</code> instance as well. First, write up our standard <code>Category</code> factory fixture:</p>
<pre><code class="lang-python"><span class="hljs-meta">@pytest.fixture</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">category_factory</span>(<span class="hljs-params">db</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">factory</span>(<span class="hljs-params">**kwargs</span>):</span>
        kwargs.setdefault(<span class="hljs-string">"name"</span>, <span class="hljs-string">"foo"</span>)
        <span class="hljs-comment"># same for other fields</span>
        <span class="hljs-keyword">return</span> Category.objects.create(**kwargs)
       <span class="hljs-keyword">return</span> factory
</code></pre>
<p>And the factory fixture for <code>Product</code>. Remember we will need a <code>Category</code> instance for that.</p>
<pre><code class="lang-python"><span class="hljs-meta">@pytest.fixture</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">product_factory</span>(<span class="hljs-params">db, category_factory</span>):</span>  <span class="hljs-comment"># see how i injected `category_factory`</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">factory</span>(<span class="hljs-params">**kwargs</span>):</span>
        kwargs.setdefault(<span class="hljs-string">"price"</span>, <span class="hljs-number">1.5</span>)
        kwargs.setdefault(<span class="hljs-string">"category"</span>, category_factory())  <span class="hljs-comment"># and i invoked `category_factory` here</span>
        <span class="hljs-comment"># same for other fields</span>
        <span class="hljs-keyword">return</span> Product.objects.create(**kwargs)
    <span class="hljs-keyword">return</span> factory
</code></pre>
<p>Finally, whenever I need a <code>Product</code> instance in test, I can only inject <code>product_factory</code> and invoke it. It will implicitly create a <code>Category</code> instance for itself.</p>
<pre><code class="lang-python"><span class="hljs-meta">@pytest.fixture</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_product</span>(<span class="hljs-params">db, product_factory</span>):</span>
    product = product_factory()
    <span class="hljs-keyword">assert</span> product.price == <span class="hljs-number">1.5</span>
    <span class="hljs-keyword">assert</span> product.category.name == <span class="hljs-string">"foo"</span>
</code></pre>
<h2 id="options">Options</h2>
<p>Let's take a look at the example below:</p>
<pre><code class="lang-python"><span class="hljs-comment"># models.py</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Post</span>(<span class="hljs-params">models.Model</span>):</span>  <span class="hljs-comment"># a blog post</span>
    title = models.CharField(max_length=<span class="hljs-number">128</span>)
    content = models.TextField()
    share_rss = models.BooleanField()
    share_facebook = models.BooleanField()
    share_twitter = models.BooleanField()
    share_telegram = models.BooleanField()
    share_reddit = models.BooleanField()

<span class="hljs-comment"># fixtures.py</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">post_factory</span>(<span class="hljs-params">db</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">factory</span>(<span class="hljs-params">**kwargs</span>):</span>
        kwargs.setdefault(<span class="hljs-string">"title"</span>, <span class="hljs-string">"Foo Bar Baz"</span>)
        kwargs.setdefault(<span class="hljs-string">"content"</span>, <span class="hljs-string">"lorem ipsum dolor sit amet"</span>)
        kwargs.setdefault(<span class="hljs-string">"share_rss"</span>, <span class="hljs-literal">False</span>)
        kwargs.setdefault(<span class="hljs-string">"share_facebook"</span>, <span class="hljs-literal">False</span>)
        kwargs.setdefault(<span class="hljs-string">"share_twitter"</span>, <span class="hljs-literal">False</span>)
        kwargs.setdefault(<span class="hljs-string">"share_telegram"</span>, <span class="hljs-literal">False</span>)
        kwargs.setdefault(<span class="hljs-string">"share_reddit"</span>, <span class="hljs-literal">False</span>)

        <span class="hljs-keyword">return</span> Post.objects.create(**kwargs)
    <span class="hljs-keyword">return</span> factory
</code></pre>
<p>Let's assume we have a test case that all <code>share_*</code> fields need to be <em>different</em>. To do that, we would set it on test manually, one by one, as below:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_not_share</span>(<span class="hljs-params">post_factory</span>):</span>
    post_factory(
        share_rss=<span class="hljs-literal">True</span>,
        share_facebook=<span class="hljs-literal">False</span>,
        share_twitter=<span class="hljs-literal">True</span>,
        share_telegram=<span class="hljs-literal">True</span>,
        share_reddit=<span class="hljs-literal">False</span>,
    )
    <span class="hljs-comment"># ... your test logic here ...</span>
</code></pre>
<p>What about we could pass some extra arguments to <code>post_factory</code> fixture and make it <em>set all</em> to <code>True</code> or <code>False</code> in a shorthand way? Here we can use <code>*args</code> as a help. Let's refactor <code>post_factory</code>:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">post_factory</span>(<span class="hljs-params">db</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">factory</span>(<span class="hljs-params">*args, **kwargs</span>):</span>  <span class="hljs-comment"># notice i've added args</span>
        <span class="hljs-comment"># setting default values</span>
        kwargs.setdefault(<span class="hljs-string">"title"</span>, <span class="hljs-string">"Foo Bar Baz"</span>)
        kwargs.setdefault(<span class="hljs-string">"content"</span>, <span class="hljs-string">"lorem ipsum dolor sit amet"</span>)
        kwargs.setdefault(<span class="hljs-string">"share_rss"</span>, <span class="hljs-literal">False</span>)
        kwargs.setdefault(<span class="hljs-string">"share_facebook"</span>, <span class="hljs-literal">False</span>)
        kwargs.setdefault(<span class="hljs-string">"share_twitter"</span>, <span class="hljs-literal">False</span>)
        kwargs.setdefault(<span class="hljs-string">"share_telegram"</span>, <span class="hljs-literal">False</span>)
        kwargs.setdefault(<span class="hljs-string">"share_reddit"</span>, <span class="hljs-literal">False</span>)

        <span class="hljs-comment"># option defaults</span>
        opts = next(iter(args), dict())
        <span class="hljs-comment"># here i take the first element of *arg</span>
        <span class="hljs-comment"># if there is no such thing (no first element)</span>
        <span class="hljs-comment"># then it will default to an empty dict</span>

        <span class="hljs-comment"># do the same thing to opts as we do to **kwargs</span>
        opts.set_default(<span class="hljs-string">"share_all"</span>, <span class="hljs-literal">None</span>)
        <span class="hljs-comment"># if True, will set all share_* fields to True</span>
        <span class="hljs-comment"># if False, will set all share_* fields to False</span>
        <span class="hljs-comment"># else (which is None or sth else), will use **kwargs</span>

        share_all = opts[<span class="hljs-string">"share_all"</span>]

        <span class="hljs-comment"># options logic</span>
        <span class="hljs-comment"># if share_all is True or False</span>
        <span class="hljs-keyword">if</span> opts[<span class="hljs-string">"share_all"</span>] <span class="hljs-keyword">in</span> (<span class="hljs-literal">True</span>, <span class="hljs-literal">False</span>):
            share_all = opts[<span class="hljs-string">"share_all"</span>]
            kwargs.update(
                share_rss=share_all,
                share_facebook=share_all,
                share_twitter=share_all,
                share_telegram=share_all,
                share_reddit=share_all,
            )
        <span class="hljs-comment"># if it is None, it will use **kwargs default or the one you provide in **kwargs</span>

        <span class="hljs-keyword">return</span> Post.objects.create(**kwargs)
    <span class="hljs-keyword">return</span> factory
</code></pre>
<p>So, what did we achieve? Let's see it in test:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestShare</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_share_all</span>(<span class="hljs-params">self, post_factory</span>):</span>
        post_factory({<span class="hljs-string">"share_all"</span>: <span class="hljs-literal">True</span>})
        <span class="hljs-comment"># sets all share_* fields to True</span>
        <span class="hljs-comment"># even if we pass share_facebook=False,</span>
        <span class="hljs-comment"># share_facebook will be True</span>

        <span class="hljs-comment"># ... your test logic ...</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_share_none</span>(<span class="hljs-params">self, post_factory</span>):</span>
        post_factory({<span class="hljs-string">"share_all"</span>: <span class="hljs-literal">False</span>})
        <span class="hljs-comment"># the reverse of test_share_all</span>

        <span class="hljs-comment"># ... your test logic ...</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_share_some</span>(<span class="hljs-params">self, post_factory</span>):</span>
        post_factory(share_twitter=<span class="hljs-literal">True</span>)
        <span class="hljs-comment"># rest will be False</span>

        <span class="hljs-comment"># ... your test logic ...</span>
</code></pre>
<p>With this way, we can define custom behavior or quick assignment on multiple fields easily.</p>
<p>Now you might ask why I have used <code>*args</code> instead of <code>**kwargs</code>. With this method, I seperated the purpose of <code>*args</code> and <code>**kwargs</code>. <code>*args</code> is for options and <code>**kwargs</code> is for fields. Maybe you might go far saying "You could've swap places, <code>*args</code> to use fields and <code>**kwargs</code> to use options.". This is purely a choice of design. In my case, I find it easier to write and read:</p>
<pre><code class="lang-python">post_factory({<span class="hljs-string">"share_all"</span>: <span class="hljs-literal">True</span>}, title=<span class="hljs-string">"foo"</span>, content=<span class="hljs-string">"lorem"</span>)
</code></pre>
<p>...than the monstrosity below:</p>
<pre><code class="lang-python">post_factory({<span class="hljs-string">"title"</span>: <span class="hljs-string">"foo"</span>, <span class="hljs-string">"content"</span>: <span class="hljs-string">"lorem"</span>}, share_all=<span class="hljs-literal">True</span>)
</code></pre>
<p>The decision is up to you, however.</p>
<h2 id="final-words">Final Words</h2>
<p>This is how I deal with generating models on the test and I do that with each model and update the factory fixtures when I update models. I will put some possible questions/thoughts in your mind in case you are interested.</p>
<h3 id="user-is-a-built-in-model-in-django-do-you-know-a-method-for-user-model"><code>User</code> is a built-in model in Django. Do you know a method for <code>User</code> model?</h3>
<p>Ah, yes. I can even give the code away.</p>
<pre><code class="lang-python"><span class="hljs-meta">@pytest.fixture</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">author_factory</span>(<span class="hljs-params">db</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">factory</span>(<span class="hljs-params">**kwargs</span>):</span>
        total_instances = User.objects.count()
        username = <span class="hljs-string">f"user<span class="hljs-subst">{total_instances}</span>"</span>  <span class="hljs-comment"># (i)</span>
        email = <span class="hljs-string">f"foo<span class="hljs-subst">{total_instances}</span>@bar.baz"</span>

        kwargs.setdefault(<span class="hljs-string">"username"</span>, username)
        kwargs.setdefault(<span class="hljs-string">"password"</span>, <span class="hljs-string">"111111"</span>)
        kwargs.setdefault(<span class="hljs-string">"email"</span>, email)

        <span class="hljs-keyword">return</span> User.objects.create_user(**kwargs)  <span class="hljs-comment"># (ii)</span>

    <span class="hljs-keyword">return</span> factory
</code></pre>
<p>As you probably can see, (i) I generate <code>username</code> based on the user instances <em>and</em> (ii) I have used <code>create_user</code> instead of <code>create</code> mainly because it is a special method for <code>User</code>'s manager.</p>
<h3 id="nice-now-i-can-generate-a-lot-of-instances-with-faker-or-alike">Nice, now I can generate a lot of instances with <code>faker</code> (or alike).</h3>
<p>While I find <code>faker</code> to be useful in some cases, I recommend to avoid overusing it. I do not usually use it because, in my opinion, you usually test the behavior instead of the data.</p>
<blockquote>
<h4 id="warning">⚠️ Warning</h4>
<p>In the example below, I assume you have already written required models, views, serializers and factory fixtures.</p>
</blockquote>
<p>To give a more concrete example (also assuming it's going to be an API endpoint and will use <a target="_blank" href="https://www.django-rest-framework.org/">Django Rest Framework</a>), let's assume that you have an endpoint <code>/whatever/</code> that will return a list of, well, <em>whatevers</em> and those objects are related to <code>User</code>s.</p>
<pre><code class="lang-python"><span class="hljs-comment"># model of it</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Whatever</span>(<span class="hljs-params">models.Model</span>):</span>
    <span class="hljs-comment"># ...</span>
    user = models.ForeignKey(User)
    <span class="hljs-comment"># ...</span>
</code></pre>
<p>So, if <code>user1</code> is logged in, he will see his <em>whatevers</em> and not <code>user2</code>'s <em>whatevers</em>.</p>
<p>In this case, it is just enough to create 2 instances of <code>Whatever</code> for <code>user1</code> and 1 instance of <code>Whatever</code> for <code>user2</code> and do the test.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_whatever_list_endpoint</span>(<span class="hljs-params">client, user_factory, whatever_factory</span>):</span>  <span class="hljs-comment"># assuming you've written factory for it</span>
    user1 = user_factory()  <span class="hljs-comment"># (ii)</span>
    user2 = user_factory()  <span class="hljs-comment"># (ii)</span>

    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">2</span>):  <span class="hljs-comment"># 2 whatevers for user1 # (i)</span>
        whatever_factory(user=user1)

    whatever_factory(user=user2)   <span class="hljs-comment"># 1 whatever for user2 # (i)</span>

    url = reverse(<span class="hljs-string">"whatever-list"</span>)  <span class="hljs-comment"># from django.urls import reverse</span>

    <span class="hljs-comment"># whatever list of user1</span>
    client.login(username=user1.username, password=<span class="hljs-string">"111111"</span>)  <span class="hljs-comment"># (ii)</span>
    data1 = client.get(url).json()
    client.logout()

    <span class="hljs-comment"># whatever list of user2</span>
    client.login(username=user2.username, password=<span class="hljs-string">"111111"</span>)  <span class="hljs-comment"># (ii)</span>
    data2 = client.get(url).json()

    <span class="hljs-comment"># assertions</span>
    <span class="hljs-keyword">assert</span> len(data[<span class="hljs-string">"results"</span>]) == <span class="hljs-number">2</span>  <span class="hljs-comment"># because we've created 2 for user1 # (i)</span>
    <span class="hljs-keyword">assert</span> len(data[<span class="hljs-string">"results"</span>]) == <span class="hljs-number">1</span>  <span class="hljs-comment"># because we've created 1 for user2 # (i)</span>
</code></pre>
<p>In this context, you can notice many things:</p>
<ul>
<li>(i) I have never needed the test the content (the other fields and values or its serializer's values) of <code>Whatever</code> instances. I do not need to because they will most likely render the same. You should test data <em>if your data changes by a behavior</em>. In the case above, the data does not matter anyway, because there is no logic that changes it.</li>
<li>(ii) By not using <code>faker</code>, I could keep the content of <code>User</code> instances predictable and consistent. I know the password for every testing user will be <code>"111111"</code> and I know I would not (and you should <em>never</em> attempt to) test the password anyway.</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Quick Note: Validating PNG in Rust]]></title><description><![CDATA[So, I have been learning Rust for, say, 7 months or so. I kinda get the grasp of it but still not fluent at it.
I'd like to create a project on it but have been also thinking what kind of things I can create. This is a low-level, system programming l...]]></description><link>https://erayerdin.com/quick-note-validating-png-in-rust</link><guid isPermaLink="true">https://erayerdin.com/quick-note-validating-png-in-rust</guid><category><![CDATA[Rust]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Sat, 28 Dec 2019 12:35:37 GMT</pubDate><content:encoded><![CDATA[<p>So, I have been learning Rust for, say, 7 months or so. I kinda get the grasp of it but still not fluent at it.</p>
<p>I&#39;d like to create a project on it but have been also thinking what kind of things I can create. This is a low-level, system programming language and you get to bare metal as close as you can. So I thought maybe implementing a specification of a file format can get my feet wet.</p>
<p>So I chose PNG. It naturally has a <a target='_blank' rel='noopener noreferrer'  href="https://www.w3.org/TR/PNG/">specification</a> <em>and</em> thank-W3-gods it&#39;s free unlike many file specifications you can find on the internet. For instance, I have found PDF specification, which is reviewed by ISO and it costs 198 CHF. PNG was free.</p>
<p>Whatever, back to topic, <a target='_blank' rel='noopener noreferrer'  href="https://www.w3.org/TR/PNG/#5PNG-file-signature">this section of PNG specification</a> says the first 8 bytes of PNG is as below:</p>
<pre><code class="lang-plain">137 80 78 71 13 10 26 10
</code></pre>
<p>And I thought testing this would be a good small practice. I have created a <code>const</code> containing these first 8 bytes so that I can compare.</p>
<pre><code class="lang-rust">const VALID_PNG_SIGNATURE: [u8; 8] = [137, 80, 78, 71, 13, 10, 26, 10];
</code></pre>
<p>Then, we need a struct pointing to a <code>std::io::File</code>.</p>
<pre><code class="lang-rust">struct PNG {
    file: File
}
</code></pre>
<p>There are two built-in traits in Rust that will help me implement this PNG struct as a file-like thing. I have added those as comments and these will not be the topic of this post, I just show them so that you understand how implementing a file-like struct works.</p>
<pre><code class="lang-rust">// to read data from PNG file
// impl Read for PNG {}

// to deallocate PNG data on destruction
// impl Drop for PNG {}

// i might be wrong or lack things about this concept. if i do, you can ring my bell.
</code></pre>
<p>Later on, I have implemented raw PNG struct, see below:</p>
<pre><code class="lang-rust">impl PNG {
    pub fn open(path: &amp;str) -&gt; Result&lt;PNG, Error&gt; {
        let mut file = match File::open(path) {
            Err(e) =&gt; return Err(e),
            Ok(f) =&gt; f
        };

        if PNG::is_valid_signature(&amp;mut file) {
            Ok(PNG{file})
        } else {
            Err(Error::new(ErrorKind::Other, "File does not have a valid PNG signature."))
        }
    }

    fn is_valid_signature(file: &amp;mut File) -&gt; bool {
        let mut buffer = [0u8; 8];
        let size = file.read(&amp;mut buffer).unwrap();

        if size &lt; 8 {
            false
        } else {
            buffer == VALID_PNG_SIGNATURE
        }
    }
}
</code></pre>
<p>Actually, both methods are self-explanatory but let&#39;s discuss it anyways. <code>open</code> tries to open a <code>std::io::File</code> and returns <code>std::io::Error</code> if:</p>
<ul>
<li><code>File</code> returns <code>Error</code> or</li>
<li>The file is not a valid PNG.</li>
</ul>
<p><code>is_valid_signature</code> does the validation. Basically, it returns <code>false</code> if:</p>
<ul>
<li>The file size is less than 8 bytes or</li>
<li>The first 8 bytes are not equal to <code>VALID_PNG_SIGNATURE</code></li>
</ul>
<p>I can test it as below:</p>
<pre><code class="lang-rust">// assuming you have resources/64.png and resources/invalid.png in project root

// 64.png is generated with placeholder.com, is valid and 64x64
// invalid PNG is actually a text file containing the content &quot;foo&quot;

#[cfg(test)]
mod tests {
    use crate::PNG;

    #[test]
    fn valid_png() {
        let png_r = PNG::open(&quot;resources/64.png&quot;);
        assert!(png_r.is_ok())
    }

    #[test]
    fn invalid_png() {
        let png_r = PNG::open(&quot;resources/invalid.png&quot;);
        assert!(png_r.is_err())
    }
}
</code></pre>
<p>Overall:</p>
<pre><code class="lang-rust">use std::fs::File;
use std::io::Error;
use std::io::ErrorKind;
use std::io::Read;

const VALID_PNG_SIGNATURE: [u8; 8] = [137, 80, 78, 71, 13, 10, 26, 10];

struct PNG {
    file: File,
}

impl PNG {
    pub fn open(path: &amp;str) -&gt; Result&lt;PNG, Error&gt; {
        let mut file = match File::open(path) {
            Err(e) =&gt; return Err(e),
            Ok(f) =&gt; f,
        };

        if PNG::is_valid_signature(&amp;mut file) {
            Ok(PNG { file })
        } else {
            Err(Error::new(
                ErrorKind::Other,
                "File does not have a valid PNG signature.",
            ))
        }
    }

    fn is_valid_signature(file: &amp;mut File) -&gt; bool {
        let mut buffer = [0u8; 8];
        let size = file.read(&amp;mut buffer).unwrap();

        if size &lt; 8 {
            false
        } else {
            buffer == VALID_PNG_SIGNATURE
        }
    }
}

// impl Read for PNG {}

// impl Drop for PNG {}

#[cfg(test)]
mod tests {
    use crate::PNG;

    #[test]
    fn valid_png() {
        let png_r = PNG::open("resources/64.png");
        assert!(png_r.is_ok())
    }

    #[test]
    fn invalid_png() {
        let png_r = PNG::open("resources/invalid.png");
        assert!(png_r.is_err())
    }
}
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Quick Note: Creating A Type-Agnostic Custom Field in Django]]></title><description><![CDATA[Model fields in Django always have a type defined. While it is not simply desirable many times, there might be some edge-cases that you simply would like to create a field that can accept any or many types.
I will cover a very primitive case about it...]]></description><link>https://erayerdin.com/quick-note-creating-a-type-agnostic-custom-field-in-django</link><guid isPermaLink="true">https://erayerdin.com/quick-note-creating-a-type-agnostic-custom-field-in-django</guid><category><![CDATA[Python]]></category><category><![CDATA[Django]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Sat, 14 Dec 2019 23:28:08 GMT</pubDate><content:encoded><![CDATA[<p>Model fields in Django always have a type defined. While it is <em>not</em> simply desirable many times, there might be some <em>edge-cases</em> that you simply would like to create a field that can accept <em>any</em> or <em>many</em> types.</p>
<p>I will cover a very primitive case about it. We will create a custom field that will accept <em>any type of data</em>, but again, a typeless field with no validation (which is this example) <em>can</em> and <em>eventually will</em> lead to faulty results, so keep that in mind.</p>
<p>First, let&#39;s talk about that <a target='_blank' rel='noopener noreferrer'  href="https://docs.djangoproject.com/en/3.0/ref/models/fields/#binaryfield">BinaryField</a>. This field simply stores <em>raw bytes</em> in database <em>and</em> retrieve raw bytes upon querying.</p>
<p>There&#39;s also that built-in library called <a target='_blank' rel='noopener noreferrer'  href="https://docs.python.org/3/library/pickle.html">pickle</a>. Pickle is a native Python marshalling library, which serializes Python objects into <em>bytes</em> and back to Python objects upon deserializing.</p>
<pre><code class="lang-python">age = <span class="hljs-number">5</span>
age_bytes = pickle.dumps(age)  <span class="hljs-comment"># into bytes</span>
age_again = pickle.loads(age_bytes)  <span class="hljs-comment"># back to python</span>
<span class="hljs-keyword">assert</span> age == age_again  <span class="hljs-comment"># will fail if not same</span>
</code></pre>
<p>So assume we have a model called <code>Student</code> and it has a field called <code>points</code> which we desire it to contain an <code>int</code> or <code>float</code> for some alien reason. Okay, okay, I <em>know</em> one can store <code>5</code> as <code>5.0</code> but the point is different types (or the fact that <em>we are inherently bad at programming</em>), but bare with me.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Student</span><span class="hljs-params">(models.Model)</span>:</span>
    name = models.CharField()  <span class="hljs-comment"># for purely cosmetic reason</span>
    points = models.BinaryField()
</code></pre>
<p>Nice nice nice. Now we can do some operations on it.</p>
<pre><code class="lang-python"><span class="hljs-comment"># creating</span>
Student.objects.create(name=<span class="hljs-string">"Steve"</span>, points=pickle.dumps(<span class="hljs-number">5</span>))

<span class="hljs-comment"># retrieving</span>
print(pickle.loads(student.points))

<span class="hljs-comment"># updating</span>
student.points = pickle.dumps(<span class="hljs-number">5.5</span>)
</code></pre>
<p>You see those <code>pickle.loads</code> or <code>dumps</code>. Well I hate them as much as you do. The <em>pure</em> stylistic choice is not the only reason we despise these, but these can be error prone as well. I could forget <code>load</code> or <code>dump</code> while writing code, again and again. I would like to make that <code>points</code> field (i) to accept any type of data and serialize to bytes using <code>pickle.dumps</code> while writing to database and (ii) to deserialize bytes on database with <code>pickle.loads</code> while reading <em>from</em> the database. That&#39;s what I&#39;m definitely after.</p>
<h1 id="custom-field-comes-into-play">Custom Field Comes into Play</h1>
<p>So, as you are probably aware, we can <a target='_blank' rel='noopener noreferrer'  href="https://docs.djangoproject.com/en/stable/howto/custom-model-fields/">write our custom model fields</a>. We will use this method to make <code>points</code> field above to automatically serialize and deserialize the given values.</p>
<p>You remember <code>BinaryField</code>, right? We will use that because it takes many huge details away instead of simply extending <code>Field</code>.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PickleField</span><span class="hljs-params">(models.BinaryField)</span>:</span>  <span class="hljs-comment"># extending BinaryField</span>
    <span class="hljs-keyword">pass</span>   <span class="hljs-comment"># to be implemented</span>
</code></pre>
<p>Before implementing the body, we need to know a few methods to override, those are:</p>
<ul>
<li><a target='_blank' rel='noopener noreferrer'  href="https://docs.djangoproject.com/en/stable/ref/models/fields/#django.db.models.Field.from_db_value">from_db_value</a>: This deserializes from database.</li>
<li><a target='_blank' rel='noopener noreferrer'  href="https://docs.djangoproject.com/en/stable/ref/models/fields/#django.db.models.Field.to_python">to_python</a>: This deserializes <em>for</em> Django forms.</li>
<li><p><a target='_blank' rel='noopener noreferrer'  href="https://docs.djangoproject.com/en/3.0/ref/models/fields/#django.db.models.Field.get_prep_value">get_prep_value</a>: This serializes value into database query.</p>
<blockquote>
<h4 id="warning">Warning</h4>
<p><code>from_db_value</code> and <code>to_python</code> methods sound similar. In our example, they do similar things. However, if you&#39;d like to see how they differ, click <a target='_blank' rel='noopener noreferrer'  href="https://docs.djangoproject.com/en/stable/howto/custom-model-fields/#converting-values-to-python-objects">here</a>.</p>
</blockquote>
</li>
</ul>
<p>Since <code>from_db_value</code> and <code>to_python</code> have the same implementation:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">from_db_value</span><span class="hljs-params">(self, value, expression, connection)</span>:</span>
    <span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-keyword">None</span>:
        <span class="hljs-comment"># none here assumes the field will be nullable</span>
        <span class="hljs-comment"># if not nullable, the code will not be reach here. an error is thrown.</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">None</span>

    <span class="hljs-keyword">return</span> pickle.loads(value)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">to_python</span><span class="hljs-params">(self, value)</span>:</span>
    <span class="hljs-keyword">if</span> isinstance(value, bytes) <span class="hljs-keyword">or</span> value <span class="hljs-keyword">is</span> <span class="hljs-keyword">None</span>:
        <span class="hljs-comment"># if intentionally bytes or None</span>
        <span class="hljs-keyword">return</span> value

    <span class="hljs-keyword">return</span> pickle.loads(value)
</code></pre>
<p>And the serialization:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_prep_value</span><span class="hljs-params">(self, value)</span>:</span>
    <span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-keyword">None</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">None</span>

    <span class="hljs-keyword">return</span> pickle.dumps(value)
</code></pre>
<p>Overall, our custom field looks like this:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PickleField</span><span class="hljs-params">(models.BinaryField)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">from_db_value</span><span class="hljs-params">(self, value, expression, connection)</span>:</span>
        <span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-keyword">None</span>:
            <span class="hljs-comment"># none here assumes the field will be nullable</span>
            <span class="hljs-comment"># if not nullable, the code will not be reach here. an error is thrown.</span>
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">None</span>

        <span class="hljs-keyword">return</span> pickle.loads(value)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">to_python</span><span class="hljs-params">(self, value)</span>:</span>
        <span class="hljs-keyword">if</span> isinstance(value, bytes) <span class="hljs-keyword">or</span> value <span class="hljs-keyword">is</span> <span class="hljs-keyword">None</span>:
            <span class="hljs-comment"># if intentionally bytes or None</span>
            <span class="hljs-keyword">return</span> value

        <span class="hljs-keyword">return</span> pickle.loads(value)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_prep_value</span><span class="hljs-params">(self, value)</span>:</span>
        <span class="hljs-keyword">if</span> value <span class="hljs-keyword">is</span> <span class="hljs-keyword">None</span>:
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">None</span>

        <span class="hljs-keyword">return</span> pickle.dumps(value)
</code></pre>
<p>Now we can use our custom field in our model:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Student</span><span class="hljs-params">(models.Model)</span>:</span>
    name = models.CharField()  <span class="hljs-comment"># for purely cosmetic reason</span>
    points = PickleField(null=<span class="hljs-keyword">True</span>)  <span class="hljs-comment"># nullable</span>
</code></pre>
<p>So we can do all our operations without ever mentioning <code>pickle</code> again:</p>
<pre><code class="lang-python"><span class="hljs-comment"># creating</span>
Student.objects.create(name=<span class="hljs-string">"Eray"</span>, point=<span class="hljs-number">5</span>)

<span class="hljs-comment"># updating</span>
student.point = <span class="hljs-number">5.5</span>

<span class="hljs-comment"># retrieving</span>
print(student.point)  <span class="hljs-comment"># 5.5</span>
</code></pre>
<p>That&#39;s all.</p>
<hr>
<p>Ah, by the way, I&#39;ve learned this while creating <a target='_blank' rel='noopener noreferrer'  href="https://github.com/erayerdin/django-persistent-settings/">Django Persistent Settings</a>. It&#39;s a library I&#39;ve created so that you can store platform specific settings in Django. Be careful, though, it&#39;s still on alpha phase. You can also view how I&#39;ve implemented <a target='_blank' rel='noopener noreferrer'  href="https://github.com/erayerdin/django-persistent-settings/blob/perma/2/persistent_settings/models.py#L21-L42">here</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Quick Note: Allow Failures on Github Actions]]></title><description><![CDATA[TL;DR
command || true
# true will return exit-code 0 no matter what


The Story
I was in the process of developing a new library for Django and thought maybe it is now a good time to try out new Github Actions. I was hesitating a bit but I've set up ...]]></description><link>https://erayerdin.com/quick-note-allow-failures-on-github-actions</link><guid isPermaLink="true">https://erayerdin.com/quick-note-allow-failures-on-github-actions</guid><category><![CDATA[Python]]></category><category><![CDATA[GitHub]]></category><dc:creator><![CDATA[Eray Erdin]]></dc:creator><pubDate>Sat, 07 Dec 2019 21:34:52 GMT</pubDate><content:encoded><![CDATA[<h1 id="tl-dr">TL;DR</h1>
<pre><code class="lang-bash"><span class="hljs-built_in">command</span> || <span class="hljs-literal">true</span>
<span class="hljs-comment"># true will return exit-code 0 no matter what</span>
</code></pre>
<hr>
<h1 id="the-story">The Story</h1>
<p>I was in the process of developing a new library for Django and thought maybe it is now a good time to try out new Github Actions. I was hesitating a bit but I&#39;ve set up things and it is actually pretty good. Github Actions is <em>a lot</em> faster. I was using TravisCI but the remote machines of Github Actions service spawn quicker and finish faster. What&#39;s more it is integrated right into Github.</p>
<p>To the point, I&#39;ve built up my matrix from Python 3.5 through 3.7. However, <code>black</code> only supports from 3.6. So Python 3.5 tests naturally fail on <code>pip</code> installation. That&#39;s why I&#39;ve looked up how to get <code>pip</code> running even if it fails on one package and I&#39;ve found one. While <code>pip</code> does not have a built-in solution to this, I have found <a target='_blank' rel='noopener noreferrer'  href="https://stackoverflow.com/a/54053100/2926992">this hack</a> to be quite useful. Basically, <em>bash</em> reads <code>requirements.txt</code> one by one <em>and</em> redirects lines to <code>pip install</code>. I thought that&#39;s enough and spawned the CI.</p>
<p>It looked like it was going good at the beginning. The installation step finished, <em>yet</em> it rendered as failure. Yes, there was failures here and there (on <code>black</code>, mainly) but it ended. Then I thought maybe Github Actions considers it as failing if any <code>pip install</code> fails.</p>
<p>There was one way to do this and it was <em>to allow failures</em> in installation step. I&#39;ve looked up for it <em>but</em> Github Actions did not have that. It is not surprising since Github Actions is a relatively new service. Then, I finally resolved my problem by appending <code>true</code> with &quot;or&quot; (double pipes).</p>
<pre><code class="lang-bash"><span class="hljs-built_in">command</span> || <span class="hljs-literal">true</span>
</code></pre>
<p>You know how logic works. If one returns true, exit-code is true. <code>true</code> here always return exit-code 0, so that solves the problem. I hope the internet is a calmer place now.</p>
]]></content:encoded></item></channel></rss>