From: Robert Klemme Date: 2010-04-17T00:50:15+09:00 Subject: Re: Writing a parser On 04/16/2010 03:57 PM, Martin Hansen wrote: > This got pretty advanced fast :/. Multiple things are going on at the > same time - and I have grown up learning that a piece of code should > only do one thing at a time - only one! Hey, that's a good thing to learn early! :-) > I think, I need to back up a > step or two to understand what is going on. Perhaps you could enlighten > me on how you addressed this problem strategically? Well, basically I oriented myself on the way IO (and File) and similar classes work (for example CSV): they iterate all elements which are individually handed over to a block. That's the interface part. Basically this is also the contract of Enumerable; #each hands off every item to the block provided. I separated the file opening from the iteration because you may want to iterate other types of things that respond to #each_line (ARGF comes to mind, but String and StringIO as well). This gives you the flexibility to pull the data from wherever you like. Parsing itself is pretty straightforward I'd say; at least I am using the idiom frequently. You read line by line and decide what kind of line you see and what you need to do with it. Regular expressions are nice for this combined with a "case". Finally, I aliased #each to #each_record so including Enumerable makes sense (Enumerable relies on #each being present). That gives you all the nice methods like #select, #find etc. for free. And I added the convenience method #foreach to the class so you can use that IO#foreach / File#foreach. Downside of this approach is of course that you cannot fetch records individually like in your code where you have a method that fetches only the next record. > And how would the appropriate Unit Tests for this thing look like? You could create a IO mock that returns lines as that of valid (and invalid!) records and verify that parsing returns exactly those records that you expect. Of course you need various tests for valid and invalid data etc. Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/