Ruby

There are many languages used to generate dynamic web content. We’re going to start with Ruby on Rails. In order to break up the long evening, we’re going to do some Ruby for a while.

class Stats

  # constructor is named "initialize"
  def initialize

    # instance variables begin with "@"
    @values = [] # create an empty array
    @sum = 0
    @sum_sq = 0
  end

  # Notice that parameters don't need a type
  def add(value)
    @values << value
    @sum += value
    @sum_sq += value * value
  end

  def mean
    # value of last expression becomes return value for the method
    @sum.to_f / @values.count # to_f is "to float"
  end

  def median
    sorted_values = @values.sort
    mid = @values.count / 2

    # notice that the if statement takes the value of the
    # last line of the block that is run
    if (@values.count % 2 == 0)
      (@values[mid] + @values[mid - 1]) / 2.0
    else
      @values[mid]
    end
  end # method median
end # class Stats

s1 = Stats.new
s1.add(8)
s1.add(6)
s1.add(7)

puts "Mean is #{s1.mean}.  Median: #{s1.median}"

s1.add(5)
puts "Mean is #{s1.mean}.  Median: #{s1.median}"

Code blocks

filter(students) do |s|
   s[:gpa] > 3.0
end

filter(students) do |s|
    # You can't be on probation until 
    #you have completed 30 hours.
    if s[:credit_hours] < 30
      false
    elsif s[:credit_hours] < 60
      s[:gpa] < 2.0
    elsif s[:credit_hours] < 90
      s[:gpa] < 2.25
    else
      s[:gpa] < 2.5
    end
end
def sum_list(numbers)
  sum = 0
  numbers.each do |num|
    sum += num
  sum  # <---- yes, this is common in Ruby
end 

def is_increasing(numbers)
  numbers.each_with_index do |num, index|
    if index > 0 && num < numbers[index - 1]
      return false
    end
  end 
  true
end

def is_increasing_v2(numbers)
  numbers.each_with_index do |num, index|
    return false if index > 0 && num < numbers[index - 1]
  end 
  true
end

# Ruby has an insane number of "convenience method" built-in!
def is_increasing(numbers)
  numbers.each_cons(2) do |a, b|
    return false if a >= b
  end
  true
end

def filter(list)
  answer = []
  list.each { |item| answer << item if yield(item) }
  answer
end

#
# Again, there is an even more ruby-like way to do this:
#
def filter2(list)
  # "inject" is often called "reduce" in other languages.
  list.inject([]) do |accumulator, item|
    accumulator << item if yield(item)
    accumulator
end
def selection_sort(list)
  n = list.length
  (0...n).each do |i|
    min_index = i

    # Find the minimum element in the unsorted portion
    (i + 1...n).each do |j|
      min_index = j if yield list[j], list[min_index]
    end

    # Swap the found minimum element with the first element of the unsorted portion
    list[i], list[min_index] = list[min_index], list[i] unless i == min_index
  end
  list
end

# Sorted low to high
p selection_sort([8, 6, 7, 5, 3, 0, 9]) { |a, b| a < b}

# Sorted high to low
p selection_sort([8, 6, 7, 5, 3, 0, 9]) { |a, b| a > b}

# Sort dogs by age
dog1 = {name: 'Fido', age: 14, weight: 6}
dog2 = {name: 'Spot', age: 4, weight: 12}
dog3 = {name: 'Rover', age: 12, weight: 22}

p selection_sort([dog1, dog2, dog3]) {|a, b| a[:age] < b[:age]}
array = [1, 2, 3, 4, 5, 6, 7]
squared = array.map { |i| i * i }
p squared

names = [
  { first: 'George', last: 'Washington' },
  { first: 'John', last: 'Adams' },
  { first: 'Thomas', last: 'Jefferson' },
  { first: 'James', last: 'Madison' },
  { first: 'James', last: 'Monroe' }
]

full_names = names.map { |i| "#{i[:last]}, #{i[:first]}"}
p full_names