tags:

views:

74

answers:

4

Can I create Ruby classes within functions bodies ? I seem to be getting error which tells me its not allowed but I think it should be as classes are too objects here.

class A
    def method
        class B
        end
    end
end

This fails with error 'class definition inside method body. If we cant, why cant we create classes inside methods ?

+1  A: 

you can create classes, but you cannot assign constans from inside a method.

this example works:

class A
  def a
    b = Class.new
    def b.xxx
      "XXX"
    end
    b
  end
end

a = A.new.a
p a         # #<Class:0x7fa74fe6cc58>
p a.xxx     # "XXX"
zed_0xff
+2  A: 

You can create classes from within methods and assign them to a constant, as in the following

class A
  def create_class class_name
    new_class = Class.new
    new_class.send :define_method, :speak do
      "Hi, There"
    end
    Object.const_set class_name, new_class
  end
end

A.new.create_class "Harry"
h = Harry.new
puts h.speak  # responds => "Hi, There"

because a class name as in String is just a constant in ruby unlike many other languages.

Joc
+2  A: 
class A
  def method
    self.class.const_set :B, Class.new {
      def foo
        'bar'
      end
    }
  end
end

A.new.method
A::B.new.foo # => 'bar'

However, why do you want to assign a constant inside a method? That doesn't make sense: constants are constant, you can only assign to them once which means you can only run your method once. Then, why do you write a method at all, if it is only ever going to be run once, anyway?

Jörg W Mittag
I can think of several patterns that might conceivably define classes in a method, most notably things like bridges, adapters, and factories. It would be useful if you need to get some static resource (like an LDAP connection), but you don't want to dictate the implementation (e.g. net/ldap vs ruby-net-ldap). Still, it's far from an everyday need.
James A. Rosen
+1  A: 

The question is about creating classes, but in the comment you talk about creating anonymous objects. Not the same thing.

If you need anonymous object, you can always do Object.new. If you need simple struct-like container, you should take a look at Struct class. With it, you can do something like:

def foo
  anon_obj = Struct.new(:prop1, :prop2).new
  anon_obj.prop1 = 123
  anon_obj.prop2 = 'bar'

  return anon_obj
end

BTW, Ruby is a strongly typed language. But it is a dynamic typed as well, and you can't expect it to behave like static-typed.

Mladen Jablanović