<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Adjoa</title>
    <description>The latest articles on DEV Community by Adjoa (@adjoa).</description>
    <link>https://dev.to/adjoa</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F40008%2Fe5e8ba33-75f7-402b-95b7-b9b187af3b1e.jpg</url>
      <title>DEV Community: Adjoa</title>
      <link>https://dev.to/adjoa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adjoa"/>
    <language>en</language>
    <item>
      <title>Rails' Polymorphic Associations</title>
      <dc:creator>Adjoa</dc:creator>
      <pubDate>Sat, 14 Jul 2018 11:00:27 +0000</pubDate>
      <link>https://dev.to/adjoa/rails-polymorphic-associations-511n</link>
      <guid>https://dev.to/adjoa/rails-polymorphic-associations-511n</guid>
      <description>&lt;p&gt;In this post I'll give you an overview of how polymorphic associations work in Rails and how to add them to your projects.  &lt;/p&gt;

&lt;h2&gt;
  
  
  How I Got Here
&lt;/h2&gt;

&lt;p&gt;I'm on my final lap at &lt;a href="https://flatironschool.com/"&gt;Flatiron School&lt;/a&gt; now and completing my final project. If the last 4 cycles of project-building have taught me anything, it’s the importance of considering the data. &lt;em&gt;‘What sorts of models will be appropriate and how should they be associated in the database?’&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;To answer the first question, I wanted to build an application that would allow users to browse through upcoming events. I also wanted organizers to be able to log in and add to the listings. So, 2 models then: &lt;code&gt;Organizer&lt;/code&gt; and &lt;code&gt;Event&lt;/code&gt;. But both of these models need an &lt;code&gt;Address&lt;/code&gt;, right? 3 models. But, how to associate them? This question led me right into unfamiliar territory: &lt;strong&gt;polymorphic associations&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Polymorphism?
&lt;/h2&gt;

&lt;p&gt;Working with Rails’ Active Record library up to that point I had encountered and come to understand most of the available &lt;a href="http://guides.rubyonrails.org/association_basics.html"&gt;Active Record associations&lt;/a&gt;: &lt;code&gt;belongs_to&lt;/code&gt;, &lt;code&gt;has_many&lt;/code&gt;, &lt;code&gt;has_many :through&lt;/code&gt;, and so on. But in this instance, I needed a way to associate two different models with one model while keeping things DRY. Specifically, I needed a way to associate an Organizer and an Event with an Address that didn’t involve creating separate Address-like models for each.&lt;/p&gt;

&lt;p&gt;A polymorphic association to the Address turned out to be the perfect tool for accomplishing this because as the &lt;a href="http://guides.rubyonrails.org/association_basics.html#polymorphic-associations"&gt;documentation&lt;/a&gt; explains, with this type of association “a model can belong to more than one other model, on a single association”.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ok, but how do I implement this?
&lt;/h2&gt;

&lt;p&gt;We can think of implementing a polymorphic association as creating an interface between the reusable model and the models that need to connect to it. The conventional way to name such interfaces is by adding an '-able' to the end of the model name so, addressable, commentable, imageable etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Address&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
&lt;span class="c1"&gt;# name the interface to the Address model addressable&lt;/span&gt;
&lt;span class="c1"&gt;# establish that it is polymorphic&lt;/span&gt;
&lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:addressable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;polymorphic: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Organizer&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
&lt;span class="c1"&gt;# establish a relationship to the Address model &lt;/span&gt;
&lt;span class="c1"&gt;# via the addressable interface&lt;/span&gt;
&lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;as: :addresssable&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
&lt;span class="c1"&gt;# establish a relationship to the Address model&lt;/span&gt;
&lt;span class="c1"&gt;# via the addressable interface &lt;/span&gt;
&lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;as: :addressable&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I won't lie. When I saw that &lt;code&gt;belongs_to&lt;/code&gt; line, my initial reaction was, 'Cool. So there's an &lt;code&gt;Addressable&lt;/code&gt; class somewhere?'. Nope! That line names the interface on our polymorphic model. Once the relationship between the polymorphized model and it’s parent is created, it is possible to refer to the parent like this: &lt;code&gt;@address.addressable&lt;/code&gt;. We'll also be able to use statements like &lt;code&gt;@organizer.address&lt;/code&gt; and &lt;code&gt;@event.address&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To make this work, you need to declare both a &lt;strong&gt;foreign key column&lt;/strong&gt; and a &lt;strong&gt;type column&lt;/strong&gt; in the model that will point to the parent model, &lt;code&gt;Organizer&lt;/code&gt; or &lt;code&gt;Event&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateAddresses&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;5.2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;change&lt;/span&gt;
    &lt;span class="n"&gt;create_table&lt;/span&gt; &lt;span class="ss"&gt;:address&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:line1&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:line2&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:city&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:state&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:zip&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;integer&lt;/span&gt; &lt;span class="ss"&gt;:addressable_id&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;integer&lt;/span&gt; &lt;span class="ss"&gt;:addressable_type&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timestamps&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;add_index&lt;/span&gt; &lt;span class="ss"&gt;:addresses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:addressable_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:addressable_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This migration can be simplified by using the &lt;code&gt;t.references&lt;/code&gt; form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateAddresses&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;5.2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;change&lt;/span&gt;
    &lt;span class="n"&gt;create_table&lt;/span&gt; &lt;span class="ss"&gt;:address&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:line1&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:line2&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:city&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:state&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:zip&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;references&lt;/span&gt; &lt;span class="ss"&gt;:addressable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;polymorphic: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;index: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timestamps&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The migration can be generated like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails g migration create_addresses line1:string line2:string city:string state:string zip:string addressable_id:integer addressable_type:string
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails g migration create_addresses line1:string line2:string city:string state:string zip:string addressable:references&lt;span class="o"&gt;{&lt;/span&gt;polymorphic&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Polymorphic associations allow one model to belong to many models while keeping code nice and DRY. This kind of association enables such relationships by creating a special interface on the polymorphic or reusable model that allows other models to interact with it. Not convinced this is the pattern for you? Check out this &lt;a href="https://robots.thoughtbot.com/whats-the-deal-with-rails-polymorphic-associations"&gt;post&lt;/a&gt; by Jared Carroll where he guides readers through a more in-depth exploration of this approach. &lt;/p&gt;

</description>
      <category>rails</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a Command-Line Interface with Ruby</title>
      <dc:creator>Adjoa</dc:creator>
      <pubDate>Tue, 20 Feb 2018 00:54:13 +0000</pubDate>
      <link>https://dev.to/adjoa/building-a-command-line-interface-with-ruby--370k</link>
      <guid>https://dev.to/adjoa/building-a-command-line-interface-with-ruby--370k</guid>
      <description>&lt;p&gt;In this post I’ll talk about my experience building a command-line interface application with Ruby; generating a gem directory, scraping the data with Nokogiri, and putting together the user interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Draw Your Own Map
&lt;/h2&gt;

&lt;p&gt;After several weeks of gradually levelling up my Ruby-wielding skills through &lt;a href="https://flatironschool.com/"&gt;Flatiron School&lt;/a&gt;, this was my first solo project --a command-line interface application. In the exercises leading up to it, there had been tests to pass or fail, to tell me when I was indeed headed in the right direction. But this time my only guides were my vision of the end result and these project requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provide a CLI.&lt;/li&gt;
&lt;li&gt;CLI must provide access to data from a webpage.&lt;/li&gt;
&lt;li&gt;The data provided must go at least one level deep, generally by showing the user a list of available data and then being able to drill down into a specific item.&lt;/li&gt;
&lt;li&gt;Use good object-oriented design patterns.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Finding North
&lt;/h2&gt;

&lt;p&gt;Before I could write a line of code, I needed to pick a website to scrape. This would dictate the kind of data my application would provide access to i.e., its purpose. And, I needed to choose something I could scrape from without too much difficulty.&lt;/p&gt;

&lt;p&gt;Thankfully, I had a website in my back pocket that I suspected would work just fine. The &lt;a href="https://hackdesign.org/"&gt;Hack Design&lt;/a&gt; website provides lessons about design in various categories. Its pages lent themselves to the one layer deep model that was required. And they were rendered via static HTML putting them just in the range of difficulty I was hoping for. Being able to access these lessons from the minimal environment of the command-line struck me as a cool idea. So after a cursory assessment of whether I’d be able to scrape the content I needed, I decided to go for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up
&lt;/h2&gt;

&lt;p&gt;I knew at the beginning that I wanted to be able to wrap my application in the self-contained, distributable format of a gem. &lt;a href="http://bundler.io/v1.16/guides/creating_gem.html#getting-started"&gt;Bundler&lt;/a&gt; made it easy to get started with a scaffold directory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SY_wr794--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/Adjoa/words-with-pictures/master/pictures/bundler.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SY_wr794--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/Adjoa/words-with-pictures/master/pictures/bundler.PNG" alt="Getting Started with Gems using Bundler" title="Getting Started with Gems using Bundler"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first time you run the &lt;code&gt;bundle gem&lt;/code&gt; command, you have the option of including a &lt;code&gt;CODE_OF_CONDUCT.md&lt;/code&gt; and &lt;code&gt;LICENSE.txt&lt;/code&gt;. I chose the license. I updated my &lt;code&gt;.gemspec&lt;/code&gt; file with details about my gem: a short summary of what my gem would do and a slightly more detailed description of the same. As I nudged its functionality forward, I added a short list of other gems it would depend on to function.&lt;/p&gt;

&lt;h2&gt;
  
  
  A View of the Destination
&lt;/h2&gt;

&lt;p&gt;I started by writing code for a user interface that would mimic the intended behaviour of my application. The user would be greeted by a welcome message and options to: view categories, view lessons, view a random lesson, or quit. I didn’t have any categories or lessons yet so, I threw in some fillers to start. This code lives in &lt;code&gt;lib/hack_design/cli.rb&lt;/code&gt;. I would call this code in an executable file called &lt;code&gt;bin/hack-design&lt;/code&gt; and run my program.&lt;/p&gt;

&lt;p&gt;I didn’t have any tests but, I knew what I expected my code to do. Debugging was a matter of trial-and-error-ing my way to success. This technique would take me through the development of my app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fits and Starts
&lt;/h2&gt;

&lt;p&gt;I intended to make the data two layers deep --providing content (including exercises) from within a lesson, and lessons from within a category. Taking my cue from the UI I had built, I created classes to model a &lt;code&gt;Category&lt;/code&gt;, a &lt;code&gt;Lesson&lt;/code&gt;, an &lt;code&gt;Exercise&lt;/code&gt;, and a &lt;code&gt;Scraper&lt;/code&gt;. I used &lt;code&gt;./bin/console&lt;/code&gt; to test drive these classes by looking for expected behaviour. However, as I set out to teach my &lt;code&gt;Scraper&lt;/code&gt; how to find and gather categories, life threw me a few curve balls which effectively stalled my progress for about 2 weeks.&lt;/p&gt;

&lt;p&gt;When I returned, I was anxious about the time I had lost. Closer investigation of the data from my &lt;code&gt;Scraper&lt;/code&gt; soon revealed that scraping each category would prove to be more difficult that I first imagined. So, I thought about it. First and foremost, I wanted to provide users with lesson content. Was listing categories really that essential to the purpose of the application? I decided not, and began to simplify.&lt;/p&gt;

&lt;p&gt;I threw out the &lt;code&gt;Category&lt;/code&gt; and &lt;code&gt;Exercise&lt;/code&gt; classes. And I was left with what I needed: a &lt;code&gt;Lesson&lt;/code&gt; class whose objects would organize data about each lesson, a &lt;code&gt;Scraper&lt;/code&gt; to gather this data from the website, and a &lt;code&gt;CLI&lt;/code&gt; to manage the user interface. I refactored the UI to reflect the changes. It would list lessons to choose from, not categories. And, the data was now just one layer deep.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep Your Data Sources Close
&lt;/h2&gt;

&lt;p&gt;With my UI was up and running, it was time to supply it with real data. I knew it would take a few tries to get the search queries right. From my previous attempt at scraping, I also knew that too many queries would very likely get me blocked. I decided to solve this problem by copying the pages I’d be scraping to a fixtures folder. This would allow me to keep my requests to the live site to a minimum.&lt;/p&gt;

&lt;p&gt;The way Hack Design is set up, all 51 lessons can be found listed on a lesson &lt;a href="https://hackdesign.org/lessons"&gt;homepage&lt;/a&gt;. From that page, each lesson is links to its own page. Copying down the source code of the homepage was simply accomplished by using &lt;a href="https://curl.haxx.se/docs/manpage.html"&gt;cURL&lt;/a&gt; to get the HTML and shovelling it into a new file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://hackdesign.org/lessons/ &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; fixtures/site/lessons.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The other 51 pages however, would pose a greater challenge. No way was I going to navigate to each page and copy down hundreds of lines of HTML for 51 individual files. I wrote a little Bash script to do it instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;#get-lesson.sh&lt;/span&gt;

&lt;span class="nb"&gt;typeset&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; - END
&lt;span class="nb"&gt;let &lt;/span&gt;&lt;span class="nv"&gt;END&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;50 &lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;i&amp;lt;&lt;span class="o"&gt;=&lt;/span&gt;END&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; “Script starting now…”
  curl https://hackdesign.org/lessons/&lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="nt"&gt;-O&lt;/span&gt;
  &lt;span class="nb"&gt;let &lt;/span&gt;i++
&lt;span class="k"&gt;done
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; “Done”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Scraping Forward with Nokogiri
&lt;/h2&gt;

&lt;p&gt;Before long, I had all the files I needed to get to scraping. For this task, I used an HTML Parser called Nokogiri. It has the ability to search documents using CSS. I used CSS selectors to zero in on the HTML elements containing the data I wanted. In keeping with the setup of the Hack Design website, the &lt;code&gt;Scraper&lt;/code&gt; has two methods.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;::scrape_lessons_page&lt;/code&gt; scrapes the lesson homepage. creates a hash for each lesson, adds the lesson title and url to that hash, then adds that hash to an array of all the lessons.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;::scrape_lesson&lt;/code&gt;scrapes a lesson's content page. It adds the instructor name and other content for a particular lesson to a hash and returns the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Homecoming: Return to the CLI
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;CLI&lt;/code&gt; is where the &lt;code&gt;Scraper&lt;/code&gt; and &lt;code&gt;Lesson&lt;/code&gt; classes join forces to produce &lt;code&gt;Lesson&lt;/code&gt; objects that model individual lessons filled with content. Here, hashes act as the glue between the &lt;code&gt;Scraper&lt;/code&gt; and &lt;code&gt;Lesson&lt;/code&gt; classes, carrying data from the &lt;code&gt;Scraper&lt;/code&gt; to the &lt;code&gt;Lesson&lt;/code&gt;, allowing them to work together while remaining independent and focused in purpose.&lt;/p&gt;

&lt;p&gt;A title and a URL are all I need to create a &lt;code&gt;Lesson&lt;/code&gt; object.  I created 51 &lt;code&gt;Lesson&lt;/code&gt; objects by iterating over the array of hashes from &lt;code&gt;::scrape_lessons_page&lt;/code&gt;. Then I passed the URL of each &lt;code&gt;Lesson&lt;/code&gt; object to &lt;code&gt;::scrape_lesson&lt;/code&gt; which returned a hash of data I could add to my ready-made &lt;code&gt;Lesson&lt;/code&gt; objects. This process went smoothly until… it didn’t.&lt;/p&gt;

&lt;p&gt;One of the pages was breaking my &lt;code&gt;Scraper&lt;/code&gt;. Using Pry and some temporary tweaks to my code, I was able to track down the page that was causing trouble. Turns out &lt;a href="https://hackdesign.org/lessons/41"&gt;lesson 41&lt;/a&gt; has a list within one of its exercises. However, my &lt;code&gt;Scraper&lt;/code&gt; was identifying exercises as list items. On discovering this list within a list, it would class the list item as another exercise and then crash when it didn't find the typical contents of an exercise inside. It needed a way to differentiate between an exercise and its content. To do this, I made the CSS selectors a little more specific. I had fun debugging this one. &lt;/p&gt;

&lt;p&gt;51 completed &lt;code&gt;Lesson&lt;/code&gt; objects made filling out the user interface wonderfully straightforward. I could just loop through all the &lt;code&gt;Lesson&lt;/code&gt; objects and display the information they contained accordingly. I added a few methods to enable navigation from one lesson’s content to another without returning to the list, and added a bit of color with the &lt;a href="https://github.com/fazibear/colorize"&gt;colorize&lt;/a&gt; gem. And then, I was done. I had built a Ruby command-line-application! &lt;/p&gt;

&lt;p&gt;To wrap up, I packaged, installed, and tested my gem. Bundler makes &lt;a href="http://bundler.io/v1.16/guides/creating_gem.html#releasing-the-gem"&gt;packaging and releasing your gem&lt;/a&gt; as easy as it does getting started. I chose not to release my gem but, I have included instructions on how to package and install it locally. Check out my code, &lt;a href="http://github.com/Adjoa/hack_design-cli-app"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fond Farewell
&lt;/h2&gt;

&lt;p&gt;Completing this project was an exercise in confronting fear of failure. Every step was absolutely worth it. I am proud of this simpler, final product and really excited about what’s next.&lt;/p&gt;

&lt;p&gt;Thanks for taking the time to read this post. See you in the next one!&lt;/p&gt;

&lt;p&gt;Cover Art: &lt;a href="https://matsumayu.deviantart.com/"&gt;Mayumi Matsumoto&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>programming</category>
      <category>showdev</category>
      <category>cnc2018</category>
    </item>
  </channel>
</rss>
