So I went later than I wanted to tonight, but I was on a roll. I would have finished much earlier but I spent 2.5 hours today at a developer meetup. It was interesting as I’ve only been to one other so far. It was good to meet some people and start putting real people to the dev community in Nashville. I did find out that basically nobody is learning/using Ruby (at least at this meetup). The largest language according to the people today is .NET because of all the healthcare companies. I showed a lab to a guy who’s 4 months in at Nashville Software School and he was impressed with the TDD and seeing how it worked. He said he never sees tests like that and doesn’t know anything about writing them. I assured him I didn’t know much about writing tests either but I did read them all day long.

The big announcement is … I FINISHED MY CLI GEM PROJECT! Now, I haven’t done my review with my instructor and passed yet but it’s done. I’m currently working through my Travis CI tests and getting those to pass. I expect that to be passing soon and then I’ll update my gem. It’s already live on RubyGems.org! I’ll have a new version pushed up when I get my Travis passing.

So I had a few hang-ups along the way but most of it had to do with scraping. I figured it out though by trial and error. From what I understand scraping is mostly trial and error so there isn’t much to pass along knowledge wise. I did run into the problem of trying to turn this: "7\n" + "\n" + "\n" + "Paddlers\n" + "\n" + "going" into this: "7 Paddlers going". When I did gsub("\n", "") it returned 7Paddlersgoing and gsub("\n", " ") returned "7 Paddlers going" with too many spaces. I was thinking I was going to have to split the string into an array, filter out the \n and then join the array. Then I thought, “Why not Google turning multiple spaces into a single space.” That seems like a problem someone would have solved already. Guess what? They have. So I ended up with row.css("div.attendee-count").text.strip.gsub("\n", " ").gsub(/\s+/, ' '). Called gsub on a string that had already been changed.

I just realized that Travis is never going to pass because I don’t have any tests in my gem. Whoops! So I’ll remove that integration for now. It’ll be a nice future project to write tests for the gem.

To explain my project, in brief, you run the program from the command line, it asks you to input a zip code to see meetups from, if you enter less or more than 5 digits or not 5 digits, say 5 letter, it tells you to input 5 numbers. Then it asks for a radius to search in, I limited the radius to <100 miles. Then it returns a list of all the meetups scheduled for today. If there are none it tells you such. It then asks you if you’d like to search again. I’m proud as well as ready to move on to SQL.

Time spent today: 7:24
Time spent total: 118:21
Lessons completed today: 1
Lessons completed total: 286

Tonight I made some good progress on my CLI project. I finished watching Avi’s video on the project and it helped A LOT. It was long so I decided to just complete the basic stub of my project and leave it at that for tonight. I really like working with fake placeholder data for as long as possible. This way it’ll all hopefully just work when real data is passed in. So taking the stub I’m sharing below and abstracting that out to have objects holding the data for each meetup. Then building the methods to create those objects in another class.

What I have so far:

class MeetupsAround::CLI
  attr_reader :todays_date

  def call
    @todays_date = "Saturday, March 25"
    input_zipcode
    input_radius
    list_meetups
    again?
  end

  def input_zipcode
    puts "What zip code would you like to see meetups for?"
    zip_code = gets.strip
    if /\b\d{5}\b/.match?(zip_code)
      nil
    else
      puts "Please enter a five digit zip code."
      self.input_zipcode
    end
  end

  def input_radius
    puts "What radius around that zip code would you like to see meetups for?"
    radius = gets.strip
    if /\b\d{1,2}\b/.match?(radius)
      nil
    else
      puts "Please enter a radius less than 100."
      self.input_radius
    end
  end

  def list_meetups
    puts "Today #{todays_date} are the following meetups:"
    puts <<~HEREDOC
    1. 2:30PM - Developer Launchpad Nashville - Coding Jam - 19 Developers going
    2. 9:00AM - Score Nashville Events, Networking and Workshops - Join us for a "Start your Business" workshop! - 2 Members going
    3. 10:00AM - Paid to Speak Entrepreneurs - How To Get Your Speaking Career Started - 18 Members Going
    HEREDOC
  end

  def again?
    puts "Would you like to search again? [Y/N]"
    input = gets.strip.downcase
    puts input == "y" || input == "yes" ? call : "Goodbye =)"
  end

end

Next up I’ll change the HEREDOC block and utilize an object iteration to list each object. Something like:

meetups.each.with_index(1) do |meetup, i|
  puts "#{i}. #{meetup.time} - #{meetup.group} - #{meetup.event} - #{meetup.attendees}"
end  

Now I don’t know if this is exactly what I’ll end up with but it’s what I’m thinking at this point in time. I’ll also need to have an array with the meetup objects called meetups in this scenario. For this project I’m suppose to record myself coding for 30 minutes so I think when I go to tackle this I’ll do that recording. I’ll watch the video Avi made another time and get a solid plan of action down and then go for it. Pretty sure they don’t want a video of me watching videos hehe.

Tonight I also installed a couple more packages into Atom. Specifically minimap, seti-icons, atom-beautify, highlight-selected, pigments, minimap-highlight-selected, and minimap-pigments. I highly recommend them all so check them out.

Time spent today: 2:22
Time spent total: 110:57
Lessons completed today: 0
Lessons completed total: 285

So tonight I started my CLI Gem project. This one is going to be in my portfolio and has A LOT more to it. Okay, well maybe not a lot more but it’s the first time I’m starting from scratch to build something. Luckily, I’m not left out to dry and there is a how-to that’s over an hour long that Avi did. Of course, it’s not exactly what I’ll need to do and I’ll run into problems along the way but it’s nice to have a good resource to start with. I’m sure I could find a nice video around but having one provided definitely saves some time.

I decided to build a CLI Gem that will return the meetups in a specified radius from a specific zip code for the current day from Meetup.com. The first big time saver was bundle gem new_gem_name which basically scaffolded a new gem with the name provided and even initialized it as a git repo. Avi provided a great set of steps to build a Gem:
1. Plan your gem, imagine your interface.
2. Start with the project structure – google.
3. Start with the entry point – the file run.
4. Force that to build the CLI interface.
5. Stub out the interface.
6. Start making things real.
7. Discover objects.
8. Program.

I’ve completed 1-4 in a very basic way now. Next is to stub out my interface with fake data. That will allow me to ensure my flow is working correctly and then basically code to the exact info I need. This workflow is also allowing me to make progress quickly and see the iterations that I’m going through to get to the end result. Not much else to share as I didn’t do anything too “deep” today. Just getting started on this project. If you’re interested in building your own gem using bundler check out RailsCasts #245 New Gem With Bundler. If you want the walkthrough that Avi does you’ll have to join Flatiron. I’m hopefully going to be able to finish this project on Saturday. However, I have a meetup to attend and I have my son this weekend. This will be the first weekend I have my son since I’ve started the program. I only have my son one weekend a month so I’ll have to see how much time I truly can sacrifice when the kids are awake.

You can follow along with my progress on GitHub here.

Time spent today: 2:29
Time spent total: 108:35
Lessons completed today: 0
Lessons completed total: 285

yawn it’s been a long day. My 3-month-old was up early today. Either way, I got my scraping project done tonight. Nokogiri can be quite particular about the things you use to select content. Turned out I was pretty much there and just needed to change how I was accessing the info I needed.

Attended a Study Group tonight which taught me something very important. When using pry inside a loop when you enter exit into the pry prompt it runs the next loop. This way you can see what is being passed in each time. I was struggling trying to see what was being passed in each time in my scraping project. So now I know and that key piece of info is what helped me finish my scraping project which can be found in full here.

I’m calling it a night. I start my first portfolio project tomorrow building a CLI Ruby Gem.

Time spent today: 2:35
Time spent total: 106:07
Lessons completed today: 1
Lessons completed total: 285

So working on my scraping project. It’s hurting my head. Scraping is no fun to figure out. What I’m stuck on right now is iterating. When I have some time tomorrow I’m going to work on completely understanding iterating when scraping. Here’s what I’m looking at currently:

<div class="social-icon-container">
  <a href="https://twitter.com/empireofryan"><img class="social-icon" src="../assets/img/twitter-icon.png"></a>
  <a href="https://www.linkedin.com/in/ryan-johnson-321629ab"><img class="social-icon" src="../assets/img/linkedin-icon.png"></a>
  <a href="https://github.com/empireofryan"><img class="social-icon" src="../assets/img/github-icon.png"></a>
  <a href="https://www.youtube.com/watch?v=C22ufOqDyaE"><img class="social-icon" src="../assets/img/rss-icon.png"></a>
</div>

Then I’m doing (among other things above it):

social = doc.css(".social-icon-container a")
social.each do |link|

I’m struggling to understand what |link| is inside the loop. I’m thinking it’s each instance of a because there are 4 of those and I’m setting social equal to the a. However, I’m not sure. I know when I call doc.css(".social-icon-container a") in pry I end up with Nokogiri’s version of everything inside the div. I’m sure I’ll crush it tomorrow. I know my logic of looping over each a and using an if or even case to check if the img src= is == to one of the social networks, then setting the href value to equal a variable I’ll use later is the way to go and solid.

Time spent today: 2:08
Time spent total: 103:32
Lessons completed today: 0
Lessons completed total: 284

About 10 minutes before I was supposed to get to my computer the power went out in my subdivision. I quickly realized that while I had set up flashlights in strategic locations in our apartment, when we moved into our house I never did the same. My wife and I both did not have our phones on us and it was DARK. Needless to say, I closed the baby gate at the top of the stairs to keep the little ones safe and made my way to the kitchen where I knew a flashlight was. While I was downstairs the power came back on and my daughter yelled out, “Thanks Daddy!” I’ll take credit, yes I will. This put me behind. I then found out that I hadn’t installed Zoom and couldn’t get into the Study Group I was planning on attending. I had already decided to “take the night off” and just do the study group and work on my Tic-Tac-Toe AI some. Needless to say 30 minutes later I confirmed Zoom was working.

Tonight I realized it’s amazing what coming at a project fresh can do. I figured out why my random move in Tic-Tac-Toe wasn’t working in less than 3 minutes tonight. I had an = instead of an ==. However, after that, I couldn’t get into the groove. I wrote out a couple more methods to decide on the first and second move for the computer but then just left it as random moves after that. I did some TTT strategy ready and came up with the best first move is a corner and the best second move is the center. If the center is taken the best second move is a corner. So I built that logic into the game. From move 3 on the computer plays randomly. The computer never beat me, it did, however, tie a few times with this little bit of knowledge. I have an idea though and want to see if I can pair with someone to implement it. Here’s my final code:

module Players
  class Computer < Player
    def move(board)
      if board.cells.count{|square| square != " " } == 0
        "1"
      elsif board.cells.count{|square| square != " " } == 1
        board.cells.find_index("X") == 4 ? "1" : "5"
      else
        possible_moves = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
        valid_moves = []
        possible_moves.each do |move|
          valid_moves << move if board.cells[move.to_i-1] == " "
        end
        valid_moves.sample
      end
    end
  end
end

I started on the next project which is a scraping project. I don’t have much practice with Nokogiri but on my first attempt, I was pulling the data I needed. I can see this project might go quicker than the last two. I’m going to hit it hard tomorrow night and get it done.

Time spent today: 1:33
Time spent total: 101:24
Lessons completed today: 1
Lessons completed total: 284

Another productive project day means not much to talk about! I got through all the tests that I needed to for my Tic-Tac-Toe with AI project. I started trying to build out my “AI” but didn’t get very far. I know I need to start simple so I decided to just attempt the computer making random moves. I tried to implement the following workflow:
1. Get the current board array (although this should be passed in by default).
2. Set an array equal to all the possible moves as strings, 1-9.
3. Set a new empty array to collect open squares.
4. Loop over the current board array and if a square is empty = " " shovel to the array collecting open squares. I will do this by utilizing the possible moves array as the index numbers. I’ll just turn each array value into an integer and subtract one.
5. If the board square is empty shovel the possible move string to the empty array collecting open squares.
6. Return a random string from the possible moves array.

This should get my computer playing only random open squares. However, my code created an infinite loop and I decided I could call it a day after that. I’m hoping I can pair with someone just for the AI part and get it done. If you’re interested in the project you can find it on my GitHub here. My current computer logic (although it might be hard to understand without looking at all the files) is this:

module Players
class Computer < Player
def move(board)
possible_moves = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
valid_moves = []
possible_moves.each do |move|
valid_moves << move if board.cells[move.to_i-1] = " "
end
valid_moves.sample
end
end
end

I’m sure I’ll get at least this little bit of logic working tomorrow even if on my own. Other than that the game works for 2 humans to play!

So day by day I’m enjoying my new OS even more. Today I setup workspaces which just made all of life easier.

My workspaces overview:
Ubuntu Desktop workspaces overview
I have one with Atom and the Terminal (I’ve since changed to “Solarized Light” themes on both because I was getting glare during the day):
My coding workspace
One with Slack:
My Slack workspace
Finally, one with Chrome:
My web workspace

I also got f.lux installed today which is one the things on my must have list when it comes to apps on my computers. I even have installed it at shared work computers in the past and freaked some coworkers out the first time they use the computer afterward. I’ll write a post about my biohacks here sometime soon. Maybe when I’m done with this set of projects and before I move to the next section. I have more than a few things that I do to keep my mind running in top form. From nootropics to meditation.

Time spent today: 7:02
Time spent total: 99:50
Lessons completed today: 0
Lessons completed total: 283