diff --git a/00_hello/hello.rb b/00_hello/hello.rb new file mode 100644 index 000000000..4967a31d0 --- /dev/null +++ b/00_hello/hello.rb @@ -0,0 +1,7 @@ +def hello + "Hello!" +end + +def greet(person) + "Hello, #{person}!" +end \ No newline at end of file diff --git a/01_temperature/temperature.rb b/01_temperature/temperature.rb new file mode 100644 index 000000000..55a18e678 --- /dev/null +++ b/01_temperature/temperature.rb @@ -0,0 +1,7 @@ +def ftoc(f) + (f - 32) * 5.0 / 9 +end + +def ctof(c) + (c * 9.0 / 5) + 32 +end \ No newline at end of file diff --git a/02_calculator/calculator.rb b/02_calculator/calculator.rb new file mode 100644 index 000000000..dcdac7c2b --- /dev/null +++ b/02_calculator/calculator.rb @@ -0,0 +1,29 @@ +def add(a, b) + a + b +end + +def subtract(a, b) + a - b +end + +def sum(numbers) + numbers.inject(0) { |sum, number| sum + number } +end + +def multiply(numbers) + numbers.inject(1) { |product, number| product * number } +end + +def power(base, exponent) + base ** exponent +end + +def factorial(number) + raise "Invalid input" if number < 0 + + 1 if number == 0 || number == 1 + + result = 1 + number.downto(1) { |n| result *= n } + result +end \ No newline at end of file diff --git a/02_calculator/calculator_spec.rb b/02_calculator/calculator_spec.rb index fef7e9d00..ee254cab8 100644 --- a/02_calculator/calculator_spec.rb +++ b/02_calculator/calculator_spec.rb @@ -78,22 +78,44 @@ # write tests and code for the following: describe "#multiply" do + it "multiplies two numbers" do + expect(multiply([2, 5])).to eq(10) + expect(multiply([5, 10])).to eq(50) + end - it "multiplies two numbers" - - it "multiplies several numbers" - + it "multiplies several numbers" do + expect(multiply([1, 2, 3])).to eq(6) + expect(multiply([0, 5, 10])).to eq(0) + end end describe "#power" do - it "raises one number to the power of another number" + it "raises one number to the power of another number" do + expect(power(2, 2)).to eq(4) + expect(power(5, 2)).to eq(25) + expect(power(10, 0)).to eq(1) + end end # http://en.wikipedia.org/wiki/Factorial describe "#factorial" do - it "computes the factorial of 0" - it "computes the factorial of 1" - it "computes the factorial of 2" - it "computes the factorial of 5" - it "computes the factorial of 10" + it "computes the factorial of 0" do + expect(factorial(0)).to eq(1) + end + + it "computes the factorial of 1" do + expect(factorial(1)).to eq(1) + end + + it "computes the factorial of 2" do + expect(factorial(2)).to eq(2) + end + + it "computes the factorial of 5" do + expect(factorial(5)).to eq(120) + end + + it "computes the factorial of 10" do + expect(factorial(10)).to eq(3628800) + end end diff --git a/03_simon_says/simon_says.rb b/03_simon_says/simon_says.rb new file mode 100644 index 000000000..139e25aa4 --- /dev/null +++ b/03_simon_says/simon_says.rb @@ -0,0 +1,31 @@ +def echo(phrase) + phrase +end + +def shout(phrase) + phrase.upcase +end + +def repeat(phrase, num_times=2) + output = (" " + phrase) * num_times + output.strip +end + +def start_of_word(word, num_letters) + word[0..(num_letters - 1)] +end + +def first_word(sentence) + sentence.split[0] +end + +def titleize(sentence) + excluded_words = %w(a an the for and nor but or yet so + at around by after along for from of + on to with without over) + + words = sentence.split(" ") + words.map { |word| word.capitalize! unless excluded_words.include?(word) } + words[0].capitalize! + words.join(" ") +end \ No newline at end of file diff --git a/04_pig_latin/pig_latin.rb b/04_pig_latin/pig_latin.rb new file mode 100644 index 000000000..ec8c15e16 --- /dev/null +++ b/04_pig_latin/pig_latin.rb @@ -0,0 +1,66 @@ +def translate(sentence) + words = sentence.split + words = words.map { |word| translate_word(word) } + words = words.map { |word| correct_capitalization(word) } + words.join(" ") +end + +def translate_word(word) + vowels = %w(a e i o u) + ay_sound = "ay" + + # word starts with a vowel + if vowels.include?(word[0]) + return word + ay_sound + end + + # word contains "qu" phoneme + if has_qu_phoneme?(word) + qu_index = word.index(/[Qq]u/) + + # word starts with "qu" + if qu_index == 0 + return word[2..-1] + word[qu_index..qu_index + 1] + ay_sound + else + # "qu" is preceded by another character, check if it's a consonant + if !vowels.include?(word[qu_index - 1]) + return word[qu_index + 2..-1] + word[qu_index - 1..qu_index + 1] + ay_sound + end + end + end + + # word starts with a variable number of consonants (up to 3) + case num_starting_consonants(word) + when 1 + return word[1..-1] + word[0] + ay_sound + when 2 + return word[2..-1] + word[0..1] + ay_sound + when 3 + return word[3..-1] + word[0..2] + ay_sound + end +end + +# check how many consonants the word starts with +def num_starting_consonants(word) + vowels = %w(a e i o u) + count = 0 + + word.downcase.chars.each do |char| + vowels.include?(char) ? break : count += 1 + end + + count +end + +# check if word has the "qu" phoneme +def has_qu_phoneme?(word) + word.downcase[0..2].include?("qu") +end + +def correct_capitalization(word) + if word.downcase != word + return word.downcase.capitalize + else + return word + end +end diff --git a/04_pig_latin/pig_latin_spec.rb b/04_pig_latin/pig_latin_spec.rb index cc659edfd..a204fdc34 100644 --- a/04_pig_latin/pig_latin_spec.rb +++ b/04_pig_latin/pig_latin_spec.rb @@ -68,5 +68,13 @@ # Test-driving bonus: # * write a test asserting that capitalized words are still capitalized (but with a different initial capital letter, of course) # * retain the punctuation from the original phrase + it "ensures that words that were originally capitalized are still capitalized (with a different initial capital letter, of course)" do + s = translate("The Quick Brown Fox") + expect(s).to eq("Ethay Ickquay Ownbray Oxfay") + end + xit "retains the punctuation from the original phrase" do + s = translate("The Good, The Bad, and The Ugly") + expect(s).to eq("Ethay Oodgay, Ethay Adbay, anday Ethay Uglyay") + end end diff --git a/05_silly_blocks/silly_blocks.rb b/05_silly_blocks/silly_blocks.rb new file mode 100644 index 000000000..5a73a3626 --- /dev/null +++ b/05_silly_blocks/silly_blocks.rb @@ -0,0 +1,34 @@ +def reverser + if block_given? + block = yield + if block.split(" ").length > 1 + strings = block.split(" ") + strings.map { |string| string.reverse! } + return strings.join(" ") + else + return block.reverse + end + end +end + +def adder(input=0) + if block_given? + block = yield + + if input == 0 + return block + 1 + else + return input + 5 + end + end +end + +def repeater(num_times=1) + if block_given? + if num_times == 1 + yield + else + num_times.times { yield } + end + end +end \ No newline at end of file diff --git a/06_performance_monitor/performance_monitor.rb b/06_performance_monitor/performance_monitor.rb new file mode 100644 index 000000000..08d290c46 --- /dev/null +++ b/06_performance_monitor/performance_monitor.rb @@ -0,0 +1,10 @@ +def measure(passes = 1) + if block_given? + start_time = Time.now + passes.times { |pass| yield } + return (Time.now - start_time) / passes.to_f + end + + start_time = Time.now + Time.now - start_time +end \ No newline at end of file diff --git a/07_hello_friend/friend.rb b/07_hello_friend/friend.rb new file mode 100644 index 000000000..a020530b2 --- /dev/null +++ b/07_hello_friend/friend.rb @@ -0,0 +1,5 @@ +class Friend + def greeting(person = nil) + person ? "Hello, #{person}!" : "Hello!" + end +end \ No newline at end of file diff --git a/08_book_titles/book.rb b/08_book_titles/book.rb new file mode 100644 index 000000000..126bdc7ed --- /dev/null +++ b/08_book_titles/book.rb @@ -0,0 +1,20 @@ +class Book + attr_accessor :title + + def title + words_always_in_lowercase = %w(the a an and in the of) + + words_in_title = @title.split + words_in_title.each do |word| + if words_always_in_lowercase.include?(word) + next + else + word.capitalize! + end + end + + words_in_title[0].capitalize! + + @title = words_in_title.join(" ") + end +end \ No newline at end of file diff --git a/09_timer/timer.rb b/09_timer/timer.rb new file mode 100644 index 000000000..5013914e9 --- /dev/null +++ b/09_timer/timer.rb @@ -0,0 +1,23 @@ +class Timer + attr_accessor :seconds + + def initialize + @seconds = 0 + end + + def time_string + hours = @seconds / 60 / 60 + minutes = @seconds / 60 % 60 + seconds = @seconds % 60 + + "#{padded(hours)}:#{padded(minutes)}:#{padded(seconds)}" + end + + def padded(number) + if number.to_s.length == 2 + number.to_s + else + "0#{number}" + end + end +end \ No newline at end of file diff --git a/09_timer/timer_spec.rb b/09_timer/timer_spec.rb index 40b33f23f..0ae1dd31f 100644 --- a/09_timer/timer_spec.rb +++ b/09_timer/timer_spec.rb @@ -45,16 +45,16 @@ # Uncomment these specs if you want to test-drive that # method, then call that method from inside of time_string. # - # describe 'padded' do - # it 'pads zero' do - # expect(@timer.padded(0)).to eq('00') - # end - # it 'pads one' do - # expect(@timer.padded(1)).to eq('01') - # end - # it "doesn't pad a two-digit number" do - # expect(@timer.padded(12)).to eq('12') - # end - # end + describe 'padded' do + it 'pads zero' do + expect(@timer.padded(0)).to eq('00') + end + it 'pads one' do + expect(@timer.padded(1)).to eq('01') + end + it "doesn't pad a two-digit number" do + expect(@timer.padded(12)).to eq('12') + end + end end diff --git a/10_temperature_object/temperature.rb b/10_temperature_object/temperature.rb new file mode 100644 index 000000000..68532f31c --- /dev/null +++ b/10_temperature_object/temperature.rb @@ -0,0 +1,54 @@ +class Temperature + @fahrenheit = nil + @celsius = nil + + attr_accessor :celsius, :fahrenheit + + def self.from_celsius(degrees) + temperature = Temperature.new(c: degrees) + end + + def self.from_fahrenheit(degrees) + temperature = Temperature.new(f: degrees) + end + + def initialize(options = {}) + if options.has_key?(:f) + @fahrenheit = options[:f] + elsif options.has_key?(:c) + @celsius = options[:c] + end + end + + def in_fahrenheit + unless @fahrenheit.nil? + @fahrenheit + else + (@celsius * 9.0 / 5) + 32 + end + end + + def in_celsius + unless @celsius.nil? + @celsius + else + (@fahrenheit - 32) * 5.0 / 9 + end + end +end + +class Celsius < Temperature + attr_accessor :celsius + + def initialize(degrees) + @celsius = degrees + end +end + +class Fahrenheit < Temperature + attr_accessor :fahrenheit + + def initialize(degrees) + @fahrenheit = degrees + end +end \ No newline at end of file diff --git a/11_dictionary/dictionary.rb b/11_dictionary/dictionary.rb new file mode 100644 index 000000000..bd95053b9 --- /dev/null +++ b/11_dictionary/dictionary.rb @@ -0,0 +1,40 @@ +class Dictionary + attr_accessor :entries, :keywords + + def initialize + @entries = {} + @keywords = [] + end + + def add(items = {}) + if items.is_a?(String) + @keywords.push(items) + @entries[items] = nil + else + items.each do |key, value| + @entries[key] = value + @keywords.push(key) + end + end + + @keywords.sort! + end + + def include?(keyword) + @keywords.include?(keyword) + end + + def find(word) + output = {} + @keywords.each { |keyword| output[keyword] = @entries[keyword] if keyword.start_with?(word) } + + output + end + + def printable + output = "" + @keywords.each { |keyword| output += "[#{keyword}] \"#{@entries[keyword]}\"\n" } + + output.chomp + end +end diff --git a/12_rpn_calculator/rpn_calculator.rb b/12_rpn_calculator/rpn_calculator.rb new file mode 100644 index 000000000..42d100cda --- /dev/null +++ b/12_rpn_calculator/rpn_calculator.rb @@ -0,0 +1,101 @@ +class RPNCalculator + attr_accessor :expression, :stack + + def initialize + @expression = "" + @stack = [] + end + + def push(operand) + @expression << operand.to_s + " " + end + + def plus + if @expression.empty? + raise "calculator is empty" + else + @expression << "+ " + end + end + + def minus + if @expression.empty? + raise "calculator is empty" + else + @expression << "- " + end + end + + def divide + if @expression.empty? + raise "calculator is empty" + else + @expression << "/ " + end + end + + def times + if @expression.empty? + raise "calculator is empty" + else + @expression << "* " + end + end + + def value + tokens = @expression.split + + until tokens.empty? + token = tokens.shift + + unless operator?(token) + @stack.push(token) + else + second_operand = @stack.pop.to_f + first_operand = @stack.pop.to_f + result = nil + + case token + when "+" + result = first_operand + second_operand + when "-" + result = first_operand - second_operand + when "/" + result = first_operand / second_operand + when "*" + result = first_operand * second_operand + end + + @stack.push(result) + end + end + + return @stack.last + end + + def tokens(string) + tokens = string.split + result = [] + + tokens.each do |token| + if operator?(token) + result << token.to_sym + else + result << token.to_f + end + end + + result + end + + def evaluate(string) + calc = RPNCalculator.new + calc.expression = string + calc.value + end + + def operator?(value) + operators = %w(+ - / *) + operators.include?(value) + end +end diff --git a/13_xml_document/xml_document.rb b/13_xml_document/xml_document.rb new file mode 100644 index 000000000..db22274a8 --- /dev/null +++ b/13_xml_document/xml_document.rb @@ -0,0 +1,53 @@ +class XmlDocument + attr_accessor :content + + def initialize(to_indent = false) + @to_indent = to_indent + @content = "" + end + + def send(tag_name, options = {}, &block) + block_content = "" + attributes = "" + + # handle block if a block is provided + # block_content = yield if block_given? + if block_given? + block_content = yield + end + + # build attributes string + unless options.empty? + options.each do |key, value| + attributes += "#{key}='#{value}' " + end + + attributes.rstrip! + end + + # no block and no attributes provided + if block_content.empty? && attributes.empty? + return "<#{tag_name}/>" + end + + # block provided, with no attributes + if !block_content.empty? && attributes.empty? + return "<#{tag_name}>#{block_content}" + end + + # no block provided, but attributes provided + if block_content.empty? && !attributes.empty? + return "<#{tag_name} #{attributes}/>" + end + + # both block and attributes provided + if !block_content.empty? && !attributes.empty? + return "<#{tag_name} #{attributes}>#{block_content}" + end + end + + def method_missing(symbol, options = {}, &block) + @content = send(symbol, options, &block) + end + +end diff --git a/14_array_extensions/array_extensions.rb b/14_array_extensions/array_extensions.rb new file mode 100644 index 000000000..b603fb9d6 --- /dev/null +++ b/14_array_extensions/array_extensions.rb @@ -0,0 +1,23 @@ +class Array + def sum + return 0 if self.size == 0 + + total = 0 + self.each { |element| total += element } + + total + end + + def square + return self if self.size == 0 + + squares = [] + self.each { |element| squares.push(element ** 2) } + + squares + end + + def square! + self.map! { |element| element ** 2} + end +end \ No newline at end of file diff --git a/15_in_words/in_words.rb b/15_in_words/in_words.rb new file mode 100644 index 000000000..86fb87bdc --- /dev/null +++ b/15_in_words/in_words.rb @@ -0,0 +1,61 @@ +class Fixnum + def in_words + number_to_word = { + 0 => "zero", + 1 => "one", + 2 => "two", + 3 => "three", + 4 => "four", + 5 => "five", + 6 => "six", + 7 => "seven", + 8 => "eight", + 9 => "nine", + 10 => "ten", + 11 => "eleven", + 12 => "twelve", + 13 => "thirteen", + 14 => "fourteen", + 15 => "fifteen", + 16 => "sixteen", + 17 => "seventeen", + 18 => "eighteen", + 19 => "nineteen", + 20 => "twenty", + 30 => "thirty", + 40 => "forty", + 50 => "fifty", + 60 => "sixty", + 70 => "seventy", + 80 => "eighty", + 90 => "ninety", + 100 => "hundred", + 1000 => "thousand", + 1_000_000 => "million" + } + + # determine length of number + length = self.to_s.length + + # number within 0 to 20 + # or a multiple of 10 within 20 to 90 + if (0..20).include?(self) || (length == 2 && self % 10 == 0) + return number_to_word[self] + end + + # 2-digit number that does not fit the above case + if length == 2 + tens = self / 10 * 10 + ones = self % 10 + return "#{number_to_word[tens]} #{number_to_word[ones]}" + end + + # 3-digit number and a multiple of 100 + if (length == 3 && self % 100 == 0) + hundreds = self / 100 + return "#{number_to_word[hundreds]} hundred" + end + + + end +end