views:

87

answers:

3

I'd like to write this:

[:p, :h1, :h3].each do |tag|
  define_method(tag) { |text| "<#{tag}>#{text}</#{tag}>" }
end

It's just some simple methods to wrap text in HTML tags. I want to be able to use these methods in the rest of the script. Unfortunately the define_method method seems to only work inside of a module. But if I did this inside a module, I wouldn't be able to cleanly write p "This is a paragraph.", it'd be something like HTML::p "This is a paragraph." which would be pretty terrible.

So how do I define methods like this globally?

+3  A: 

I don't know your whole situation, but you probably don't really want to be defining global methods. If you don't want to type the HTML:: then add an include HTML statement at the beginning of your code.

Alex Reisner
this seemed hacky at first but I guess it's pretty clean and it works perfectly. Thankyou!
yjerem
+2  A: 

One hack would be to create the method inside Object, which would then be global method you desire:

class Object
  def create_method(name, &block)
    self.class.send(:define_method, name, &block)
  end
end

tag = 'p'
a = Object.new
a.create_method(tag.intern) {|v| puts "<#{tag}>#{v}</#{tag}>"}

send(tag.intern, 'content') # => <p>content</p>
bryantsai
This code does not define 'global' methods, it only defines methods on the class of the receiver. In this example `a` is an instance of Object so the methods would be 'global' but in general this is not true with your code.
banister
This of course only works with class Object ... within which I added the method create_method. Just to be clear, this is not a good style , from my personal feeling, but just one way to meet the original question's intension.
bryantsai
+2  A: 

If you really need to do it:

[:p, :h1, :h3].each do |tag|
    Object.send(:define_method, tag) { |text| "<#{tag}>#{text}</#{tag}>" }
end
banister