Jekyll2024-01-19T21:31:53+00:00https://www.burgestrand.se/feed.xmlKim Burgestrand’s websiteHeartfelt software development. Sometimes other things.Kim BurgestrandToday is international men’s day2020-11-19T11:12:31+00:002020-11-19T11:12:31+00:00https://www.burgestrand.se/articles/today-is-international-men's-day<p>Translated from Swedish.</p>
<p>Today’s the first time I’m doing something like this, but it might be closer
to my heart than usual now that I have a small boy of my own to care for.</p>
<p>Today is international men’s day.</p>
<ul>
<li>You shouldn’t have to feel bad about enjoying pink cocktails, spice girls, manicure, lace embroidery, and sex and the city.</li>
<li>You shouldn’t have to feel bad about enjoying colorful clothing.</li>
<li>You shouldn’t have to feel bad about enjoying color and glitter.</li>
<li>You shouldn’t have to feel as if you need to be aggressive.</li>
<li>You shouldn’t have to feel as if you need to be tough.</li>
<li>You shouldn’t have to feel that you must drink a rough whiskey, smoke cigar, and eat copious amounts of bacon.</li>
<li>It should not be unmanly to pull your own weight at home; to do the dishes, clean, cook, and take care of your kids.</li>
</ul>
<p>This kind of shit is bad, repressive. It forces people to feel like shit. Drives them to suicide. Lung cancer, alcohol poisoning, obesity. They die in traffic accidents. They get assaulted. Distant and cold.</p>
<p>Alone. Depressed. Miserable.</p>
<p>It has to be OK to show weakness, to cry, to need help. It has to.</p>
<p>Manliness is real. It’s a good thing. It’d be nice if it was only a good thing.</p>Kim BurgestrandTranslated from Swedish.A ruby-inspired Swift-specific UIKit-tip2018-06-01T10:06:26+00:002018-06-01T10:06:26+00:00https://www.burgestrand.se/articles/a-ruby-inspired-uikit-monkey-patch-in-swift<p>You ever code views? I do. Not all of them, all the time, but some times. I’d
like to share with you a little helper I’ve been using.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">import</span> <span class="kt">Foundation</span>
<span class="kd">import</span> <span class="kt">UIKit</span>
<span class="kd">protocol</span> <span class="kt">SubviewAddable</span> <span class="p">{}</span>
<span class="kd">extension</span> <span class="kt">UIView</span><span class="p">:</span> <span class="kt">SubviewAddable</span> <span class="p">{}</span>
<span class="kd">extension</span> <span class="kt">SubviewAddable</span> <span class="k">where</span> <span class="k">Self</span><span class="p">:</span> <span class="kt">UIView</span> <span class="p">{</span>
<span class="kd">@discardableResult</span>
<span class="kd">func</span> <span class="n">add</span><span class="o"><</span><span class="kt">Subview</span><span class="p">:</span> <span class="kt">UIView</span><span class="o">></span><span class="p">(</span><span class="nv">subview</span><span class="p">:</span> <span class="kt">Subview</span><span class="p">,</span> <span class="nv">fn</span><span class="p">:</span> <span class="p">(</span><span class="kt">Subview</span><span class="p">,</span> <span class="k">Self</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Void</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Subview</span> <span class="p">{</span>
<span class="nf">addSubview</span><span class="p">(</span><span class="n">subview</span><span class="p">)</span>
<span class="nf">fn</span><span class="p">(</span><span class="n">subview</span><span class="p">,</span> <span class="k">self</span><span class="p">)</span>
<span class="k">return</span> <span class="n">subview</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>It’s helpful in that it allows you to add a subview, and within the same place
configure the subview (optionally using its superview). Usage is rather simple:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">subview</span> <span class="o">=</span> <span class="n">view</span><span class="o">.</span><span class="nf">add</span><span class="p">(</span><span class="nv">subview</span><span class="p">:</span> <span class="kt">MyAmazingView</span><span class="p">())</span> <span class="p">{</span> <span class="n">amazingView</span><span class="p">,</span> <span class="n">superview</span> <span class="k">in</span>
<span class="c1">// configure amazingView</span>
<span class="c1">// maybe constrain it to superview?</span>
<span class="p">}</span>
</code></pre></div></div>
<p>While small, it brings us a few really nice benefits:</p>
<ul>
<li>We can add and configure the subview in the same logical code block.</li>
<li>Your block/code hierarchy follows the view hierarchy.</li>
<li>The subview is returned after it’s been added and configured.</li>
<li>Because we’re using generics from Swift, we don’t lose any type information
in neither the configure block nor the return value.</li>
</ul>
<p>Answers to some things that might not be obvious:</p>
<ul>
<li>Why are we using a protocol for our extension? It’s because we want to allow
using <code class="language-plaintext highlighter-rouge">Self</code> as the type, which allows us keep type information about which
kind of view we’re adding to. Otherwise it would have to be always <code class="language-plaintext highlighter-rouge">UIView</code>,
instead of whatever <code class="language-plaintext highlighter-rouge">AmazingView: UIView</code>-subclass we might have.</li>
<li>Why are we passing <code class="language-plaintext highlighter-rouge">Self</code> to the configure block? It’s to avoid dealing with
the optional <code class="language-plaintext highlighter-rouge">view.superview</code>, and instead deal with a concrete non-optional
type when configuring our subview.</li>
<li>Why are we using <code class="language-plaintext highlighter-rouge"><Subview: UIView></code>? It’s to keep the type information about
our subview when configuring it in the block, otherwise it would have to be
a <code class="language-plaintext highlighter-rouge">UIView</code>, instead of our <code class="language-plaintext highlighter-rouge">AmazingView: UIView</code>-subclass.</li>
</ul>
<p>A full, working example, might look like this:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="kt">LoadingViewController</span><span class="p">:</span> <span class="kt">UIViewController</span> <span class="p">{</span>
<span class="k">weak</span> <span class="k">var</span> <span class="nv">loadingView</span><span class="p">:</span> <span class="kt">UIView</span><span class="o">!</span>
<span class="k">override</span> <span class="kd">func</span> <span class="nf">viewDidLoad</span><span class="p">()</span> <span class="p">{</span>
<span class="k">super</span><span class="o">.</span><span class="nf">viewDidLoad</span><span class="p">()</span>
<span class="n">view</span><span class="o">.</span><span class="n">backgroundColor</span> <span class="o">=</span> <span class="o">.</span><span class="n">blue</span>
<span class="c1">// Using it here to to add and configure the subview before weakly</span>
<span class="c1">// storing a reference to it for later</span>
<span class="n">loadingView</span> <span class="o">=</span> <span class="n">view</span><span class="o">.</span><span class="nf">add</span><span class="p">(</span><span class="nv">subview</span><span class="p">:</span> <span class="kt">UIView</span><span class="p">())</span> <span class="p">{</span> <span class="n">loadingView</span><span class="p">,</span> <span class="n">view</span> <span class="k">in</span>
<span class="n">loadingView</span><span class="o">.</span><span class="n">backgroundColor</span> <span class="o">=</span> <span class="kt">UIColor</span><span class="p">(</span><span class="nv">white</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="nv">alpha</span><span class="p">:</span> <span class="mf">0.6</span><span class="p">)</span>
<span class="n">loadingView</span><span class="o">.</span><span class="n">translatesAutoresizingMaskIntoConstraints</span> <span class="o">=</span> <span class="kc">false</span>
<span class="kt">NSLayoutConstraint</span><span class="o">.</span><span class="nf">activate</span><span class="p">([</span>
<span class="n">loadingView</span><span class="o">.</span><span class="n">topAnchor</span><span class="o">.</span><span class="nf">constraint</span><span class="p">(</span><span class="nv">equalTo</span><span class="p">:</span> <span class="n">view</span><span class="o">.</span><span class="n">topAnchor</span><span class="p">),</span>
<span class="n">loadingView</span><span class="o">.</span><span class="n">trailingAnchor</span><span class="o">.</span><span class="nf">constraint</span><span class="p">(</span><span class="nv">equalTo</span><span class="p">:</span> <span class="n">view</span><span class="o">.</span><span class="n">trailingAnchor</span><span class="p">),</span>
<span class="n">loadingView</span><span class="o">.</span><span class="n">bottomAnchor</span><span class="o">.</span><span class="nf">constraint</span><span class="p">(</span><span class="nv">equalTo</span><span class="p">:</span> <span class="n">view</span><span class="o">.</span><span class="n">bottomAnchor</span><span class="p">),</span>
<span class="n">loadingView</span><span class="o">.</span><span class="n">leadingAnchor</span><span class="o">.</span><span class="nf">constraint</span><span class="p">(</span><span class="nv">equalTo</span><span class="p">:</span> <span class="n">view</span><span class="o">.</span><span class="n">leadingAnchor</span><span class="p">)</span>
<span class="p">])</span>
<span class="c1">// Using it here to configure a spinner, and save it temporarily for</span>
<span class="c1">// constraining the label to it</span>
<span class="k">let</span> <span class="nv">spinnerView</span> <span class="o">=</span> <span class="n">loadingView</span><span class="o">.</span><span class="nf">add</span><span class="p">(</span><span class="nv">subview</span><span class="p">:</span> <span class="kt">UIActivityIndicatorView</span><span class="p">())</span> <span class="p">{</span> <span class="n">spinnerView</span><span class="p">,</span> <span class="n">contentView</span> <span class="k">in</span>
<span class="n">spinnerView</span><span class="o">.</span><span class="n">hidesWhenStopped</span> <span class="o">=</span> <span class="kc">false</span>
<span class="n">spinnerView</span><span class="o">.</span><span class="nf">startAnimating</span><span class="p">()</span>
<span class="n">spinnerView</span><span class="o">.</span><span class="n">translatesAutoresizingMaskIntoConstraints</span> <span class="o">=</span> <span class="kc">false</span>
<span class="kt">NSLayoutConstraint</span><span class="o">.</span><span class="nf">activate</span><span class="p">([</span>
<span class="n">spinnerView</span><span class="o">.</span><span class="n">centerXAnchor</span><span class="o">.</span><span class="nf">constraint</span><span class="p">(</span><span class="nv">equalTo</span><span class="p">:</span> <span class="n">contentView</span><span class="o">.</span><span class="n">centerXAnchor</span><span class="p">),</span>
<span class="n">spinnerView</span><span class="o">.</span><span class="n">centerYAnchor</span><span class="o">.</span><span class="nf">constraint</span><span class="p">(</span><span class="nv">equalTo</span><span class="p">:</span> <span class="n">contentView</span><span class="o">.</span><span class="n">centerYAnchor</span><span class="p">)</span>
<span class="p">])</span>
<span class="p">}</span>
<span class="c1">// Using it here mainly to configure the label</span>
<span class="n">loadingView</span><span class="o">.</span><span class="nf">add</span><span class="p">(</span><span class="nv">subview</span><span class="p">:</span> <span class="kt">UILabel</span><span class="p">())</span> <span class="p">{</span> <span class="n">textView</span><span class="p">,</span> <span class="n">contentView</span> <span class="k">in</span>
<span class="n">textView</span><span class="o">.</span><span class="n">textColor</span> <span class="o">=</span> <span class="o">.</span><span class="n">white</span>
<span class="n">textView</span><span class="o">.</span><span class="n">text</span> <span class="o">=</span> <span class="s">"Loading…"</span>
<span class="n">textView</span><span class="o">.</span><span class="n">translatesAutoresizingMaskIntoConstraints</span> <span class="o">=</span> <span class="kc">false</span>
<span class="kt">NSLayoutConstraint</span><span class="o">.</span><span class="nf">activate</span><span class="p">([</span>
<span class="n">textView</span><span class="o">.</span><span class="n">topAnchor</span><span class="o">.</span><span class="nf">constraint</span><span class="p">(</span><span class="nv">equalTo</span><span class="p">:</span> <span class="n">spinnerView</span><span class="o">.</span><span class="n">bottomAnchor</span><span class="p">,</span> <span class="nv">constant</span><span class="p">:</span> <span class="mi">8</span><span class="p">),</span>
<span class="n">textView</span><span class="o">.</span><span class="n">centerXAnchor</span><span class="o">.</span><span class="nf">constraint</span><span class="p">(</span><span class="nv">equalTo</span><span class="p">:</span> <span class="n">spinnerView</span><span class="o">.</span><span class="n">centerXAnchor</span><span class="p">)</span>
<span class="p">])</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>That’s all! Any questions, or feedback? Send me a tweet, or an e-mail.</p>Kim BurgestrandYou ever code views? I do. Not all of them, all the time, but some times. I’d like to share with you a little helper I’ve been using.String-like errors in Swift without monkey patching2017-10-12T10:34:45+00:002017-10-12T10:34:45+00:00https://www.burgestrand.se/articles/string-like-errors-in-swift-without-monkey-patching<p>A while back I <a href="https://stackoverflow.com/a/40629365/187710">read about a neat trick</a>.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">extension</span> <span class="kt">String</span><span class="p">:</span> <span class="kt">Swift</span><span class="o">.</span><span class="kt">Error</span> <span class="p">{}</span>
</code></pre></div></div>
<p>I am a bit afraid of it.</p>
<p>By adding this line, you can now <code class="language-plaintext highlighter-rouge">throw "Any string"</code> since Strings now conform
to <code class="language-plaintext highlighter-rouge">Error</code>. However, I’ve always been a bit afraid of monkey patching things
that are not mine. It tends to cause problems. This is personal FUD.</p>
<h2 id="there-are-strings-other-than-just-string">There are strings other than just <code class="language-plaintext highlighter-rouge">String</code>!</h2>
<p>Swift has many neat protocols, and we’ll be using three in particular today to
make a new kind of error that we’ll call <code class="language-plaintext highlighter-rouge">ErrorMessage</code>.</p>
<h3 id="error"><code class="language-plaintext highlighter-rouge">Error</code></h3>
<blockquote>
<p>A type representing an error value that can be thrown</p>
</blockquote>
<p>By adopting this protocol on our types, we make it possible to <code class="language-plaintext highlighter-rouge">throw</code> them.
If you use <a href="https://github.com/ReactiveCocoa/ReactiveSwift/#readme">Reactive Swift</a>, for example, the error type of all signals must
have adopted this protocol.</p>
<p>By adopting this protocol, we can <code class="language-plaintext highlighter-rouge">throw</code> any <code class="language-plaintext highlighter-rouge">ErrorMessage</code>.</p>
<h3 id="losslessstringconvertible"><code class="language-plaintext highlighter-rouge">LosslessStringConvertible</code></h3>
<blockquote>
<p>A type that can be represented as a string in a lossless, unambiguous way.</p>
</blockquote>
<p>By adopting this protocol, we’re saying that every <code class="language-plaintext highlighter-rouge">ErrorMessage</code> is a <code class="language-plaintext highlighter-rouge">String</code>;
keep in mind that we’re <em>not</em> saying that every <code class="language-plaintext highlighter-rouge">String</code> is an <code class="language-plaintext highlighter-rouge">ErrorMessage</code>.</p>
<h3 id="expressiblebystringliteral"><code class="language-plaintext highlighter-rouge">ExpressibleByStringLiteral</code></h3>
<blockquote>
<p>A type that can be initialized with a string literal.</p>
</blockquote>
<p>Remember that we said before that not <em>every</em> <code class="language-plaintext highlighter-rouge">String</code> is an <code class="language-plaintext highlighter-rouge">ErrorMessage</code>? By
adopting this protocol, we now said that it is. <em>Every</em> <code class="language-plaintext highlighter-rouge">String</code> is also an
<code class="language-plaintext highlighter-rouge">ErrorMessage</code>.</p>
<p>Without this protocol we would need to explicitly wrap our error messages as
<code class="language-plaintext highlighter-rouge">ErrorMessage(…)</code> <em>every frickin’ time</em>. With this protocol, however:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">error</span><span class="p">:</span> <span class="kt">ErrorMessage</span> <span class="o">=</span> <span class="s">"Oh no, something went wrong!"</span>
</code></pre></div></div>
<p>Yes, that’ll work. No, I’m not pulling your leg. Yes, this <em>is</em> the bees knees.</p>
<h3 id="all-of-us-together-now">All of us together, now!</h3>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">struct</span> <span class="kt">ErrorMessage</span><span class="p">:</span> <span class="kt">Swift</span><span class="o">.</span><span class="kt">Error</span><span class="p">,</span> <span class="kt">ExpressibleByStringLiteral</span><span class="p">,</span> <span class="kt">LosslessStringConvertible</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span>
<span class="c1">// ExpressibleByStringLiteral</span>
<span class="nf">init</span><span class="p">(</span><span class="n">stringLiteral</span> <span class="nv">string</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="p">{</span>
<span class="k">self</span><span class="o">.</span><span class="n">description</span> <span class="o">=</span> <span class="n">string</span>
<span class="p">}</span>
<span class="c1">// LosslessStringConvertible</span>
<span class="nf">init</span><span class="p">(</span><span class="n">_</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="p">{</span>
<span class="k">self</span><span class="o">.</span><span class="n">description</span> <span class="o">=</span> <span class="n">description</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li><code class="language-plaintext highlighter-rouge">Error</code> says we can <code class="language-plaintext highlighter-rouge">throw</code> it.</li>
<li><code class="language-plaintext highlighter-rouge">LosslessStringConvertible</code> says every <code class="language-plaintext highlighter-rouge">ErrorMessage</code> is also a <code class="language-plaintext highlighter-rouge">String</code>.</li>
<li><code class="language-plaintext highlighter-rouge">ExpressibleByStringLiteral</code> says every <code class="language-plaintext highlighter-rouge">String</code> is also an <code class="language-plaintext highlighter-rouge">ErrorMessage</code>.</li>
</ul>
<h3 id="usage">Usage</h3>
<p>If you have no type information available you’ll need to cast it.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">func</span> <span class="nf">crashBangBoom</span><span class="p">()</span> <span class="k">throws</span> <span class="p">{</span>
<span class="k">throw</span> <span class="s">"Boom!"</span> <span class="k">as</span> <span class="kt">ErrorMessage</span>
<span class="p">}</span>
<span class="k">let</span> <span class="nv">error</span><span class="p">:</span> <span class="kt">ErrorMessage</span> <span class="o">=</span> <span class="s">"Oh no!"</span>
</code></pre></div></div>
<p>However, if you <em>do</em> have inferred type information and can play with string
literals then things will be <em>smooooth</em>.</p>
<p><em>Note: This example uses ReactiveSwift.</em></p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">producer</span> <span class="o">=</span> <span class="kt">SignalProducer</span><span class="o"><</span><span class="kt">String</span><span class="p">,</span> <span class="kt">ErrorMessage</span><span class="o">></span> <span class="p">{</span> <span class="n">observer</span><span class="p">,</span> <span class="n">lifetime</span> <span class="k">in</span>
<span class="n">observer</span><span class="o">.</span><span class="nf">send</span><span class="p">(</span><span class="nv">error</span><span class="p">:</span> <span class="s">"Oh no!"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="tips">Tips</h3>
<p>You might want to check out <code class="language-plaintext highlighter-rouge">LocalizedError</code>, it has some more of that error
handling goodness.</p>
<p>That was all. Be well!</p>Kim BurgestrandA while back I read about a neat trick.Fun with Swift protocols and view controllers in storyboards2017-08-31T13:00:00+00:002017-08-31T13:00:00+00:00https://www.burgestrand.se/articles/fun-with-swift-protocols-and-view-controllers-in-storyboards<p>Xibs, storyboards, or programmatic view controllers… what to use? My answer? It
depends. Very helpful, I know! I’ll elaborate. In order of what I’m most
likely to use:</p>
<ol>
<li>One storyboard per screen (view controller). Like a xib, but works with prototyped table view and collection view cells.</li>
<li>No storyboard, so a programmatic view controller. Dependency injection through initializer.</li>
<li>A self-contained storyboard, possibly multiple screens, I only use this if I don’t need any data from the outside.</li>
</ol>
<p>I’ve been meaning to experiment with xibs more, since they allow for dependency
injection through the initializer, but haven’t quite needed it yet. I digress…</p>
<p>Anyhow! I wanted to share a Swift snippet with you to help with number <strong>1</strong> up there. It’s not
unique, ground-breaking or new by any means, but it’s useful and it feels nice.
Without any bells or whistles, here it is in all it’s glory.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">import</span> <span class="kt">UIKit</span>
<span class="c1">/// A protocol conformed to by all view controllers that expect to be</span>
<span class="c1">/// instantiated from a storyboard.</span>
<span class="kd">public</span> <span class="kd">protocol</span> <span class="kt">StoryboardDesigned</span><span class="p">:</span> <span class="kd">class</span> <span class="p">{</span>
<span class="kd">static</span> <span class="k">var</span> <span class="nv">storyboard</span><span class="p">:</span> <span class="kt">Storyboard</span><span class="o"><</span><span class="k">Self</span><span class="o">></span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
<span class="p">}</span>
<span class="c1">/// By default, a storyboard-designed view controller has named the storyboard</span>
<span class="c1">/// it belongs to the same as itself, sans `Controller`, and is the initial view</span>
<span class="c1">/// controller.</span>
<span class="c1">///</span>
<span class="c1">/// - example: PostViewController -> PostView.storyboard</span>
<span class="kd">public</span> <span class="kd">extension</span> <span class="kt">StoryboardDesigned</span> <span class="k">where</span> <span class="k">Self</span><span class="p">:</span> <span class="kt">UIViewController</span> <span class="p">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="k">var</span> <span class="nv">storyboard</span><span class="p">:</span> <span class="kt">Storyboard</span><span class="o"><</span><span class="k">Self</span><span class="o">></span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">className</span> <span class="o">=</span> <span class="kt">String</span><span class="p">(</span><span class="nv">describing</span><span class="p">:</span> <span class="k">self</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">storyboardName</span> <span class="o">=</span> <span class="n">className</span><span class="o">.</span><span class="nf">replacingOccurrences</span><span class="p">(</span><span class="nv">of</span><span class="p">:</span> <span class="s">"Controller"</span><span class="p">,</span> <span class="nv">with</span><span class="p">:</span> <span class="s">""</span><span class="p">)</span>
<span class="k">return</span> <span class="kt">Storyboard</span><span class="o"><</span><span class="k">Self</span><span class="o">></span><span class="p">(</span><span class="n">storyboardName</span><span class="p">,</span> <span class="nv">identifier</span><span class="p">:</span> <span class="kc">nil</span><span class="p">,</span> <span class="nv">bundle</span><span class="p">:</span> <span class="kc">nil</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">/// A simple wrapper-type that we use to identify storyboards.</span>
<span class="kd">public</span> <span class="kd">struct</span> <span class="kt">Storyboard</span><span class="o"><</span><span class="kt">T</span><span class="o">></span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span>
<span class="k">let</span> <span class="nv">identifier</span><span class="p">:</span> <span class="kt">String</span><span class="p">?</span>
<span class="k">let</span> <span class="nv">bundle</span><span class="p">:</span> <span class="kt">Bundle</span><span class="p">?</span>
<span class="nf">init</span><span class="p">(</span><span class="n">_</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">identifier</span><span class="p">:</span> <span class="kt">String</span><span class="p">?</span> <span class="o">=</span> <span class="kt">String</span><span class="p">(</span><span class="nv">describing</span><span class="p">:</span> <span class="kt">T</span><span class="o">.</span><span class="k">self</span><span class="p">),</span> <span class="nv">bundle</span><span class="p">:</span> <span class="kt">Bundle</span><span class="p">?</span> <span class="o">=</span> <span class="kc">nil</span><span class="p">)</span> <span class="p">{</span>
<span class="k">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
<span class="k">self</span><span class="o">.</span><span class="n">identifier</span> <span class="o">=</span> <span class="n">identifier</span>
<span class="k">self</span><span class="o">.</span><span class="n">bundle</span> <span class="o">=</span> <span class="n">bundle</span>
<span class="p">}</span>
<span class="k">var</span> <span class="nv">storyboard</span><span class="p">:</span> <span class="kt">UIStoryboard</span> <span class="p">{</span>
<span class="k">return</span> <span class="kt">UIStoryboard</span><span class="p">(</span><span class="nv">name</span><span class="p">:</span> <span class="n">name</span><span class="p">,</span> <span class="nv">bundle</span><span class="p">:</span> <span class="n">bundle</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">instantiate</span><span class="p">()</span> <span class="o">-></span> <span class="kt">T</span> <span class="p">{</span>
<span class="k">guard</span> <span class="k">let</span> <span class="nv">identifier</span> <span class="o">=</span> <span class="n">identifier</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">storyboard</span><span class="o">.</span><span class="nf">instantiateInitialViewController</span><span class="p">()</span> <span class="k">as!</span> <span class="kt">T</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">storyboard</span><span class="o">.</span><span class="nf">instantiateViewController</span><span class="p">(</span><span class="nv">withIdentifier</span><span class="p">:</span> <span class="n">identifier</span><span class="p">)</span> <span class="k">as!</span> <span class="kt">T</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>By using the above code, and assuming you stick to my convention of naming your
single-view storyboards the same as your view controller, and mark it as the
initial view controller of the storyboard, then you may use the above code like this:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">final</span> <span class="kd">class</span> <span class="kt">PostViewController</span><span class="p">:</span> <span class="kt">UIViewController</span><span class="p">,</span> <span class="kt">StoryboardDesigned</span> <span class="p">{</span>
<span class="c1">// … outlets and other code in here …</span>
<span class="p">}</span>
</code></pre></div></div>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">func</span> <span class="nf">showPostViewController</span><span class="p">(</span><span class="n">from</span> <span class="nv">viewController</span><span class="p">:</span> <span class="kt">UIViewController</span><span class="p">)</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">postViewController</span> <span class="o">=</span> <span class="kt">PostViewController</span><span class="o">.</span><span class="n">storyboard</span><span class="o">.</span><span class="nf">instantiate</span><span class="p">()</span>
<span class="n">viewController</span><span class="o">.</span><span class="nf">present</span><span class="p">(</span><span class="n">postViewController</span><span class="p">,</span> <span class="nv">animated</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nv">completion</span><span class="p">:</span> <span class="kc">nil</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>That’s all! There’s nothing more for now. Thanks for reading, I hope you found
it worthwhile.</p>Kim BurgestrandXibs, storyboards, or programmatic view controllers… what to use? My answer? It depends. Very helpful, I know! I’ll elaborate. In order of what I’m most likely to use:A statically typed NotificationCenter in Swift2017-01-20T14:54:00+00:002017-01-20T14:54:00+00:00https://www.burgestrand.se/articles/statically-typed-notificationcenter-in-swift<p>Event hubs, event bus, notification center… all names for an architectural
solution to decouple components of your program. You do some work, and then you
announce to the world you did, but you don’t care if anybody is listening.</p>
<p>There’s an Apple-provided implementation available for this when doing mobile
development for iOS, it’s called <a href="https://developer.apple.com/reference/foundation/nsnotificationcenter">NotificationCenter</a>. An example of where
you’d use this could be to post a notification every time the current user
changes.</p>
<p>To use it, you come up with a magic name for an event, let’s say <code class="language-plaintext highlighter-rouge">userChanged</code>,
and every time we post this notification we vow to include the new user in
<a href="https://developer.apple.com/reference/foundation/notification/1779652-userinfo"><code class="language-plaintext highlighter-rouge">userInfo</code></a> dictionary, let’s say <code class="language-plaintext highlighter-rouge">userInfo["user"]</code> holds the new <code class="language-plaintext highlighter-rouge">User</code>
instance.</p>
<p>My main problem with this, is what’s to say that:</p>
<ul>
<li>I won’t misspell the event name? (<code class="language-plaintext highlighter-rouge">usrChanged</code>)</li>
<li>I won’t misspell the <code class="language-plaintext highlighter-rouge">user</code> key in <code class="language-plaintext highlighter-rouge">userInfo</code>? (<code class="language-plaintext highlighter-rouge">usr</code>, <code class="language-plaintext highlighter-rouge">newUser</code>)</li>
<li>I won’t forget to include the new <code class="language-plaintext highlighter-rouge">User</code> at all?</li>
<li>I won’t send the wrong type as the new user? (perhaps <code class="language-plaintext highlighter-rouge">nil</code>?)</li>
</ul>
<p>I have good news though. Swift’s generics allow us to make a very nice solution
that alleviates all these problems!</p>
<script src="https://gist.github.com/575ee47fae55cba18d29f28227740a18.js?file=hub.swift"> </script>
<p>The above definition of <code class="language-plaintext highlighter-rouge">Hub</code>, <code class="language-plaintext highlighter-rouge">Events</code> and <code class="language-plaintext highlighter-rouge">Event<T></code> allows us to:</p>
<ul>
<li>
<p>Ensure nobody ever misstypes an event by extending <code class="language-plaintext highlighter-rouge">Events</code> to allow usage of
of the dot short-hand on <code class="language-plaintext highlighter-rouge">observe</code> and <code class="language-plaintext highlighter-rouge">post</code>:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">extension</span> <span class="kt">Events</span> <span class="p">{</span>
<span class="kd">static</span> <span class="k">let</span> <span class="nv">userUpdated</span> <span class="o">=</span> <span class="kt">Event</span><span class="o"><</span><span class="kt">User</span><span class="p">?</span><span class="o">></span><span class="p">(</span><span class="s">"UserUpdated"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div> </div>
</li>
<li>
<p>Guarantee that all <em>observed</em> events of type <code class="language-plaintext highlighter-rouge">T</code> actually contains a <code class="language-plaintext highlighter-rouge">T</code>:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">hub</span><span class="o">.</span><span class="nf">observe</span><span class="p">(</span><span class="o">.</span><span class="n">userUpdated</span><span class="p">)</span> <span class="p">{</span> <span class="p">(</span><span class="nv">user</span><span class="p">:</span> <span class="kt">User</span><span class="p">?)</span> <span class="k">in</span> <span class="cm">/* … */</span> <span class="p">}</span>
</code></pre></div> </div>
</li>
<li>
<p>Guarantee that all <em>posted</em> events of type <code class="language-plaintext highlighter-rouge">T</code> actually includes a <code class="language-plaintext highlighter-rouge">T</code>:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">hub</span><span class="o">.</span><span class="nf">post</span><span class="p">(</span><span class="o">.</span><span class="n">userUpdated</span><span class="p">,</span> <span class="kt">User</span><span class="p">(</span><span class="nv">name</span><span class="p">:</span> <span class="s">"Alice"</span><span class="p">))</span>
<span class="n">hub</span><span class="o">.</span><span class="nf">post</span><span class="p">(</span><span class="o">.</span><span class="n">userUpdated</span><span class="p">,</span> <span class="kc">nil</span><span class="p">)</span>
</code></pre></div> </div>
</li>
</ul>
<p>And all of this is built on top of Apple’s own NotificationCenter and your
normal Swift generics!</p>
<p>There’s a GitHub repository for the code in this post, you’re very welcome to
send pull-requests: <a href="https://github.com/Burgestrand/swift-hub">https://github.com/Burgestrand/swift-hub</a>. That’s all for
now, thanks for staying!</p>Kim BurgestrandEvent hubs, event bus, notification center… all names for an architectural solution to decouple components of your program. You do some work, and then you announce to the world you did, but you don’t care if anybody is listening.How I reduced PostgreSQL memory usage from our Sidekiq workers2016-07-06T22:00:00+00:002016-07-06T22:00:00+00:00https://www.burgestrand.se/articles/how-i-reduced-postgresql-memory-usage-from-our-sidekiq-workers<p>Like all good stories do, it started with a bunch of errors in my inbox:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ActiveRecord::StatementInvalid sidekiq#pro
PG::ConnectionBad: PQconsumeInput() SSL connection has been closed unexpectedly : SELECT …
PG::ConnectionBad analytics:attribution
could not fork new process for connection: Cannot allocate memory could not fork new process for connection: Cannot allocate memory could not fork new process for connection: Cannot allocate memory
ActionView::Template::Error admin#stats
PG::OutOfMemory: ERROR: out of memory DETAIL: Failed on request of size 48. : SELECT …
</code></pre></div></div>
<p><em>“How strange!”</em>, I thought, <em>“I wonder what the memory usage looks like.”</em></p>
<p><img src="/assets/images/posts/2016-07-03/saw-pattern.png" alt="Saw pattern" class="centered" /></p>
<figcaption class="caption">
It was actually worse than this and hit 1GB, but I don't have an earlier image.
</figcaption>
<p>Well, saw patterns in graphs are rarely good. These errors cropped up after
increasing the number of Sidekiq workers, and thus also the number of
connections to the database.</p>
<p>After some intense googling, I found out that <a href="https://www.postgresql.org/docs/current/static/sql-prepare.html">PostgreSQL stores PREPAREd statements per session</a>.
I know Rails uses prepared statements, and I know prepared statements need to be
referenced by name, which means Rails keeps this name around somewhere. After
looking through the source of Rails on GitHub, I found this:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># https://github.com/rails/rails/blob/v5.0.0/activerecord/lib/active_record/connection_adapters/statement_pool.rb#L6</span>
<span class="k">module</span> <span class="nn">ActiveRecord</span>
<span class="k">module</span> <span class="nn">ConnectionAdapters</span>
<span class="k">class</span> <span class="nc">StatementPool</span> <span class="c1"># :nodoc:</span>
<span class="kp">include</span> <span class="no">Enumerable</span>
<span class="no">DEFAULT_STATEMENT_LIMIT</span> <span class="o">=</span> <span class="mi">1000</span>
</code></pre></div></div>
<p>So, turns out Rails by default stores the 1 000 most recently used prepared statements.
Quick math! With 30 workers, we can expect 30 000 prepared statements kept
around in memory. All in all it’s not that much, but we’re sporting a humble 1GB of memory, so it
turns out that this is enough to hit the roof!</p>
<p>So, what to do? More googling! Turns out that Rails has support for disabling
prepared statements, and it’s had it <a href="http://guides.rubyonrails.org/v4.0/configuring.html#configuring-a-postgresql-database">since at least Rails v4.0</a>!
So, I sent a pull request with a configuration change to disable prepared statements
for our Sidekiq workers:</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">default: &default
</span> adapter: postgresql
⋮
<span class="gi">+ prepared_statements: <%= ! Sidekiq.server? %>
</span></code></pre></div></div>
<p>Once merged and deployed, memory usage for PostgreSQL dropped considerably, and
has since been stable at just under 200 MB!</p>
<p><img src="/assets/images/posts/2016-07-03/post-fix.png" alt="Post-fix" class="centered" />
<img src="/assets/images/posts/2016-07-03/stability.png" alt="Stability" class="centered" /></p>
<figcaption class="caption">
Blue line is postgres memory, green line is free memory.
</figcaption>
<p>This probably comes with a cost of increased load, the good old Memory vs CPU
tradeoff. We could possibly have lowered the <a href="http://guides.rubyonrails.org/v4.2/configuring.html#configuring-a-postgresql-database">statement limit</a>
(available since at least Rails 4.2) but the load on our servers
is not too high, so we’re happy with just turning them off!</p>Kim BurgestrandLike all good stories do, it started with a bunch of errors in my inbox:Clearing your Rails database in development2016-06-01T15:17:00+00:002016-06-01T15:17:00+00:00https://www.burgestrand.se/articles/clearing-your-rails-database-in-development<p>You ever been hit with this?</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>rake db:reset
PG::ObjectInUse: ERROR: database <span class="s2">"yolo_development"</span> is being accessed by other <span class="nb">users
</span>DETAIL: There is 1 other session using the database.
: DROP DATABASE IF EXISTS <span class="s2">"yolo_development"</span>
<span class="nv">$ </span>rake db:drop db:create db:migrate db:seed
PG::ObjectInUse: ERROR: database <span class="s2">"yolo_development"</span> is being accessed by other <span class="nb">users
</span>DETAIL: There is 1 other session using the database.
</code></pre></div></div>
<p>During development in Ruby on Rails it’s often necessary to wipe the database,
seed, and start over.</p>
<p>In my case, I often also do not want to re-migrate the entire thing just because
I want a new set of data. Until recently I used to terminate my Rails server, run
<code class="language-plaintext highlighter-rouge">rake db:reset</code>, and I’d be happy and annoyed at the same time.</p>
<p>Today I just run <code class="language-plaintext highlighter-rouge">rake db:prune db:seed</code> and I will have a fresh database, and
now you can too! Meet <a href="https://github.com/Burgestrand/rails_prune">rails_prune</a>,
the first gem that I’ve created where the implementation is shorter than its announcement!</p>
<p><em>PS: It works fine with foreign key constraints.</em></p>Kim BurgestrandYou ever been hit with this?Peeling layers off from Heroku deployments of Phoenix2016-05-04T16:00:00+00:002016-05-04T16:00:00+00:00https://www.burgestrand.se/articles/peeling-layers-off-from-heroku-deployments-of-phoenix<p><a href="https://github.com/gjaldon/heroku-buildpack-phoenix-static">Heroku Buildpack: Phoenix Static</a> can be used to
compile static assets when deploying Phoenix to Heroku. I used it a while, until I realized:</p>
<ol>
<li>I’m not using brunch, I use webpack. Thank you, <a href="http://matthewlehner.net/using-webpack-with-phoenix-and-elixir/">Matthew Lehner</a> for saving me a lot of time setting this up.</li>
<li>I’m not using bower, because webpack.</li>
<li><a href="https://devcenter.heroku.com/articles/using-multiple-buildpacks-for-an-app">Heroku supports multiple buildpacks for the same application</a>, so why
does Phoenix Static install Node and NPM on it’s own?</li>
</ol>
<p>Question no. 3 got me going. Could I use only the Elixir and Node buildpacks, and thus remove
the Phoenix Static buildpack and the assumption that I’m using brunch from my set-up, all at the same time?</p>
<p>Yes! It did require <a href="https://github.com/HashNuke/heroku-buildpack-elixir/pull/74">a pull request to allow for the Elixir buildpack to be used in multi-buildpack setups</a>,
but that was a nice thing to be done anyway. I still use two buildpacks: <a href="https://github.com/HashNuke/heroku-buildpack-elixir">Elixir & Mix</a> together with
<a href="https://github.com/heroku/heroku-buildpack-nodejs">Node & NPM</a> (which, by the way, is maintained by Heroku), in that order.</p>
<p>Once that was configured, I used the <code class="language-plaintext highlighter-rouge">postbuild</code> hook from the Node buildpack to compile my assets. It looks like this:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"scripts"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"start"</span><span class="p">:</span><span class="w"> </span><span class="s2">"webpack --watch-stdin --progress --color"</span><span class="p">,</span><span class="w">
</span><span class="nl">"compile"</span><span class="p">:</span><span class="w"> </span><span class="s2">"webpack --optimize-minimize"</span><span class="p">,</span><span class="w">
</span><span class="nl">"heroku-postbuild"</span><span class="p">:</span><span class="w"> </span><span class="s2">"npm run compile && mix phoenix.digest"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>It feels like a cleaner separation of concerns. In my previous setup, Phoenix Static was not only in charge of installing Node, NPM, and
Bower, but also for compiling my assets using Brunch and digesting them with Phoenix.</p>
<p>Now the Elixir buildpack is in charge of installing Elixir, the Node buildpack is in charge of installing Node, and I am in charge of
compiling my assets.</p>
<p>Oh, final caveat, you might want a <code class="language-plaintext highlighter-rouge">Procfile</code> to communicate to Heroku how your application should be run.
I like to have this anyway, again because of explicitness, but because the Node buildpack is the last in
the pipeline I think it might actually be required.</p>Kim BurgestrandHeroku Buildpack: Phoenix Static can be used to compile static assets when deploying Phoenix to Heroku. I used it a while, until I realized:Reverse-engineering the Philips Hue2011-11-07T07:06:00+00:002011-11-07T07:06:00+00:00https://www.burgestrand.se/articles/reverse-engineering-the-hue<p>With the help of <a href="https://itunes.apple.com/us/app/philips-hue/id557206189?mt=8">tcpflow</a> and the current <a href="https://itunes.apple.com/us/app/philips-hue/id557206189?mt=8">Hue iPhone-application</a>, I’ve managed to
capture parts of the Hue API. As a result of this, I’ve begun working on a complete Hue API
reference — available on GitHub at the <a href="https://github.com/Burgestrand/ruhue">Ruhue</a> repository.</p>
<p>A few notes about the Hue hub API:</p>
<ul>
<li>Hub discovery is done via <a href="http://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol">SSDP</a>. This makes it very easy to find a Hue hub connected
to your home network, without any manual setup necessary.</li>
<li>Commands to the Hue are sent via HTTP, and allow full access to lamp color, brightness,
and schedule. Data payloads are sent as JSON!</li>
</ul>
<p>Further details can be found in the <a href="https://github.com/Burgestrand/ruhue">Ruhue</a> GitHub repository. It will be updated as the
API calls are explored. Pull requests are very welcome, so fork away and send patches and
I’ll accept them into the repository!</p>
<h3 id="technical-hue-hacking-discussion-is-on-the-mailing-list">Technical Hue hacking discussion is on the mailing list</h3>
<p>In addition to the GitHub repository, there is also a Google Groups mailing
list, <a href="https://groups.google.com/forum/#!forum/hue-hackers">Philips Hue Hackers</a>, a mailing list for anybody exploring their Hue
lights. Expect a lot of technical discussions on this mailing list.</p>
<p>The mailing list e-mail address is <a href="mailto:hue-hackers@googlegroups.com">hue-hackers@googlegroups.com</a>.</p>
<h3 id="for-you-who-are-eager-to-start-hacking-the-hue">For you who are eager to start hacking the Hue…</h3>
<p>The <a href="https://github.com/Burgestrand/ruhue">Ruhue</a> repository contains a console script, allowing you
to use an interactive ruby interpreter to control your Hue lights. Further details
are in the Ruhue README.</p>
<h3 id="additional-resources">Additional resources</h3>
<p>A few others have begun exploring how their Hue lights really work as well, and
have written articles about their own progress. These articles existed before
I started the documentation effort, and they’ve helped immensely.</p>
<ul>
<li><a href="http://rsmck.co.uk/hue">Hack the Hue</a></li>
<li><a href="http://www.nerdblog.com/2012/10/a-day-with-philips-hue.html?showComment=1352172383498">A Day with Philips Hue</a></li>
</ul>Kim BurgestrandThe "Philips Hue":http://www.meethue.com/ became available last week. It’s a system of LED lamps that support a wide range of colors and brightness, and allows complete remote control from the Hue mobile application, or the Philips Hue website. With the starter kit you’ll receive a Hue bridge, three lamps with an E27 socket, and it’s extremely easy to set up! Philips have said they’ll eventually release a developer kit, which would allow anybody with a computer to control their lights without using the app supplied by Philips. Personally, I don’t want to wait for that…Hallon, delicious Ruby bindings for libspotify2011-07-18T10:25:54+00:002011-07-18T10:25:54+00:00https://www.burgestrand.se/articles/hallon-delicious-ruby-bindings-to-libspotify<p>First, a little bit of background. When I first joined the <a href="http://radiofy.se/">Radiofy</a>
project 18 months ago, we were using a java variant of libspotify named Jotify.
Jotify worked quite well for us, but after six months it suddenly stopped working.</p>
<p>So, what gives? From what we gathered, Spotify had updated their protocol,
right at the same time the Jotify project was abandoned by its’ author, and all
other alternative projects either didn’t have required functionality or plain
out didn’t work for us. Having a service relying very much on having a Spotify
API we had to find a solution.</p>
<p>And so, <a href="http://github.com/Burgestrand/Hallon">Hallon</a> was born. During the
weekend I revisited my C knowledge, studied up on <a href="http://www.ruby-doc.org/docs/ProgrammingRuby/html/ext_ruby.html">Ruby C extensions</a>
and quickly wrote the most minimal thing that could possibly work. By Monday
we had our service up and running, using Hallon as back-end. And that’s how
Hallon was born.</p>
<h2 id="so-what-is-hallon-really">So, what is Hallon, really?</h2>
<p>Hallon is Swedish for <a href="http://www.flickr.com/photos/todorrovic/4815941952/">raspberry</a>,
and is really just one side of a coin.</p>
<p>On one side we have <a href="https://rubygems.org/gems/spotify">libspotify for Ruby</a>.
This gem, Spotify, is a ruby wrapper for the libspotify API. What this
means is that anything you can do in C with libspotify, you can now do with Ruby.</p>
<p>However, as the Spotify gem is written using <a href="https://github.com/ffi/ffi">Ruby FFI</a>,
you still need to manage memory by yourself, freeing pointers where necessary and
all other kinds of stuff that we should be spared from doing when coding Ruby.</p>
<p><a href="https://rubygems.org/gems/hallon">Hallon</a> is meant to remedy this. Hallon is
is a layer written on top of the Spotify gem. The goal of Hallon is to provide
a simple-to-use API, allowing you to worry about things you enjoy worring about,
rather than thinking about memory or pesky pointers.</p>
<h3 id="why-two-gems-isnt-hallon-enough">Why two gems? Isn’t Hallon enough?</h3>
<p>Hallon is not complete, and is <em>much</em> harder to implement than the Spotify gem.
Luckily, when Hallon’s functionality is not enough, one can use the Spotify gem
to fill in the gaps, providing an all-around solution until Hallon reaches
v1.0.0.</p>
<p>However, do note that when Hallon reaches v1.0.0, there will be <em>no</em> reason
to use the Spotify gem directly, and Hallon’s API will easy and fun to use.
That is my goal.</p>
<p>Finally, this post would not be complete without a code sample.</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="nb">require</span> <span class="s1">'hallon'</span>
<span class="n">session</span> <span class="o">=</span> <span class="no">Hallon</span><span class="o">::</span><span class="no">Session</span><span class="p">.</span><span class="nf">instance</span><span class="p">(</span><span class="n">spotify_appkey</span><span class="p">,</span> <span class="ss">user_agent: </span><span class="s1">'Hallon'</span><span class="p">)</span> <span class="k">do</span>
<span class="n">on</span><span class="p">(</span><span class="ss">:connection_error</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">error</span><span class="o">|</span>
<span class="nb">puts</span> <span class="s2">"[ERROR] %s"</span> <span class="o">%</span> <span class="no">Hallon</span><span class="o">::</span><span class="no">Error</span><span class="p">.</span><span class="nf">explain</span><span class="p">(</span><span class="n">error</span><span class="p">)</span>
<span class="nb">abort</span>
<span class="k">end</span>
<span class="n">on</span><span class="p">(</span><span class="ss">:log_message</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">message</span><span class="o">|</span>
<span class="nb">puts</span> <span class="s2">"[LOG] </span><span class="si">#{</span><span class="n">message</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">session</span><span class="p">.</span><span class="nf">login</span> <span class="n">username</span><span class="p">,</span> <span class="n">password</span>
<span class="n">session</span><span class="p">.</span><span class="nf">wait_for</span><span class="p">(</span><span class="ss">:logged_in</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">status</span><span class="o">|</span>
<span class="no">Hallon</span><span class="o">::</span><span class="no">Error</span><span class="p">.</span><span class="nf">maybe_raise</span><span class="p">(</span><span class="n">status</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1"># make absolutely sure we’ve logged in</span>
<span class="n">session</span><span class="p">.</span><span class="nf">wait_for</span><span class="p">(</span><span class="ss">:connection_error</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">error</span><span class="o">|</span>
<span class="n">session</span><span class="p">.</span><span class="nf">logged_in?</span> <span class="n">or</span> <span class="no">Hallon</span><span class="o">::</span><span class="no">Error</span><span class="p">.</span><span class="nf">maybe_raise</span><span class="p">(</span><span class="n">error</span><span class="p">)</span>
<span class="k">end</span>
<span class="n">image</span> <span class="o">=</span> <span class="no">Hallon</span><span class="o">::</span><span class="no">Image</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s2">"spotify:image:3ad93423add99766e02d563605c6e76ed2b0e450"</span><span class="p">)</span>
<span class="n">session</span><span class="p">.</span><span class="nf">wait_for</span><span class="p">(</span><span class="ss">:metadata_updated</span><span class="p">)</span> <span class="p">{</span> <span class="n">image</span><span class="p">.</span><span class="nf">loaded?</span> <span class="p">}</span>
<span class="nb">puts</span> <span class="s2">"Image format: </span><span class="si">#{</span><span class="n">image</span><span class="p">.</span><span class="nf">format</span><span class="si">}</span><span class="s2">"</span>
<span class="nb">puts</span> <span class="s2">"Where to save raw image data?"</span>
<span class="n">path</span> <span class="o">=</span> <span class="nb">gets</span>
<span class="no">File</span><span class="p">.</span><span class="nf">open</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s1">'w'</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">f</span><span class="o">|</span> <span class="n">f</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="n">image</span><span class="p">.</span><span class="nf">data</span><span class="p">)</span> <span class="p">}</span>
<span class="nb">puts</span> <span class="s2">"Image saved to </span><span class="si">#{</span><span class="n">path</span><span class="si">}</span><span class="s2">!"</span></code></pre></figure>
<p>Thank you for reading! If there’s any questions, feel
free to contact me. My details can be found on the <a href="/about-me/">About Me</a> page.</p>Kim BurgestrandI’ve always loved the "Spotify":http://spotify.com/ service. I love it so much that I find no need to pirate music anymore, and I’ve been a paying customer for nearly a year. Me being me, that’s nothing short of an amazing acomplishement. Spotify also has a developer API, "libspotify":https://developer.spotify.com/technologies/libspotify/, written in C. Thing is, Ruby is a much nicer language to use than C, so what to do?