2

I have a program that create classes which looks like:

  MyClass = Class.new do
    def initialize; end
    # ...
  end

But I would like to name dynamically MyClass, from a string. And because it's for the name of a class, I would like to classify that string, for instance (thanks Rails methods):

  "hello_world".classify # => "HelloWorld"

I don't know if in pure Ruby there is a method for that.

Thank you

lejlot
  • 64,777
  • 8
  • 131
  • 164
moshimoshi
  • 251
  • 1
  • 6
  • 15

4 Answers4

6

No, there isn't. Here's the String reference page.

You could do so like this:

"hello_world".split('_').collect!{ |w| w.capitalize }.join

You could easily implement this by reclassing the String class.

However, if you're using Rails for whatever reason, classify is added for convenience, along with the underscore method. I believe it's still used in Rails 3.

mway
  • 4,334
  • 3
  • 26
  • 37
  • 1
    Good solution. It can (in MRI 1.8.7 and later) be shortened to: `hello_world".split('_').collect(&:capitalize).join` – Wayne Conrad Nov 01 '10 at 23:51
  • Ah, great! Been out of the Ruby world for a bit. Thanks for the tip! – mway Nov 02 '10 at 00:34
  • Thanks for your method; I will improve my String class with this hehe – moshimoshi Nov 03 '10 at 07:35
  • 1
    You may find it easiest to get and use ActiveSupport. – Mladen Jablanović Nov 03 '10 at 15:06
  • @Mladen Jablanović - thanks for the tip, using ActiveSupport is probably a good idea for most cases. If you just need to classify a singular underscored_word, though, that adds a bit of bloat; otherwise, it's tremendously useful. – mway Nov 03 '10 at 16:47
5

Not sure if your question is only about constructing a camelcased string, or also about assigning a newly created class to it. Because, for the latter, you should use Module::const_set method:

class_name = 'MyClass'
#=> "MyClass"
klass = Class.new do
  def foo
    "foo"
  end
end
#=> #<Class:0xa093a68>
Object.const_set class_name, klass
#=> Module::MyClass
MyClass.new.foo
#=> "foo"
Mladen Jablanović
  • 43,461
  • 10
  • 90
  • 113
  • That's what I was thinking he wanted. – the Tin Man Nov 01 '10 at 23:23
  • Thanks, that's what I would like to do Mladen. There's also this version which is okay for me: Object::const_set(class_name.intern, Class::new { def foo; "foo"; end } – moshimoshi Nov 03 '10 at 07:33
  • I am curious as to what benefit this would be? If the class names are dynamic and you want to write additional code which calls the newly created class, with a name you don't know at the point of writing the code ... how would you then intend to use this new class??? – grail Mar 30 '17 at 08:57
  • @grail: Are you asking about `const_set` generally, or using it to dynamically create named classes? The latter is just a consequence of classes being first-class objects in Ruby. – Mladen Jablanović Mar 30 '17 at 12:20
  • @MladenJablanović: I followed what you did and whist kinda cool, how would you write future code to now access this new class, ie. in your example you create a class called MyClass, but at the time of writing the code you won't know that, so how would you then call MyClass.new.foo when you don't know the name of the class? Are you somehow going to call class_name.new.foo and it will now that this is to be done for your new class? – grail Mar 30 '17 at 13:26
  • 1
    @grail: That's a question for the OP. I just answered his question. Perhaps he knows the name of the class, but does not know its definition before runtime. Perhaps there are couple of classes and their meaning could be dynamically determined. Perhaps the question was purely academic and not intended to be used in real code. Who knows. – Mladen Jablanović Mar 30 '17 at 14:47
1

This is much later, but I am going through this process and expanding on mway's answer I am using this:

class String
  def classify
    self.split('/').collect do |c|
      c.split('_').collect(&:capitalize).join
    end.join('::')
  end
end

This will allow you to add namespaces to strings. So:

"api/post_comments".classify
=> "Api::PostComments" 
Thomas07vt
  • 219
  • 1
  • 4
  • 11
0

If you wanted just to access the class from a string name, and not define it from a string, you can also use this:

MyClass = Class.new do
    def test; end
    # ...
end
"MyClass".constantize.test # => what you wanted ?
Cosmin Atanasiu
  • 2,532
  • 3
  • 21
  • 26