# BitStruct technique

**URL:** <https://www.ruby-forum.com/t/bitstruct-technique/168013>\
**Category:** Ruby\
**Created:** [May 14, 2009, 11:19pm UTC](https://www.ruby-forum.com/t/bitstruct-technique/168013 "2009-05-14T23:19:12Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![cremes](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/e19b73/32.png) [@cremes](https://www.ruby-forum.com/u/cremes)\
**Post date:** [May 14, 2009, 11:19pm UTC](https://www.ruby-forum.com/t/bitstruct-technique/168013/1 "2009-05-14T23:19:12Z")

</div>

While working on a problem this morning I came up with an interesting  
technique for using the BitStruct gem to produce binary strings. After  
some hacking around I discovered I didn’t need to use BitStruct at  
all. Even so I thought I would share what I learned so the technique  
doesn’t get lost.

Imagine you need to construct a binary string from some arbitrary  
object. BitStruct allows you to do this in 3 ways: pass a binary  
string directly, pass in a hash, or yield a block. It’s easy to extend  
this mechanism for parsing your own classes by building on the block  
yield initialization mechanism.

hsh = {:a =\> 1, :b =\> “foo”, :c =\> “bar”}

class C \< BitStruct  
signed :context, 32, “c id”  
char :password, 12_8, “pw”  
char :usr\_name, 12_8, “name”

# important to initialize these values so the

# block passed to #super is evaluated correctly

initial\_value.context = 0  
initial\_value.password = ‘’  
initial\_value.usr\_name = ‘’

def initialize message  
# parens on #super are important so no args  
# are passed up to the parent; if this part fails  
# then you missed  
super() do |struct|  
struct.context = message[:a]  
struct.password = message[:b]  
struct.usr\_name = message[:c]  
end  
end  
end

c = C.new hsh # very clean!  
c.inspect

In this example I passed in a hash as my message, but the +message+  
variable could have been any object that could be interrogated to  
retrieve values for setting the bitstruct fields. I like this  
technique because it delegates the responsibility of proper bitstruct  
initialization to the class under construction. It nicely encapsulates  
that operation which I believe demonstrates the Single Responsibility  
principle.

I hope this is of use to someone someday.

cr

---

<div class="post-metadata">

**Author:** ![cremes](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/e19b73/32.png) [@cremes](https://www.ruby-forum.com/u/cremes)\
**Post date:** [May 14, 2009, 11:49pm UTC](https://www.ruby-forum.com/t/bitstruct-technique/168013/2 "2009-05-14T23:49:39Z")

</div>

Chuck R. wrote:

> def initialize message
> 
> # parens on #super are important so no args
> 
> # are passed up to the parent; if this part fails
> 
> # then you missed
> 
> super() do |struct|  
> struct.context = message[:a]  
> struct.password = message[:b]  
> struct.usr\_name = message[:c]

If you add this line here:

```
   yield struct if block_given?

```

then the block initialization can still be used by subclasses or by the  
caller of #new:

c = C.new hsh do |struct|  
struct.context = 2  
end

---

<div class="post-metadata">

**Author:** ![cremes](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/e19b73/32.png) [@cremes](https://www.ruby-forum.com/u/cremes)\
**Post date:** [May 14, 2009, 11:54pm UTC](https://www.ruby-forum.com/t/bitstruct-technique/168013/3 "2009-05-14T23:54:55Z")

</div>

Chuck R. wrote:

> initialization mechanism.  
> initial\_value.context = 0  
> struct.usr\_name = message[:c]  
> because it delegates the responsibility of proper bitstruct  
> initialization to the class under construction. It nicely encapsulates  
> that operation which I believe demonstrates the Single Responsibility  
> principle.
> 
> I hope this is of use to someone someday.
> 
> cr

I think I see where you’re going with that, but just so others know, the  
hash-based initialization is simple (though it does require that the  
hash keys match the field names–and avoiding this is probably the point  
of your code):

require ‘bit-struct’

hsh = { :context =\> 1, :password =\> “foo”, :usr\_name =\> “bar” }

class C \< BitStruct  
signed :context, 32, “c id”  
char :password, 12_8, “pw”  
char :usr\_name, 12_8, “name”  
end

c = C.new hsh

---

<div class="post-metadata">

**Author:** ![cremes](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/e19b73/32.png) [@cremes](https://www.ruby-forum.com/u/cremes)\
**Post date:** [May 16, 2009, 10:31pm UTC](https://www.ruby-forum.com/t/bitstruct-technique/168013/4 "2009-05-16T22:31:43Z")

</div>

On May 14, 2009, at 4:53 PM, Joel VanderWerf wrote:

> Chuck R. wrote:
> 
> >

> I think I see where you’re going with that, but just so others know,  
> char :password, 12_8, “pw”  
> char :usr\_name, 12_8, “name”  
> end
> 
> c = C.new hsh

Joel,

that’s right. I probably shouldn’t have used a hash as my example  
since you already have hash-based initialization built in. I meant for  
this to be a nice way to pass an arbitrary object to the constructor  
so the logic of getting data from that object would be encapsulated in  
one spot. I also could have built a temporary hash from the object  
argument and passed that to the superclass’ constructor but I prefer  
the block-based initialization for readability.

And thanks for creating such a neat library. I don’t have a need for  
it now that I understand my problem domain better, but rest assured it  
is now a member of my toolbox for some future problem when I do need it.

cr
