Ruby TDD - RSpec, Arrays, Expectations

Question Click to View Answer
describe "#has_string?" do
  it "returns true if self has a string" do
    arr = [:bob, "the", 42]
    expect(arr.has_string?).to eq true
  end

  it "returns false if self doesn't have a string" do
    arr = [:shut, :em, :down]
    expect(arr.has_string?).to eq false
  end
end
class Array
  def has_string?
    self.any? {|e| e.instance_of?(String)}
  end
end
describe "#sort_by_length" do
  it "orders words from smallest to largest" do
    arr = %w|this is the story of a girl|
    expected = %w|a is of the this girl story|
    expect(arr.sort_by_length).to eq expected
  end
end
class Array
  def sort_by_length
    self.sort {|x, y| x.length <=> y.length}
  end
end
describe "#mean" do
  it "calculates average" do
    arr = [1, 2, 3, 4]
    expect(arr.mean).to eq 2.5
  end
end
class Array
  def mean
    self.inject(&:+).to_f / self.length
  end
end
describe "#unzip" do
  it "deconstructs nested array" do
    nums = [1, 2, 3]
    lets = %w|a b c|
    zipped = nums.zip(lets)
    expected = [["a", "b", "c"], [1, 2, 3]]
    expect(zipped.unzip).to eq expected
  end
end
class Array
  def unzip
    self.inject([[], []]) do |m, (l, n)|
      m[0] << n
      m[1] << l
      m
    end
  end
end
describe "#hashify" do
  it "converts to hash" do
    arr = [:a, :b, :c, :d]
    expected = {a: :b, c: :d}
    expect(arr.hashify).to eq expected
  end
end
class Array
  def hashify
    Hash[*self]
  end
end
describe "#super_compact" do
  it "removes nil and empty elements" do
    arr = [:bob, "", nil, [], "joe"]
    expected = [:bob, "joe"]
    expect(arr.super_compact).to eq expected
  end
end
class Array
  def super_compact
    self.reject do |e|
      e.nil? || e.empty?
    end
  end
end
describe "#tight_zip" do
  it "zips arrays of unequal length" do
    a = [1, 2, 3, 4]
    b = %w|a b|
    expected = [1, "a", 2, "b", 3, 4]
    expect(a.tight_zip(b)).to eq expected
  end
end
class Array
  def tight_zip(arr)
    self.zip(arr).flatten.compact
  end
end
describe "#mode" do
  it "returns most common element" do
    arr = %w|a b dog a b b|
    expect(arr.mode).to eq "b"
  end
end
class Array
  def mode
    freq = inject(Hash.new(0)) do |m,v|
      m[v] += 1
      m
    end
    sort do |x, y|
      freq[x] <=> freq[y]
    end.last
  end
end
describe "#first_duplicate" do
  it "returns first duplicate in an array" do
    arr = %w|b c d c a a a|
    expect(arr.first_duplicate).to eq "c"
  end
end
class Array
  def first_duplicate
    find {|e| count(e) > 1}
  end
end
describe "#symbolize" do
  it "creates an array of symbols" do
    arr = %w|b c d c a|
    expected = [:b, :c, :d, :c, :a]
    expect(arr.symbolize).to eq expected
  end
end
class Array
  def symbolize
    map(&:to_sym)
  end
end
describe "#index_of_max" do
  it "returns index of largest array element" do
    arr = [1, 99, 10, 104, 5]
    expect(arr.index_of_max).to eq 3
  end
end
class Array
  def index_of_max
    index(self.max)
  end
end
describe "#merge" do
  it "converts array of hashes to a hash" do
    arr = [
      { a: 1, b: 2 },
      { a: 3, b: 24, c: 4 }
    ]
    expected = {
      a: [1, 3],
      b: [2, 24],
      c: [4]
    }
    expect(arr.merge).to eq expected
  end
end
class Array
  def merge
    inject({}) do |memo, hash|
      hash.each do |k, v|
        (memo[k] ||= []) << v
      end
      memo
    end
  end
end
describe "#merge_overlapping_ranges" do
  it "consolidates overlapping ranges" do
    ranges = [(1..2), (3..6), (5..8)]
    expected = [(1..2), (3..8)]
    expect(ranges.merge_overlapping_ranges).to eq expected
  end
end
class Array
  def merge_overlapping_ranges
    self.sort_by(&:begin).inject([]) do |memo, range|
      if !memo.empty? && ranges_overlap?(memo.last, range)
        memo[0...-1] + [merge_ranges(memo.last, range)]
      else
        memo + [range]
      end
    end
  end

  private

  def ranges_overlap?(a, b)
    a.include?(b.begin) || b.include?(a.begin)
  end

  def merge_ranges(a, b)
    [a.begin, b.begin].min..[a.end, b.end].max
  end
end