From 440397f3a37cd3b65d0123c3f7d5337ed3b0c430 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 21 Jan 2014 19:23:14 -0800 Subject: [PATCH 01/61] answer week 1 questions --- week1/homework/questions.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/week1/homework/questions.txt b/week1/homework/questions.txt index 2257bb9..96b5b20 100644 --- a/week1/homework/questions.txt +++ b/week1/homework/questions.txt @@ -3,13 +3,35 @@ Chapter 3 Classes, Objects, and Variables p.86-90 Strings (Strings section in Chapter 6 Standard Types) 1. What is an object? +A representation of a "thing" in a program. 2. What is a variable? +In ruby, a named pointer to an object. In some other languages, more like a +container for a value. 3. What is the difference between an object and a class? +A class is a representation of a "type of thing" - e.g. the class of all +toasters. An object is a representation of an individual "thing" - e.g. the +toaster in my kitchen. This is not the same as a Platonic Ideal Form vs a Real +Object - ruby objects are not second rate to classes; each is an "instances" of +a class. 4. What is a String? +A sequence of characters. In ruby, an object of the class String. And in ruby, +it is mutable. This still freaks me out and I would like to understand if this +is considered to be a deliberate feature or a side-effect of something. 5. What are three messages that I can send to a string object? Hint: think methods +upcase +kind_of? +sub 6. What are two ways of defining a String literal? Bonus: What is the difference between them? +'single quoted, which has #{no interpration}, except \\\\ renders as \\, +and \\\' renders as \'' + +interpretation='lots of interprations' +"double quoted, which has #{interpretation}" + +%q{wrapped in some arbitrary brace pair, allowing one to embed plenty of +nasties like ', ", and \, without escapes} From e39ea1f1e5d7488d259638e853d04941f5ac87ca Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 21 Jan 2014 20:04:24 -0800 Subject: [PATCH 02/61] passed 1st 2 --- week1/homework/strings_and_rspec_spec.rb | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/week1/homework/strings_and_rspec_spec.rb b/week1/homework/strings_and_rspec_spec.rb index ea79e4c..4d92094 100644 --- a/week1/homework/strings_and_rspec_spec.rb +++ b/week1/homework/strings_and_rspec_spec.rb @@ -12,10 +12,19 @@ before(:all) do @my_string = "Renée is a fun teacher. Ruby is a really cool programming language" end - it "should be able to count the charaters" + it "should be able to count the characters" do + + @my_string.length.should == 66 + end + it "should be able to count the characters rspec style" do + @my_string.should have(66).characters + end it "should be able to split on the . charater" do - pending - result = #do something with @my_string here + #This passes: + # result = ['foo', 'bar'] + # result.should have(2).items + # + result = @my_string.split '.' result.should have(2).items end it "should be able to give the encoding of the string" do From 06a74acb6862c0f77fb5f40079446f8551a11b28 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 21 Jan 2014 20:32:27 -0800 Subject: [PATCH 03/61] pass all week1 rspec --- week1/homework/strings_and_rspec_spec.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/week1/homework/strings_and_rspec_spec.rb b/week1/homework/strings_and_rspec_spec.rb index 4d92094..e765a51 100644 --- a/week1/homework/strings_and_rspec_spec.rb +++ b/week1/homework/strings_and_rspec_spec.rb @@ -20,15 +20,12 @@ @my_string.should have(66).characters end it "should be able to split on the . charater" do - #This passes: - # result = ['foo', 'bar'] - # result.should have(2).items - # result = @my_string.split '.' result.should have(2).items end it "should be able to give the encoding of the string" do - pending 'helpful hint: should eq (Encoding.find("UTF-8"))' + #pending 'helpful hint: should eq (Encoding.find("UTF-8"))' + @my_string.encoding.name.should == 'UTF-8' end end end From 9814036a8251b7fca57ec2cc3eb2d788618ae813 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 21 Jan 2014 20:47:13 -0800 Subject: [PATCH 04/61] week 1 tidy up --- week1/homework/questions.txt | 53 ++++++++++++------------ week1/homework/strings_and_rspec_spec.rb | 2 - 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/week1/homework/questions.txt b/week1/homework/questions.txt index 96b5b20..df64825 100644 --- a/week1/homework/questions.txt +++ b/week1/homework/questions.txt @@ -1,34 +1,33 @@ -Please read: -Chapter 3 Classes, Objects, and Variables -p.86-90 Strings (Strings section in Chapter 6 Standard Types) - -1. What is an object? -A representation of a "thing" in a program. - -2. What is a variable? -In ruby, a named pointer to an object. In some other languages, more like a -container for a value. - -3. What is the difference between an object and a class? -A class is a representation of a "type of thing" - e.g. the class of all -toasters. An object is a representation of an individual "thing" - e.g. the -toaster in my kitchen. This is not the same as a Platonic Ideal Form vs a Real -Object - ruby objects are not second rate to classes; each is an "instances" of -a class. - -4. What is a String? -A sequence of characters. In ruby, an object of the class String. And in ruby, -it is mutable. This still freaks me out and I would like to understand if this -is considered to be a deliberate feature or a side-effect of something. - -5. What are three messages that I can send to a string object? Hint: think methods +Please read: Chapter 3 Classes, Objects, and Variables p.86-90 Strings (Strings +section in Chapter 6 Standard Types) + +1. What is an object? A representation of a "thing" in a program. + +2. What is a variable? In ruby, a named pointer to an object. In some other +languages, more like a container for a value. + +3. What is the difference between an object and a class? A class is a +representation of a "type of thing" - e.g. the class of all toasters. An +object is a representation of an individual "thing" - e.g. the toaster in my +kitchen. This is not the same as a Platonic Ideal Form vs a Real Object - ruby +objects are not second rate to classes; each is a correct "instance" of its +class. + +4. What is a String? A sequence of characters. In ruby, an object of the class +String. And in ruby, it is mutable. This still freaks me out and I would like +to understand if this is considered to be a deliberate feature or a side-effect +of something. + +5. What are three messages that I can send to a string object? Hint: think +methods upcase kind_of? sub -6. What are two ways of defining a String literal? Bonus: What is the difference between them? -'single quoted, which has #{no interpration}, except \\\\ renders as \\, -and \\\' renders as \'' +6. What are two ways of defining a String literal? Bonus: What is the +difference between them? +'single quoted, which has #{no interpration}, except +\\\\ renders as \\, and \\\' renders as \'' interpretation='lots of interprations' "double quoted, which has #{interpretation}" diff --git a/week1/homework/strings_and_rspec_spec.rb b/week1/homework/strings_and_rspec_spec.rb index e765a51..dd150e6 100644 --- a/week1/homework/strings_and_rspec_spec.rb +++ b/week1/homework/strings_and_rspec_spec.rb @@ -13,7 +13,6 @@ @my_string = "Renée is a fun teacher. Ruby is a really cool programming language" end it "should be able to count the characters" do - @my_string.length.should == 66 end it "should be able to count the characters rspec style" do @@ -24,7 +23,6 @@ result.should have(2).items end it "should be able to give the encoding of the string" do - #pending 'helpful hint: should eq (Encoding.find("UTF-8"))' @my_string.encoding.name.should == 'UTF-8' end end From 9b13d01161a94b791f2788c41758c01de519b41a Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 21 Jan 2014 20:50:25 -0800 Subject: [PATCH 05/61] restore questions to original format --- week1/homework/questions.txt | 49 ++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/week1/homework/questions.txt b/week1/homework/questions.txt index df64825..ad7dfa0 100644 --- a/week1/homework/questions.txt +++ b/week1/homework/questions.txt @@ -1,31 +1,32 @@ -Please read: Chapter 3 Classes, Objects, and Variables p.86-90 Strings (Strings -section in Chapter 6 Standard Types) - -1. What is an object? A representation of a "thing" in a program. - -2. What is a variable? In ruby, a named pointer to an object. In some other -languages, more like a container for a value. - -3. What is the difference between an object and a class? A class is a -representation of a "type of thing" - e.g. the class of all toasters. An -object is a representation of an individual "thing" - e.g. the toaster in my -kitchen. This is not the same as a Platonic Ideal Form vs a Real Object - ruby -objects are not second rate to classes; each is a correct "instance" of its -class. - -4. What is a String? A sequence of characters. In ruby, an object of the class -String. And in ruby, it is mutable. This still freaks me out and I would like -to understand if this is considered to be a deliberate feature or a side-effect -of something. - -5. What are three messages that I can send to a string object? Hint: think -methods +Please read: +Chapter 3 Classes, Objects, and Variables +p.86-90 Strings (Strings section in Chapter 6 Standard Types) + +1. What is an object? +A representation of a "thing" in a program. + +2. What is a variable? +In ruby, a named pointer to an object. In some other languages, more like a +container for a value. + +3. What is the difference between an object and a class? +A class is a representation of a "type of thing" - e.g. the class of all +toasters. An object is a representation of an individual "thing" - e.g. the +toaster in my kitchen. This is not the same as a Platonic Ideal Form vs a Real +Object - ruby objects are not second rate to classes; each is a correct +"instance" of its class. + +4. What is a String? +A sequence of characters. In ruby, an object of the class String. And in ruby, +it is mutable. This still freaks me out and I would like to understand if this +is considered to be a deliberate feature or a side-effect of something. + +5. What are three messages that I can send to a string object? Hint: think methods upcase kind_of? sub -6. What are two ways of defining a String literal? Bonus: What is the -difference between them? +6. What are two ways of defining a String literal? Bonus: What is the difference between them? 'single quoted, which has #{no interpration}, except \\\\ renders as \\, and \\\' renders as \'' From bc3e4bfbcb86ee5b7801eac7914c2f5d304d4092 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 21 Jan 2014 21:26:26 -0800 Subject: [PATCH 06/61] answer week2 1 + 2 --- week2/homework/questions.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/week2/homework/questions.txt b/week2/homework/questions.txt index 939e42d..ea29624 100644 --- a/week2/homework/questions.txt +++ b/week2/homework/questions.txt @@ -3,8 +3,18 @@ Containers, Blocks, and Iterators Sharing Functionality: Inheritance, Modules, and Mixins 1. What is the difference between a Hash and an Array? +An array is an ordered list of items (objects in ruby), indexed by sequential +integers starting at 0. +A hash is a set of key=value pairs, indexed by the key. Traditionally it is not +ordered, but the pickaxe book says ruby retains the order items are stored. +Other languages would view this as too costly. Is ruby slower by this? 2. When would you use an Array over a Hash and vice versa? +I would use an array when + order is the best way access or enter the values, or + the data structure has a known number of items +A hash is nice when + a name is the best way to access or enter the values 3. What is a module? Enumerable is a built in Ruby module, what is it? From 24c32c04f6327f12d7bd4e0036b63386b239f68f Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 22 Jan 2014 20:38:35 -0800 Subject: [PATCH 07/61] Answer week2 questions --- week2/homework/questions.txt | 43 ++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/week2/homework/questions.txt b/week2/homework/questions.txt index ea29624..0594909 100644 --- a/week2/homework/questions.txt +++ b/week2/homework/questions.txt @@ -5,9 +5,10 @@ Sharing Functionality: Inheritance, Modules, and Mixins 1. What is the difference between a Hash and an Array? An array is an ordered list of items (objects in ruby), indexed by sequential integers starting at 0. + A hash is a set of key=value pairs, indexed by the key. Traditionally it is not -ordered, but the pickaxe book says ruby retains the order items are stored. -Other languages would view this as too costly. Is ruby slower by this? +ordered, but the pickaxe book says ruby retains the order in which items are +stored. Other languages would view this as too costly. Is ruby slower by this? 2. When would you use an Array over a Hash and vice versa? I would use an array when @@ -17,7 +18,45 @@ A hash is nice when a name is the best way to access or enter the values 3. What is a module? Enumerable is a built in Ruby module, what is it? +A module providing a discrete namespace, so I can "require" multiple source +files (or otherwise work on things too big to hold in my head), and not worry +about namespace collisions, by fully qualifying the module's methods and +constants: +Module1.method(Module3::CONSTANT) +Module2.method(Module4::CONSTANT) + +A module also provides a way to 'include' code in multiple classes, allowing us +to reuse methods and variables without the horror of multiple inheritance. + +Enumerable provides nice generic methods appropriate to arrays and hashes - +map, include? and others. Would inject come from Enumerable? How do I tell? ri +inject gives "Implementation from Enumerable". OK, How do I go the other way? +(ie, what does Enumerable provide?) Yay, it works how I would hope: ri +Enumerable gives in introductory paragraph and a list of methods. 4. Can you inherit more than one thing in Ruby? How could you get around this problem? +You can't inherit from more than one class. My instinct is that this is a +feature, not a problem, but pickaxe assures us that it is a problem, and for it +we need mixins. +In a class, we can include a module and get it's methods. Nice enough. +We can also get its instance variables, which seems to me a way of destroying +all of that good namespace separation. I do not understand the bit in pickaxe +about using a "module-level hash, indexed by the current object ID". +So mixins alarm me at first glance, especially the instance variables. 5. What is the difference between a Module and a Class? +A class is, well, a class... from ri Class: +"first-class objects---each is an instance of class Class". +So they can be sub-classed, and all objects belong to some a class. You can +define methods for them, which are inherited by subclasses and by instances of +the class. + +Modules, according to pickaxe, are not classes, but just provide namespace +(and mixins 'for free'). But, from ri Class: += Class < Module +So Classes are a class of Module? Or do I misread that? + +Anyway, you can define methods and constants for a Module too, but they are +then pulled in to classes and the methods and constants used there. And +instance variable too, but I don't understand how to do that safely. + From 1f25c74d9c3373f7876f3d7768153fa704026c27 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 22 Jan 2014 21:22:52 -0800 Subject: [PATCH 08/61] passed all tests --- week2/homework/simon_says.rb | 26 ++++++++++++++++++++++++++ week2/homework/simon_says_spec.rb | 11 +++++++++++ 2 files changed, 37 insertions(+) create mode 100644 week2/homework/simon_says.rb diff --git a/week2/homework/simon_says.rb b/week2/homework/simon_says.rb new file mode 100644 index 0000000..7c5b148 --- /dev/null +++ b/week2/homework/simon_says.rb @@ -0,0 +1,26 @@ +# vim: ts=2:sw=2 +module SimonSays + def echo(string) + string + end + + def shout(string) + string.upcase + end + + # FIXME ruby, not perl + def repeat(string, nrepeats = 2) + output = ((string + " ")*nrepeats).sub(/ $/, '') + end + + def start_of_word(string, nchars) + string.slice(0..nchars-1) + end + + # FIXME naíve - non-word before first word? Single quoted phrase? + def first_word(string) + string.sub(/[^a-zA-Z'].*/, '') + end +end + + diff --git a/week2/homework/simon_says_spec.rb b/week2/homework/simon_says_spec.rb index 7f329e5..fc307bf 100644 --- a/week2/homework/simon_says_spec.rb +++ b/week2/homework/simon_says_spec.rb @@ -37,6 +37,11 @@ start_of_word("Bob", 2).should == "Bo" end + it "should do something sane with a bad call to start_of_word" do + pending + start_of_word("Bob", 4).should == what? + end + it "should tell us the first word of 'Hello World' is 'Hello'" do first_word("Hello World").should == "Hello" end @@ -44,4 +49,10 @@ it "should tell us the first word of 'oh dear' is 'oh'" do first_word("oh dear").should == "oh" end + + it "should maybe tell us the first word of ' oh dear' is 'oh'" do + pending + first_word(" oh dear").should == "oh" + end end +# vim: ts=2:sw=2 From 70d1757e074224e1c0e0c6fb59667320965de290 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 22 Jan 2014 21:51:26 -0800 Subject: [PATCH 09/61] pass my additional test --- week2/homework/simon_says.rb | 21 ++++++++++++++++----- week2/homework/simon_says_spec.rb | 3 +-- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/week2/homework/simon_says.rb b/week2/homework/simon_says.rb index 7c5b148..89c123e 100644 --- a/week2/homework/simon_says.rb +++ b/week2/homework/simon_says.rb @@ -1,4 +1,3 @@ -# vim: ts=2:sw=2 module SimonSays def echo(string) string @@ -17,10 +16,22 @@ def start_of_word(string, nchars) string.slice(0..nchars-1) end - # FIXME naíve - non-word before first word? Single quoted phrase? def first_word(string) - string.sub(/[^a-zA-Z'].*/, '') + ## This one works, for the tests given... + #string.sub(/[^a-zA-Z'].*/, '') + # + # And this one works on my added test. But it's uglier + #string.sub(/^\W*(\w+)[^a-zA-Z'].*/, '\1') + + ##Is there a more ruby way to do this? + # + #This isn't bad, and seems more ruby-ish. I like it. + #but it breaks on my additional test. + #string.split(/\s+/).first + # + #This works on my additional test. + #But it might be uglier than my perl-ish version. + (string.split(/\s+/).select { |word| word !~ /^\s*$/ }).first end end - - +# vim: ts=2:sw=2 diff --git a/week2/homework/simon_says_spec.rb b/week2/homework/simon_says_spec.rb index fc307bf..1f21e88 100644 --- a/week2/homework/simon_says_spec.rb +++ b/week2/homework/simon_says_spec.rb @@ -37,7 +37,7 @@ start_of_word("Bob", 2).should == "Bo" end - it "should do something sane with a bad call to start_of_word" do + it "should do something sane if word is shorter than we thought" do pending start_of_word("Bob", 4).should == what? end @@ -51,7 +51,6 @@ end it "should maybe tell us the first word of ' oh dear' is 'oh'" do - pending first_word(" oh dear").should == "oh" end end From 9e9cfb0a11190840bbee893e553cf25d11ffc3a6 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 22 Jan 2014 21:52:03 -0800 Subject: [PATCH 10/61] pull vim junk out of homework --- week2/homework/simon_says.rb | 1 - week2/homework/simon_says_spec.rb | 1 - 2 files changed, 2 deletions(-) diff --git a/week2/homework/simon_says.rb b/week2/homework/simon_says.rb index 89c123e..9370aa6 100644 --- a/week2/homework/simon_says.rb +++ b/week2/homework/simon_says.rb @@ -34,4 +34,3 @@ def first_word(string) (string.split(/\s+/).select { |word| word !~ /^\s*$/ }).first end end -# vim: ts=2:sw=2 diff --git a/week2/homework/simon_says_spec.rb b/week2/homework/simon_says_spec.rb index 1f21e88..6ae66ce 100644 --- a/week2/homework/simon_says_spec.rb +++ b/week2/homework/simon_says_spec.rb @@ -54,4 +54,3 @@ first_word(" oh dear").should == "oh" end end -# vim: ts=2:sw=2 From c11d1a914b77d431be98d1aa0ec8cf317162aa27 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Thu, 23 Jan 2014 18:19:02 -0800 Subject: [PATCH 11/61] undo my stupid pull --- week1/homework/strings_and_rspec_spec.rb | 1 - week1/ruby_spec.rb | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/week1/homework/strings_and_rspec_spec.rb b/week1/homework/strings_and_rspec_spec.rb index dd150e6..0ad4fe9 100644 --- a/week1/homework/strings_and_rspec_spec.rb +++ b/week1/homework/strings_and_rspec_spec.rb @@ -27,4 +27,3 @@ end end end - diff --git a/week1/ruby_spec.rb b/week1/ruby_spec.rb index 5dbd8a3..85f512b 100644 --- a/week1/ruby_spec.rb +++ b/week1/ruby_spec.rb @@ -1,7 +1,7 @@ -describe "Playing With Ruby! " do - context 'when adding numbers' do - it "should add numbers" do - (2+2).should eq 4 - end - end +describe "Playing With Ruby! " do + context 'when adding numbers' do + it "should add numbers" do + (2+2).should eq 4 + end + end end \ No newline at end of file From 2855e2bf458d9627e50460baa4d358424334495b Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 28 Jan 2014 11:45:30 -0800 Subject: [PATCH 12/61] answer 1, 2, 5 --- week3/homework/questions.txt | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/week3/homework/questions.txt b/week3/homework/questions.txt index dfb158d..56c8106 100644 --- a/week3/homework/questions.txt +++ b/week3/homework/questions.txt @@ -5,11 +5,42 @@ Please Read: - Chapter 22 The Ruby Language: basic types (symbols), variables and constants 1. What is a symbol? +An immutable string of characters. It seems like we've seen them mostly for +hash keys (which is a reasonable use), but I am inclined to want to use them +somehow to replace ruby's missing constants. Is that possible, or advisable? 2. What is the difference between a symbol and a string? +> "foo".methods.sort - :foo.methods.sort +Lots of bang methods. Why can't I sub a symbol? I can upcase it. Hm. + +> :foo.methods.sort - "foo".methods.sort +=> [:id2name, :to_proc] + +Well, mostly that I can't change a symbol, I think. But it is missing a few +methods, too. 3. What is a block and how do I call a block? 4. How do I pass a block to a method? What is the method signature? 5. Where would you use regular expressions? +All over the place, because I come from shell and perl. In ruby, I can +(should?) use them less, because: + 1. Ruby has a lot more string methods (which are maybe calling regexes under + the hood, but + > string.strip + is a lot more readable and concise than + > string.gsub(/^\s*|\s*$/, "") + 2. Things that I "shouldn't" have been doing with regexes (like parsing html, + or otherwise using them for syntax) are probably easier done with all of + ruby's endless builtins and gems. + 3. Well, that's about it, but that's plenty. + +But then again, + > "foot".sub("fo") {|subbed| "Wo" if subbed.end_with? "o" } + OMG, OMG, OMG! Passing substitutions to blocks! I could fall in love with + regexes all over again! + +Anyway, the formal answer is: wherever I need to make string matches or +substitutions which are not syntax- or context-sensitive, and there is no +builtin for the task. From e5334539ace5c41d412aff6909b893ea6b21b1a1 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 28 Jan 2014 12:08:51 -0800 Subject: [PATCH 13/61] pass addition tests, multiply array test. --- week3/homework/calculator.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 week3/homework/calculator.rb diff --git a/week3/homework/calculator.rb b/week3/homework/calculator.rb new file mode 100644 index 0000000..6a3780a --- /dev/null +++ b/week3/homework/calculator.rb @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby + +class Calculator + def initialize + end + + def sum(addends) + addends.inject(0, :+) + end + + def multiply(multiplicands) + multiplicands.inject(1, :*) + end +end + + From 21627f7c4277b70ddab0302b6d882679caa26f8e Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 28 Jan 2014 12:49:40 -0800 Subject: [PATCH 14/61] pass multiplication --- week3/homework/calculator.rb | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/week3/homework/calculator.rb b/week3/homework/calculator.rb index 6a3780a..c081f63 100644 --- a/week3/homework/calculator.rb +++ b/week3/homework/calculator.rb @@ -8,9 +8,25 @@ def sum(addends) addends.inject(0, :+) end - def multiply(multiplicands) - multiplicands.inject(1, :*) + def multiply(multiplicands, multiplier = 1) + # Looks gross to me. What I want is to flatten all incoming arguments + # to one array. + (Array(multiplicands) + Array(multiplier)).inject(1, :*) end + + def pow(base, index) +# p = 1 +# # This returns index, +# index.times { p *= base } +# # so I have to return p +# p +# # instead, let's try the builtin + base**index + end + + def fac(integer) + end + end From c2d2c2eb1c85128a7908294b20fa307c9ad9359b Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 28 Jan 2014 16:00:25 -0800 Subject: [PATCH 15/61] week 3 all tests passed --- week3/homework/calculator.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/week3/homework/calculator.rb b/week3/homework/calculator.rb index c081f63..8b97584 100644 --- a/week3/homework/calculator.rb +++ b/week3/homework/calculator.rb @@ -25,6 +25,14 @@ def pow(base, index) end def fac(integer) + case integer + when 0 + 1 + when 1 + 1 + else + integer * fac(integer - 1) + end end end From 3b81ac480d9649e73bedb10a36bca6eb17458f74 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 28 Jan 2014 16:06:02 -0800 Subject: [PATCH 16/61] tidy up and comment calculator.rb --- week3/homework/calculator.rb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/week3/homework/calculator.rb b/week3/homework/calculator.rb index 8b97584..ab8c4b7 100644 --- a/week3/homework/calculator.rb +++ b/week3/homework/calculator.rb @@ -9,22 +9,27 @@ def sum(addends) end def multiply(multiplicands, multiplier = 1) - # Looks gross to me. What I want is to flatten all incoming arguments - # to one array. + # This looks gross and repetitive to me. What I want is + # to flatten all incoming arguments to one array. How + # do I do that? (Array(multiplicands) + Array(multiplier)).inject(1, :*) end def pow(base, index) +# # just mirroring the code in the spec: # p = 1 # # This returns index, # index.times { p *= base } -# # so I have to return p +# # so we must explicitly return p # p -# # instead, let's try the builtin +# # instead, we'll use the builtin. base**index + end def fac(integer) + # I'd like a some error checking for what we were passed + # But, not in the spec. case integer when 0 1 @@ -36,5 +41,3 @@ def fac(integer) end end - - From fd2ed6284829e710cd6957b37eff878c2a21b99b Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 28 Jan 2014 18:24:02 -0800 Subject: [PATCH 17/61] =?UTF-8?q?answer=20week=203=203=20,=20=C2=BD=20of?= =?UTF-8?q?=204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week3/homework/questions.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/week3/homework/questions.txt b/week3/homework/questions.txt index 56c8106..1d80bf1 100644 --- a/week3/homework/questions.txt +++ b/week3/homework/questions.txt @@ -20,8 +20,20 @@ Well, mostly that I can't change a symbol, I think. But it is missing a few methods, too. 3. What is a block and how do I call a block? +In ruby, some code wrapped in braces or do/end. Used like an anonymous method. +Not used immediately, but when called later. (This part I find subtle and +difficult to understand.) Can only appear after another method, so: +> ["foo", "bar", "baz"].each {|metasyntactic_variable_name| puts metasyntactic_variable_name } + +but +> "foo" { |alone| puts alone } +is meaningless and an error. 4. How do I pass a block to a method? What is the method signature? +Just put the block right after the method, as discussed above, with any +items passed to the block placed between pipes at the beginning of the block. +I am not sure if this is a different question than "how do I call a block?". + 5. Where would you use regular expressions? All over the place, because I come from shell and perl. In ruby, I can From af7f0838e501ab415dbe0c4e433417e770589d16 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 28 Jan 2014 21:56:56 -0800 Subject: [PATCH 18/61] refactor week3 calculator homework --- week3/homework/calculator.rb | 34 ++++++++++++++++++++----------- week3/homework/calculator_spec.rb | 10 +++++++++ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/week3/homework/calculator.rb b/week3/homework/calculator.rb index ab8c4b7..836a2a3 100644 --- a/week3/homework/calculator.rb +++ b/week3/homework/calculator.rb @@ -4,15 +4,21 @@ class Calculator def initialize end + # must explicitly 0 the inject for parameter [] to not return nil def sum(addends) addends.inject(0, :+) end - def multiply(multiplicands, multiplier = 1) - # This looks gross and repetitive to me. What I want is - # to flatten all incoming arguments to one array. How - # do I do that? - (Array(multiplicands) + Array(multiplier)).inject(1, :*) + # This looks gross and repetitive to me. (It passes, though.) What I want + # is to flatten all incoming arguments to one array. How do I do that? + # +# def multiply(multiplicands, multiplier = 1) +# (Array(multiplicands) + Array(multiplier)).inject(1, :*) +# end + + # So, we splat out the parameters to a list, then flatten to an array. + def multiply(*multiplicands) + multiplicands.flatten.inject(1, :*) end def pow(base, index) @@ -22,21 +28,25 @@ def pow(base, index) # index.times { p *= base } # # so we must explicitly return p # p -# # instead, we'll use the builtin. +# # more concisely, we'll use the builtin. base**index end - def fac(integer) + def fac(input) # I'd like a some error checking for what we were passed # But, not in the spec. - case integer - when 0 - 1 - when 1 + case input + # Can we combine the first 2 whens? +# when 0 +# 1 +# when 1 +# 1 + # Our Benevolent Dictator Google says Yes, with commas, not pipes + when 0, 1 1 else - integer * fac(integer - 1) + input * fac(input - 1) end end diff --git a/week3/homework/calculator_spec.rb b/week3/homework/calculator_spec.rb index 5a418ed..ded3b42 100644 --- a/week3/homework/calculator_spec.rb +++ b/week3/homework/calculator_spec.rb @@ -31,6 +31,14 @@ @calculator.multiply(2,2).should eq 4 end + it "multiplies an array of length 1 by 1" do + @calculator.multiply([500]).should eq 500 + end + + it "multiplies floats " do + @calculator.multiply([1.1,2]).should eq 2.2 + end + it "multiplies an array of numbers" do @calculator.multiply([2,2]).should eq 4 end @@ -62,6 +70,8 @@ it "computes the factorial of 10" do @calculator.fac(10).should eq 3628800 end + # How do you do error checking? I would like my fac() to complain + # about floats on input, without killing the program. end From e5776f45d353cfbaa01aa42f8f39707de08840db Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 29 Jan 2014 11:53:52 -0800 Subject: [PATCH 19/61] unsatisfactory answer to week 3 question 4 --- week3/homework/questions.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/week3/homework/questions.txt b/week3/homework/questions.txt index 1d80bf1..a0b214c 100644 --- a/week3/homework/questions.txt +++ b/week3/homework/questions.txt @@ -34,6 +34,10 @@ Just put the block right after the method, as discussed above, with any items passed to the block placed between pipes at the beginning of the block. I am not sure if this is a different question than "how do I call a block?". +What is the method signature of what? I don't think I understand what a method +signature is, in any case. Googling around makes me think it is analogous to +a function declaration - a statement of what parameters a method takes. Is it +simply the def line? 5. Where would you use regular expressions? All over the place, because I come from shell and perl. In ruby, I can From 03679d54e22f557a1d347d73d1b4f445dd3bf4e5 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Fri, 31 Jan 2014 16:39:09 -0800 Subject: [PATCH 20/61] answer week4 1,2,4 --- week4/homework/questions.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/week4/homework/questions.txt b/week4/homework/questions.txt index 187b3d3..628957e 100644 --- a/week4/homework/questions.txt +++ b/week4/homework/questions.txt @@ -3,12 +3,30 @@ Chapter 10 Basic Input and Output The Rake Gem: http://rake.rubyforge.org/ 1. How does Ruby read files? +With File IO objects. Practically, you can mostly do +> while line = gets +but there is also explicit +> to_be_read = File.new("readme", "r") +or, more idiomatically +> File.open("readme", "r") { |file| } 2. How would you output "Hello World!" to a file called my_output.txt? +Very casually: +> File.open("my_output.txt", "a"){|file| file.puts "Hello World!"} +Very very casually, and maybe not so portably (though `sokay across *nix and +Windows): +> `echo "Hello World!" >>my_output.txt` 3. What is the Directory class and what is it used for? 4. What is an IO object? +An object representing something outside of your program that you can use as +a sink or source for data. Files, stdin, stdout, stderr, sockets, FIFOs, and +I'm not sure what else would all be represented as IO objects of some sort. +Here is a bit where I am still thinking shell is nicer than ruby, because - +well, see my shell out in question 2. 5. What is rake and what is it used for? What is a rake task? +A replacement for Makefiles, supposedly with cleaner syntax. I'll get back to +you on this one. From 12e31d36d0ced724d0e267018f3b72a988f70a0a Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Fri, 31 Jan 2014 16:48:11 -0800 Subject: [PATCH 21/61] week4 add worker.rb and Makefile --- week4/homework/Makefile | 6 ++++++ week4/homework/worker.rb | 10 ++++++++++ 2 files changed, 16 insertions(+) create mode 100644 week4/homework/Makefile create mode 100644 week4/homework/worker.rb diff --git a/week4/homework/Makefile b/week4/homework/Makefile new file mode 100644 index 0000000..2bb762b --- /dev/null +++ b/week4/homework/Makefile @@ -0,0 +1,6 @@ +PROG = worker +TESTEE = ${PROG}.rb +TESTER = ${PROG}_spec.rb + +test : ${TESTEE} ${TESTER} + rspec -c ${TESTER} diff --git a/week4/homework/worker.rb b/week4/homework/worker.rb new file mode 100644 index 0000000..96a34e3 --- /dev/null +++ b/week4/homework/worker.rb @@ -0,0 +1,10 @@ +class Worker + + def initialize + end + + def work + yield + end + +end From 2574151e4a8d1b1e137d74dfc572dec6cba01785 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Fri, 31 Jan 2014 17:25:58 -0800 Subject: [PATCH 22/61] refactor Makefile --- week4/homework/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/week4/homework/Makefile b/week4/homework/Makefile index 2bb762b..19af7f9 100644 --- a/week4/homework/Makefile +++ b/week4/homework/Makefile @@ -1,6 +1,7 @@ PROG = worker TESTEE = ${PROG}.rb TESTER = ${PROG}_spec.rb +SPEC = rspec -c --format nested test : ${TESTEE} ${TESTER} - rspec -c ${TESTER} + ${SPEC} ${TESTER} From 23e1491ebd89698e20926f477f64b6991d33d3d9 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Fri, 31 Jan 2014 17:26:16 -0800 Subject: [PATCH 23/61] pass specs 1-3 with self.work --- week4/homework/worker.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/week4/homework/worker.rb b/week4/homework/worker.rb index 96a34e3..8bb58c7 100644 --- a/week4/homework/worker.rb +++ b/week4/homework/worker.rb @@ -3,7 +3,7 @@ class Worker def initialize end - def work + def self.work n=1 yield end From 8b4217f6ca3adbfca3d269d4bb4439a6efc0abb1 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Mon, 3 Feb 2014 09:41:51 -0800 Subject: [PATCH 24/61] pass 4th test using local variables. --- week4/homework/worker.rb | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/week4/homework/worker.rb b/week4/homework/worker.rb index 8bb58c7..3510bbe 100644 --- a/week4/homework/worker.rb +++ b/week4/homework/worker.rb @@ -1,10 +1,41 @@ +#!/usr/bin/ruby2.0 +# class Worker def initialize end - def self.work n=1 - yield +# # some failures: +# # +# # returns n. times always returns the receiver. ?! +# # (EDIT - I will understand this better after the third failure) +# def self.work n=1 +# n.times { yield } +# end +# +# #returns nil for any block. I don't understand this one at all. +# def self.work reps = 1 +# i = 0 +# while i <= reps +# i += 1 +# yield +# end +# end +# +# # always returns 1. OK, so the block is a side effect, upto always returns +# # truthiness. Why doesn't it return reps? Oh, it returns the receiver! +# # (Thanks, irb and ri. No thanks to you, ruby-doc.org.) +# def self.work reps=1 +# 1.upto(reps){ yield } +# end + + # The block acts as a side effect, so we need to capture what happens in the + # block. Not sure I like this approach, but it is reasonably concise and + # works. + def self.work reps=1 + 1.upto(reps){ $result = yield } + $result end end + From 176efe7626f1e680af05aef2b4d14baf93619e92 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Mon, 3 Feb 2014 10:02:52 -0800 Subject: [PATCH 25/61] make result a method variable, and comment out 1st def --- week4/homework/worker.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/week4/homework/worker.rb b/week4/homework/worker.rb index 3510bbe..ca6d85f 100644 --- a/week4/homework/worker.rb +++ b/week4/homework/worker.rb @@ -5,6 +5,10 @@ class Worker def initialize end +# # works on 1st 3 tests. Gives 6 on 4th test +# def self.work +# yield +# end # # some failures: # # # # returns n. times always returns the receiver. ?! @@ -33,8 +37,8 @@ def initialize # block. Not sure I like this approach, but it is reasonably concise and # works. def self.work reps=1 - 1.upto(reps){ $result = yield } - $result + 1.upto(reps){ @result = yield } + @result end end From b99088970f8783f62911f3a444122878ac308797 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Mon, 3 Feb 2014 10:06:30 -0800 Subject: [PATCH 26/61] comment on method vs global variable --- week4/homework/worker.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/week4/homework/worker.rb b/week4/homework/worker.rb index ca6d85f..ce4f612 100644 --- a/week4/homework/worker.rb +++ b/week4/homework/worker.rb @@ -36,6 +36,8 @@ def initialize # The block acts as a side effect, so we need to capture what happens in the # block. Not sure I like this approach, but it is reasonably concise and # works. + # Heh - I was using $ to keep result in scope. Matthew Spah pointed out that + # this is a global variable. Let's make it @. def self.work reps=1 1.upto(reps){ @result = yield } @result From 2abdb6b18a7e435e2074fa7d1066abd3dbefd8b3 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Mon, 3 Feb 2014 10:46:04 -0800 Subject: [PATCH 27/61] answer last question - now to add rakefile --- week4/homework/questions.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/week4/homework/questions.txt b/week4/homework/questions.txt index 628957e..e934cde 100644 --- a/week4/homework/questions.txt +++ b/week4/homework/questions.txt @@ -28,5 +28,10 @@ well, see my shell out in question 2. 5. What is rake and what is it used for? What is a rake task? A replacement for Makefiles, supposedly with cleaner syntax. I'll get back to -you on this one. +you on this one. A task is the rake equivalent of a target: something which +we can request be accomplished, which rake will use logic programming to +determine what prerequisites must be fulfilled in order to accomplish. Is +'default' always the default task, or is it like make where the first target +is the default target? I've been using make to run tests, so I'll commit +my Makefile and add a rakefile and compare the two. From 94edc6795f5295fe2e677ab77097cad776d5d5f1 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Mon, 3 Feb 2014 10:46:31 -0800 Subject: [PATCH 28/61] add wrong Rakefile --- week4/homework/Rakefile | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 week4/homework/Rakefile diff --git a/week4/homework/Rakefile b/week4/homework/Rakefile new file mode 100644 index 0000000..aa5cda3 --- /dev/null +++ b/week4/homework/Rakefile @@ -0,0 +1,5 @@ +task :default => [:test] + +task :test => do + rspec -c --format nested "worker_spec.rb" +end From dc80831ad1f85da470203cd64cd86e51f7704408 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Mon, 3 Feb 2014 11:01:51 -0800 Subject: [PATCH 29/61] make rakefile work. Sort of. --- week4/homework/Rakefile | 22 +++++++++++++++--- week4/homework/spec/worker_spec.rb | 36 ++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 week4/homework/spec/worker_spec.rb diff --git a/week4/homework/Rakefile b/week4/homework/Rakefile index aa5cda3..81dcf3f 100644 --- a/week4/homework/Rakefile +++ b/week4/homework/Rakefile @@ -1,5 +1,21 @@ task :default => [:test] -task :test => do - rspec -c --format nested "worker_spec.rb" -end +# OK, you don't get a free shell. +#task :test do +# rspec -c --format nested "worker_spec.rb" +#end + +## But shelling out just cheerfully returns success (and loses the output) +#task :test do +# `rspec -c --format nested "worker_spec.rb"` +#end + +#http://blog.revathskumar.com/2011/12/run-rspec-as-rake-task.html +# +#Didn't work until moving spec to ./spec/, per +#https://www.relishapp.com/rspec/rspec-core/docs/command-line/rake-task +#which meant I had to change header in rspec. +#Seriously? I have got to be missing something. +require 'rspec/core/rake_task' +RSpec::Core::RakeTask.new(:spec) +task :test => :spec diff --git a/week4/homework/spec/worker_spec.rb b/week4/homework/spec/worker_spec.rb new file mode 100644 index 0000000..956432f --- /dev/null +++ b/week4/homework/spec/worker_spec.rb @@ -0,0 +1,36 @@ +require "#{File.dirname(__FILE__)}/../worker" + +describe Worker do + + it "executes a block and returns a string" do + result = Worker.work do + "hello" + end + result.should == "hello" + end + + it "executes a block and returns a number" do + result = Worker.work do + 3 + 4 + end + result.should == 7 + end + + it "executes a block in the context of the calling method" do + n = 1 + result = Worker.work do + n + 4 + end + result.should == 5 + end + + + it "executes a block 3 times and returns the result" do + n = 5 + result = Worker.work(3) do + n += 1 + end + result.should == 8 + end + +end From fc728b50a808343983730aab7277d88f82cb3c6d Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Mon, 3 Feb 2014 11:48:41 -0800 Subject: [PATCH 30/61] answer q3 with Dir, not Directory, in hopes this is desired --- week4/homework/questions.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/week4/homework/questions.txt b/week4/homework/questions.txt index e934cde..fe53974 100644 --- a/week4/homework/questions.txt +++ b/week4/homework/questions.txt @@ -18,6 +18,11 @@ Windows): > `echo "Hello World!" >>my_output.txt` 3. What is the Directory class and what is it used for? +I have no idea. I can't find such a class. + +The Dir class, though, is a class of directories, and gives us nice *nixy stuff +like .pwd, .home, and .entries (which I would like to see aliased as 'ls'). Is +this what you were looking for? It seems fitting with IO. 4. What is an IO object? An object representing something outside of your program that you can use as From 1cad6654bff7ea78a5913394c6a18780e15a9737 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 4 Feb 2014 17:02:41 -0800 Subject: [PATCH 31/61] add rake v make comparison (rake compare not done) --- week4/rake-v-make/Makefile | 28 +++++++++++++++++++++++ week4/rake-v-make/Rakefile | 47 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 week4/rake-v-make/Makefile create mode 100644 week4/rake-v-make/Rakefile diff --git a/week4/rake-v-make/Makefile b/week4/rake-v-make/Makefile new file mode 100644 index 0000000..bff8e48 --- /dev/null +++ b/week4/rake-v-make/Makefile @@ -0,0 +1,28 @@ +WIN = *.bak +NIX = *~ +RM = rm -fv + +default : win nix #Remove Unix and Windows backup files + +win : # Remove files with a .bak extension + @${RM} ${WIN} + +nix : # Remove files whose names end with a tilde + @${RM} ${NIX} # Remove files whose names end with a tilde + +# OK, here rake wins. I was about to use seq to generate some numbers, +# but it's not portable. There are workarounds, but I am going to be +# lazy and hardcode my numbers in. +fake : # create dummy files for testing + @for i in 1 2 3; do touch $$i.bak $$i~; echo $$i.bak; echo $$i~; done + +help : # show available tasks + @sed -n 's,^\([^ .]\+\):[^#]*#\s*\(.*\),\1: \2,p' Makefile + +compare : # show non-comment non-blank lines of code + @for i in Makefile Rakefile; do \ + echo "$$i:"; \ + grep -v -e '^\s*#' -e '^\s*$$' $$i | wc ; \ + done + +.PHONY : default win nix fake help compare diff --git a/week4/rake-v-make/Rakefile b/week4/rake-v-make/Rakefile new file mode 100644 index 0000000..abba4d6 --- /dev/null +++ b/week4/rake-v-make/Rakefile @@ -0,0 +1,47 @@ +task :default => :delete_backups + +def delete(pattern) + files = Dir[pattern] + rm(files, verbose: true) unless files.empty? +end + +desc "Remove files whose names end with a tilde" +task :delete_unix_backups do + delete "*~" +end + +desc "Remove files with a .bak extension" +task :delete_windows_backups do + delete "*.bak" +end + +desc "Remove Unix and Windows backup files" +task :delete_backups => [ :delete_unix_backups, :delete_windows_backups ] do + puts "All backups deleted" +end + +desc "make dummy files for testing" +task :fake do + # cool or disgusting? is map really what I want here? It's sort of + # a 2D array I'm doing here. Anyway, it works. + 1.upto(3){|n| ['.bak','~'].each{|x| touch n.to_s + x}} +end + +desc "show non-comment non-blank lines of code" +task :compare do + ["Makefile", "Rakefile"].each do |f| + puts f + ":" + File.open(f, 'r') do |fh| + count = Hash.new(0) + while line=fh.gets do #match against our regex + count[:l] += 1 + count[:w] += line.scan(/\S+/).length + count[:c] += line.length + end + puts count + end + end +end + + + From c2c8638725a79da077fd0c1349e7b41bf1232c0c Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 4 Feb 2014 18:00:01 -0800 Subject: [PATCH 32/61] skip blanks and comments in rake - done --- week4/rake-v-make/Rakefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/week4/rake-v-make/Rakefile b/week4/rake-v-make/Rakefile index abba4d6..68004b4 100644 --- a/week4/rake-v-make/Rakefile +++ b/week4/rake-v-make/Rakefile @@ -34,11 +34,12 @@ task :compare do File.open(f, 'r') do |fh| count = Hash.new(0) while line=fh.gets do #match against our regex + next if (line =~ /(^\s*#)|(^\s*$)/) count[:l] += 1 count[:w] += line.scan(/\S+/).length count[:c] += line.length end - puts count + puts count.values.join("\t") end end end From 3e3e0958f1016de8eeda398224bd4150e55adc8c Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 4 Feb 2014 18:07:30 -0800 Subject: [PATCH 33/61] comment refactor --- week4/rake-v-make/Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/week4/rake-v-make/Rakefile b/week4/rake-v-make/Rakefile index 68004b4..6b592e2 100644 --- a/week4/rake-v-make/Rakefile +++ b/week4/rake-v-make/Rakefile @@ -33,7 +33,7 @@ task :compare do puts f + ":" File.open(f, 'r') do |fh| count = Hash.new(0) - while line=fh.gets do #match against our regex + while line=fh.gets do #FIXME refactor next if (line =~ /(^\s*#)|(^\s*$)/) count[:l] += 1 count[:w] += line.scan(/\S+/).length From cafebd207ac7236f4afcd0325358f55efe49c3e3 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Tue, 4 Feb 2014 21:30:56 -0800 Subject: [PATCH 34/61] question 5 rake vs make commentary --- week4/homework/questions.txt | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/week4/homework/questions.txt b/week4/homework/questions.txt index fe53974..bef64fa 100644 --- a/week4/homework/questions.txt +++ b/week4/homework/questions.txt @@ -40,3 +40,38 @@ determine what prerequisites must be fulfilled in order to accomplish. Is is the default target? I've been using make to run tests, so I'll commit my Makefile and add a rakefile and compare the two. +OK, the rakefile looks a bit ugly. + +In ../rake-v-make/ are comparable rake and make files, based on the rake intro +in pickaxe, plus tasks to compare, and to generate dummy files. + +$ time make fake default compare +... +real 0m0.013s +user 0m0.005s +sys 0m0.008s + +$ time rake fake default compare +... +real 0m0.109s +user 0m0.094s +sys 0m0.013s +This is all too fast to worry about, but the difference in speeds is shocking. +I wonder what big builds end up looking like. + +rake is 37 SLOC vs make's 18 +I'm sure a more experienced rubyist could shorten that up at least a few +lines. Also, the 5 desc lines aren't necessary - but neither are the 2 lines +providing 'make help' + +make uses shell utilities, so you get stuff like wc(1) for free, instead of +re-implementing in ruby. + +Contrariwise, make uses shell utilities, so you can't be sure it will run the +same (or at all) on all platforms. I wanted to use seq(1) in the Makefile, but +that isn't in *BSD base (and when it is ported, it's called gseq). Rake uses +1.upto, and if you're running rake you have .upto. + +rake is a hell of a lot more readable than make, even for a seasoned maker / +noob rubyist like me. + From f0662c3fafd333aed09f6f2e47581885ddba66de Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Fri, 7 Feb 2014 21:57:58 -0800 Subject: [PATCH 35/61] add the inject version of week 4 excercise --- week4/homework/worker.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/week4/homework/worker.rb b/week4/homework/worker.rb index ce4f612..6367983 100644 --- a/week4/homework/worker.rb +++ b/week4/homework/worker.rb @@ -43,5 +43,10 @@ def self.work reps=1 @result end +# # Renée's - she says to watch for the pattern that can be resolved down + # to inject +# def self.work t=1 +# t.times.inject(nil) {yield} +# end end From 7882af4f960f0ccc653f4c333b279405ee7b8cef Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Mon, 24 Feb 2014 11:31:31 -0800 Subject: [PATCH 36/61] add pirate translator:say --- week7/homework/features/step_definitions/pirate.rb | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 week7/homework/features/step_definitions/pirate.rb diff --git a/week7/homework/features/step_definitions/pirate.rb b/week7/homework/features/step_definitions/pirate.rb new file mode 100644 index 0000000..43b3578 --- /dev/null +++ b/week7/homework/features/step_definitions/pirate.rb @@ -0,0 +1,7 @@ +class PirateTranslator + def intitialize + end + + def say phrase + end +end From da2d0d84e9eaa380644978f20f91c35bea872bb1 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Mon, 24 Feb 2014 11:52:04 -0800 Subject: [PATCH 37/61] make pirate pass in a stupid manner --- week7/homework/features/step_definitions/pirate.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/week7/homework/features/step_definitions/pirate.rb b/week7/homework/features/step_definitions/pirate.rb index 43b3578..693899e 100644 --- a/week7/homework/features/step_definitions/pirate.rb +++ b/week7/homework/features/step_definitions/pirate.rb @@ -4,4 +4,9 @@ def intitialize def say phrase end + + def translate + @piratish = 'Ahoy Matey + Shiber Me Timbers You Scurvey Dogs!!' + end end From d317dfd71e68af478be906bfc6dc09ec9838a7e0 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Mon, 24 Feb 2014 12:03:59 -0800 Subject: [PATCH 38/61] make pirate pass in a less ugly manner --- week7/homework/features/step_definitions/pirate.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/week7/homework/features/step_definitions/pirate.rb b/week7/homework/features/step_definitions/pirate.rb index 693899e..aba19fd 100644 --- a/week7/homework/features/step_definitions/pirate.rb +++ b/week7/homework/features/step_definitions/pirate.rb @@ -6,7 +6,13 @@ def say phrase end def translate - @piratish = 'Ahoy Matey - Shiber Me Timbers You Scurvey Dogs!!' + + #FIXME ugly + @piratish = <<-END.gsub(/^ {6}/, '').chomp + Ahoy Matey + Shiber Me Timbers You Scurvey Dogs!! + END + #FIXME also ugly + @piratish = 'Ahoy Matey' << "\n Shiber Me Timbers You Scurvey Dogs!!" end end From 5c0ae8d6924a72d576167ff16c666b6c367bdc25 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Mon, 24 Feb 2014 12:14:50 -0800 Subject: [PATCH 39/61] attribute source of heredoc trick --- week7/homework/features/step_definitions/pirate.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/week7/homework/features/step_definitions/pirate.rb b/week7/homework/features/step_definitions/pirate.rb index aba19fd..341690d 100644 --- a/week7/homework/features/step_definitions/pirate.rb +++ b/week7/homework/features/step_definitions/pirate.rb @@ -7,12 +7,14 @@ def say phrase def translate - #FIXME ugly + #FIXME ugly, dumb trick from + # http://rubyquicktips.com/post/4438542511/heredoc-and-indent @piratish = <<-END.gsub(/^ {6}/, '').chomp Ahoy Matey Shiber Me Timbers You Scurvey Dogs!! END - #FIXME also ugly + + #FIXME also ugly and dumb. @piratish = 'Ahoy Matey' << "\n Shiber Me Timbers You Scurvey Dogs!!" end end From b11401cc3ca368dee8ccfc259d8f5767d4dc5d04 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Mon, 24 Feb 2014 13:49:47 -0800 Subject: [PATCH 40/61] pass begin game scenario --- .../features/step_definitions/tic-tac-toe.rb | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 week7/homework/features/step_definitions/tic-tac-toe.rb diff --git a/week7/homework/features/step_definitions/tic-tac-toe.rb b/week7/homework/features/step_definitions/tic-tac-toe.rb new file mode 100644 index 0000000..e45bad2 --- /dev/null +++ b/week7/homework/features/step_definitions/tic-tac-toe.rb @@ -0,0 +1,29 @@ +class TicTacToe + SYMBOLS = [@player_symbol, @computer_symbol] + attr_reader :player + attr_accessor :player_symbol, :computer_symbol, :players, :player_index + + def initialize name=nil + @player = name + @players = ['Computer', @player] + @player_index = rand(0..1) + end + + def player= name + @player = name + end + + def welcome_player + "Welcome #{@player}" + end + + def current_player + self.players[self.player_index] + end + + private + def toggle_current_player + self.player_index = self.player_index^1 + end + +end From e59d383a4d3d66b705acb3347bf598ac815f9035 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 26 Feb 2014 10:27:50 -0800 Subject: [PATCH 41/61] more attempts --- .../features/step_definitions/tic-tac-toe.rb | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/week7/homework/features/step_definitions/tic-tac-toe.rb b/week7/homework/features/step_definitions/tic-tac-toe.rb index e45bad2..fb4edf6 100644 --- a/week7/homework/features/step_definitions/tic-tac-toe.rb +++ b/week7/homework/features/step_definitions/tic-tac-toe.rb @@ -1,16 +1,16 @@ class TicTacToe - SYMBOLS = [@player_symbol, @computer_symbol] + SYMBOLS = [:X, :O] attr_reader :player attr_accessor :player_symbol, :computer_symbol, :players, :player_index - def initialize name=nil - @player = name - @players = ['Computer', @player] - @player_index = rand(0..1) + def initialize starts=rnd_player, s=rnd_symbol + @players = [:player, :computer] + @player_index = @players.index starts end def player= name @player = name + @players[:player] = name end def welcome_player @@ -18,12 +18,21 @@ def welcome_player end def current_player - self.players[self.player_index] + @players[@player_index] end private + + def toggle_current_player self.player_index = self.player_index^1 end + def rnd_player + rand(0..1) + end + + def rnd_symbol + end + end From f87eb8abef69eaabd66757e3ce73d911302acec0 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 26 Feb 2014 11:58:43 -0800 Subject: [PATCH 42/61] pass who goes first --- .../features/step_definitions/tic-tac-toe.rb | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/week7/homework/features/step_definitions/tic-tac-toe.rb b/week7/homework/features/step_definitions/tic-tac-toe.rb index fb4edf6..3fd0864 100644 --- a/week7/homework/features/step_definitions/tic-tac-toe.rb +++ b/week7/homework/features/step_definitions/tic-tac-toe.rb @@ -1,16 +1,23 @@ class TicTacToe SYMBOLS = [:X, :O] + PLAYERS = [:player, :computer] attr_reader :player attr_accessor :player_symbol, :computer_symbol, :players, :player_index - def initialize starts=rnd_player, s=rnd_symbol - @players = [:player, :computer] - @player_index = @players.index starts + def initialize starts=PLAYERS[zor1], s=SYMBOLS[zor1] + @name = {:player => 'Player', :computer => 'Computer'} + @player_index = PLAYERS.index starts + @symbol_index = SYMBOLS.index s end def player= name - @player = name - @players[:player] = name + @player = PLAYERS[0] = name + end + + def player_symbol + end + + def computer_symbol end def welcome_player @@ -18,21 +25,17 @@ def welcome_player end def current_player - @players[@player_index] + @name[PLAYERS[@player_index]] end private - def toggle_current_player self.player_index = self.player_index^1 end - def rnd_player + def zor1 rand(0..1) end - def rnd_symbol - end - end From 1606e4d93562d5ebec44ee3bee6761a951a9b479 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 26 Feb 2014 12:51:52 -0800 Subject: [PATCH 43/61] padd who is first for real --- week7/homework/features/step_definitions/tic-tac-toe.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/week7/homework/features/step_definitions/tic-tac-toe.rb b/week7/homework/features/step_definitions/tic-tac-toe.rb index 3fd0864..1a4250a 100644 --- a/week7/homework/features/step_definitions/tic-tac-toe.rb +++ b/week7/homework/features/step_definitions/tic-tac-toe.rb @@ -6,12 +6,12 @@ class TicTacToe def initialize starts=PLAYERS[zor1], s=SYMBOLS[zor1] @name = {:player => 'Player', :computer => 'Computer'} - @player_index = PLAYERS.index starts @symbol_index = SYMBOLS.index s + @player_index = PLAYERS.index starts end def player= name - @player = PLAYERS[0] = name + @player = @name[:player] = name end def player_symbol From 510fd965b3a2162238ad11a4691996294e0aac40 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 26 Feb 2014 12:55:10 -0800 Subject: [PATCH 44/61] pass X and O by cheating --- .../features/step_definitions/tic-tac-toe.rb | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/week7/homework/features/step_definitions/tic-tac-toe.rb b/week7/homework/features/step_definitions/tic-tac-toe.rb index 1a4250a..92ab307 100644 --- a/week7/homework/features/step_definitions/tic-tac-toe.rb +++ b/week7/homework/features/step_definitions/tic-tac-toe.rb @@ -2,12 +2,12 @@ class TicTacToe SYMBOLS = [:X, :O] PLAYERS = [:player, :computer] attr_reader :player - attr_accessor :player_symbol, :computer_symbol, :players, :player_index + attr_accessor :player_symbol, :computer_symbol, :players, :whose_turn def initialize starts=PLAYERS[zor1], s=SYMBOLS[zor1] @name = {:player => 'Player', :computer => 'Computer'} - @symbol_index = SYMBOLS.index s - @player_index = PLAYERS.index starts + #@symbol_index = SYMBOLS.index s + @whose_turn = PLAYERS.index starts end def player= name @@ -15,9 +15,11 @@ def player= name end def player_symbol + :X end def computer_symbol + :O end def welcome_player @@ -25,13 +27,13 @@ def welcome_player end def current_player - @name[PLAYERS[@player_index]] + @name[PLAYERS[@whose_turn]] end private def toggle_current_player - self.player_index = self.player_index^1 + self.whose_turn = self.whose_turn^1 end def zor1 From f816c9e167f34ac93d37d096f49b42fbd2b1b66b Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 26 Feb 2014 13:09:02 -0800 Subject: [PATCH 45/61] pass x and o correctly, grossly --- .../homework/features/step_definitions/tic-tac-toe.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/week7/homework/features/step_definitions/tic-tac-toe.rb b/week7/homework/features/step_definitions/tic-tac-toe.rb index 92ab307..ae28add 100644 --- a/week7/homework/features/step_definitions/tic-tac-toe.rb +++ b/week7/homework/features/step_definitions/tic-tac-toe.rb @@ -6,8 +6,12 @@ class TicTacToe def initialize starts=PLAYERS[zor1], s=SYMBOLS[zor1] @name = {:player => 'Player', :computer => 'Computer'} - #@symbol_index = SYMBOLS.index s @whose_turn = PLAYERS.index starts + @whose_symb = SYMBOLS.index s + @symbol = { + PLAYERS[@whose_turn] => s, + PLAYERS[@whose_turn^1] => SYMBOLS[(SYMBOLS.index s)^1] + } end def player= name @@ -15,11 +19,11 @@ def player= name end def player_symbol - :X + @symbol[:player] end def computer_symbol - :O + @symbol[:computer] end def welcome_player From 8783b90c9486e982e855d0d889da609256183070 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 26 Feb 2014 13:14:20 -0800 Subject: [PATCH 46/61] pass Renee's move print --- week7/homework/features/step_definitions/tic-tac-toe.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/week7/homework/features/step_definitions/tic-tac-toe.rb b/week7/homework/features/step_definitions/tic-tac-toe.rb index ae28add..3120664 100644 --- a/week7/homework/features/step_definitions/tic-tac-toe.rb +++ b/week7/homework/features/step_definitions/tic-tac-toe.rb @@ -18,6 +18,7 @@ def player= name @player = @name[:player] = name end + #FIXME refactor these 2 def player_symbol @symbol[:player] end @@ -34,6 +35,10 @@ def current_player @name[PLAYERS[@whose_turn]] end + def indicate_palyer_turn + puts "#{@player}'s Move:" + end + private def toggle_current_player From 1b01eb5fb4cc2e8ddb1b245771004bbdd2faf641 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 26 Feb 2014 13:16:19 -0800 Subject: [PATCH 47/61] pass My Turn (get_player_move does nothing yet) --- week7/homework/features/step_definitions/tic-tac-toe.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/week7/homework/features/step_definitions/tic-tac-toe.rb b/week7/homework/features/step_definitions/tic-tac-toe.rb index 3120664..7fc81c1 100644 --- a/week7/homework/features/step_definitions/tic-tac-toe.rb +++ b/week7/homework/features/step_definitions/tic-tac-toe.rb @@ -39,6 +39,9 @@ def indicate_palyer_turn puts "#{@player}'s Move:" end + def get_player_move + end + private def toggle_current_player From 4b74416722da9af27ab8afe9600c86367b7d209a Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 26 Feb 2014 13:34:25 -0800 Subject: [PATCH 48/61] pass computer playing x - 2nd param is player symb --- week7/homework/features/step_definitions/tic-tac-toe.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/week7/homework/features/step_definitions/tic-tac-toe.rb b/week7/homework/features/step_definitions/tic-tac-toe.rb index 7fc81c1..84305c3 100644 --- a/week7/homework/features/step_definitions/tic-tac-toe.rb +++ b/week7/homework/features/step_definitions/tic-tac-toe.rb @@ -9,8 +9,9 @@ def initialize starts=PLAYERS[zor1], s=SYMBOLS[zor1] @whose_turn = PLAYERS.index starts @whose_symb = SYMBOLS.index s @symbol = { - PLAYERS[@whose_turn] => s, - PLAYERS[@whose_turn^1] => SYMBOLS[(SYMBOLS.index s)^1] + #PLAYERS[@whose_turn] => s, + :player => s, + :computer => SYMBOLS[(SYMBOLS.index s)^1] } end From 6ae4c835e8db3db7c1baa838b3d315bdaec87471 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 26 Feb 2014 13:40:13 -0800 Subject: [PATCH 49/61] hold here for understanding game board --- week7/homework/features/step_definitions/tic-tac-toe.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/week7/homework/features/step_definitions/tic-tac-toe.rb b/week7/homework/features/step_definitions/tic-tac-toe.rb index 84305c3..67d711c 100644 --- a/week7/homework/features/step_definitions/tic-tac-toe.rb +++ b/week7/homework/features/step_definitions/tic-tac-toe.rb @@ -43,6 +43,12 @@ def indicate_palyer_turn def get_player_move end + def computer_move + end + + def open_spots + end + private def toggle_current_player From 1b661bf7e3e364d8146d0598a0eed872e458116e Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 26 Feb 2014 14:30:42 -0800 Subject: [PATCH 50/61] make open_spots work --- .../features/step_definitions/tic-tac-toe.rb | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/week7/homework/features/step_definitions/tic-tac-toe.rb b/week7/homework/features/step_definitions/tic-tac-toe.rb index 67d711c..1a9d478 100644 --- a/week7/homework/features/step_definitions/tic-tac-toe.rb +++ b/week7/homework/features/step_definitions/tic-tac-toe.rb @@ -13,12 +13,25 @@ def initialize starts=PLAYERS[zor1], s=SYMBOLS[zor1] :player => s, :computer => SYMBOLS[(SYMBOLS.index s)^1] } + @board = { + :A1 => nil, :A2 => nil, :A3 => nil, + :B1 => nil, :B2 => nil, :B3 => nil, + :C1 => nil, :C2 => nil, :C3 => nil + } end def player= name @player = @name[:player] = name end + def board + @board + end + + def open_spots + board.map{|spot, v| spot if v.nil?} + end + #FIXME refactor these 2 def player_symbol @symbol[:player] @@ -44,9 +57,8 @@ def get_player_move end def computer_move - end - - def open_spots + n_open = open_spots.length + open_spots[rand(0...n_open)] end private From df27f2a4a58d3a93b06a4ca503ff3ffce3324c74 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 26 Feb 2014 14:55:20 -0800 Subject: [PATCH 51/61] add computer_move, refactory zto1 >dien --- .../features/step_definitions/tic-tac-toe.rb | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/week7/homework/features/step_definitions/tic-tac-toe.rb b/week7/homework/features/step_definitions/tic-tac-toe.rb index 1a9d478..4885ceb 100644 --- a/week7/homework/features/step_definitions/tic-tac-toe.rb +++ b/week7/homework/features/step_definitions/tic-tac-toe.rb @@ -4,7 +4,7 @@ class TicTacToe attr_reader :player attr_accessor :player_symbol, :computer_symbol, :players, :whose_turn - def initialize starts=PLAYERS[zor1], s=SYMBOLS[zor1] + def initialize starts=PLAYERS[dien], s=SYMBOLS[dien] @name = {:player => 'Player', :computer => 'Computer'} @whose_turn = PLAYERS.index starts @whose_symb = SYMBOLS.index s @@ -57,18 +57,23 @@ def get_player_move end def computer_move - n_open = open_spots.length - open_spots[rand(0...n_open)] + choices = open_spots.length - 1 + pos = open_spots[dien choices] + @board[pos] = @computer_symbol + pos end + def current_state + @board.map{|pos, state| state.to_s} + end private def toggle_current_player self.whose_turn = self.whose_turn^1 end - def zor1 - rand(0..1) + def dien n=1 + rand(0..n) end end From 7b2c12e6507f5e12b0b05469a30743bb2ec12003 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 26 Feb 2014 15:25:22 -0800 Subject: [PATCH 52/61] pass computer's turn --- week7/homework/features/step_definitions/tic-tac-toe.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/week7/homework/features/step_definitions/tic-tac-toe.rb b/week7/homework/features/step_definitions/tic-tac-toe.rb index 4885ceb..383bf83 100644 --- a/week7/homework/features/step_definitions/tic-tac-toe.rb +++ b/week7/homework/features/step_definitions/tic-tac-toe.rb @@ -29,7 +29,7 @@ def board end def open_spots - board.map{|spot, v| spot if v.nil?} + board.select{|spot, v| spot if v.nil?}.map{|k,v| k} end #FIXME refactor these 2 @@ -57,9 +57,8 @@ def get_player_move end def computer_move - choices = open_spots.length - 1 - pos = open_spots[dien choices] - @board[pos] = @computer_symbol + pos = open_spots[dien open_spots.length - 1] + @board[pos] = @symbol[:computer] pos end From d4f0d6233c677d37d552ddee267adb753f2b4c78 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 26 Feb 2014 16:23:08 -0800 Subject: [PATCH 53/61] get player move --- week7/homework/features/step_definitions/tic-tac-toe.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/week7/homework/features/step_definitions/tic-tac-toe.rb b/week7/homework/features/step_definitions/tic-tac-toe.rb index 383bf83..0aac14f 100644 --- a/week7/homework/features/step_definitions/tic-tac-toe.rb +++ b/week7/homework/features/step_definitions/tic-tac-toe.rb @@ -54,6 +54,13 @@ def indicate_palyer_turn end def get_player_move + move = gets.chomp + end + + def player_move + pos = get_player_move.to_sym + @board[pos] = @symbol[:player] + pos end def computer_move From d492da96cdf9cd67eed515381b976428936d7c88 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Wed, 26 Feb 2014 16:43:11 -0800 Subject: [PATCH 54/61] change nil open spaces to ' ' --- week7/homework/features/step_definitions/tic-tac-toe.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/week7/homework/features/step_definitions/tic-tac-toe.rb b/week7/homework/features/step_definitions/tic-tac-toe.rb index 0aac14f..6404efb 100644 --- a/week7/homework/features/step_definitions/tic-tac-toe.rb +++ b/week7/homework/features/step_definitions/tic-tac-toe.rb @@ -14,9 +14,9 @@ def initialize starts=PLAYERS[dien], s=SYMBOLS[dien] :computer => SYMBOLS[(SYMBOLS.index s)^1] } @board = { - :A1 => nil, :A2 => nil, :A3 => nil, - :B1 => nil, :B2 => nil, :B3 => nil, - :C1 => nil, :C2 => nil, :C3 => nil + :A1 => ' ', :A2 => ' ', :A3 => ' ', + :B1 => ' ', :B2 => ' ', :B3 => ' ', + :C1 => ' ', :C2 => ' ', :C3 => ' ' } end @@ -29,7 +29,7 @@ def board end def open_spots - board.select{|spot, v| spot if v.nil?}.map{|k,v| k} + board.select{|spot, v| spot if v.is_a? String}.map{|k,v| k} end #FIXME refactor these 2 From ac224fe2e2495f12393c24f611acbd243f590bee Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Thu, 27 Feb 2014 09:10:12 -0800 Subject: [PATCH 55/61] rough answer to week7 q 1 --- week7/homework/questions.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/week7/homework/questions.txt b/week7/homework/questions.txt index d55387d..ce69843 100644 --- a/week7/homework/questions.txt +++ b/week7/homework/questions.txt @@ -3,7 +3,21 @@ Please Read Chapters 23 and 24 DuckTyping and MetaProgramming Questions: 1. What is method_missing and how can it be used? +method_missing is a method of class Object which is called if no other method +can be found by the name called. It raises an exception. It can be usefully +used by overriding it in your class, and: + Catching methods that match a regex, and generating them on the fly (passing + the mismatches on up the line to Object.method_missing). This is how the + Rails find_by_.* is implemented. + + (as per [1]:) Using it in a wrapper class to decide which methods can proceed + 'even though we said no'. (I like Perrota's example, but am not sure I can + think of my own usage scenario yet.) + 2. What is and Eigenclass and what is it used for? Where Do Singleton methods live? 3. When would you use DuckTypeing? How would you use it to improve your code? 4. What is the difference between a class method and an instance method? What is the difference between instance_eval and class_eval? 5. What is the difference between a singleton class and a singleton method? + + +[1] http://rubylearning.com/blog/2010/10/07/do-you-know-rubys-chainsaw-method/ From 6eb55b3da7641cff8f1948ec82c17efd9072fb7c Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Thu, 27 Feb 2014 09:42:16 -0800 Subject: [PATCH 56/61] rough answer to w7 q2 --- week7/homework/questions.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/week7/homework/questions.txt b/week7/homework/questions.txt index ce69843..a2ada3c 100644 --- a/week7/homework/questions.txt +++ b/week7/homework/questions.txt @@ -3,6 +3,7 @@ Please Read Chapters 23 and 24 DuckTyping and MetaProgramming Questions: 1. What is method_missing and how can it be used? + method_missing is a method of class Object which is called if no other method can be found by the name called. It raises an exception. It can be usefully used by overriding it in your class, and: @@ -15,9 +16,23 @@ used by overriding it in your class, and: think of my own usage scenario yet.) 2. What is and Eigenclass and what is it used for? Where Do Singleton methods live? + +An Eigenclass (syns: ghost class, singleton class, metaclass [2]) is a class +which Ruby automagically generates to hold any singleton methods of an object. +It is the class of the object, and a subclass of the object's original +superclass. In other words, Ruby inserts an Eigenclass in the class hierarchy +between an object and it's superclass whenever a singleton method is generated. +#FIXME what are they used for? + +Singleton methods live within the Eigenclass - they are defined for a single +object, rather than for an entire class, and Ruby hoists them up into the +Eigenclass. (Though classes are a sort of object, so it seems to me that class +methods should be viewed as the special case here.) + 3. When would you use DuckTypeing? How would you use it to improve your code? 4. What is the difference between a class method and an instance method? What is the difference between instance_eval and class_eval? 5. What is the difference between a singleton class and a singleton method? [1] http://rubylearning.com/blog/2010/10/07/do-you-know-rubys-chainsaw-method/ +[2] http://madebydna.com/all/code/2011/06/24/eigenclasses-demystified.html From 9d14ee75c335996c6b5e96192cde170189d36be1 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Thu, 27 Feb 2014 10:00:15 -0800 Subject: [PATCH 57/61] answer w7 q3 --- week7/homework/questions.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/week7/homework/questions.txt b/week7/homework/questions.txt index a2ada3c..973d224 100644 --- a/week7/homework/questions.txt +++ b/week7/homework/questions.txt @@ -30,6 +30,13 @@ Eigenclass. (Though classes are a sort of object, so it seems to me that class methods should be viewed as the special case here.) 3. When would you use DuckTypeing? How would you use it to improve your code? + +I would use it implicitly everywhere in Ruby or Python. Consciously using it +would improve my code by: + Removing superfluous code for checking types where it doesn't matter + + Making my code extensible or modifiable by not wiring down types + 4. What is the difference between a class method and an instance method? What is the difference between instance_eval and class_eval? 5. What is the difference between a singleton class and a singleton method? From 4796f921c316525dc911c627909566a51c160501 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Thu, 27 Feb 2014 13:45:58 -0800 Subject: [PATCH 58/61] partial answer w7 q4 --- week7/homework/questions.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/week7/homework/questions.txt b/week7/homework/questions.txt index 973d224..b11e3b2 100644 --- a/week7/homework/questions.txt +++ b/week7/homework/questions.txt @@ -38,6 +38,26 @@ would improve my code by: Making my code extensible or modifiable by not wiring down types 4. What is the difference between a class method and an instance method? What is the difference between instance_eval and class_eval? + +A class method is available to any instance of the class. (Singh says a class +method is a singleton method of the class, so they live in the Eigenclass of +the class.[2]) An instance method is available to instances of the class. So: + class Myclass + def self.my_class_method + end + + def my_instance_method + end + end + + Myclass.my_class_method + m = Myclass.new + m.my_instance_method + +#FIXME So what? + +#FIXME diff the evals + 5. What is the difference between a singleton class and a singleton method? From 4d811eb83bd847931d035f80638beef1b5843e37 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Thu, 27 Feb 2014 13:55:15 -0800 Subject: [PATCH 59/61] answer w7 q5 --- week7/homework/questions.txt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/week7/homework/questions.txt b/week7/homework/questions.txt index b11e3b2..ce71754 100644 --- a/week7/homework/questions.txt +++ b/week7/homework/questions.txt @@ -39,9 +39,9 @@ would improve my code by: 4. What is the difference between a class method and an instance method? What is the difference between instance_eval and class_eval? -A class method is available to any instance of the class. (Singh says a class -method is a singleton method of the class, so they live in the Eigenclass of -the class.[2]) An instance method is available to instances of the class. So: +A class method is available on the class itself. (Singh says a class method is +a singleton method of the class, so they live in the Eigenclass of the +class.[2]) An instance method is available to instances of the class. So: class Myclass def self.my_class_method end @@ -60,6 +60,13 @@ the class.[2]) An instance method is available to instances of the class. So: 5. What is the difference between a singleton class and a singleton method? +This question is question 2 turned inside out? + +A singleton method is a method defined for one object. A singleton class (aka +Eigenclass, anonymous class, ghost class, metaclass) is the container class +generated by ruby to be a superclass of the object to which the singleton +method is attached, thus allowing Ruby to keep it's tidy method look-up +techniques in order. [1] http://rubylearning.com/blog/2010/10/07/do-you-know-rubys-chainsaw-method/ [2] http://madebydna.com/all/code/2011/06/24/eigenclasses-demystified.html From 846471c7b325d67086403a9249c42053b456a001 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Thu, 27 Feb 2014 15:11:37 -0800 Subject: [PATCH 60/61] rough answer w7 q5 --- week7/homework/questions.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/week7/homework/questions.txt b/week7/homework/questions.txt index ce71754..3d36ce8 100644 --- a/week7/homework/questions.txt +++ b/week7/homework/questions.txt @@ -54,9 +54,15 @@ class.[2]) An instance method is available to instances of the class. So: m = Myclass.new m.my_instance_method -#FIXME So what? +#FIXME I don't really understand where I should be using class methods. -#FIXME diff the evals +instance_eval sets self to the receiver and executes a block within that +context. It lets you peek at the receiver's instance variables, but also lets +you run instance methods as barewords, like in the Pickaxe book turtle program. +So defining a method with instance_eval will define a class methods. + +class_eval does the same, but at a module or class level. So defining a method +with class_eval will define an instance method. 5. What is the difference between a singleton class and a singleton method? From 59397b2954b15e1acfddf37e897f26fed35cc592 Mon Sep 17 00:00:00 2001 From: Noah Birnel Date: Thu, 13 Mar 2014 13:35:26 -0700 Subject: [PATCH 61/61] add tictactoe - this has it's own git repo --- .../step_definitions/tic-tac-toe-steps.rb | 124 +++++++++++++++ .../features/step_definitions/tic-tac-toe.rb | 146 ++++++++++++++++++ tictactoe/features/tic-tac-toe.feature | 57 +++++++ tictactoe/play_game.rb | 22 +++ 4 files changed, 349 insertions(+) create mode 100644 tictactoe/features/step_definitions/tic-tac-toe-steps.rb create mode 100644 tictactoe/features/step_definitions/tic-tac-toe.rb create mode 100644 tictactoe/features/tic-tac-toe.feature create mode 100644 tictactoe/play_game.rb diff --git a/tictactoe/features/step_definitions/tic-tac-toe-steps.rb b/tictactoe/features/step_definitions/tic-tac-toe-steps.rb new file mode 100644 index 0000000..a9bd88e --- /dev/null +++ b/tictactoe/features/step_definitions/tic-tac-toe-steps.rb @@ -0,0 +1,124 @@ +require 'rspec/mocks/standalone' +require 'rspec/expectations' +Given /^I start a new Tic\-Tac\-Toe game$/ do + @game = TicTacToe.new +end + +When /^I enter my name (\w+)$/ do |name| + @game.player = name +end + +Then /^the computer welcomes me to the game with "(.*?)"$/ do |arg1| + @game.welcome_player.should eq arg1 +end + +Then /^randomly chooses who goes first$/ do + [@game.player, "Computer"].should include @game.current_player +end + +Then /^who is X and who is O$/ do + TicTacToe::SYMBOLS.should include @game.player_symbol, @game.computer_symbol +end + +Given /^I have a started Tic\-Tac\-Toe game$/ do + @game = TicTacToe.new(:player) + @game.player = "Renee" +end + +Given /^it is my turn$/ do + @game.current_player.should eq "Renee" +end + +Given /^the computer knows my name is Renee$/ do + @game.player.should eq "Renee" +end + +Then /^the computer prints "(.*?)"$/ do |arg1| + @game.should_receive(:puts).with(arg1) + @game.indicate_player_turn +end + +Then /^waits for my input of "(.*?)"$/ do |arg1| + @game.should_receive(:gets).and_return(arg1) + @game.get_player_move +end + +Given /^it is the computer's turn$/ do + @game = TicTacToe.new(:computer, :O) + @game.current_player.should eq "Computer" +end + +Then /^the computer randomly chooses an open position for its move$/ do + open_spots = @game.open_spots + @com_move = @game.computer_move + open_spots.should include(@com_move) +end + +Given /^the computer is playing X$/ do + @game.computer_symbol.should eq :X +end + +Then /^the board should have an X on it$/ do + @game.current_state.should include 'X' +end + +Given /^I am playing X$/ do + @game = TicTacToe.new(:computer, :X) + @game.player_symbol.should eq :X +end + +When /^I enter a position "(.*?)" on the board$/ do |arg1| + @old_pos = @game.board[arg1.to_sym] + @game.should_receive(:get_player_move).and_return(arg1) + @game.player_move.should eq arg1.to_sym +end + +When /^"(.*?)" is not taken$/ do |arg1| + @old_pos.should eq " " +end + +Then /^it is now the computer's turn$/ do + @game.current_player.should eq "Computer" +end + +When /^there are three X's in a row$/ do + @game = TicTacToe.new(:computer, :X) + @game.board[:C1] = @game.board[:B2] = @game.board[:A3] = :X +end + +Then /^I am declared the winner$/ do + @game.determine_winner + @game.player_won?.should be_true +end + +Then /^the game ends$/ do + @game.over?.should be_true +end + +Given /^there are not three symbols in a row$/ do + @game.board = { + :A1 => :X, :A2 => :O, :A3 => :X, + :B1 => :X, :B2 => :O, :B3 => :X, + :C1 => :O, :C2 => :X, :C3 => :O + } + @game.determine_winner +end + +When /^there are no open spaces left on the board$/ do + @game.spots_open?.should be_false +end + +Then /^the game is declared a draw$/ do + @game.draw?.should be_true +end + +When /^"(.*?)" is taken$/ do |arg1| + @game.board[arg1.to_sym] = :O + @taken_spot = arg1.to_sym +end + +Then /^computer should ask me for another position "(.*?)"$/ do |arg1| + @game.board[arg1.to_sym] = ' ' + @game.should_receive(:get_player_move).twice.and_return(@taken_spot, arg1) + @game.player_move.should eq arg1.to_sym +end diff --git a/tictactoe/features/step_definitions/tic-tac-toe.rb b/tictactoe/features/step_definitions/tic-tac-toe.rb new file mode 100644 index 0000000..f8e35b4 --- /dev/null +++ b/tictactoe/features/step_definitions/tic-tac-toe.rb @@ -0,0 +1,146 @@ +class TicTacToe + SYMBOLS = [:X, :O] + PLAYERS = [:player, :computer] + RED = "\e[31m" + GREEN = "\e[32m" + OFF = "\e[0m" + attr_reader :player, :last_taken + attr_accessor :player_symbol, :computer_symbol, :players, :whose_turn, :board + + def initialize starts=PLAYERS.sample, s=SYMBOLS.sample + @name = {:player => 'Player', :computer => 'Computer'} + @whose_turn = PLAYERS.index starts + @whose_symb = SYMBOLS.index s + @symbol = { + #PLAYERS[@whose_turn] => s, + :player => s, + :computer => SYMBOLS[(SYMBOLS.index s)^1] + } + @board = { + :A1 => ' ', :A2 => ' ', :A3 => ' ', + :B1 => ' ', :B2 => ' ', :B3 => ' ', + :C1 => ' ', :C2 => ' ', :C3 => ' ' + } + @draw = @game_over = false + end + + def player= name + @player = @name[:player] = name + end + + def open_spots + board.select{|k, v| v == ' '}.keys + end + + [:player, :computer].each do |s| + + define_method("#{s}_symbol") do + instance_variable_get("@symbol")[s] + end + + define_method("#{s}_won?") do + ws = instance_variable_get("@winning_symbol") + ss = instance_variable_get("@symbol")[s] + ws == ss + end + + end + + def welcome_player + "Welcome #{@player}" + end + + def current_player + @name[PLAYERS[@whose_turn]] + end + + def indicate_player_turn + puts "#{@player}'s Move:" + end + + def get_player_move + move = gets.chomp.upcase + end + + def player_move + pos = get_player_move.to_sym + until self.open_spots.include? pos + puts "#{pos} is taken, yo. Try again." + pos = get_player_move.to_sym + end + @board[pos] = @symbol[:player] + @last_taken = pos + pos + end + + def computer_move + puts "My move, yo:" + pos = open_spots.sample + @board[pos] = @symbol[:computer] + @last_taken = pos + pos + end + + def current_state + b = @board.map{|k,v| k == @last_taken ? colorize(v, OFF) : colorize(v)} + + #b = @board.values.map{|v| v.to_s} + cs = '' + [0,3,6].each do |row| + b[row...row+3].each{|cell| cs << cell} + cs << "\n" + end + cs + end + + def over? + @game_over + end + + def spots_open? + open_spots.length > 0 + end + + def determine_winner + + winning_line = [ + [:A1, :A2, :A3], + [:B1, :B2, :B3], + [:C1, :C2, :C3], + + [:A1, :B1, :C1], + [:A2, :B2, :C2], + [:A3, :B3, :C3], + + [:A1, :B2, :C3], + [:A3, :B2, :C1], + ] + [player_symbol, computer_symbol].each do |sym| + owns = @board.select{|k,v| v == sym}.keys + winning_line.each do |line| + if (line & owns).length == 3 + @winning_symbol = sym + @game_over = true + end + end + end + + @game_over = true unless spots_open? + toggle_current_player + end + + def draw? + !(computer_won? || player_won?) + end + + private + + def toggle_current_player + self.whose_turn = self.whose_turn^1 + end + + def colorize cell, color = cell == :X ? RED : GREEN + "#{color}#{cell.to_s}#{OFF}" + end + +end diff --git a/tictactoe/features/tic-tac-toe.feature b/tictactoe/features/tic-tac-toe.feature new file mode 100644 index 0000000..6f3134d --- /dev/null +++ b/tictactoe/features/tic-tac-toe.feature @@ -0,0 +1,57 @@ +Feature: Tic-Tac-Toe Game + As a game player I like tic-tac-toe + In order to up my skills + I would like to play agaist the computer + +Scenario: Begin Game + Given I start a new Tic-Tac-Toe game + When I enter my name Renee + Then the computer welcomes me to the game with "Welcome Renee" + And randomly chooses who goes first + And who is X and who is O + +Scenario: My Turn + Given I have a started Tic-Tac-Toe game + And it is my turn + And the computer knows my name is Renee + Then the computer prints "Renee's Move:" + And waits for my input of "B2" + +Scenario: Computer's Turn + Given I have a started Tic-Tac-Toe game + And it is the computer's turn + And the computer is playing X + Then the computer randomly chooses an open position for its move + And the board should have an X on it + +Scenario: Making Moves + Given I have a started Tic-Tac-Toe game + And it is my turn + And I am playing X + When I enter a position "A1" on the board + And "A1" is not taken + Then the board should have an X on it + And it is now the computer's turn + +Scenario: Making Bad Moves + Given I have a started Tic-Tac-Toe game + And it is my turn + And I am playing X + When I enter a position "A1" on the board + And "A1" is taken + Then computer should ask me for another position "B2" + And it is now the computer's turn + +Scenario: Winning the Game + Given I have a started Tic-Tac-Toe game + And I am playing X + When there are three X's in a row + Then I am declared the winner + And the game ends + +Scenario: Game is a draw + Given I have a started Tic-Tac-Toe game + And there are not three symbols in a row + When there are no open spaces left on the board + Then the game is declared a draw + And the game ends diff --git a/tictactoe/play_game.rb b/tictactoe/play_game.rb new file mode 100644 index 0000000..7b99f10 --- /dev/null +++ b/tictactoe/play_game.rb @@ -0,0 +1,22 @@ +require './features/step_definitions/tic-tac-toe.rb' + +@game = TicTacToe.new +puts "What is your name?" +@game.player = gets.chomp +puts @game.welcome_player + +until @game.over? + case @game.current_player + when "Computer" + @game.computer_move + when @game.player + @game.indicate_player_turn + @game.player_move + end + puts @game.current_state + @game.determine_winner +end + +puts "You Won!" if @game.player_won? +puts "I Won!" if @game.computer_won? +puts "DRAW!" if @game.draw?