# Best DRY solution for this task

**URL:** <https://www.ruby-forum.com/t/best-dry-solution-for-this-task/106136>\
**Category:** Ruby\
**Created:** [June 6, 2007, 8:01pm UTC](https://www.ruby-forum.com/t/best-dry-solution-for-this-task/106136 "2007-06-06T20:01:20Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![anansi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/9fc348/32.png) [@anansi](https://www.ruby-forum.com/u/anansi)\
**Post date:** [June 6, 2007, 8:01pm UTC](https://www.ruby-forum.com/t/best-dry-solution-for-this-task/106136/1 "2007-06-06T20:01:20Z")

</div>

Hi,  
I have a certain problem here and can’t find a proper DRY solution for  
this so I wondered if someone here has an idea and could help me.

I’m reading a file byte for byte. This file is structured and I try to  
give out each structures element and the meaning of it. So let’s pretend  
the file content would be this in bytes (you get it e.g. with  
file.read(7)): 1 3d 0 233 0 1 2f

now I wanna read the file byte for byte and output if the first 3 bytes  
are equal 1 3d 0:  
startflag : good (1 3d 0)  
or if the check fails  
startflag : bad (2 3d 0)  
now the fourth byte is read and if it is 1  
debg\_mode : on  
if it is 0 : out and if it is 233 : don’t know …

My problem with a DRY solution is that some bytes in this file are  
grouped together and have just together a meaning as the first three  
starting bytes: 1 3d 0 at the beginning and some bytes have alone a  
meaning as the fourth byte 233 in the example.  
And that everything has another ouput. So the first three bytes meaning  
is another than the one of the fourt or the fifth byte.

My solution until now:

target = open(‘testfile.txt’,‘r’)

startflag = target.read(3)  
print(“startflag: “)  
if startflag == $startflag # here I took a global var because  
“\x13d0” didn’t work  
print(” good”)  
else  
print(" bad")  
end  
startflag.each\_byte do |x|  
printf("%x ",x)  
end  
puts “”

dbg\_mode = target.read(1)  
printf(“dbg\_mode: “)  
if dbg\_mode == “\x1”  
print(” on”)  
elseif dbg\_mode == “\x255”  
print(“don’t know”)  
else  
print(" bad")  
end  
dbg\_mode.each\_byte {|x| printf("%x ",x) }  
puts “”

and so on and on and on…

so how can I do this check and outputting better? Because there are many  
bytes with many different meanings and as said sometimes I need to read  
in 4 bytes then just one then again 2 bytes… is this at all possible  
to do dry-like?

thanks

–  
greets

```
                 one must still have chaos in oneself to be able to

```

give birth to a dancing star

---

<div class="post-metadata">

**Author:** ![anansi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/9fc348/32.png) [@anansi](https://www.ruby-forum.com/u/anansi)\
**Post date:** [June 6, 2007, 10:01pm UTC](https://www.ruby-forum.com/t/best-dry-solution-for-this-task/106136/2 "2007-06-06T22:01:39Z")

</div>

On Jun 6, 11:57 am, anansi [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I’m reading a file byte for byte. This file is structured and I try to  
> give out each structures element and the meaning of it. So let’s pretend  
> the file content would be this in bytes (you get it e.g. with  
> file.read(7)): 1 3d 0 233 0 1 2f

a) You might want to look into the BitStruct library.  
b) See the following. It’s up to you how much work you want to put in  
the common ‘eat’ method, versus how much you want to leave up to the  
proc for each particular matcher.

# Just for no-file testing

require ‘stringio’  
bytes = [1, 0x3d, 0, 233, 0, 1, 0x2f]  
byte\_string = StringIO.new( bytes.map{ |b| b.chr }.join )

class ByteEater  
def initialize( title, num\_bytes, &block )  
@title = title  
@num\_bytes = num\_bytes  
@proc = block  
end  
def eat( file )  
bytes = file.read( @num\_bytes )  
print( "#@title: " )  
@proc.call( bytes )  
bytes.each\_byte{ |x| print “%x” % x }  
puts “”  
end  
end

structure = [  
ByteEater.new( ‘startflag’, 3 ){ |bytes|  
if bytes == “\01\x3d\0”  
print " good"  
else  
print " bad"  
end  
},  
ByteEater.new( ‘dbg\_mode’, 1 ){ |bytes|  
case bytes  
when 1.chr  
print " on"  
when 255.chr  
print “don’t know”  
else  
print “bad”  
end  
},  
]

structure.each{ |eater|  
eater.eat( byte\_string )  
}

#=\> startflag: good13d0  
#=\> dbg\_mode: bade9

---

<div class="post-metadata">

**Author:** ![anansi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/9fc348/32.png) [@anansi](https://www.ruby-forum.com/u/anansi)\
**Post date:** [June 6, 2007, 10:13pm UTC](https://www.ruby-forum.com/t/best-dry-solution-for-this-task/106136/3 "2007-06-06T22:13:44Z")

</div>

> so how can I do this check and outputting better? Because  
> there are many  
> bytes with many different meanings and as said sometimes I  
> need to read  
> in 4 bytes then just one then again 2 bytes… is this at all  
> possible  
> to do dry-like?

Without knowing the details of the file you’re trying to parse it’s hard  
to say, but you might be well-served to write a simple finite state  
machine. E.g. something like:

mode = :expect\_header  
while !(mode == :done || mode == :fail)  
case mode  
when :expect\_header  
if target.read(3) == $startflag  
mode = :expect\_debug  
else  
mode = :fail  
end  
when :expect\_debug  
case target.read(1)  
when “\x1”  
debug = true  
mode = :expect\_body  
when “\x255”  
debug = nil  
mode = :expect\_body  
else  
mode = :fail  
end  
end  
end

- donald

---

<div class="post-metadata">

**Author:** ![anansi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/9fc348/32.png) [@anansi](https://www.ruby-forum.com/u/anansi)\
**Post date:** [June 7, 2007, 6:51pm UTC](https://www.ruby-forum.com/t/best-dry-solution-for-this-task/106136/4 "2007-06-07T18:51:01Z")

</div>

On 06.06.2007 22:12, Ball, Donald A Jr (Library) wrote:

> machine. E.g. something like:  
> when :expect\_debug  
> end  
> end

You can even nest cases

mode = :expect\_header  
while !(mode == :done || mode == :fail)  
case mode  
when :expect\_header  
mode = case target.read(3)  
when “\x1\x3d\x0”  
:expect\_debug  
else  
:fail  
end  
when :expect\_debug  
mode = case target.read(1)  
when “\x1”  
debug = true  
:expect\_body  
when “\xff”  
debug = nil  
:expect\_body  
else  
:fail  
end  
end  
end  
end

If you use nil as :fail then it becomes even simpler because you can  
omit “else” branches in “case”. Another alternative is to throw  
immediately when an error occurs.

Just some more food for experimening.

Kind regards

robert
