This 3-part homework gives some basic practice in Ruby as well as getting you accustomed to making testing a regular part of your workflow.
NOTE: do not fork this repo. Click the "Use this template" button then clone the repo that it generates
After completing this assignment, you will be able to:
- Write simple code that uses basic constructs in the Ruby language, including methods and arguments, conditionals, string and array manipulation, regular expressions, and basic object-oriented programming mechanisms
- Describe the Ruby project conventions for where code files and test files are located in a project's directory hierarchy
- Run individual tests or suites of tests using the RSpec unit testing tool
- Describe the basic syntax of RSpec unit tests
You may find the Ruby documentation at ruby-doc.org helpful to have on hand.
The repo for this assigment follows a fairly standard Ruby convention for codebases: the code files are stored in lib/
and the test files are stored in spec/
. (We will use the RSpec unit-testing framework; if we were using Ruby's default framework, known as Test::Unit
, the test files would be under
test/
.)
We've placed "starter code" in lib/ruby_intro.rb
.
Install Ruby. (I recommend rbenv, in particular the rbenv-installer tool.)
The current stable version of ruby is: 3.3.4
The ruby version on Gradescope is: 3.0.2p107
When the above completes successfully you'll have RSpec installed and can run rspec
from the command line to test your code.
Run rspec
now. You should see 34 examples, 20 failures
in red.
Runing rspec
with no arguments will execute the tests in all the files spec/*_spec.rb
. However, you can test each of the 3 parts separately. The files spec/part[123]_spec.rb
contain RSpec tests for each of the three parts. For example, to test your answers to Part 1, run rspec spec/part1_spec.rb
.
Run rspec spec/part1_spec.rb
. You should see 12 examples, 9 failures
in red.
The line numbers in the RSpec error report will give you guidance as to which tests failed. (You can check the RSpec documentation to see how the .rspec
file can be used to customize the output format.)
Check the Ruby 3.x documentation on Array
, Hash
and Enumerable
as they could help tremendously with these exercises. Various Ruby cheatsheets are also helpful as a quick reference! Although Ruby supports looping constructs like 'for' and 'while', consider using block syntax with each for a more idiomatic use of Ruby.
The method sum(arr)
should return the sum of the values in arr
.
- Run the tests:
rspec -fd -e '#sum ' spec/part1_spec.rb
. You should see3 examples, 2 failures
in red.- Problem? Make sure you are in the correct directory:
cd assignment
and RSpec is installed.
- Problem? Make sure you are in the correct directory:
- Read the RSpec report.
- Pick one of the failures to correct. (In fact, we could "fix" both at the same time)
- Suppose we pick
expect(sum([1, 2, 3, 4, 5])).to be_a_kind_of Integer
.
- Suppose we pick
- Add just enough code to the method
sum(array)
inlib/ruby_intro.rb
to pass the selected test.- The simplest code we can add is to return a constant. Let's
return 0
. Because Ruby is neat, we can do this by simply putting0
in the function body:
def sum(arr) 0 end
- The simplest code we can add is to return a constant. Let's
- Re-run the tests:
rspec -fd -e '#sum ' spec/part1_spec.rb
. You should see3 examples, 1 failure
in red. - Add and commit changes:
git add . && git commit -m "improved correctness of sum"
- Read the RSpec report.
- Pick one of the failures to correct. (Pick the only failure...)
- Add just enough code to pass the test.
- Re-run the tests. You should see
3 examples, 0 failures
in green.- Yay?
- Yay!
- Add and commit changes:
git add . && git commit -m "sum is passing all tests"
- Push changes:
git push
- Nay?
- Go back to step 6 and Try Harder.
- Yay?
The method max_2_sum(arr)
should return the sum of its two largest elements in arr
.
- Run the tests:
rspec -fd -e '#max_2_sum' spec/part1_spec.rb
. You should see5 examples, 4 failures
in red. - Read the RSpec report.
- Pick one of the failures to correct.
- Add just enough code to pass the selected test.
- Add and commit changes:
git add . && git commit -m "<comment>"
- Until all tests are passing (0 failures), go back to step 0.
- Push changes:
git push
The method sum_to_n?(arr, n)
takes an array of integers arr
and an additional integer, n
, as arguments and returns true if any two elements in arr
sum to n
.
- Run the tests:
rspec -fd -e '#sum_to_n?' spec/part1_spec.rb
. - Read the RSpec report.
- Pick one of the failures to correct.
- Add just enough code to pass the selected test.
- Add and commit changes.
- Until all tests are passing (0 failures), go back to step 0.
- Push changes.
Check your progress on all Part 1 methods: rspec -fd spec/part1_spec.rb
. All tests should be green.
Now is a good time (and the right time) to go back and consider how you can improve your code? Might there be a better way (a more rubyistic / efficient / readable / etc.) to implement the methods? Try at least 1 alternative solution (with a focus on making the solution use more of Ruby's language features) for each method. Settle on the one you like the best.
Check the documentation on String
and Regexp
as they could help tremendously with these exercises. For future reference as well, check out Rubular for regex related queries.
-
Define a method
hello(name)
that takes a string representing a name and returns the string "Hello, " concatenated with the name. Run associated tests via:rspec -e '#hello' spec/part2_spec.rb
.- Everytime a new test passes, add and commit changes:
git add . && git commit -m "<comment>"
- Once all tests are passing, push changes:
git push
- Everytime a new test passes, add and commit changes:
-
Define a method
starts_with_consonant?(s)
that takes a string and returns true if it starts with a consonant and false otherwise. (For our purposes, a consonant is any English letter other than A, E, I, O, U.) Make sure it works for both upper and lower case and for non-letters. Run associated tests via:rspec -e '#starts_with_consonant?' spec/part2_spec.rb
.- Everytime a new test passes, add and commit changes:
git add . && git commit -m "<comment>"
- Once all tests are passing, push changes:
git push
- Everytime a new test passes, add and commit changes:
-
Define a method
binary_multiple_of_4?(s)
that takes a string and returns true if the string represents a binary number that is a multiple of 4, such as '1000'. Make sure it returns false if the string is not a valid binary number. Run associated tests via:rspec -e '#binary_multiple_of_4?' spec/part2_spec.rb
.- Everytime a new test passes, add and commit changes:
git add . && git commit -m "<comment>"
- Once all tests are passing, push changes:
git push
- Everytime a new test passes, add and commit changes:
You can check your progress on all of the above by running rspec -fd spec/part2_spec.rb
. All tests should be green.
Consider ways to improve your code.
Remember:
- Everytime a new test passes, add and commit changes:
git add . && git commit -m "<comment>"
- Once all tests are passing, push changes:
git push
-
Implement the constructor for class
BookInStock
which represents a book with an ISBN number,isbn
, and price of the book,price
. The constructor should accept the ISBN number (a string, since in real life ISBN numbers can begin with zero and can include hyphens) as the first argument and price (a floating point number) as the second argument. Also implement the getter and setter methods forisbn
andprice
. Run associated tests via:rspec -e 'getters and setters' spec/part3_spec.rb
-
The constructor should raise
ArgumentError
(one of Ruby's built-in exception types) if the ISBN number is the empty string or if the price is less than or equal to zero. Run associated tests via:rspec -e 'constructor' spec/part3_spec.rb
-
Implement the method
BookInStock#price_as_string
that returns the price of the book formatted with a leading dollar sign and two decimal places, that is, a price of 20 should format as$20.00
and a price of 33.8 should format as$33.80
. Check out formatted string methods in Ruby. Run associated tests via:rspec -e '#price_as_string' spec/part3_spec.rb
You can check your progress on all of the above by running rspec -fd spec/part3_spec.rb
.
Generate a test log file using rspec -fd -o <LastName>_<FirstName>_PA1.txt spec/
, where <LastName>
and <FirstName>
are your last and first names, respectively. This will put the entire RSpec report into one file.
Don't forget to add, commit, and push!
-
I strongly recommend that you conform to a Ruby style guide:
gem install rubocop
, then runrubocop [list of filenames to check]
. -
Try getting setup with an automated test framework such as guard or autotest. Guard or AutoTest can be set up so that they will run all the tests in
spec/
, but every time you edit and save your code file, the tests are automatically re-run, so you don't have to run them manually. As you should have seen in this assignment, this is the "watch the test fail" part of the TDD or test-driven process of development: write the tests before you write the code, watch the test fail, fill in the code and save the code file, then watch the test pass!