Skip to content

Commit

Permalink
Introduction to Ruby
Browse files Browse the repository at this point in the history
  • Loading branch information
dcdelia committed Mar 4, 2024
1 parent 6f5d585 commit 405b991
Show file tree
Hide file tree
Showing 18 changed files with 708 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pickle-email-*.html
# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
*/tmp/*
!/log/.keep
!/tmp/.keep

Expand Down Expand Up @@ -65,3 +66,6 @@ yarn-debug.log*
# Ignore uploaded files in development
/storage/*
!/storage/.keep

# MacOS stuff
.DS_Store
43 changes: 43 additions & 0 deletions BIAR.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
VM BIAR Notes
========

These notes may be helpful if you are using the LXLE-BIAR VM (version 4.3 or higher), especially at the lab.

## Getting started with RVM

### Loading the environment

In this course, we will typically use Ruby `v2.7.2`:

```
### Load specific Ruby build
biar@biar:~$ rvm use ruby-2.7.2
Using /home/biar/.rvm/gems/ruby-2.7.2
```

To save time, you may add the following line at the end of your `.profile` file in your `$HOME` directory:

```
shopt -q login_shell && rvm use ruby-2.7.2
```

Which will check for a login shell before loading RVM.

### Package installation
We install packages locally using `gem`. For example, to install `rspec` use:
```
biar@biar:~$ gem install rspec
Fetching rspec-core-3.12.1.gem
Fetching rspec-3.12.0.gem
[...]
```

### Login shell
To load a Ruby build, RVM needs to work on a *login shell* (or you will get an error instead). There are two ways to obtain one:

1. Run this command to spawn a login shell before calling RVM:
```
biar@biar:~$ /bin/bash --login
```

2. Modify the settings of the `Sakura` terminal emulator. Click on the Start icon of the desktop environment, then `Control Menu` -> `Utilities` -> `Sakura` (right-click) -> `Properties`. Go to the `Desktop Entry` pane and modify the `Command` option to add the `-l` flag (so as it reads: `sakura -l`). From now on, every instance of Sakura will run a login shell and you can invoke RVM directly. You may look up instructions online for other terminal emulators.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Laboratorio di Architetture Software e Sicurezza Informatica [AAF1569]
=============

This repository hosts class material for the 2023-2024 edition of the course.

Instructors: [Leonardo Querzoni](https://sites.google.com/diag.uniroma1.it/querzoni/) and [Daniele Cono D'Elia](https://www.diag.uniroma1.it/~delia/)

Teaching assistant: [Nicola Bottura](https://nicolabottura.github.io/)

### Contents
*Listed as: class date, enclosing folder, topic*
- 05/03/2024 `ruby-intro/` Ruby essentials
2 changes: 2 additions & 0 deletions ruby-intro/book-lab/.bundle/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
BUNDLE_WITHOUT: "production"
8 changes: 8 additions & 0 deletions ruby-intro/book-lab/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
source 'http://rubygems.org'

#ruby "2.6.6"

gem 'rspec' #, '~> 3.8'
gem 'cucumber' #, '2.0.0'
gem 'byebug'

89 changes: 89 additions & 0 deletions ruby-intro/book-lab/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
Ruby Intro
=============

This material is taken from the [GitHub repository](https://github.com/saasbook/hw-ruby-intro) for the Ruby introductory homework of the *Engineering Software as a Service* book we use for this class.

Organized in three parts, it gives some basic practice in Ruby as well as getting you accustomed to making testing a regular part of your workflow. Make sure `rspec` is available in your environment (otherwise: `gem install rspec`).

Learning Goals
--------------

* 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
* Understand 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
* Understand the basic syntax of RSpec unit tests

Overview
--------

**You may find the [Ruby documentation at ruby-doc.org](https://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 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`; when you're all done, you
can submit this single file to the autograder.**

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, say `rspec
spec/part1_spec.rb`. `rspec` with no arguments runs the tests in all
the files `spec/*_spec.rb`.

* The line numbers in the RSpec error report will
give you guidance as to which tests failed. (You can check the [RSpec
documentation](http://rspec.info) to see how the `.rspec` file can be
used to customize the output format.)


To ensure you have the rspec gem installed you need bundler and can then
run bundle install like so:
```sh
$ gem install bundler
$ cd <folder_with_lab_assignment>
$ bundle install
```
When the above completes successfully you'll have RSpec installed and can
run `rspec` from the command line to test your code.

# 1. Arrays, Hashes, and Enumerables

Check the [Ruby documentation](http://ruby-doc.org) 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. :-)

0. Define a method `sum(array)` that takes an array of integers as an argument and returns the sum of its elements. For an empty array it should return zero. Run associated tests via: `$ rspec -e '#sum ' spec/part1_spec.rb` (Make sure you are in the correct directory: `cd assignment` and rspec is installed)

0. Define a method `max_2_sum(array)` which takes an array of integers as an argument and returns the sum of its two largest elements. For an empty array it should return zero. For an array with just one element, it should return that element (Consider if the two largest elements are the same value as well). Run associated tests via: `$ rspec -e '#max_2_sum' spec/part1_spec.rb`

0. Define a method `sum_to_n?(array, n)` that takes an array of integers and an additional integer, n, as arguments and returns true if any two elements in the array of integers sum to n. `sum_to_n?([], n)` should return false for any value of n, by definition. Run associated tests via: `$ rspec -e '#sum_to_n' spec/part1_spec.rb`

You can check your progress on all of the above by running `$ rspec spec/part1_spec.rb`.


# 2. Strings and Regular Expressions

Check the documentation on String and Regexp as they could help tremendously with these exercises. For future reference as well, check out https://rubular.com/ for regex related queries. :-)

0. 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` (Make sure you are in the correct directory: `cd assignment`)

0. 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`

0. 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`

You can check your progress on all of the above by running `$ rspec spec/part2_spec.rb`.


# 3. Object Oriented Basics


Define a class `BookInStock` which represents a book with an ISBN number, `isbn`, and price of the book as a floating-point number, `price`, as attributes. Run associated tests via: `$ rspec -e 'getters and setters' spec/part3_spec.rb` (Make sure you are in the correct directory: `cd assignment`)

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 as second argument, and 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. Include the proper getters and setters for these attributes. Run associated tests via: `$ rspec -e 'constructor' spec/part3_spec.rb`

Include a method `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 spec/part3_spec.rb`.
51 changes: 51 additions & 0 deletions ruby-intro/book-lab/lib/ruby_intro.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# When done, submit this entire file to the autograder.

# Part 1

def sum arr
#Define a method `sum(array)` that takes an array of integers as an argument and returns the sum of its elements. For an empty array it should return zero.
#Run associated tests via: `$ rspec -e '#sum ' spec/part1_spec.rb`
# YOUR CODE HERE
end

def max_2_sum arr
#Define a method `max_2_sum(array)` which takes an array of integers as an argument and returns the sum of its two largest elements. For an empty array it should return zero. For an array with just one element, it should return that element (Consider if the two largest elements are the same value as well).
#Run associated tests via: `$ rspec -e '#max_2_sum' spec/part1_spec.rb`
# YOUR CODE HERE
end

def sum_to_n? arr, n
#Define a method `sum_to_n?(array, n)` that takes an array of integers and an additional integer, n, as arguments and returns true if any two elements in the array of integers sum to n. `sum_to_n?([], n)` should return false for any value of n, by definition.
#Run associated tests via: `$ rspec -e '#sum_to_n' spec/part1_spec.rb`
# YOUR CODE HERE
end

# Part 2

def hello(name)
#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`
# YOUR CODE HERE
end

def starts_with_consonant? s
#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`
# YOUR CODE HERE
end

def binary_multiple_of_4? s
#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`
# YOUR CODE HERE
end

# Part 3

class BookInStock
#Define a class `BookInStock` which represents a book with an ISBN number, `isbn`, and price of the book as a floating-point number, `price`, as attributes.
#Run associated tests via: `$ rspec -e 'getters and setters' spec/part3_spec.rb` (Make sure you are in the correct directory: `cd assignment`)
#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 as second argument, and 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. Include the proper getters and setters for these attributes. Run associated tests via: `$ rspec -e 'constructor' spec/part3_spec.rb`
#Include a method `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`
# YOUR CODE HERE
end
92 changes: 92 additions & 0 deletions ruby-intro/book-lab/lib/ruby_intro_solutions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Part 1

def sum arr
sum = 0
if arr.length == 0
return sum
else
arr.each do |item|
sum += item
end
return sum
end
end

def max_2_sum arr
if arr.length == 0
return 0
elsif arr.length == 1
return arr[0]
else
max1 = arr[0] #greater
max2 = arr[1]
if max1 < max2
max1, max2 = max2, max1
end
(2...arr.length).each do |index|
if arr[index] > max1
max2, max1 = max1, arr[index]
elsif arr[index] > max2
max2 = arr[index]
end
end
return max1 + max2
end
end

def sum_to_n? arr, n
if arr.length <= 1
return false
else
(0...arr.length-1).each do |index1|
(index1+1...arr.length).each do |index2|
if arr[index1] + arr[index2] == n
return true
end
end
end
return false
end
end

# Part 2

def hello(name)
return 'Hello, '+name
end

def starts_with_consonant? s
c = s.downcase[0]
if (c =~ /[a-z]/) != nil && c != 'a' && c != 'e' && c != 'i' && c != 'o' && c != 'u'
return true
end
return false
end

def binary_multiple_of_4? s
if s =~ /^([01]+00|0)$/
return true
else
return false
end
end

# Part 3

class BookInStock

def initialize(isbn, price)
if isbn == '' || price <= 0
raise ArgumentError.new()
end
@isbn = isbn
@price = price
end

attr_accessor :isbn, :price

def price_as_string()
"$%0.2f" % [@price]
end

end
65 changes: 65 additions & 0 deletions ruby-intro/book-lab/spec/part1_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# frozen_string_literal: true

require_relative '../lib/ruby_intro.rb'

describe 'Ruby intro part 1' do
describe '#sum' do
it 'should be defined' do
expect { sum([1, 3, 4]) }.not_to raise_error
end

it 'returns correct sum [20 points]', points: 20 do
expect(sum([1, 2, 3, 4, 5])).to be_a_kind_of Integer
expect(sum([1, 2, 3, 4, 5])).to eq(15)
expect(sum([1, 2, 3, 4, -5])).to eq(5)
expect(sum([1, 2, 3, 4, -5, 5, -100])).to eq(-90)
end

it 'works on the empty array [10 points]', points: 10 do
expect { sum([]) }.not_to raise_error
expect(sum([])).to be_zero
end
end

describe '#max_2_sum' do
it 'should be defined' do
expect { max_2_sum([1, 2, 3]) }.not_to raise_error
end
it 'returns the correct sum [7 points]', points: 7 do
expect(max_2_sum([1, 2, 3, 4, 5])).to be_a_kind_of Integer
expect(max_2_sum([1, -2, -3, -4, -5])).to eq(-1)
end
it 'works even if 2 largest values are the same [3 points]', points: 3 do
expect(max_2_sum([1, 2, 3, 3])).to eq(6)
end
it 'returns zero if array is empty [10 points]', points: 10 do
expect(max_2_sum([])).to be_zero
end
it 'returns value of the element if just one element [10 points]', points: 10 do
expect(max_2_sum([3])).to eq(3)
end
end

describe '#sum_to_n' do
it 'should be defined' do
expect { sum_to_n?([1, 2, 3], 4) }.not_to raise_error
end
it 'returns true when any two elements sum to the second argument [30 points]', points: 30 do
expect(sum_to_n?([1, 2, 3, 4, 5], 5)).to be true # 2 + 3 = 5
expect(sum_to_n?([3, 0, 5], 5)).to be true # 0 + 5 = 5
expect(sum_to_n?([-1, -2, 3, 4, 5, -8], -3)).to be true # handles negative sum
expect(sum_to_n?([-1, -2, 3, 4, 5, -8], 12)).to be false # 3 + 4 + 5 = 12 (not 3 elements)
expect(sum_to_n?([-1, -2, 3, 4, 6, -8], 12)).to be false # no two elements that sum
end
it 'returns false for any single element array [5 points]', points: 5 do
expect(sum_to_n?([0], 0)).to be false
expect(sum_to_n?([1], 1)).to be false
expect(sum_to_n?([-1], -1)).to be false
expect(sum_to_n?([-3], 0)).to be false
end
it 'returns false for an empty array [5 points]', points: 5 do
expect(sum_to_n?([], 0)).to be false
expect(sum_to_n?([], 7)).to be false
end
end
end
Loading

0 comments on commit 405b991

Please sign in to comment.