An Introduction to Metaprogramming
The string 'x + 1' is translated and executed when the code is run, printing 4 as a result. Note that even the value bound to variable x is available during the runtime evaluation.
The following Ruby code demonstrates a contrived way to find the result of adding all the integer numbers between 1 and 100. Instead of using a normal loop or iteration method, we generate a big string containing the expression “1+2+3+...+99+100” and then proceed to evaluate it:
puts eval((1..100).to_a.join('+'))
The eval function should be used with care. If the string used as the argument to eval comes from an untrusted source (for example, from user input), it can be potentially dangerous (imagine what could happen if the string to evaluate contains the Ruby expression rm -r *). In many cases, there are alternatives to eval that are more flexible, less insecure and do not require the speed hit of parsing code during runtime.
A quine is special kind of source code generator. The jargon file defines a quine as “a program that generates a copy of its own source text as its complete output”. You might be right if you think this lacks any practical value by itself, but as a brain-teaser, it can be mind-blowing. Here's a quine written by Ryan Davis, which is one of the shortest ones for the Ruby language:
f="f=%p;puts f%%f";puts f%f
Run this program, and you will get it as output. You might even try something like this from a shell prompt:
ruby -e 'f="f=%p;puts f%%f";puts f%f' | ruby
Here we're using the -e option from the command line to specify one line of Ruby source to execute, and then we use a pipe to send its output to another instance of the Ruby interpreter. The output is once again the same program source.
Dynamic languages, such as Ruby, allow you to modify different parts of your program easily during runtime without having to generate source code explicitly as we did previously. Ruby's core API and frameworks, such as Ruby on Rails, employ this facility to automate common programming tasks. For example, in a class definition, you can use the attr_accessor method to produce the read/write access methods automatically for a given attribute name. Thus, the following code:
class Person attr_accessor :name end
is equivalent to this more verbose code:
class Person
def name
@name
end
def name=(new_name)
@name = new_name
end
end
The previous code has a minor drawback: the corresponding instance variable @name is not really created until you first set its value. This means you'll get a nil value if you happen to read the name attribute before writing to it. If you're not careful, this could introduce a few subtle bugs into your programs. The easiest way to avoid this problem is to set the @name instance variable to a reasonable value in the Person#initialize method. Because this is a quite common scenario, wouldn't it be nice to have this method generated automatically, in addition to the read/write accessors? Let's define an attr_initialize method that'll do that using Ruby's metaprogramming facilities.
First, let's briefly address two methods that are key to performing our desired metaprogramming magic:
cls.define_method(name) { body }
This adds a new instance method to the receiving class. It takes as input the method's name (as a symbol or string) and its body (as a code block):
obj.instance_variable_set(name, value)
The above code binds an instance variable to the specified value. The name of the instance variable should be a symbol or string, and it also should include the @ prefix.
Now, we're ready to define the attr_initialize class method as an extension to the Object class so that any other class can use it:
require 'generator'
class Object
def Object.attr_initialize(*attrs)
define_method(:initialize) do |*args|
if attrs.length != args.length
raise ArgumentError,
"wrong number of arguments " +
"(#{args.length} for #{attrs.length})"
end
SyncEnumerator.new(attrs, args).each do
|attr, arg|
instance_variable_set("@#{attr}", arg)
end
end
attr_accessor *attrs
end
end
The attr_initialize method takes as input a variable number of attribute names (attrs). Each attribute name has the same position reserved for it in the dynamically created initialize method parameter list (args) in order to set its initial value. We start the new method's code by checking that the number of arguments being received are the same as the number of attributes we originally specified. If not, we raise an error with a descriptive message. Afterward, we use a SyncEnumerator object (from the generator library) to iterate at the same time over the declared attributes list (attrs) and the actual arguments list (args) so as to perform a one-by-one attribute-argument binding using the instance_variable_set method. Finally, we delegate to the attr_accessor method in order to create the read/write access methods for all the declared attributes.
Here's how we can use the attr_initialize method:
class Student
attr_initialize :name, :id, :address
end
s = Student.new('Erika', 123, '13 Fake St')
s.address = '13 Wrong Rd'
puts s.name, s.id, s.address
The expected output would be:
Erika 123 13 Wrong Rd
Today’s modular x86 servers are compute-centric, designed as a least common denominator to support a wide range of IT workloads. Those generic, virtualized IT workloads have much different resource optimization requirements than hyperscale and cloud applications. They have resulted in a “one size fits all” enterprise IT architecture that is not optimized for a specific set of IT workloads, and especially not emerging hyperscale workloads, such as web applications, big data, and object storage. In this report, you will learn how shifting the focus from traditional compute-centric IT architectures to an innovative disaggregated fabric-based architecture can optimize and scale your data center.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
| Non-Linux FOSS: Seashore | May 10, 2013 |
| Trying to Tame the Tablet | May 08, 2013 |
| Dart: a New Web Programming Experience | May 07, 2013 |
- RSS Feeds
- New Products
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Drupal Is a Framework: Why Everyone Needs to Understand This
- A Topic for Discussion - Open Source Feature-Richness?
- Home, My Backup Data Center
- Developer Poll
- Dart: a New Web Programming Experience
- May 2013 Issue of Linux Journal: Raspberry Pi
- What's the tweeting protocol?
Enter to Win an Adafruit Prototyping Pi Plate Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Prototyping Pi Plate Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- Next winner announced on 5-21-13!
Free Webinar: Linux Backup and Recovery
Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.
In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.




24 min 51 sec ago
1 hour 58 min ago
3 hours 35 min ago
5 hours 33 min ago
5 hours 50 min ago
6 hours 20 min ago
6 hours 20 min ago
6 hours 21 min ago
9 hours 22 min ago
17 hours 48 min ago