# Metaprogramming problems

**URL:** <https://www.ruby-forum.com/t/metaprogramming-problems/99536>\
**Category:** Ruby\
**Created:** [July 23, 2006, 10:48pm UTC](https://www.ruby-forum.com/t/metaprogramming-problems/99536 "2006-07-23T22:48:26Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![leslieviljoen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/3d9bf3/32.png) [@leslieviljoen](https://www.ruby-forum.com/u/leslieviljoen)\
**Post date:** [July 23, 2006, 10:48pm UTC](https://www.ruby-forum.com/t/metaprogramming-problems/99536/1 "2006-07-23T22:48:26Z")

</div>

Hello!

I am pretty new to metaprogramming, this is my first shot. I want to  
be able to take some binary data, split it into parts based on a  
template and make an object with those parts.

Basically, I have this template array which defines a binary format:

@map =  
[[“length”, “S”],[“unit\_id”, “L”],[“date”, “L”],[“transaction\_id”, “L”],  
[“type”, “c”], [“subtype”, “c”], [“version”, “c”],  
[“body”, “a\*”]]

Then I have this in my template class:

#Apply the template to a (binary data) string, producing an object  
def apply(className, string)  
evalString = “class #{className}\n”  
@map.each do |attribute|  
evalString \<\< “attr\_accessor :#{attribute[0]}\n”  
end  
evalString \<\< “end\n” \<\< “o = #{className}.new”  
eval(evalString)

```
currentPos = 0
@map.each do |attribute|
  case attribute[1]
  when "L": size = 4
  when "S": size = 2
  when "c": size = 1
  end

  if attribute[1] == "a*"
    eval("o.#{attribute[0]} =

```

string[#{currentPos}…-1].unpack("#{attribute[1]}")")  
else  
eval(“o.#{attribute[0]} = string[#{currentPos},  
#{size}].unpack(”#{attribute[1]}")")  
currentPos += size  
end  
end

```
return eval("o")

```

end

…which produces a class with accessors for each “field” in the  
binary data. An object is created and returned - exactly what I want.  
Two problems though:

1. I use the final eval(“o”) to return my object from eval-world. How  
do I get my class from there? I want the new class I make to be  
persistent at the top level so that I can make several objects of that  
class later.

2. Once the class is created, I want to be able to go back and parse  
another binary string, producing further fields and add those to the  
existing class. My object would need to have the initial accessors  
plus the new ones, and the new variables must be set.

I was thinking of a method similar to the one above:

def applyMore(object, className, string)

But I don’t know how to add accessors to an already created object,  
and since the class above is lost in eval-world (where is that??) - I  
can’t add to it.

I need this because all my binary files have the same header, but  
different bodies. I want to apply the header template and then a body  
template to produce the finished object.

So, can anyone help with these problems? If I am going completely off  
the track here, can anyone suggest a better way to do all this? I am  
reading a lot on meta-programming but I’m slow to catch on.

Les

---

<div class="post-metadata">

**Author:** ![leslieviljoen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/3d9bf3/32.png) [@leslieviljoen](https://www.ruby-forum.com/u/leslieviljoen)\
**Post date:** [July 24, 2006, 1:42am UTC](https://www.ruby-forum.com/t/metaprogramming-problems/99536/2 "2006-07-24T01:42:31Z")

</div>

Hi

Leslie V. wrote:

> I am pretty new to metaprogramming, this is my first shot. I want to  
> be able to take some binary data, split it into parts based on a  
> template and make an object with those parts.

…

You can do the kind of thing you want using eval, but there’s easier  
ways in Ruby.

> #Apply the template to a (binary data) string, producing an object  
> def apply(className, string)  
> evalString = “class #{className}\n”  
> @map.each do |attribute|  
> evalString \<\< “attr\_accessor :#{attribute[0]}\n”  
> end  
> evalString \<\< “end\n” \<\< “o = #{className}.new”  
> eval(evalString)  
>   
> return eval(“o”)  
> end

These are some ways of doing the same thing using Ruby methods:

# Create a new class, assign it to a variable.

new\_class = Class.new()

# Add an attribute accessor to the class a based on the template

new\_class.class\_eval { attr\_accessor :unit\_id }

# Create an instance of the new class

item = new\_class.new

# Assign a value based on the data in your binary format

item.unit\_id = 666

> 1. I use the final eval(“o”) to return my object from eval-world. How  
> do I get my class from there? I want the new class I make to be  
> persistent at the top level so that I can make several objects of that  
> class later.

If you want to use the class again later, store a reference to it in a  
constant or an instance variable.

@my\_class = Class.new()  
MyClass = Class.new()

> 1. Once the class is created, I want to be able to go back and parse  
> another binary string, producing further fields and add those to the  
> existing class. My object would need to have the initial accessors  
> plus the new ones, and the new variables must be set.

You can add methods dynamically to your new class at any time, using  
class\_eval as above, or other techniques. Another alternative might  
be to create subclasses.

cheers  
alex

---

<div class="post-metadata">

**Author:** ![leslieviljoen](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/3d9bf3/32.png) [@leslieviljoen](https://www.ruby-forum.com/u/leslieviljoen)\
**Post date:** [July 24, 2006, 8:51am UTC](https://www.ruby-forum.com/t/metaprogramming-problems/99536/3 "2006-07-24T08:51:43Z")

</div>

On 7/24/06, Alex F. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> You can add methods dynamically to your new class at any time, using  
> class\_eval as above, or other techniques. Another alternative might  
> be to create subclasses.

Holy macaroni that’s cool.  
Thanks Alex!
