Monday, December 26, 2016

Ruby Project Skeleton Generator on Gist!

Exercise 46 of Learn Ruby the Hard Way gives instructions for manually creating a project skeleton.  So I decided to do what I have done many times before in BASH and Python, and automate this task with a pretty Ruby script.

A few thoughts:
  1. Ruby's handling of files and folders is delightfully straightforward.
  2. Ruby handles strings elegantly.
  3. This was originally written as a straight script, but then I refactored it with object-oriented programming in mind:
    1. One Class (Project)
    2. The main components of the class broken down into methods.
    3. Names of folders and files are stored in an array and a hash.
    4. Blocks of text are stored using Squiggly HEREDOC

Using a string as a class variable

My script relies on a single argument in the form $stdin user input:

class Project
  def initialize()
    puts "What do you want to call this project?\n"
    print "> "

    $user_input = $stdin.gets.chomp


The script is organised into a single class that contains consecutive methods.

The simplest way I have found to utilise the user input is to declare it in each method.

  def define_folders()
    project_name = $user_input


  def create_gemfile()
    project_name = $user_input

However, this is repetitive.

What would be a better way?


Sunday, December 25, 2016

Slow Ubuntu Bootup

Bootup was being extended by 90 seconds with this message:
A start job is running for disk...
 After consulting the help forums, I checked Gparted:


And found an empty partition where I expected to find a swap partition.

Then, I checked /etc/fstab and, yes, found that it expected a swap partition.



So I created a swap partition.  We'll see how how we go.


Saturday, December 24, 2016

Note to Self about Modules in Ruby

Make sure to include the name of the module in the method:

module GameDictionary

  def GameDictionary.scene_enter()
    puts "This scene is not yet configured. Subclass it and implement enter()."
    exit(1)
  end

Everything else is rather straightforward, but for some reason I keep on missing that detail.  I'll just keep on drilling it until it sinks in.

In other words, I'll keep on crashing until I learn how to fly this damn aeroplane :)


Defining Scenes in a Text Adventure Game

In my text adventure game, the user starts outside in meadow, and eventually gets inside a six-storey tree castle with a staircase that runs from the ground floor to the fifth.

Here is a map of the world:


The scene of greatest interest here is the Staircase, for it is actually not a scene at all, but rather a method within the HouseScene subclass of Scene.  That is, the user can leave any room and go back to the landing of the staircase on the floor of that room.

For example, the bedroom is on the fourth floor, and if the user elects to leave the bedroom, she will return to the fourth floor landing of the staircase.

Using 'relative_require' to separate functions, classes, instantiation

My goal is to create a main.rb file that does nothing but instantiate the classes and execute their methods.  As you can see below, this is possible, at least in a simple application, but is this good practice?

It feels neater to separate classes, functions, etc; but then again, this might be akin to separating vocabulary sheets by parts of speech -- tidy, but impracticable.

It might be better practice to group blocks of code that work on the same portion of the program.  Please let me know what works in your experience.

A simple function:

## demo_function.rb

def hello_world()
  puts "Hello world!"
end

A class that uses this function as a method:

## demo_class.rb

require_relative 'demo_function.rb'

class Demo
  def enter()
    hello_world()
  end
end

Finally, an instance of the class that executes its method:

## demo_main.rb
require_relative 'demo_class'

a_class = Demo.new()
a_class.enter()

Output:

Hello World! 


Wednesday, December 21, 2016

Objected-oriented Programming, Part 1

I am working on my first text-adventure game as part of Exercise 43 of Learn Ruby the Hard Way.  I have defined a simple class called Scene:

class Scene
  def enter()
    puts "This scene is not yet configured. Subclass it and implement enter()."
    exit(1)
  end
end

In other words, the only thing that "Scenes" have in common is that the player "enters" them.  What she does and whither she goes thereafter has to be defined. 

Within the game there are broadly speaking two kinds of scenes:
  1. Scenes outside the house
  2. Scenes inside the house

Scenes Outside the House

 
The very limited movements afforded at the start of the game serve to illustrate the point that not a lot of thought went into (or had to go into) defining how you navigate the first part of the map. 
 
Meadow => River
Meadow => Front door

River => Front door 
Front door => riddle => Ground floor of the house.

Scenes Inside the House

This is where things get tricky.  All the rooms in the house are connected by a staircase, which means that when you leave one room, you have access to all the others by means of the staircase.

At first I defined the method for getting up the stairs from the ground floor entrance composed of the following elements:
  • Text for the player
  • Declared value for floorNumber
  • While loop
  • Case conditional that calls the engine.
def enter()

"""
    You are at a spiral staircase.  There is a sign on the landing:

    0. Ground Floor: Entrance to the castle

    1. First Floor: Machine room

    2. Second Floor: Kitchen

    3. Third Floor: Library

    4. Fourth Floor: Royal Bedroom

    5. Penthouse: Study

    6. Exit the castle and go back to the meadow.

    Where would you like to go to?

    """
    currentFloor = 0
    while currentFloor == 0
      print "> "

      floorSelection = $stdin.gets.chomp.downcase()

      case floorSelection
      when /0/, /ground/, /entrance/
        if currentFloor == 0
          puts "You are already here.  Try another floor."
        elsif currentFloor != 0
          puts "You descend the stairs to the ground floor."
          return 'spiral_staircase'
        else
          puts "Something has clearly gone wrong."
        end
      when /1/, /first/, /machine/
        if currentFloor < 1
          puts "You ascend the stairs to the machine room."
          currentFloor == 1
          return 'machine_room'
        elsif currentFloor > 1
          puts "You descend the stairs to the machine room."
          currentFloor == 1
          return 'machine_room'
        elsif currentFloor == 1
        puts "You are already here.  Try another floor."
        else
          puts "There has clearly been a mistake somewhere."
        end
      when /2/, /second/, /kitchen/
        if currentFloor < 2
          puts "You ascend the stairs to the kitchen."
          currentFloor == 2
          return 'kitchen'
        elsif currentFloor > 2
          puts "You descend the stairs to the kitchen."
          currentFloor == 2
          return 'kitchen'
        elsif currentFloor == 2
        puts "You are already here.  Try another floor."
        else
          puts "There has clearly been a mistake somewhere."
        end
      when /3/, /third/, /library/
        if currentFloor < 3
          puts "You ascend the stairs to the library."
          currentFloor == 3
          return 'library'
        elsif currentFloor > 3
          puts "You descend the stairs to the library."
          currentFloor == 3
          return 'library'
        elsif currentFloor == 3
        puts "You are already here.  Try another floor."
        else
          puts "There has clearly been a mistake somewhere."
        end
      when /4/, /fourth/, /bedroom/
        if currentFloor < 4
          puts "You ascend the stairs to the bedroom."
          currentFloor == 4
          return 'bedroom'
        elsif currentFloor > 4
          puts "You descend the stairs to the bedroom."
          currentFloor == 4
          return 'bedroom'
        elsif currentFloor == 4
        puts "You are already here.  Try another floor."
        else
          puts "There has clearly been a mistake somewhere."
        end
      when /5/, /fifth/, /study/, /penthouse/
        if currentFloor < 5
          puts "You ascend the stairs to the study."
          currentFloor == 5
          return 'study'
        elsif currentFloor > 5
          puts "You descend the stairs to the study."
          currentFloor == 5
          return 'study'
        elsif currentFloor == 5
        puts "You are already here.  Try another floor."
        else
          puts "There has clearly been a mistake somewhere."
        end
      when /6/, /leave/, /exit/, /back/, /meadow/
        if currentFloor != 0
          puts WordWrap.ww "You descend the stairs, walk out the door, and keep going until the you reach the edge of the meadow."
          currentFloor == 0
          return 'meadow'
        elsif currentFloor == 0
          puts "You walk out the door, and keep going until the you reach the edge of the meadow."
          return 'meadow'
        else
          puts "There has clearly been a mistake somewhere."
        end
      else
        puts "I don't understand your request"
      end

    end
end

But copy-pasting all of this would violate the DRY principle, so I thought about how to write it better:
  • All 'Scenes' use the enter() function.
  • All the rooms are 'Scenes'.
  • All the rooms are 'Scenes' that require the same function for selecting a floor.
  • Ergo, all the rooms are 'Scenes' use a function that could be defined as 'selectFloor()'.
  • However, every room is located on a particular floor, which changes whether the player goes up or down the stairs, or is already at that floor.
  • Ergo, every 'House Scene' needs to inherit the function 'selectFloor()' but with a variable for its floor, i.e. 'selectFloor(floorNumber)'
 First, I created a sub-class of 'Scene' called 'HouseScene':
class HouseScene < Scene

  def floorSelection()
    puts "This scene is not yet configured.  Subclass it and implement floorSelection()."
    exit(1)
  end

end


But remember that the floorSelection function is a while loop, so it needs a constant to hold true while it runs.  The obvious candidate is the floor number, so the function takes an argument and starts like this:
  def floorSelection(floorNumber)
    puts "Filler text for the moment"
    currentFloor = floorNumber
    while currentFloor == floorNumber


From there it's simply a matter of pasting the rest of the floorSelection(floorNumber) function into the sub-class 'HouseScene'.

Then, for each room, call the functions:
  • enter()
  • floorSelection()
If the player leaves the room, she will go back to the landing of the staircase and choose again whither she wants to go.

This slightly more complex code brings me finally to the point where testing my program becomes a drag.  Until now, I could effortlessly run a straightforward program from start to finish; now, I have many potential routes to follow, and testing them all will take exponentially more time as I add games and puzzles to each room.

In my next post I will share my first experience of testing and Rake files in Ruby.

Thursday, December 15, 2016

Sometimes one must be a night owl to see the light

It's 03:08 and I am finally starting to make sense of object-oriented programming.  It's not that I didn't understand it conceptually, but the little game I'm making works and I'm beginning to understand -- not merely comprehend -- why it works.

Good night.


Image source

Wednesday, December 14, 2016

Adding a Snippet for Ruby in Atom Text Editor

Actually unnecessary, as Atom's Ruby bundle already has this built in, but I realised this after I had worked out a "class" snippet.


'.source.ruby':
  'Console class':
    'prefix': 'class'
    'body': 'class ${1:method_name}\n\t$0\nend'

Oh well, I learned a bit about CSON.


T-Shirt: I Don't Always Test My Code...

I have T-shirts on Redbubble, some of them geeky... ok, ok, they're all geeky.

Anyway, here's the latest one, go check out the rest.


Sunday, December 11, 2016

State of the Mission: Sunday, 11th December 2016

Week 50 of 2016


Mission DevOps

Work Completed

I started Learn Ruby the Hard Way, got up to Chapter 40, and have been posting about my learning along the way.

Plans for Next Week

Focusing on Learn Ruby the Hard Way is proving as beneficial as I had hoped, and I have every reason to complete it by the end of Week 51 of 2016.  Thereafter, my focus will be on PROJECTS, i.e. something to show for all my efforts.
  1. Transferring my Pastebin to Gist using APIs.
  2. The Toy Robot Challenge
  3. Advent of Code
  4. Starting my job research web scraper and analysis tool.
There is every reason for me to get started on substantive projects that I can put on Github and then direct all and sundry to.  Owing to the paucity of code in my Github, I have been reticent to contact potential recruiters and apply for jobs, but come the last of December, business shutting down notwithstanding, I should have every reason to send out missives and apply online. 

Special Project

My super-special-but-perhaps-not-so-top-secret project is ticking along on schedule.  I have a few more weeks to go, so that's all I've got to say about it for now.

The Odessia

Not much progress on the Odessia this week, but my schedule will permit a lot more creative writing time soon.

Personal Matters

Just the usual washing, cleaning, tidying for the most part.  I have been in touch with uncle, who has been unwell, and attended to the usual bits and pieces that crop up.  One day, when I'm very wealthy and successful, I will have a secretary to handle these matters.





Friday, December 9, 2016

State of the Mission: Friday, 9th December 2016




At some point I'd like to build my own blogging tool, or help to improve an open source one, but in the meantime Blogger gives me what I need and does a good job of formatting the posts for mobile devices as well.  In the long term I'd like to become independent of Google's services -- it's heading in the same, invasive, politicised direction as Facebook and Apple, so it's important but not urgent yet.

My first task is to transfer the contents of my Pastebin to Gist.

My first major project is a career research tool composed of a web scraper and an analyser.  It'll start by parsing job ads for key words, and ultimately seek out a variety of data points to give a complete overview of what professions are in demand, what skills are up-and-coming in said professions, and what the prospects of someone starting out are.  It can be done in various languages -- Python comes to mind -- but I think Ruby and Rails will give me everything I need.  Maybe some JavaScript too.

I'm up to Chapter 38 of Learn Ruby the Hard Way, and find it to be one of the best resources I've come across.  In fact, I've suspended my Code Academy account until I've got everything I can from Learn Ruby the Hard Way, it's really as good as that.

On Monday, I had a very encouraging catch-up with a local technical recruiter, and he laid out the Three Ps that in his experience are the key ingredients to success: Passion, presence, and projects.
As you can see, I'm putting everything to do with this mission on my blog, which is a big part of answering the question: What do I have to show for my efforts?

I've been thinking, tinkering, reading, deliberating, and pondering since July, and the more good stuff I have to show for my efforts, the better my chances.  As soon as practicable, I want that to be my Github repository, but in the meantime it's my blog.

Kanban Ticket Layout


The Three Ps: Passion, Presence, Projects

To be a successful programmer, I have been told, one needs to have the three "Ps": Passion, projects, and presence.

Passion or Determination?


I know that alliteration makes the set mnemonic, but a better word to my mind is determination.  Passion can wane in the face of difficulty, but determination, or resolve, or just plain grit (or vasbyt in Afrikaans) will see one through the steepest of climbs.  Yes, I am passionate about the things I do, but unless I am determined to see something through, I can't rely on passion alone.

Projects: AKA What Do You Have To Show For It?


When I was 16 I decided that I wanted to speak Afrikaans -- a strange goal, admittedly, but bear with me.  I had no resources but a novel (Die Koperkan by Mikro) and a school dictionary.  Over six months I diligently translated entire chapters word for word, until I had built up enough of a vocabulary, and could understand pronunciation, grammar, and syntax to communicate in Afrikaans.  

I put in six months of solitary study and came out of it with a meaningful grasp of the language: that's what I had to show for my efforts.

There are loads of resources for learning to code out there, but unless I apply my newly acquired knowledge by way of a program that is useful at least to me, I can't very well convince someone else to pay me do the same.

What attracts me greatly to this line of work is that there is minimal paperwork involved: if you're good enough and are a good fit for the team, you stand a good chance of getting hired.  I like that, I respect that, and I want to be part of that.

In light of that, I treat my Github profile and my Gist as my résumé, and invite you to see what I've got so far.  (At the time of writing, most of what I have to show for my efforts is in Gist, but I hope to change that over December and January)

Presence: Networking, Schmoozing, Putting Yourself Out There


For the most part I enjoy being left alone to my own devices.  Fortunately, socialising, especially one-to-one and in small groups is not difficult for me, but heading out to the city for events can be tiring.  It is easy to assume that programming is solitary in nature, because an outsider sees individuals absorbed in their work, but working in a team and getting on with one's team mates are equally important.

Those who know me trust my abilities and my work ethic, but as a new-comer to the profession, especially in my position of looking for my first job (presumably entry-level or junior), I have to distinguish myself from the hordes of would-be and aspiring programmers.

People in the industry have to know who I am, what I do, how I'm progressing, and they have to see that I mean business.

See you at the next meet-up.

Thursday, December 8, 2016

Arrays of Animals

From Exercise 34 of Learn Ruby the Hard Way.  I am sure this could be done a lot more elegantly, but I'm satisfied with what I got from this, and I know it works too.
# everything pertaining to the quiz is contained in the function below

def quiz

  # clear the screen
  puts "\e[H\e[2J"

  # gem for colorising text, very cool stuff
  require 'colorize'

  # the array of animals
  animals = ['bear', 'ruby', 'peacock', 'kangaroo', 'whale', 'platypus']

  # display the list of animals, it's not a memory test
  puts "These are the animals in our array: #{animals}"

  # preparing the ordinal and cardinal arrays for the quiz
  ordinal = ["first", "second", "third", "fourth", "fifth", "sixth"]
  cardinal = [0, 1, 2, 3, 4, 5]

  # generic question for choosing the ordinal position
  chooseOrdinal = """
  What is the ordinal position of this animal?
  first
  second
  third
  fourth
  fifth
  sixth


  """

  # generic question for choosing the cardinal position
  chooseCardinal = """
  What is the cardinal position of this animal?
  0
  1
  2
  3
  4
  5


  """

  puts """
  Type the name of an animal:
  - bear
  - ruby
  - peacock
  - kangaroo
  - whale
  - platypus

  """
  print "> "

  userSelection = $stdin.gets.chomp.downcase
  case userSelection
  when "#{animals[0]}"
    puts "You chose a #{userSelection}.\n"
    puts chooseOrdinal
    answerOrdinal = $stdin.gets.chomp.downcase
    if answerOrdinal == "#{ordinal[0]}"
      puts "Correct!\n".colorize(:green)
      puts chooseCardinal
    print "> "
      answerCardinal = $stdin.gets.chomp
      if answerCardinal == "#{cardinal[0]}"
        puts "Correct!\n".colorize(:green)
      else
        puts "Incorrect cardinal number!".colorize(:red)
      end
    else
      puts "Incorrect ordinal number!".colorize(:red)
    end
  when "#{animals[1]}"
    puts "You chose a #{userSelection}."
    puts chooseOrdinal
    answerOrdinal = $stdin.gets.chomp.downcase
    if answerOrdinal == "#{ordinal[1]}"
      puts "Correct!\n".colorize(:green)
      puts chooseCardinal
    print "> "
      answerCardinal = $stdin.gets.chomp
      if answerCardinal == "#{cardinal[1]}"
        puts "Correct!".colorize(:green)
      else
        puts "Incorrect cardinal number!".colorize(:red)
      end
    else
      puts "Incorrect ordinal number!"
    end
  when "#{animals[2]}"
    puts "You chose a #{userSelection}."
    puts chooseOrdinal
    answerOrdinal = $stdin.gets.chomp.downcase
    if answerOrdinal == "#{ordinal[2]}"
      puts "Correct!\n".colorize(:green)
      puts chooseCardinal
    print "> "
      answerCardinal = $stdin.gets.chomp
      if answerCardinal == "#{cardinal[2]}"
        puts "Correct!".colorize(:green)
      else
        puts "Incorrect cardinal number!".colorize(:red)
      end
    else
      puts "Incorrect ordinal number!"
    end
  when "#{animals[3]}"
    puts "You chose a #{userSelection}."
    puts chooseOrdinal
    answerOrdinal = $stdin.gets.chomp.downcase
    if answerOrdinal == "#{ordinal[3]}"
      puts "Correct!\n".colorize(:green)
      puts chooseCardinal
    print "> "
      answerCardinal = $stdin.gets.chomp
      if answerCardinal == "#{cardinal[3]}"
        puts "Correct!".colorize(:green)
      else
        puts "Incorrect cardinal number!".colorize(:red)
      end
    else
      puts "Incorrect ordinal number!"
    end
  when "#{animals[4]}"
    puts "You chose a #{userSelection}."
    puts chooseOrdinal
    answerOrdinal = $stdin.gets.chomp.downcase
    if answerOrdinal == "#{ordinal[4]}"
      puts "Correct!\n".colorize(:green)
      puts chooseCardinal
    print "> "
      answerCardinal = $stdin.gets.chomp
      if answerCardinal == "#{cardinal[4]}"
        puts "Correct!".colorize(:green)
      else
        puts "Incorrect cardinal number!".colorize(:red)
      end
    else
      puts "Incorrect ordinal number!"
    end
  when "#{animals[5]}"
    puts "You chose a #{userSelection}."
    puts chooseOrdinal
    answerOrdinal = $stdin.gets.chomp.downcase
    if answerOrdinal == "#{ordinal[5]}"
      puts "Correct!\n".colorize(:green)
      puts chooseCardinal
    print "> "
      answerCardinal = $stdin.gets.chomp
      if answerCardinal == "#{cardinal[5]}"
        puts "Correct!".colorize(:green)
      else
        puts "Incorrect cardinal number!".colorize(:red)
      end
    else
      puts "Incorrect ordinal number!".colorize(:red)
    end
  else
    puts "I know no such animal."
  end

end

quiz()

My Top Secret Plan for the Hiring Off-season




Let's be realistic: I shan't get a start as a junior developer  before Christmas, nor can I expect to be hired before the end of January.  Back in September, I had hoped to get a start in late November, maybe get something lined up in December, but that did not come to pass.

Would I prefer to get a start straight away?  Of course I do.
Can I change prospective employers' hiring practices?  No.

I could bemoan the effect of two months of unemployment on my savings, but that won't get me anywhere.

Instead, let's look at this as an opportunity: I have two whole months in which to learn as much as possible about programming in Ruby, and build up a portfolio of code in Github.  I can't batter down doors that are closed for Christmas and New Year's, but I can put myself in the best position for when they re-open.

So what's the plan?

  • Complete Learn Ruby the Hard Way
  • Blog about what I learn
  • Learn about test-driven development (TDD)
  • Transfer the contents of my Pastebin to Gist in an intelligent way
  • Build the web scraper for my research tool and get it up on Github
  • Build the analysis component of my research tool and get it up on Github
  • Go to meet-ups
  • Participate in Slack
  • Find a mentor to review my code
  • Write an end-of-month summary for all the Leads and Contacts in my CRM


In addition to all that, work on the Odessia, keep a clean home, cook, exercise, early to bed and early to rise, and enjoy every weekend with my beloved, friends, and family.

So this year, Christmas 2016, there will be no reason for me to slow down, and every reason to push harder into 2017.

First Small Step Into Testing

I am working on Exercise 28 of Learn Ruby the Hard Way and this is my first concrete example of using testing in the course of coding.

The exercise is a test of boolean logic: I am given a statement e.g.

true == true

And must work out whether it is "true" or "false".

As you can see, I have organised the statements in a two-dimensional array in which each sub-array is composed of three elements: a string denoting the statement, the statement itself, and my prediction.

# List of boolean statements to test my knowledge thereof, organised in a two-dimensional array
booleanTest = [
  ["true && true", true && true, true],
  ["false && true", false && true, false],
  ["1 == 1 && 2 == 1", 1 == 1 && 2 == 1, false],
  ['"test" == "test"', "test" == "test", true],
  ["1 == 1 || 2 != 1", 1 == 1 || 2 != 1, true],
  ["true && 1 == 1", true && 1 == 1, true],
  ["false && 0 != 0", false && 0 != 0, false],
  ["true || 1 == 1", true || 1 == 1, true],
  ['"test" == "testing"', "test" == "testing", false],
  ["1 != 0 && 2 == 1", 1 != 0 && 2 == 1, false],
  ['"test" != "testing"', "test" != "testing", true],
  ['"test" == 1', "test" == 1, false],
  ["!(true && false)", !(true && false), true],
  ["!(1 == 1 && 0 != 1)", !(1 == 1 && 0 != 1), false],
  ["!(10 == 1 || 1000 == 1000)", !(10 == 1 || 1000 == 1000), false],
  ["!(1 != 10 || 3 == 4)", !(1 != 10 || 3 == 4), true]
]
I test my prediction by running the following testing loop, and in keeping with the practice of "green" for good and "red" for error, I installed the colorize gem and applied it to the output of the testing loop.
# Required in order to highlight the text in the testing loop green or red.

# Colorize gem to mark the result green or red.
require 'colorize'

# Testing loop
puts "Here are the results of my test:\n\n"
booleanTest.each do|description,result,prediction|
  puts "PREDICTION: #{description} GIVES #{prediction}, RESULT: #{result}"
  if prediction == result
    puts "Correct!".colorize(:green)
  else
    puts "Incorrect!".colorize(:red)
  end
end

And here are the results:



Repairing Shoddy Code

Original, Shoddy Code


module Ex2
  # This function will break up words for us.
  def Ex25.brak_words(stuff
    words = stuff.split(' ')
    return word
  end

  # Sorts the words.
  def Ex25.sortwords(words)
    return words.sort
  end

  # Prints the first word after popping it off.
  df Ex25.print_first_word(words)
    word = words.pop(1)
    puts wor
  end

  # Prints the last word after popping it off.
  def Ex25:print_last_word(words)
    word = words.pop
    put word
  end

  # Takes in a full sentence and returns the sorted words.
  def Ex25.sort_sentence(sentence)
    words = Ex25.break_words(sentence)
    return Ex25.sort_words(words)
  ed

  # Prints the first and last words of the sentence.
  def Ex25.print_first_and_last(sentence
    words = Ex25.break_words(sentenc)
    Ex25.print_first_wrd(word)
    Ex25.print_last_word(words)
  end

  # Sorts the words then prints the first and last one.
  def Ex25.print_first_and_last_sorted(sentence)
    words = Ex25.sort_sentence(sentence)
    Ex25.print_fist_word(words)
    Ex25.print_last_word(words)
  end



puts "Let's practice everything."
puts 'You\'d need to know \'bout escapes with \\ that do \n newlines and \t tabs.'

poem = &lt&ltEND
\tThe lovely world
with logic so firmly planted
cannot discern \n the needs of love
nor comprehend passion from intuition
and requires an explanation
\n\t\twhere there is none.
ENDED

puts "--------------"
puts poem
puts "--------------"


five = 10 - 2  3 - 6
puts "This should be five: #{five"

def secret_formula(started)
  jelly_bens = started * 500
  jars = jelly_beans / 1000
  crate = jars / 100
  return jelly_beans, jars, crates
end


start_point = 10000
beans, jars crates = secret_formula(start_point)

puts "With a starting point of: #{start_point}"
puts "We'd have #{beans beans, #{jars} jars, and #{crates} crates."

start_point = start_point / 10

sentence = "All good things come to those who wait."
words = Ex25.break_words(sentence)
sorted_words = Ex25.sort_words(words)
Ex25.print_first_word(wrds)
Ex25.print_last_word words)
Ex25.print_first_word(sort_words)
Ex25.print_last_word(sorted_words)
sorted_words = Ex25.sort_sentenc(sentence)
Ex25.print_first_and_last(sentence)
Ex25:print_first_and_last_sorted(sentence)

Fresh, Clean Code

# Import the module Ex25 and define the functions

module Ex25

  # This function will break up words for us.
  def Ex25.break_words(stuff)
    words = stuff.split(' ')
    return words
  end

  # Sorts the words.
  def Ex25.sort_words(words)
    return words.sort
  end

  # Prints the first word after popping it off.
  def Ex25.print_first_word(words)
    word = words.shift
    puts word
  end

  # Prints the last word after popping it off.
  def Ex25.print_last_word(words)
    word = words.pop
    puts word
  end

  # Takes in a full sentence and returns the sorted words.
  def Ex25.sort_sentence(sentence)
    words = Ex25.break_words(sentence)
    return Ex25.sort_words(words)
  end

  # Prints the first and last words of the sentence.
  def Ex25.print_first_and_last(sentence)
    words = Ex25.break_words(sentence)
    Ex25.print_first_word(words)
    Ex25.print_last_word(words)
  end

  # Sorts the words then prints the first and last one.
  def Ex25.print_first_and_last_sorted(sentence)
    words = Ex25.sort_sentence(sentence)
    Ex25.print_first_word(words)
    Ex25.print_last_word(words)
  end
end

# Execute the functions defined from module Ex25

sentence = "All good things come to those who wait."
words = Ex25.break_words(sentence)
sorted_words = Ex25.sort_words(words)
Ex25.print_first_word(words)
Ex25.print_last_word(words)
Ex25.print_first_word(sorted_words)
Ex25.print_last_word(sorted_words)
sorted_words = Ex25.sort_sentence(sentence)
Ex25.print_first_and_last(sentence)
Ex25.print_first_and_last_sorted(sentence)

puts "--------------"

# Seperate code, nothing to do with module Ex25

puts "Let's practice everything."
puts 'You\'d need to know \'bout escapes with \\ that do \n newlines and \t tabs.'

poem = &lt&ltEND
\tThe lovely world
with logic so firmly planted
cannot discern \n the needs of love
nor comprehend passion from intuition
and requires an explanation
\n\t\twhere there is none.
END

puts "--------------"
puts poem
puts "--------------"

# Separate code again, nothing to do with module 25 or the above section

five = 10 - 2 + 3 - 6
puts "This should be five: #{five}"

puts "--------------"


def secret_formula(started)
  jelly_beans = started * 500
  jars = jelly_beans / 1000
  crate = jars / 100
  return jelly_beans, jars, crate
end

start_point = 10000
beans, jars, crates = secret_formula(start_point)

puts "With a starting point of: #{start_point}"
puts "We'd have #{beans} beans, #{jars} jars, and #{crates} crates."

puts "--------------"

start_point = start_point / 10

puts "Now, with a starting point of: #{start_point}"
puts "We'd have #{beans} beans, #{jars} jars, and #{crates} crates."

Wednesday, December 7, 2016

Opening a file with open(ARGV.first) vs declaring a variable

I am working through Exercise 20 of Learn Ruby the Hard Way, and am trying to make sense of the difference in output between defining the variable "current_file" and simply using open(ARGV.first):
Here is the input file test.txt:
This is line 1
This is line 2
This is line 3
Here is the beginning of the script:
input_file = ARGV.first

def print_a_line(f)
  puts "#{f.gets}"
end

current_file = open(input_file)
When I call the print_a_line with the declared variable:
print_a_line(current_file)
print_a_line(current_file)
print_a_line(current_file)
Then f.gets tracks to the new line each time:
This is line 1
This in line 2
This is line 3
However, if I call the function with ARGV.first:
print_a_line(open(ARGV.first))
print_a_line(open(ARGV.first))
print_a_line(open(ARGV.first))
Then f.gets does not track to the new line and remains on line 1:
This is line 1
This is line 1
This is line 1
And the same even with input_file:
print_a_line(open(input_file))
print_a_line(open(input_file))
print_a_line(open(input_file))
f.get still doesn't track to the next line:
This is line 1
This is line 1
This is line 1
Obviously, I would declare and use variables -- I understand the basics of writing neat, readable code.
My question is why does f.get track to the next line when the function is called with a declared variable and not track to the next line when called with the open(ARGV.first) or open(input_file)?
Why do I have to declare the variable again?
current_file = open(input_file)

Tuesday, December 6, 2016

Syntax Highlighting!

This blog officially has syntax highlighting!

BASH

# Hello world for the Unix shells (sh, ksh, csh, zsh, bash, fish, xonsh, ...)
echo Hello World

JavaScript

// Hello World in JavaScript
document.write('Hello World');

PHP

// Hello world in PHP
echo 'Hello World!';

Plain Text

Hello, world!

Python

# Hello world in Python 2
print "Hello World"
# Hello world in Python 3 (aka Python 3000)
print("Hello World")

Ruby

# Hello World in Ruby
puts "Hello World!"

Sunday, December 4, 2016

Breaking Down A Large Task


I wish to fill a journal with handwritten entries by the 7th of January, 2017.
I have 94 pages left, and at the time of writing, 34 days in which to do so.
I will start by writing four pages per day, Monday to Friday, and two or three per day on weekends; if I stick to this for long enough, the average per day required to accomplish this task will drop to two pages per day, which can be done fairly easily.  If I can coast on two pages, or even one page every other day in the final fortnight, I shall consider this schedule a success.

Friday, December 2, 2016

Refactor, Refactor, Refactor


Original Code

from_file, to_file = ARGV
puts "Copying from #{from_file} to #{to_file}"
# we could do these two on one line, how?
in_file = open(from_file)
indata = in_file.read
puts "The input file #{indata.length} bites long"
puts "Does the output file exist? #{File.exist?(to_file)}"
puts "Ready, hit RETURN to continue, CTRL-C to abort."
$stdin.gets
out_file = open(to_file, 'w')
out_file.write(indata)
puts "Alright, all done."
out_file.close
in_file.close

Extremely Refactored Code

File.new(ARGV[0], 'w').write(File.read(ARGV[1]))
Acknowledgement: Picture from Flickr 

A Little Bit of CSS Can Go A Long Way



These days, I have the luxury to take myself off to the beach in the morning, and if the sun comes out it makes for a pretty photograph.

By default, the background image on Blogger will tile if you're on a bigger screen, but no self-respecting developer could allow such an allow state of affairs to persist.

Feel free to use the image linked: it's a photo from Mordialloc Beach in Melbourne.

Templates >> Advanced >>  Add CSS

html, body {
background: url(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2HCYpBJd77y0JOGKD-O8duIXlcshW6oNX64fkmVUCjHRNqEGZfxFsccQjawYg8ad6m6HcjOQJtu8GfjBIkHD3RrHMO-wzfzzwvhC4Fq11hhaeTPbB-Onw9h1H0ssGb4WgFr00vKpkoopR/w1200/PHOTO_20161129_093947.jpg) no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}

From Pastebin to Gist: Not So Fast!


I published my first paste on Pastebin five years ago (at the time of writing), and Pastebin has been very good to me ever since, but it's time to migrate my data to Gist on Github.

I looked around for an automated migration solution, but couldn't find any.

Then I thought about copying and pasting all my pastes, but that's stupid, laborious work, and no self-respecting programmer would do something so repetitious.

So what's the clever solution?

The following headers are the skeleton of my plan.  I will update this post as I progress.

Part One: Get the raw pastes from Pastebin

Pastebin API

Pastebin has a scraping API and a developer's API which costs a lifetime membership.  At the time of writing there is a big discount on lifetime membership, so I bit the bullet and got it.  The practice it gives me will be more than a decent ROI.

Construct the Query, in Ruby

All the sample scripts are given in PHP, but there must be a way to do it in Ruby, or failing that, in JavaScript.

Execute the Query

Part Two: Upload the raw pastes as separate Gists

Github API

Construct the Script, in Ruby 

Execute the Script


I Don't Know Enough Ruby


I have a confession to make: I don't know enough Ruby yet.

I have working through the Ruby course on Code Academy, but that doesn't make me a Rubyist.

I am working through Learn Ruby the Hard Way, but that still doesn't make me a Rubyist.

Every day, I get a little better and learn a little more, but I'm still not fluent, I still can't attack a problem and begin to break it down into manageable components; I still need to learn the fundamentals of taking input from one source, manipulating it, and putting it into another place or displaying it.

I know from studying (human) languages, that there isn't a clear milestone after which one says, "I speak this language."  Languages, be they human or computer, don't work that way.

That's part of the reason for this blog: to remind myself of how far I've come at times when the holy grail of programming genius -- not a realistic goal -- seems out of reach.

So, one chapter, one task, one problem, one exercise at a time.  It all adds up, and besides, there's no other way.

gets.chomp VS $stdin.gets.chomp

Whilst working on Exercise 15 of Learn Ruby the Hard Way, the author prompted me to ponder the difference between gets.chomp and $stdin.gets.chomp.

The simplest explanation I found for the difference between gets.chomp and $stdin.gets.chomp is this, from Stack Overflow:
gets.chomp() = read ARGV first

STDIN.gets.chomp() = read user's input
A further clarification:
because if there is stuff in ARGV, the default gets method tries to treat the first one as a file and read from that. To read from the user's input (i.e., stdin) in such a situation, you have to use it STDIN.gets explicitly.

Source Code from Exercise 15 of Learn Ruby the Hard Way:

# Get the input file
filename = ARGV.first

# Declare a variable to open the input file
txt = open(filename)

# Output the contents of the input file
puts "Here's your file #{filename}"
print txt.read

# Ask the user to name the input file, implicitly in the local directory
print "Type the filename again: "

# Use stdin to obtain the name of the input file from the local directory
file_again = $stdin.gets.chomp
# file_again = gets.chomp

# Declare another variable to open the input file again
txt_again = open(file_again)

# Output the contents of the input file again
print txt_again.read
 Take note that I put gets.chomp and $stdin.gets.chomp and uncommented the one I wanted to test.

To this I added two text files for testing:
  1. ex_15_sample.txt
  2. ex_15_sample_2.txt

ex_15_sample.txt:

This is stuff I typed into a file.

It is really cool stuff.

Lots and lots of fun to have in here.

ex_15_sample_2.txt

THIS IS STUFF I TYPED INTO A FILE.

IT IS REALLY COOL STUFF.

LOTS AND LOTS OF FUN TO HAVE IN HERE.

Scenario 1: $stdin.gets.chomp

Script:

# Get the input file
filename = ARGV.first

# Declare a variable to open the input file
txt = open(filename)

# Output the contents of the  input file
puts "Here's your file #{filename}"
print txt.read

# Ask the user to name the input file, implicitly in the local directory
print "Type the filename again: "

# Use stdin to obtain the name of the input file from the local directory
file_again = $stdin.gets.chomp
# file_again = gets.chomp

# Declare another variable to open the input file again
txt_again = open(file_again)

# Output the contents of the input file again
print txt_again.read

Command in terminal:

$ ruby ex15.rb ex_15_sample.txt

Output:

Here's your file ex_15_sample.txt

This is stuff I typed into a file.

It is really cool stuff.

Lots and lots of fun to have in here.

Type the filename again: ex_15_sample_2.txt

THIS IS STUFF I TYPED INTO A FILE.

IT IS REALLY COOL STUFF.

LOTS AND LOTS OF FUN TO HAVE IN HERE.

Scenario 2: gets.chomp

Script:

# Get the input file

filename = ARGV.first

# Declare a variable to open the input file

txt = open(filename)

# Output the contents of the  input file

puts "Here's your file #{filename}"

print txt.read

# Ask the user to name the input file, implicitly in the local directory

print "Type the filename again: "

# Use stdin to obtain the name of the input file from the local directory

# file_again = $stdin.gets.chomp

file_again = gets.chomp

# Declare another variable to open the input file again

txt_again = open(file_again)

# Output the contents of the input file again

print txt_again.read

Command in terminal:

$ ruby ex15.rb ex_15_sample.txt

Output:

Here's your file ex_15_sample.txt

This is stuff I typed into a file.

It is really cool stuff.

Lots and lots of fun to have in here.

Type the filename again: ex15.rb:20:in `initialize': No such file or directory @ rb_sysopen - This is stuff I typed into a file. (Errno::ENOENT)

 from ex15.rb:20:in `open'

 from ex15.rb:20:in `<main>'
Let's look a little more closely at what went wrong.  

The first part of the script took the argument from the commandline and read the contents of the file ex_15_sample.txt -- great!

Then it printed "Type the filename again." -- again, that's what we want.

However, when it got to gets.chomp, it attempted to take as an input the first line of the contents of the file denoted by ARGV.

Let's look at the contents of the text file in question:

ex_15_sample.txt:

This is stuff I typed into a file.

It is really cool stuff.

Lots and lots of fun to have in here.
Do you see what Ruby tried to do here?  gets.chomp already has the filename from ARGV, but instead of reading the filename, it reads the first line of the file.

Scenario 3: gets.chomp with a hacked input file

If gets.chomp take the first line of the file named by ARGV, what would happen if I hack the text file and put the name of the second file in the first line?

ex_15_sample_hacked.txt:

ex_15_sample_2.txt

This is stuff I typed into a file.

It is really cool stuff.

Lots and lots of fun to have in here.

Script:

# Get the input file
filename = ARGV.first

# Declare a variable to open the input file
txt = open(filename)

# Output the contents of the input file
puts "Here's your file #{filename}"
print txt.read

# Ask the user to name the input file, implicitly in the local directory
print "Type the filename again: "

# Use stdin to obtain the name of the input file from the local directory
# file_again = $stdin.gets.chomp
file_again = gets.chomp

# Declare another variable to open the input file again
txt_again = open(file_again)

# Output the contents of the input file again
print txt_again.read


Command in terminal:

$ ruby ex15.rb ex_15_sample_hacked.txt 

Output:

Here's your file ex_15_sample_hacked.txt

ex_15_sample_2.txt

This is stuff I typed into a file.

It is really cool stuff.

Lots and lots of fun to have in here.

Type the filename again: THIS IS STUFF I TYPED INTO A FILE.

IT IS REALLY COOL STUFF.

LOTS AND LOTS OF FUN TO HAVE IN HERE.

Observations:

  1. The first part of the script read the input file from ARGV.
  2. The second part of the script read as input the first line of the input file from ARGV.

Conclusions

  1. If you want to prompt the user for input, use $stdin.gets.chomp.
  2. If you want to trick the program into using the first line of the first file supplied to ARGV, gets.chomp is an option, but a better way to do it would simply be to declare the variable in your code.

Thursday, December 1, 2016

Living a Kanban Life


I live a Kanban life.  Every morning, I consult my Kanban whiteboard to plan my tasks for the day, and get better every day at converting what needs to be done into tasks, and working through those tasks methodically.


The major drawback of this excellent tool is that one can lose sight of the big picture.
That's where my second whiteboard comes in.  I can use it for any kind of brainstorming.


As you can see, these two boards work hand in hand.







At the end of a week, I take all the DONE tasks and put them up on the brainstorming board, to take stock of my work, and to give myself a wee pat on the back.












Every week I find an appreciable improvement in my use of the Kanban system.

Wednesday, November 30, 2016

Command Line Course on Code Academy Complete


I didn't learn anything I didn't already know, but it was good to formalise my understanding garnered from years of bashing away in BASH.

Tuesday, November 29, 2016

Near-future Study Topics

Primary Focus


  • ES6 Javascript
  • Componentization
  • Semantic HTML Markup
  • Responsive CSS
  • CSS Animations
  • React
  • Ability to implement custom bespoke layouts from scratch

Secondary Focus


  • Node.js
  • Webpack
  • using CSS modules, Radium or Aphrodite
  • Redux
  • Server Side Rendering

JavaScript Course at CodeAcademy.com Complete!


Friday, November 25, 2016

Wednesday, November 23, 2016

Progress Report on Full Stack Web Development Training


I've committed myself completely to the full stack web development course through Code Academy, and it's going quite well.

My goal for the coming week is to complete all the courses leading up to Ruby and Ruby on Rails before I attend the Melbourne Ruby meetup next week.

My main priority is Ruby, so at this stage I am interested in the other components of the full stack only insofar as they are strictly needed for working with Ruby on Rails.  Once I've completed the main modules of all the courses in the stack, I'll go back and complete the supplementary exercises to sharpen my skills.

At the moment, this is how it looks:



Having spents years fiddling with basic Python and BASH, none of this is particularly difficult, but I commend Code Academy on putting together courses that give a good introduction to each language and framework.  I was a little bored by the HTML & CSS course because I came into fairly comfortable with both, so my only recommendation would be for Code Academy to consider a way of giving the equivalent of RPL (Recognition of Prior Learning) to students who can pass certain tests with ease.

For example, if someone already understands what a boilerplate is, a few questions on a test would bear this out and that portion of the course could be marked as completed automatically.  Instead, I had to slog through material I already knew back to front.

Still, I strongly recommend the course.  I feel that it is working well for me, and will commence the next stage of my journey towards a career as Ruby developer with confidence upon completion of these courses.

1,050 hours

It took me 13 working days to complete my first 100 "work" pomodoros as a Junior Software Tester at Profectus Group.  Much of ...