usable in any place a human can be used

Showing posts with label ruby. Show all posts
Showing posts with label ruby. Show all posts

20100126

when in rome

[caption id="attachment_624" align="alignright" width="300" caption="Trust me, you want to do what the Romans do, I mean... have you ever built a Collisium?"]collisium[/caption]

Ah the cliché of it all, "When in Rome." Although it would be nice to have a post about being in or traveling to Rome, sadly this is not the case. Instead, this post is about following convention and how that can help you learn.


I've been getting into ruby as of late, after learning Smalltalk, Objective-C, and LISP (to varying degrees), ruby hits a nice sweet spot of stealing some of the best bits from each. I was recently approached by a friend who does primarily .Net programming about the best way to go about learning ruby. He had decided that, at least in the beginning, he should use the NetBeans IDE. This seems harmless enough, even logical for someone who spends their entire day in Visual Studio to want the comforting guidance of the IDE. It is also the exact wrong approach.


As he progressed past simple "Hello World" examples and onto his first rails project he found himself battling with the IDE. Odd error messages, the IDE struggling to provide auto-completion on the dynamic models, but most importantly a complete lack of resources. The ruby and rails world to a large degree lives and breathes on the command line, right now if you go to my home computer you will find 4 terminal windows arranged with a mysql shell, script/console, script/server, and one for git. If something goes wrong and I get a weird error, I do what all great programmers do, copy and paste that sucker into Google. I normally find somewhere around a bajillion hits with solutions, huzzah!


My friend on the other hand had trouble doing the simple things through the IDE, like installing gems. I'm certain the IDE was capable of it, and that someone better versed in it would be able to help him out, but the Google-scape was barren to his questioning. All I could say to answer his questions were, "well I'm not sure how NetBeans does it, but on the command line just type gem install [gem]" (Also I can speak in teletype, I just do a robot voice.)


Despite the difficulties, my friend clung to the belief that the IDE was the way to go for beginners. I finally realized the perfect analogy to drive home the point, I asked, "Would you ever advise someone new to .Net to learn it by using the command line tools?" It's a perfectly valid question, I'm sure plenty of people who hang out in vim all day and don't mind doing things like ./configure && make && sudo make install (thanks Jeremiah for pointing out my n00bishness) would feel much more at home on the command line.


I am not free of fault on this either, when I attempted to learn git for the first time, I used TortoiseGit. I was very comfortable with TortoiseSVN and thought it would ease the transition. It sure did, I was able to treat git exactly like svn, and completely miss the point! Once I moved to the command line (and watched some screencasts and read some articles) I felt much more at home with git, and even began to understand why I would want to use it over svn. I had stopped trying to make it something it isn't and embraced the thing that it is.


The point here is that when you learn something new, it's new, don't bring along your technological baggage. If the community all rallies around some IDE (.Net, I'm looking at you) then for flying spaghetti monster's sake, use that IDE. If they rally around the command line (ruby, I'm looking at you) then by the hammer of Thor, use the command line. If they rally around some weird virtual environment machine (smalltalk, I'm looking at you) then have fun and realize you are never going to be able to use that at work (just poking fun, I <3 smalltalk).


The point here is that learning something new is often times uncomfortable, you have to feel like a tourist for a while. When in Rome though, do as the Romans do. Embrace the methodologies, naming conventions, and tools that are the community standard. Give it a few weeks, if you still find yourself hating it, then maybe that particular technology isn't for you, it's ok, we can't all love everything. Life is about trying new things and figuring out what makes you want to get out of bed in the morning, for some people it will be .Net, for some ruby, for some COBOL (just kidding, no one likes COBOL).


You never do yourself any favors by half-way learning something, because you will either hate it because it was poorly shoehorned into an inappropriate paradigm, or you will learn to love it. "That second thing doesn't sound too bad" (I can sense your thoughts), and at first blush its not, until you want to start participating with the community by using others' code and sharing your code. Then you will have to unlearn all the bad practices you've adopted and have a difficult transition into the community, attempting to erase months of muscle memory. Save yourself the difficult task of trying to unlearn something and simply embrace the technology in full to begin with. It's a steeper curve, but the payout is the depth of understanding.

20091229

book review: design patterns in ruby

[caption id="attachment_62" align="alignright" width="226" caption="Go buy this now"]design patterns in ruby[/caption]

I am back from the holiday break and a perfect storm has come together, I'm currently working on a rails project, and I have a wonderful girlfriend who embraces my geekiness and buys me Design Patterns in Ruby. I have been reading this thing for the past few days and can't put it down, I wanted to read a chapter last night before bed, I sleepily set it down 5 chapters later.


Just so you understand something, although I love to read, I am a slow reader, books are hard for me to get through, I also have a ton of things to read and play around with, so you better keep my attention. I have also read the classic GoF book, so I'm coming into this book well versed in design patterns. I've played with ruby a few times before, but nothing too serious (if you look back in the archives you will see that my first post was on ruby koans).


Let's talk about this great book by Russ Olsen. The book does not require you to know anything about ruby, the first chapter is, in fact, a great primer to the language. Olsen comes from a background of 25 years of software development experience, as he puts it


I have been building software for more than 25 years. I’ve done assembly language, FORTRAN, Pascal, C, C++, Python, Java and now Ruby.
  -Russ Olsen

The introduction to ruby feels like it was written for someone with programming experience in a Java-like language. Throughout the book Olsen makes reference to the Java way to do things (which will be easy to grasp for the .Net crowd too). The primer to the language is interesting in that it skips some of the core things that makes ruby what it is (the whole meta-programming, monkey patching, message passing thing). This would seem like an oversight at first, but was helpful for me as a new ruby user. I wasn't bogged down in the different of ruby, so I could focus on the same. This let me feel comfortable with the language and focus on the patterns, as we will see, these parts missing in the primer will be fully explored later in the book.


The book is structured very much like the GoF book, with each chapter focusing on a particular pattern. Olsen opens up the chapter with some example situation, then he moves into how you could solve it with inheritance or ugly code. Then the problem is re-examined, a pattern starts to emerge, and then is described. The pattern is explained in the classic GoF style with example code (in ruby) and UML diagrams, the best part though is the clear, concise, approachable explanation provided by Olsen. The pattern now being firmly understood, the book digs into the pattern and looks at ways that we can ruby-ize it. At this point we are normally treated to some new interesting ruby language paradigm that let's us quickly and easily rewrite the pattern, making it more concise and elegant. There is then a discussion of the uses, and probably more importantly, the abuses of the pattern. Every chapter ends with a nice summary of what was learned and (as I found out last night) an enticement to keep reading as the next pattern is introduced.


[caption id="attachment_486" align="alignleft" width="240" caption="Pure unadulterated rocket sauce!"]rocket sauce[/caption]

The writing is incredibly approachable, Olsen does not get bogged down in technical jargon, he explains everything that's going on in a concise and understandable way. There are copious code examples that are excellent at providing a concrete example to the abstract pattern Olsen is discussing. The author mixes in some humor here and there and will show how other programming languages implement the patterns and historical reasoning for why things are the way they are in ruby.


The overall impression I got from this book is that it is win, condensed down into ink on paper. I have learned a ton about ruby, relearned some great patterns, and gotten a great insight on the ruby way to solve problems. If you find yourself thinking, "Well I don't need to learn design patterns, I'm so smart!" Well you are not, I'm going to use one of my favorite quotes here with a bit of a twist.


Those who don't understand design pattern are condemned to reinvent them, poorly.
  -Matt Nowack (original attribution to Henry Spencer)

Design Patterns are all around you, learning these will help you solve future problems, understand how rails works (in fact there are several occasions in the book where Olsen shows how rails uses this pattern or that one). This book is a pleasure to read, and I suspect will serve as a nice reference for implementing patterns correctly in ruby. I'm glad to have it in my toolbox, and I would suggest you get it for yourself.

20091223

decompress

[caption id="attachment_472" align="alignnone" width="450" caption="Get ready for the feats of strength"]festivus card[/caption]

The holidays are upon us and no matter what holiday your particular sky god has you celebrate (Festivus for the Rest of Us!) there is one thread of humanity that binds us together at this time, days off from work. When you have some time off of work you can spend it doing any number of worthwhile things



  • Drinking egg nog until you black out

  • Eating your weight in sugar cookies

  • Having that same argument with your family that you've been having for the last 10 years

  • Watching 24 hours of A Christmas Story

  • Spending quality time with friends and loved ones

  • Living through the same day over and over and over, á la Groundhog's Day (Best saved for the actual Groundhog's Day)


If you are reading this blog there is a good chance that you are some sort of programming nerd, its ok, I don't care what the New York Times says. As a proud nerd you have probably heard of some sort of technology that interests you, maybe clojure has piqued your curiosity, or you finally want to learn that "rails" thing all those young whippersnappers keep talking about. I would argue that this can be a great way to decompress, if you do it right.


First off, find something different than what you are used to, if your 9-5 is .Net don't spend your precious free time learning more .Net, that's stupid. Go find something radically different, maybe look at a functional programming language, go find that weird kid in the corner and talk to him, he probably has interesting stories about fire. This might seem like a waste of time at first, but it's not. It's all too easy to get locked into an ecosystem, doing the same thing day in and day out, to get comfortable there and to start thinking that your way is the only way or the best way. Reading about other technology outside of your realm might not have a direct benefit to your 9-5, but you may gain a perspective or understanding that would be incredibly difficult to get from your standard frame of mind.


Second off, this isn't work, this is fun. You are allowed to make mistakes and change your mind. If you work through a tutorial or get done with the first chapter of something and find that you really don't care, then go find something else, the software world is full of interesting things. The thing is, only stop if you grok the subject and dislike it, don't necessarily stop just because you don't get it at first.


[caption id="attachment_475" align="alignright" width="300" caption="What? Caroling? No fuck that, I got some erlanging to do!"]erlang source in gedit[/caption]

Third off, this is just to whet your whistle. Don't ignore your loved ones, squirreled away with your Beginner's Guide to Erlang because you've fallen in love with the idea of massively parallel systems. Take this time to investigate several things, learning the basics and setting up your love affair for the next few months. Then make sure you tell the people you care about that you love them and eat too much food and do people things.


For me this break will be about Rails. I've followed rails for a while, I've always been impressed with it, and I've had a few false starts. I've gone through the Getting Started tutorial more than once. I'm a php guy at my core, but learning how other people do the web is worthwhile. I've started the adventure already and think that this time it might stick. I have a 2 hour car ride up to Cleveland and back that I plan to fill with listening to Rails podcasts.




That's all for now, go relax and decompress, that's what I plan on doing for the next 4 days. As a side note I will probably not update during the holiday break so if you obsessively check or your rss feed gets lonely don't worry I will be back on the 28th.

20091105

duck typing works

[caption id="attachment_62" align="alignleft" width="226" caption="Design Patterns in Ruby"]Design Patterns in Ruby[/caption]

I recently had the joy of picking up the book Design Patterns in Ruby which is a great book, made my Christmas wish list. If you have been living on the moon or are just one of those weird people that haven't heard of ruby yet, it is a dynamically typed interpreted language made famous by the web framework, Ruby on Rails.


Do you see what I just did right there? I gave you some background information, information that you more than likely don't need, you are reading my blog, you know what ruby is. Russ Olsen (author of Design Patterns in Ruby) does the same thing with duck typing. What is duck typing you ask? (again you probably didn't, you know what it is, or you are familiar with this thing called Google). Well it comes from the term, "If it walks like a duck, quacks like a duck, then its a duck" and according to the authority on all human knowledge it can be defined as the following



In computer programming with object-oriented programming languages, duck typing is a style of dynamic typing in which an object's current set of methods and properties determines the valid semantics, rather than its inheritance from a particular class or implementation of a specific interface.

One of the properties this gets you is the ability to pass any kind of variable anywhere and as long as it acts like the object the function is expecting it will work, no matter what class it is. In practice this allows for some great code reuse and as described in the book the evaporation of some class GoF design patterns. Olsen goes into a bit of depth about duck typing and the classic fear of someone coming from a strongly typed language.



So there is no compile time or static checks, what stops you from passing a database connection into a function that accepts an int or calling the give_big_fat_bonus method on a lowly worker instance instead of an executive instance, or of course the ceo instance which is a derived class of executive.
Anonymous Object Oriented Programmer

The answer is a resounding, nothing! (Dovetails nicely with my last post) Nothing stops you from doing this, go ahead see what happens. Depends on the language, in ruby you get a NoMethodError, and you get something like that in most duck typed languages.


The question then is how do people write any code that works, the answer is by not being full-on stupid. Ruby, and other duck typed languages, have taken to heart the sentiment of my post i can't stop you from being stupid (The shameless self promotion is getting a little rampant at this point). The language can't stop you from treating an int like a database connection, and really why should it. What in the hell are you doing mixing up an int and a database connection, you deserve to get punched in the face, a NoMethodError is the least of your worries.


But, accidents happen, so your db variable holding the database connection and your dv variable holding the direct value modifier amount are dangerously close on the keyboard. Are you going to just pray that you are 100% correct in your typing all the time, who do you think you are, me?! (I'll wait patiently as grammar-nazis and typoistas tear apart this post). This is why unit testing is so huge in duck typed languages, if you are using sweet delicious lisp then repl is your friend, ruby also has repl (irb) but its not nearly as integral to the development process as repl is to lisp. Your tests let you know that you aren't doing something stupid, and performs all the static and dynamic checking one could want.


So go out and give a duck typed language a shot, pretty soon you will enjoy the added speed, and you will realize that the static syntax checking is not necessary if you know what the hell you are doing.

20091023

treasure hunting

Working with programming languages is fun stuff. If you are a programmer then you probably only think about your language as much as you need to to get the job done. In fact you have to really, if you spent all day thinking about how the compiler is going to allocate this variable off the stack or this one off the heap or how its going to write out the virtual lookup tables, you could never get anything accomplished.

It's a shame though because our programming languages are some of the most interesting and complex software we interact with. If you are willing to look around you can find some real treasures out there, and even if you never code anything of importance in these new found treasures, the experience will pay dividends elsewhere.

I'd like to take you on a tour of the treasures I've found in my travels through the world we call programming, I'll split it into four easy to consume chunks.

The Past

The history of our field is short, still short enough that you can probably come to know most if not all of it. This is one of the interesting things about Computer Science, its a field that, in it's modern form, is about 60 years old. The amazing thing about all this is that there are some gems from the past, truly ground breaking work that we still use today.

  • Lisp
    As you may well be aware I've recently fallen in love with lisp, I'm starting to think about her all the time, and you can too. The amazing thing that, to this moment, knocks my socks off, is that Lisp was originally conceived in 1958 and has all kinds of concepts that you wouldn't expect from a language in it's 50s. Closures, homoiconic code, anonymous functions, object oriented programming, and a web framework. There is a lot more to this language, and it is definitely worth your time, go read up.
  • Smalltalk
    This one comes from the 1970's from the famous Xerox PARC. Smalltalk was way ahead of its time with a fully integrated development environment, a fully functional GUI, no files (this sounds bad at first, but its freeing not having to worry about where your source lives), everything is a file, and much more. Smalltalk's influence is far reaching even to this day, Objective-C borrows heavily from it, and the influential Gang of Four book offers source in C++ and Smalltalk.
  • C
    Hard to believe that this staple of computer programming was invented in 1972. Without C, Unix would not exist. C is still crazy fast, basically human readable assembly, and still widely used. The backbone and infrastructure of most of our technology exists because of C. Have a scripting language, need a way to shut people up who are saying it's too slow, allow them to call C modules, done. C is definitely worth knowing, you can access a giant pile of source code, and get as close to the machine as possible without busting out the x86 Assembly Guide.

The Present

  • Ruby
    This is the current hotness, although its hotness may be waning somewhat. Today ruby is the top language on github and there is a new interesting project written in ruby everyday. Ruby on Rails created the rockstar ruby programmer, and revolutionized data backed web development. Ruby is going to be around for a while, and because of REPL its easy to get started.
  • JVM Languages
    Java may be out, but the virtual maching that runs the language has never been more popular. Clojure (a JVM Lisp, which will probably get its own article soon) and Scala are up and coming. The ubiquity of the JVM means that you can run this code on almost any machine, and the languages are squeezing speed and performance out of the JVM that would have been unheard of a few years ago. These languages can also leverage the huge pile of Java Libraries out in the wild, so the first major hurdle to a new language (what can this thing actually do and are there any tools for it), is easily leapt.
  • DSLs
    Domain Specific Languages are starting to come into their own. Some of this popularity is owed to the rise of ruby which makes writing a new DSL somewhat trivial. Sass, Haml, and many others DSLs are beginning to find more and more adoption within their domain.

The Future

  • Functional Programming
    Erlang, Haskell, OCaml, etc. are beginning to see an upswing in interest. The rise of multi-processor cores and the inherent complexity of mutli-threaded programming in imperative programming makes these languages a tantalizing option. Erlang can support millions of threads with simple, easy to understand code. CouchDB will be the proving ground for Erlang's efficacy.
  • JavaScript
    As I wrote in the future: javascript
    When it get's down to it, JavaScript is a great language. It has a ton of exposure, and a huge amount of developer mindshare. JavaScript isn't going away anytime soon, and considering how hard it is to get browser vendor's to agree, isn't getting replaced anytime soon. JavaScript will become more and more prevalent both on the server and on the desktop. I welcome our new prototype based overlord, and so should you.
    So far nothing has changed.
  • Anything
    That is one of the most exciting things about this field, it could be anything. Before Ruby on Rails, the ruby language was a small odd scripting language that few outside of Japan had heard about. With the success of RoR ruby (which is an acceptable lisp) use has exploded and they have gained massive developer mindshare. Tomorrow a new technology could set the world ablaze, and the best part is that we have a chance to shape that future. This is an industry in which a man with a great idea can truly change the face of the development landscape.

These are just some of the treasures I have discovered by opening my eyes and looking around. There are plenty more gems that I have found that didn't make it into this post, but only because these one's were on the top of my brain. If you encounter a new language, take an hour or so to run through a tutorial, it could be worth it, it might not. You may find yourself falling in love, or maybe you missed a few episodes of the Simpsons. At the end of the day though, you will be glad that you took the time to learn something new, when you see glimmers of it in something old, and your knowledge of share-nothing concurrency saves the day on your next project.

This is a dynamic wonderful field, go play!

20091006

ruby koans (2)

I still have the good fortune of not having any huge problems with our production application. During this time I'm brushing up on some ruby, sharpening the blade. I've been doing this by working through EdgeCase's Ruby Koans. In my first blog post ruby koans I suggested that anyone interested in ruby utilize this resource and pointed out some problems I had encountered. I still suggest that anyone wanting to learn ruby and who has a basic understanding of programming use this great resource.

Working through the koans I have found some more issues, this time in the about_message_passing.rb file. One is just an oddity, the other a potential show stopper for someone new to programming.

Starting at line 50 there is a class called MessageCatcher (technically they are reopening the class defined on line 5)

class MessageCatcher
  def add_a_payload(*args)
    return :empty unless args
    args
  end
end

This is a very oddly named function, it doesn't seem to add a payload to the the arguments, and it is coded in such a way that it will never return :empty. For it to return :empty, args would have to evaluate to false. The only falsey values in Ruby are nil and false, the only values args can be is an array. Arrays, even empty arrays, are true in ruby. If you don't believe me, go ahead and run this in irb

:empty_arrays_are_true if []

That will evaluate to :empty_arrays_are_true, which proves my point. This is really a minor issue, but when filling out the corresponding test, the results aren't really obvious.

The much bigger problem starts with the TypicalObject example

class TypicalObject
end

def test_sending_undefined_messages_to_a_typical_object_results_in_errors
  typical = TypicalObject.new

  assert_raise(NoMethodError) do
    typical.foobar
  end
  assert_match(/foobar/, exception.message)
end

This results in a nasty error when you rake, that looks something like this

You have not yet reached enlightenment ...
undefined local variable or method `exception' for #

Please meditate on the following code:
./about_message_passing.rb:78:in `test_sending_undefined_messages_to_a_typical_object_results_in_erros'
./edgecase.rb:143:in `send'
./edgecase.rb:143:in `run_test'
./edgecase.rb:135:in `run_tests'
./edgecase.rb:134:in `each'
./edgecase.rb:134:in `run_tests'
./edgecase.rb:204
./edgecase.rb:203:in `each'
./edgecase.rb:203
./edgecase.rb:202:in `catch'
./edgecase.rb:202
path_to_enlightment.rb:27

If you are new to programming this could throw you off your game, the interpreter does helpfully tell us the line number to look at, line 78.

Looking at line 78 we see that we are using a local variable named `exception', but we never define this variable. The way to fix this is to assign the result of the assert_raise to the variable exception, like so

class TypicalObject
end

def test_sending_undefined_messages_to_a_typical_object_results_in_errors
  typical = TypicalObject.new

  exception = assert_raise(NoMethodError) do
    typical.foobar
  end
  assert_match(/foobar/, exception.message)
end

That simple assignment, which does appear correctly in the test right after this one, solves the problem and allows you to continue on your ruby learning way.



ruby koans (2)

I still have the good fortune of not having any huge problems with our production application. During this time I'm brushing up on some ruby, sharpening the blade. I've been doing this by working through EdgeCase's Ruby Koans. In my first blog post ruby koans I suggested that anyone interested in ruby utilize this resource and pointed out some problems I had encountered. I still suggest that anyone wanting to learn ruby and who has a basic understanding of programming use this great resource.


Working through the koans I have found some more issues, this time in the about_message_passing.rb file. One is just an oddity, the other a potential show stopper for someone new to programming.


Starting at line 50 there is a class called MessageCatcher (technically they are reopening the class defined on line 5)


[ruby firstline="50"]
class MessageCatcher
def add_a_payload(*args)
return :empty unless args
args
end
end
[/ruby]

This is a very oddly named function, it doesn't seem to add a payload to the the arguments, and it is coded in such a way that it will never return :empty. For it to return :empty, args would have to evaluate to false. The only falsey values in Ruby are nil and false, the only values args can be is an array. Arrays, even empty arrays, are true in ruby. If you don't believe me, go ahead and run this in irb


[ruby gutter="false"]:empty_arrays_are_true if [][/ruby]

That will evaluate to :empty_arrays_are_true, which proves my point. This is really a minor issue, but when filling out the corresponding test, the results aren't really obvious.


The much bigger problem starts with the TypicalObject example


[ruby firstline="69"]
class TypicalObject
end

def test_sending_undefined_messages_to_a_typical_object_results_in_errors
typical = TypicalObject.new

assert_raise(NoMethodError) do
typical.foobar
end
assert_match(/foobar/, exception.message)
end
[/ruby]

This results in a nasty error when you rake, that looks something like this


[plain highlight="2" gutter="false"]
You have not yet reached enlightenment ...
undefined local variable or method `exception' for #<aboutMessagePassing:0xmemory>

Please meditate on the following code:
./about_message_passing.rb:78:in `test_sending_undefined_messages_to_a_typical_object_results_in_erros'
./edgecase.rb:143:in `send'
./edgecase.rb:143:in `run_test'
./edgecase.rb:135:in `run_tests'
./edgecase.rb:134:in `each'
./edgecase.rb:134:in `run_tests'
./edgecase.rb:204
./edgecase.rb:203:in `each'
./edgecase.rb:203
./edgecase.rb:202:in `catch'
./edgecase.rb:202
path_to_enlightment.rb:27
[/plain]

If you are new to programming this could throw you off your game, the interpreter does helpfully tell us the line number to look at, line 78.


Looking at line 78 we see that we are using a local variable named `exception', but we never define this variable. The way to fix this is to assign the result of the assert_raise to the variable exception, like so


[ruby firstline="69" highlight="75"]
class TypicalObject
end

def test_sending_undefined_messages_to_a_typical_object_results_in_errors
typical = TypicalObject.new

exception = assert_raise(NoMethodError) do
typical.foobar
end
assert_match(/foobar/, exception.message)
end
[/ruby]

That simple assignment, which does appear correctly in the test right after this one, solves the problem and allows you to continue on your ruby learning way.



20091002

ruby koans

EdgeCase's Ruby Koans are a great way to get started with the Ruby programming language. I've worked through them once before and have had some free time at work so decided to work through them again.

The quality of the koans are normally excellent, there are a few times where a comment is left in the code to make you think, and you really wish that there was an answer key somewhere. There are also what look like a few errors in the code

In about_sandwich_code.rb, the find_line and find_line2 functions don't seem to make much sense. You would imagine a function would find a line matching a given regular expression, but the regular expression is hardcoded to /e/ which doesn't seem very realistic. This is the original.

def find_line(file_name)
  file = open(file_name)
  while line = file.gets
    return line if line.match(/e/)
  end
ensure
  file.close if file
end

A more realistic function would be

def find_line(file_name, regex)
  file = open(file_name)
  while line = file.gets
    return line if line.match(regex)
  end
ensure
  file.close if file
end

I'm sure this was done to simplify the exercise, but it violates the rule of least surprise by adding magic functionality to the function.

In the last function of about_scoring_project.rb, named test_score_of_mixed_is_sum, the first assert reads

 assert_equal 50, score([2, 5, 2, 2, 3]) 

The rules of the game clearly specify that

 
# * A set of three numbers (other than ones) is worth 100 times thenumber. (e.g. three fives is 500 points).
# ...
# * A five (that is not part of a set of three) is worth 50 points.

This means that the score should be 200 (for the set of three 2's) + 50 (for the 5) = 250. The first assert should be changed to

 assert_equal 250, score([2, 5, 2, 2, 3]) 

If you are interested in learning ruby, this is an indispensable way to learn not just the syntax, but to get the flavor, and to start thinking in ruby.

Click this link to reveal my solution to the scoring problem
Show Solution



ruby koans

EdgeCase's Ruby Koans are a great way to get started with the Ruby programming language. I've worked through them once before and have had some free time at work so decided to work through them again.


The quality of the koans are normally excellent, there are a few times where a comment is left in the code to make you think, and you really wish that there was an answer key somewhere. There are also what look like a few errors in the code


In about_sandwich_code.rb, the find_line and find_line2 functions don't seem to make much sense. You would imagine a function would find a line matching a given regular expression, but the regular expression is hardcoded to /e/ which doesn't seem very realistic. This is the original.


[ruby]
def find_line(file_name)
file = open(file_name)
while line = file.gets
return line if line.match(/e/)
end
ensure
file.close if file
end
[/ruby]

A more realistic function would be


[ruby]
def find_line(file_name, regex)
file = open(file_name)
while line = file.gets
return line if line.match(regex)
end
ensure
file.close if file
end
[/ruby]

I'm sure this was done to simplify the exercise, but it violates the rule of least surprise by adding magic functionality to the function.


In the last function of about_scoring_project.rb, named test_score_of_mixed_is_sum, the first assert reads


[ruby] assert_equal 50, score([2, 5, 2, 2, 3]) [/ruby]

The rules of the game clearly specify that


[ruby]
# * A set of three numbers (other than ones) is worth 100 times thenumber. (e.g. three fives is 500 points).
# ...
# * A five (that is not part of a set of three) is worth 50 points.
[/ruby]

This means that the score should be 200 (for the set of three 2's) + 50 (for the 5) = 250. The first assert should be changed to


[ruby] assert_equal 250, score([2, 5, 2, 2, 3]) [/ruby]

If you are interested in learning ruby, this is an indispensable way to learn not just the syntax, but to get the flavor, and to start thinking in ruby.


Expand this block of source to see my solution


[ruby collapse="true"]
def score(dice)
result = 0
counter = {}
(1..6).each { |x| counter[x] = 0 }
dice.each { |d| counter[d] += 1 }
if counter[1] >= 3
result += 1000
counter[1] -= 3
end

(2..6).each do |x|
if counter[x] >= 3
result += (100 * x)
counter[x] -= 3
end
end

result += (counter[1] * 100)
result += (counter[5] * 50)
end
[/ruby]