Avatar of lujanfernaud

lujanfernaud's solution

to Twelve Days in the Ruby Track

Published at Feb 10 2020 · 0 comments
Instructions
Test suite
Solution

In this exercise, you'll create a class to output the lyrics to the traditional English Christmas carol "The Twelve Days of Christmas" (complete lyrics below).

In this song, each verse is built on top of the previous verses in a repeating pattern. Can you use Ruby to build up the repeated lyrics programmatically?

Note on testing: Unlike previous exercises, this exercise doesn't include an extensive set of test cases. Instead, there is an "acceptance" test to make sure that the final output is correct. A file called song.txt is included with the exercise, but this is to be used for the acceptance test to validate the solution, not as part of the solution itself.

On the first day of Christmas my true love gave to me: a Partridge in a Pear Tree.

On the second day of Christmas my true love gave to me: two Turtle Doves, and a Partridge in a Pear Tree.

On the third day of Christmas my true love gave to me: three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.

On the fourth day of Christmas my true love gave to me: four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.

On the fifth day of Christmas my true love gave to me: five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.

On the sixth day of Christmas my true love gave to me: six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.

On the seventh day of Christmas my true love gave to me: seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.

On the eighth day of Christmas my true love gave to me: eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.

On the ninth day of Christmas my true love gave to me: nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.

On the tenth day of Christmas my true love gave to me: ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.

On the eleventh day of Christmas my true love gave to me: eleven Pipers Piping, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.

On the twelfth day of Christmas my true love gave to me: twelve Drummers Drumming, eleven Pipers Piping, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.

For installation and learning resources, refer to the Ruby resources page.

For running the tests provided, you will need the Minitest gem. Open a terminal window and run the following command to install minitest:

gem install minitest

If you would like color output, you can require 'minitest/pride' in the test file, or note the alternative instruction, below, for running the test file.

Run the tests from the exercise directory using the following command:

ruby twelve_days_test.rb

To include color from the command line:

ruby -r minitest/pride twelve_days_test.rb

Source

Wikipedia http://en.wikipedia.org/wiki/The_Twelve_Days_of_Christmas_(song)

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

twelve_days_test.rb

require 'minitest/autorun'
require_relative 'twelve_days'

class TwelveDaysTest < Minitest::Test
  def test_the_whole_song
    song_file = File.expand_path('../song.txt', __FILE__)
    expected = IO.read(song_file)
    assert_equal expected, TwelveDays.song
  end
end

twelve_days.rb

# frozen_string_literal: true

require_relative "verse"

module TwelveDays
  def self.song
    12.times.map { |number| Verse.prepare(number) }.join("\n\n") + "\n"
  end
end

verse.rb

# frozen_string_literal: true

require_relative "day"
require_relative "gifts"

module TwelveDays
  class Verse
    def self.prepare(number)
      new(number).prepare
    end

    def initialize(number)
      @number = number + 1
    end

    def prepare
      day + gifts + "."
    end

    private

    attr_reader :number

    def day
      @day ||= Day.new(number).to_s
    end

    def gifts
      @gifts ||= Gifts.new(number).to_s
    end
  end
end

day.rb

# frozen_string_literal: true

module TwelveDays
  class Verse
    class Day
      NUMBER_TO_DAY = {
        1 => "first",
        2 => "second",
        3 => "third",
        4 => "fourth",
        5 => "fifth",
        6 => "sixth",
        7 => "seventh",
        8 => "eighth",
        9 => "ninth",
        10 => "tenth",
        11 => "eleventh",
        12 => "twelfth"
      }.freeze

      def initialize(number)
        @number = number
      end

      def to_s
        "On the #{NUMBER_TO_DAY[number]} day of Christmas " \
        "my true love gave to me: "
      end

      private

      attr_reader :number
    end
  end
end

gifts.rb

# frozen_string_literal: true

module TwelveDays
  class Verse
    class Gifts
      GIFTS = [
        "a Partridge in a Pear Tree",
        "two Turtle Doves",
        "three French Hens",
        "four Calling Birds",
        "five Gold Rings",
        "six Geese-a-Laying",
        "seven Swans-a-Swimming",
        "eight Maids-a-Milking",
        "nine Ladies Dancing",
        "ten Lords-a-Leaping",
        "eleven Pipers Piping",
        "twelve Drummers Drumming"
      ].freeze

      def initialize(number)
        @number = number - 1
      end

      def to_s
        gifts[-1] = "and #{gifts[-1]}" if gifts.size > 1

        gifts.join(", ")
      end

      private

      attr_reader :number

      def gifts
        @gifts ||= GIFTS[0..number].reverse
      end
    end
  end
end

Community comments

Find this solution interesting? Ask the author a question to learn more.

What can you learn from this solution?

A huge amount can be learned from reading other people’s code. This is why we wanted to give exercism users the option of making their solutions public.

Here are some questions to help you reflect on this solution and learn the most from it.

  • What compromises have been made?
  • Are there new concepts here that you could read more about to improve your understanding?