Metaprogramming is the writing of programs that can write/manipulate the program itself or other programs. If you are using PHP and MySQL, you are already metaprogramming.
<?php
$title = mysql_real_escape_string($_GET['search']);
$r = mysql_query("SELECT * FROM database1.table1 WHERE PageTitle = '" . $search . "'");
// ......
?>
By concatenating the user-submitted data, you generated a MySQL query.
In fact, PHP generates HTML, PHP is a meta-programming language. Don’t think PHP can only generate HTML. PHP can also generate CSS and JavaScipt. In some sites, you can customize the background color of your profile. The color you’ve chosen will be part of the CSS of your profile.
<style type='text/css'>
#profile {
background-color: <?php echo $userperf['BackgroundColor'] ?>;
<?php if ($userpref['BackgroundImage']) { echo 'background-image: ' . $userpref['BackgroundImage'] } ?>
color: <?php echo $userpref['TextColor'] ?>
/* ...... */
}
</style>
You can’t get the client’s IP address with JavaScript, but PHP can. The following code generates JavaScript code that alerts your IP address.
<script type='text/javascript'>alert("Your IP address is:<?php echo $_SERVER['REMOTE_ADDR'] ?></script>")
Metaprogramming allows you to change a general-propose to a domain-specific language, for example, changing Ruby to a domain-specific language by changing the way you program.
In Ruby, there are methods such as attr_reader and attr_writer, they are not keywords, instead, they made use of metaprogramming.
class Module # if the class Module exists, extend the class Module
def attr_reader (*syms) # define the method attr_reader
syms.each do |sym|
class_eval %{def #{sym} # define the method dynamically based on the names given
@#{sym}
end}
end
end
end
There is no type checking in Ruby, writing same thing such as if arg1.kind_of? String is inconvenient, so you can use the Ruby metaprogramming capabilities to automate it: Use methods to generate methods.
First, you extend the class Module.
class Module
end
Then, add the method for the type-checking functionality,
class Module
def type_checked(name, *types, &block)
class_eval do
define_method(name) do |*args|
i = 0
if args.length < types.length
raise ArgumentError.new "Not enough number of arguments. Excepting #{types.length}. Got #{args.length}"
end
types.each do |type|
if not args[i].kind_of? type
raise TypeError.new "Excepting #{type} for paramter #{i}. Got #{args[i].class}."
end
i += 1
end
block.call(*args)
end
end
end
end
Now you can use type_checked like a keyword.
class Test
type_checked :add, Fixnum, Fixnum do |x, y|
x + y
end
end
It will make (Test.new)add("hello", "world") throw an exception because “hello” and “world” are Strings.
You can even implement unit calculation in Ruby.
class Module
def unit(name, x)
class_eval "def #{name}; self * #{x}; end;"
end
end
class Numeric
unit :mm, 0.001
unit :cm, 0.01
unit :dm, 0.1
unit :m, 1
unit :km, 1000
end
Because we extended the class Numeric, all numbers will have properties such as cm and mm. 10.cm will evaluate to 0.1, because 10cm = 0.1m.
In Python, you can use decorators to achieve metaprogramming. Decorators are like @deco, they are put before function definitions.
Here is a type-checking script in Python:
def accepts(*args):
def de(func):
def f(*fargs, **fkwargs):
i = 0
for a_type in args:
if a_type != type(fargs[i]):
raise TypeError("Expecting %s for argument %d. Got %s." % (a_type, i, type(fargs[i])))
i += 1
return func(*fargs, **fkwargs)
return f
return de
@accepts(int, int)
def add(a, b):
return a + b
By adding @accepts(int, int) decorator before the function, you wrap the function with the type-checking routine, while you need to write them one-by-one normally.
Don’t think JavaScript does not have class inheritance. JavaScript is a functional and dynamic programming language.
You can use prototypes for class extending and class inheritance.
function Base() { }
function Derived() { } // class Derived extends Base { public Derived() : Base() { } }
Derived.prototype = new Base();
// add method alert to String s.
String.prototype.alert = function() { alert(this) }
"Hello, world!".alert();
Metaprogramming links:
Tags: Code Generation, CSS, HTML, JavaScript, Metaprogramming, PHP, Python, Ruby