diff --git a/00_hello/hello.rb b/00_hello/hello.rb new file mode 100644 index 000000000..a45b057c7 --- /dev/null +++ b/00_hello/hello.rb @@ -0,0 +1,9 @@ +# /00_hello/hello.rb + +def hello + "Hello!" +end + +def greet(who) + "Hello, #{who}!" +end \ No newline at end of file diff --git a/00_hello/hello_spec.rb b/00_hello/hello_spec.rb old mode 100644 new mode 100755 diff --git a/01_temperature/temperature.rb b/01_temperature/temperature.rb new file mode 100644 index 000000000..a07393316 --- /dev/null +++ b/01_temperature/temperature.rb @@ -0,0 +1,9 @@ +# /01_temperature/temperature.rb + +def ftoc(f) + (f.to_f - 32) * (5.0 / 9.0) # convert to float and apply formula +end + +def ctof(c) + c.to_f * (9.0 / 5.0) + 32 # convert to float and apply formula +end \ No newline at end of file diff --git a/01_temperature/temperature_spec.rb b/01_temperature/temperature_spec.rb old mode 100644 new mode 100755 diff --git a/02_calculator/calculator.rb b/02_calculator/calculator.rb new file mode 100644 index 000000000..c47c375a2 --- /dev/null +++ b/02_calculator/calculator.rb @@ -0,0 +1,29 @@ +# 02_calculator/calculator.rb + +def add(x, y) + x + y +end + +def subtract(x, y) + x - y +end + +def sum(arr) + arr.inject(0) { |sum, num| sum + num } +end + +def multiply(*nums) + nums.inject(1) { |product, num| product * num } +end + +def power(base, exp) + base ** exp +end + +def factorial(n) + if n == 0 + 1 + else + n * factorial(n-1) + end +end \ No newline at end of file diff --git a/02_calculator/calculator_spec.rb b/02_calculator/calculator_spec.rb old mode 100644 new mode 100755 index 7d94327f0..e05144233 --- a/02_calculator/calculator_spec.rb +++ b/02_calculator/calculator_spec.rb @@ -79,21 +79,41 @@ describe "#multiply" do - it "multiplies two numbers" + it "multiplies two numbers" do + multiply(0, 0).should == 0 + end - it "multiplies several numbers" + it "multiplies several numbers" do + multiply(5, 4, 3, 2, 1).should == 120 + 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 + power(2, 8).should == 256 + 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 + factorial(0).should == 1 + end + + it "computes the factorial of 1" do + factorial(1).should == 1 + end + + it "computes the factorial of 2" do + factorial(2).should == 2 + end + + it "computes the factorial of 5" do + factorial(5).should == 120 + end + + it "computes the factorial of 10" do + factorial(10).should == 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..be3918226 --- /dev/null +++ b/03_simon_says/simon_says.rb @@ -0,0 +1,32 @@ +# /03_simon_says/simon_says.rb + +def echo(words) # should return the input + words +end + +def shout(words) # should return the input in all caps + words.upcase +end + +def repeat(words, n = 2) # 1 arg should repeat input twice, else repeat n times + x = (words + " ") * n + x.rstrip # return the string with the last space stripped +end + +def start_of_word(word, n) # should return the first n letters of word + word[0..(n-1)] +end + +def first_word(str) # should return the first word in a string + str.slice(/^\w+/) +end + +def titleize(str) # should return string with the first word and all subsequent non-little words capitalized + title = str.split + title[0].capitalize! + little_words = [ "a", "an", "and", "at", "but", "by", "for", "in", "nor", "of", "on", "or", "so", "the", "to", "up", "yet", "over"] # according to Associated Press style. I added 'over' because it is in the test - but in this case not-so-little words like 'between' should also remain lowercase + title.each do |word| + word.capitalize! unless little_words.include?(word) + end + title.join(" ") +end diff --git a/03_simon_says/simon_says_spec.rb b/03_simon_says/simon_says_spec.rb old mode 100644 new mode 100755 diff --git a/04_pig_latin/pig_latin.rb b/04_pig_latin/pig_latin.rb new file mode 100644 index 000000000..3ea2c0145 --- /dev/null +++ b/04_pig_latin/pig_latin.rb @@ -0,0 +1,57 @@ +# /04_pig_latin/pig_latin.rb + +def translate(str) + # check if capitalized + def is_capitalized? + return true if self == self.capitalize + end + + # check if punctuated + def is_punctuated? + return true if self[self.length-1] =~ /[\.|,|?|!]/ + end + + # where the magic happens + def pig(word) + # check if original is capitalized, downcase! and remember for later + if word.is_capitalized? + word.downcase! + was_capitalized = true + end + # check if original is punctuated, chop it off and save it for later + if word.is_punctuated? + punctuation = word.slice!(-1) + was_punctuated = true + end + + # check if there are non-vowel chars at the beginning + if word.slice(/^[^aeiouy]+/) == nil + first_consonants = Array.new + elsif word.slice(/^[^aeiouy]+/)[-1] == "q" # special case, 'qu' + first_consonants = word.slice(/^[^aeioy]+/) + else first_consonants = word.slice(/^[^aeiouy]+/) + end + + # if no consonants, add "ay ", else apply pig latin formula + if first_consonants.empty? + pigword = word + "ay " + else + pigword = word[/[^#{first_consonants}]+/] + first_consonants + "ay " + end + + # re-capitalize + if was_capitalized + pigword.capitalize! + end + # re-punctuate + if was_punctuated + pigword.insert(-2, punctuation) + end + return pigword + end + + # pigify each word in the input string, rstrip the last space + str.split.inject("") do |translated, word| + translated + pig(word) + end.rstrip +end \ No newline at end of file diff --git a/04_pig_latin/pig_latin_spec.rb b/04_pig_latin/pig_latin_spec.rb old mode 100644 new mode 100755 index 86328f2a4..15606091d --- a/04_pig_latin/pig_latin_spec.rb +++ b/04_pig_latin/pig_latin_spec.rb @@ -69,4 +69,14 @@ # * 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 "keeps word capitalization" do + s = translate("My name is Patrick") + s.should == "Ymay amenay isay Atrickpay" + end + + it "retains punctuation from the original phrase" do + s = translate("an exclamation!") + s. should == "anay exclamationay!" + end + end diff --git a/05_silly_blocks/silly_blocks.rb b/05_silly_blocks/silly_blocks.rb new file mode 100644 index 000000000..7fee217d0 --- /dev/null +++ b/05_silly_blocks/silly_blocks.rb @@ -0,0 +1,20 @@ +# /05_silly_blocks/silly_blocks.rb + +# returns the input block with each word reversed +def reverser + words = yield + words.split.map {|word| word.reverse}.join(" ") # figured out that map yield the result as an array. +end + +# default of 1, adds n to input block +def adder(n = 1) + num = yield + num += n +end + +# default argument of 1, repeats the bock n times +def repeater(n = 1) + n.times do + yield + end +end \ No newline at end of file diff --git a/05_silly_blocks/silly_blocks_spec.rb b/05_silly_blocks/silly_blocks_spec.rb old mode 100644 new mode 100755 index 6a34b2cff..88da6ab1e --- a/05_silly_blocks/silly_blocks_spec.rb +++ b/05_silly_blocks/silly_blocks_spec.rb @@ -6,7 +6,7 @@ # * loops # -require "silly_blocks" +require_relative "silly_blocks" describe "some silly block functions" do @@ -14,7 +14,7 @@ it "reverses the string returned by the default block" do result = reverser do "hello" - end + end result.should == "olleh" end diff --git a/06_performance_monitor/performance_monitor.rb b/06_performance_monitor/performance_monitor.rb new file mode 100644 index 000000000..a52ae7648 --- /dev/null +++ b/06_performance_monitor/performance_monitor.rb @@ -0,0 +1,14 @@ +# /06_performance_monitor/performance_monitor.rb + +require "time" + +# measure average time to execute block n times with a default n of 1 +def measure(n = 1) + run_times = Array.new + n.times do + start_time = Time.now + yield + run_times << (Time.now - start_time) + end + run_times.inject(0.0) {|sum, num| sum + num } / run_times.length.to_f +end \ No newline at end of file diff --git a/06_performance_monitor/performance_monitor_spec.rb b/06_performance_monitor/performance_monitor_spec.rb old mode 100644 new mode 100755 index 04820d4f7..a6da043c5 --- a/06_performance_monitor/performance_monitor_spec.rb +++ b/06_performance_monitor/performance_monitor_spec.rb @@ -8,7 +8,7 @@ # # This is (a stripped down version of) an actual useful concept: a function that runs a block of code and then tells you how long it took to run. -require "performance_monitor" +require_relative "performance_monitor" require "time" # loads up the Time.parse method -- do NOT create time.rb! diff --git a/07_hello_friend/friend.rb b/07_hello_friend/friend.rb new file mode 100644 index 000000000..4a4588254 --- /dev/null +++ b/07_hello_friend/friend.rb @@ -0,0 +1,11 @@ +# /06_hello_friend/friend.rb + +class Friend + def greeting(who = nil) + if who == nil + "Hello!" + else + "Hello, #{who}!" + end + end +end \ No newline at end of file diff --git a/07_hello_friend/hello_friend_spec.rb b/07_hello_friend/hello_friend_spec.rb old mode 100644 new mode 100755 index 29b25730f..1c1800a25 --- a/07_hello_friend/hello_friend_spec.rb +++ b/07_hello_friend/hello_friend_spec.rb @@ -88,7 +88,7 @@ # # -require "friend" +require_relative "friend" describe Friend do it "says hello" do diff --git a/08_temperature_object/temperature.rb b/08_temperature_object/temperature.rb new file mode 100644 index 000000000..86ae5d4ce --- /dev/null +++ b/08_temperature_object/temperature.rb @@ -0,0 +1,47 @@ +# /08_temperature_object/temperature.rb +# fails when trying to call the methods from_celsius and from_fahrenheit because no object is initialized to access in_x +# from_x methods need to build the class, is that what 'Factory Method' means? + +# why can't Celsius.new(50) call .from_celsius(50) and work?! + +class Temperature + attr_accessor :in_celsius, :in_fahrenheit + def initialize(options = {}) + if options[:c] + @in_celsius = options[:c] + @in_fahrenheit = Temperature.ctof(options[:c]) + elsif options[:f] + @in_celsius = Temperature.ftoc(options[:f]) + @in_fahrenheit = options[:f] + end + end + + def self.from_celsius(temp) + Temperature.new(:c => temp) + end + + def self.from_fahrenheit(temp) + Temperature.new(:f => temp) + end + + def self.ctof(temp) + temp.to_f * (9.0 / 5.0) + 32.0 + end + + def self.ftoc(temp) + (temp.to_f - 32.0) * (5.0 / 9.0) + end +end + +# I had to look this up after struggling for a very long time +class Celsius < Temperature + def initialize(temp) + super(:c => temp) + end +end + +class Fahrenheit < Temperature + def initialize(temp) + super(:f => temp) + end +end \ No newline at end of file diff --git a/08_temperature_object/temperature_object_spec.rb b/08_temperature_object/temperature_object_spec.rb old mode 100644 new mode 100755 index 5e6e3bec9..ac48a747f --- a/08_temperature_object/temperature_object_spec.rb +++ b/08_temperature_object/temperature_object_spec.rb @@ -17,7 +17,7 @@ # # -require "temperature" +require_relative "temperature" describe Temperature do @@ -98,6 +98,11 @@ # describe "utility class methods" do + it "converts using ftoc and ctof" do + Temperature.ftoc(32).should == 0 + Temperature.ctof(37).should be_within(0.1).of(98.6) + end + end # Here's another way to solve the problem! diff --git a/09_book_titles/book.rb b/09_book_titles/book.rb new file mode 100644 index 000000000..286e2ca93 --- /dev/null +++ b/09_book_titles/book.rb @@ -0,0 +1,21 @@ +# /09_book_titles/book.rb + +class Book + attr_accessor :title + def title=(title) + @title = titleize(title) + end + +# titleize should capitalize the first word no matter what +# titleize should capitalize all words except +# articles (the, a, an), conjunctions < four letters (and, but, or), prepositions (at, of, on, in, to, with) + def titleize(title) + leave_lower = ["the", "a", "an", "and", "but", "or", "at", "of", "on", "in", "to", "with"] + + title.capitalize! + + title.split.each do |word| + word.capitalize! unless leave_lower.include?(word) + end.join(" ") + end +end \ No newline at end of file diff --git a/09_book_titles/book_titles_spec.rb b/09_book_titles/book_titles_spec.rb index d7bc9a359..1c4f29264 100644 --- a/09_book_titles/book_titles_spec.rb +++ b/09_book_titles/book_titles_spec.rb @@ -12,7 +12,7 @@ # Book Titles in English obey some strange capitalization rules. For example, "and" is lowercase in "War and Peace". This test attempts to make sense of some of those rules. # -require 'book' +require_relative 'book' describe Book do diff --git a/10_timer/timer.rb b/10_timer/timer.rb new file mode 100644 index 000000000..0cde689df --- /dev/null +++ b/10_timer/timer.rb @@ -0,0 +1,24 @@ +# /10_timer/timer.rb + +class Timer + attr_accessor :seconds + def initialize + @hours = 00 + @mins = 00 + @seconds = 00 + end + + def seconds=(seconds) + @hours = seconds / 3600 + @mins = (seconds % 3600) / 60 + @seconds = (seconds % 3600) % 60 + end + + def time_string + padded(@hours) + ":" + padded(@mins) + ":" + padded(@seconds) + end + + def padded(num) + num.to_s.rjust(2, "0") + end +end \ No newline at end of file diff --git a/10_timer/timer_spec.rb b/10_timer/timer_spec.rb index d1baf90b3..7d10d2a6a 100644 --- a/10_timer/timer_spec.rb +++ b/10_timer/timer_spec.rb @@ -7,7 +7,7 @@ # # # Timer -require 'timer' +require_relative 'timer' describe "Timer" do before(:each) do @@ -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 - # @timer.padded(0).should == '00' - # end - # it 'pads one' do - # @timer.padded(1).should == '01' - # end - # it "doesn't pad a two-digit number" do - # @timer.padded(12).should == '12' - # end - # end + describe 'padded' do + it 'pads zero' do + @timer.padded(0).should == '00' + end + it 'pads one' do + @timer.padded(1).should == '01' + end + it "doesn't pad a two-digit number" do + @timer.padded(12).should == '12' + end + end end diff --git a/11_dictionary/dictionary.rb b/11_dictionary/dictionary.rb new file mode 100644 index 000000000..a4bf9e7e6 --- /dev/null +++ b/11_dictionary/dictionary.rb @@ -0,0 +1,46 @@ +# /11_dictionary/dictionary.rb + +class Dictionary + attr_accessor :entries + def initialize + @entries = Hash.new + end + + def add(entry = {}) + if entry.class != Hash + @entries.merge!({entry => nil}) + else + @entries.merge!(entry) + end + end + + def entries + @entries + end + + def keywords + @entries.keys.sort + end + + def include?(key) + true if @entries.keys.include?(key) + end + + def find(str) + match_key_value_pairs = [] + @entries.each do |key, val| + if key =~ /#{str}/ + match_key_value_pairs << [key, val] + end + end + Hash[match_key_value_pairs] + end + + def printable + defs = "" + @entries.sort.each do |key, val| + defs = defs + "[#{key}] \"#{val}\"\n" + end + defs.chomp + end +end \ No newline at end of file diff --git a/12_rpn_calculator/rpn_calculator.rb b/12_rpn_calculator/rpn_calculator.rb new file mode 100644 index 000000000..37bef14be --- /dev/null +++ b/12_rpn_calculator/rpn_calculator.rb @@ -0,0 +1,85 @@ +# /12_rpn_calculator/rpn_calculator.rb + +# RPNCalculator will implement a stack data structure +# the user will push numbers onto the stack +# when the user calls an operation, it performs it on the preceding numbers +# should be able to tokenize a str, and evaluate it + +class RPNCalculator + + def initialize + @stack = [] + end + + def push(val) + @stack << val + end + + def plus + if @stack.empty? + raise "calculator is empty" + else + @stack << @stack.pop + @stack.pop + end + end + + def minus + if @stack.empty? + raise "calculator is empty" + else + @stack << @stack.pop - @stack.pop + end + end + + def times + if @stack.empty? + raise "calculator is empty" + else + @stack << @stack.pop * @stack.pop + end + end + + def divide + if @stack.empty? + raise "calculator is empty" + else + @stack << @stack.pop.to_f / @stack.pop.to_f + end + end + + def value + @stack[-1] + end + + def tokens(str) + str.split.map do |chr| + if chr =~ /[+\-*\/]/ + chr.to_sym + else + chr.to_i + end + end + end + + def evaluate(str) + operator_tokens = [:+, :-, :*, :/] + eval = tokens(str) + eval.each do |token| + if operator_tokens.include?(token) + case token + when :+ + self.plus + when :- + self.minus + when :* + self.times + when :/ + self.divide + end + else + push(token) + end + end + self.value + end +end \ No newline at end of file diff --git a/13_xml_document/xml_document.rb b/13_xml_document/xml_document.rb new file mode 100644 index 000000000..b68ce1cea --- /dev/null +++ b/13_xml_document/xml_document.rb @@ -0,0 +1,62 @@ +# /13_xml_document/xml_document.rb + +class XmlDocument + def initialize(indent = false) + if indent + @indent = true + @level = 0 + end + end + + def method_missing(method_name, arg = {}) + doc = '' + if block_given? + + if @indent + @level.times {doc = doc + " "} + end + + doc = doc + "<#{method_name}>" + + if @indent + @level += 1 + doc = doc + "\n" + end + + doc = doc + yield + + if @indent + @level -= 1 + print "\n" + @level.times {doc = doc + " "} + end + + doc = doc + "" + + if @indent + doc = doc + "\n" + end + + elsif !arg.empty? + + if @indent + @level.times {doc = doc + " "} + @level += 1 + end + + doc = doc + "<#{method_name} #{arg.keys[0]}='#{arg.values[0]}'/>" + + if @indent + doc = doc + "\n" + @level -= 1 + end + else + if @indent + @level.times {print " "} + end + doc = doc + "<#{method_name}/>" + end + + doc + end +end \ No newline at end of file diff --git a/14_array_extensions/array_extensions.rb b/14_array_extensions/array_extensions.rb new file mode 100644 index 000000000..29366a0aa --- /dev/null +++ b/14_array_extensions/array_extensions.rb @@ -0,0 +1,16 @@ +# /14_array_extensions/array_extensions.rb + +class Array + + def sum + self.inject(0) {|sum, num| sum + num} + end + + def square + self.map {|num| num * num} + end + + def square! + self.map! {|num| num * num} + end +end \ No newline at end of file