# Metaprogramming is fun!

**URL:** <https://www.ruby-forum.com/t/metaprogramming-is-fun/58558>\
**Category:** Ruby\
**Created:** [April 23, 2006, 6:08am UTC](https://www.ruby-forum.com/t/metaprogramming-is-fun/58558 "2006-04-23T06:08:40Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![mgreenly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/85f322/32.png) [@mgreenly](https://www.ruby-forum.com/u/mgreenly)\
**Post date:** [April 23, 2006, 6:08am UTC](https://www.ruby-forum.com/t/metaprogramming-is-fun/58558/1 "2006-04-23T06:08:40Z")

</div>

I finally decided to dive in and give metaprogramming in Ruby a shot.  
I’m  
not sure that my example is exactly practical, but it seemed useful at  
the  
time. There’s a few areas I would like to hear others suggestions on:

1. Does the syntax appear to be in line with the community standards?

2. Are my uses of class\_eval and instance\_eval okay / is there a better  
way?

3. I am using facets because I like the Dictionary (OrderedHash), but  
I’m  
sure there are better ways to build the structure while preserving the  
field  
order. I especially don’t like the fact that I have to specify  
Dictionary[]  
in the structure of the subclass.

4. Please comment on the code in general, I’m open to any kind of  
criticism.

I’m not sure if it’s customary to attach the code in a file or post it  
in  
the email. I apologize if I should have attached the code in a file.

Michael G.

* * *

require ‘rubygems’  
require ‘facets’  
require ‘dictionary’

class FixedLength

def self.structure(ordered\_hash)

```
class_eval do
  @@structure = ordered_hash
end

keys = @@structure.keys
instance_eval do
  attr_accessor *keys
end

```

end

# this entire method could probably be a lot cleaner

def self.open(file\_name)  
class\_eval do  
data = IO.read(file\_name)  
records = []  
data.each\_line do |line|  
last\_position = 0  
record = self.new  
@@structure.each\_pair do |name, length|  
record.instance\_variable\_set( “@#{name.to\_s}”,  
line.slice(last\_position,  
length.to\_i).strip)  
last\_position += length.to\_i  
end  
records \<\< record  
end  
return records  
end  
end

end

class InputStructure \< FixedLength

# I’d like to clean this up, either removing the need for Dictionary[]

and  
the separation by commas

# or with something like this

# column.add :id, 10

# column.add :phone, 10

# column.add :first\_name, 25

# etc. I’d love to hear some suggestions.

structure Dictionary[ :id , 10,  
:phone , 10,  
:first\_name , 25, :middle\_name , 1, :last\_name , 25,  
:address , 30,  
:city , 25,  
:state , 2,  
:zip , 5, :zip4 , 4 ]

end

require ‘test/unit’

class InputStructureTest \< Test::Unit::TestCase

def setup  
@records = InputStructure.open(‘fixed\_data.txt’)  
end

def test\_first  
record = @records.first  
assert\_equal “1”, record.id  
assert\_equal “1234567890”, record.phone  
assert\_equal “SOME RANDOM”, record.first\_name  
assert\_equal “”, record.middle\_name  
assert\_equal “PERSON”, record.last\_name  
assert\_equal “1234 SOME RANDOM STREET”, record.address  
assert\_equal “RANDOM CITY”, record.city  
assert\_equal “OH”, record.state  
assert\_equal “45219”, record.zip  
assert\_equal “”, record.zip4  
end

end

---

<div class="post-metadata">

**Author:** ![mgreenly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/85f322/32.png) [@mgreenly](https://www.ruby-forum.com/u/mgreenly)\
**Post date:** [April 23, 2006, 6:11am UTC](https://www.ruby-forum.com/t/metaprogramming-is-fun/58558/2 "2006-04-23T06:11:46Z")

</div>

I forgot, here’s the test data in case anyone wants it.

Michael G.

---

<div class="post-metadata">

**Author:** ![mgreenly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/85f322/32.png) [@mgreenly](https://www.ruby-forum.com/u/mgreenly)\
**Post date:** [April 23, 2006, 2:16pm UTC](https://www.ruby-forum.com/t/metaprogramming-is-fun/58558/3 "2006-04-23T14:16:51Z")

</div>

Hi –

On Sun, 23 Apr 2006, Michael G. wrote:

> I finally decided to dive in and give metaprogramming in Ruby a shot. I’m  
> not sure that my example is exactly practical, but it seemed useful at the  
> time. There’s a few areas I would like to hear others suggestions on:
> 
> 1. Does the syntax appear to be in line with the community standards?

You’re indenting one space instead of two on the first indent, but  
generally it looks good.

> 1. Are my uses of class\_eval and instance\_eval okay / is there a better way?

See below.

> end
> 
> keys = @@structure.keys  
> instance\_eval do  
> attr\_accessor \*keys  
> end

I’m not sure why you’re using all these \*\_eval calls. Try this:

def self.structure(ordered\_hash)  
@@structure = ordered\_hash  
attr\_accessor \*@@structure.keys  
end

> end
> 
> # this entire method could probably be a lot cleaner
> 
> def self.open(file\_name)  
> class\_eval do

I haven’t tested it but I don’t see any reason for that one either.

> ```
> data = IO.read(file_name)
> records = []
> data.each_line do |line|
> last_position = 0
> record = self.new
> @@structure.each_pair do |name, length|
> record.instance_variable_set( "@#{name.to_s}",
> 
> ```

The #{} thing does an automatic to\_s. Also, since you’ve gone to the  
trouble of creating accessors, why not do:

record.send(“#{name}=”), line.slice…

> end  
> You could tighten that method up a bit. Here’s an untested rewrite;  
> see if this is of any use:

def self.open(file\_name)  
records = []  
File.open(file\_name) do |fh|  
fh.each\_line do |line|  
record = new  
@@structure.each do |name,len|  
record.send(“#{name}=”, line.slice!(0,len))  
end  
records \<\< record  
end  
end  
return records  
end

(I’ll save my reflections on the likelihood of class variables being  
necessary for another time 🙂

David

–  
David A. Black (removed\_email\_address@domain.invalid)  
Ruby Power and Light, LLC ([http://www.rubypowerandlight.com](http://www.rubypowerandlight.com))

“Ruby for Rails” PDF now on sale! [Ruby for Rails](http://www.manning.com/black)  
Paper version coming in early May!

---

<div class="post-metadata">

**Author:** ![mgreenly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/85f322/32.png) [@mgreenly](https://www.ruby-forum.com/u/mgreenly)\
**Post date:** [April 23, 2006, 3:12pm UTC](https://www.ruby-forum.com/t/metaprogramming-is-fun/58558/4 "2006-04-23T15:12:19Z")

</div>

Thanks David! I removed the evals, cleaned up self.open, and ran my  
tests  
and everything works.

I really like the fact that I don’t have to use the last\_position  
variable  
and I can use String#slice! to incrementally chop it down.

Any time you feel like reflecting on the need for class variables, my  
ears  
are open.

Thanks again!

Michael G.
