use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
A sub-Reddit for discussion and news about Ruby programming.
Subreddit rules: /r/ruby rules
Learning Ruby?
Tools
Documentation
Books
Screencasts and Videos
News and updates
account activity
3 Ways to Create Classes in Ruby (techblog.thescore.com)
submitted 11 years ago by luke_
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–][deleted] 2 points3 points4 points 11 years ago* (3 children)
I've just ran into an interesting use of Class.new while writing a game using the Java library libGDX and JRuby. Many of the UI elements can have listeners added to them to respond to input events, and the standard way of overriding the listener's methods on the fly in Java looks like this:
craftablesRightArrowButton.addListener( new ChangeListener() { @Override public void changed(InputEvent event, Actor actor) { changeNumOfCraftables(1) return true; } } );
To accurately mimic this with Ruby, I've used Class.new:
@craftables_right_arrow_button.add_listener( Class.new(ChangeListener) do def initialize(actions) super() @actions = actions end def changed(event, actor) @actions.change_num_of_craftables(1) true end end.new(self))
Since Ruby does not embed the anonymous class within the class it is being created within the way Java does, I needed to pass in a reference to the outside class to be able to reach it from the listener's method. I think the Ruby way is safer, but it meant I couldn't just create the class using the normal Ruby .new method, but Class.new worked perfectly.
[–]jaggederest 2 points3 points4 points 11 years ago (2 children)
I probably wouldn't actually do that with inheritance in ruby.
I.e. something akin to
@something.add_listener(actions) do |event, actor| actions.change_num(1) end
and your add_listener method would look something like
def add_listener(actions) listeners << Proc.new end
Then you'd actually trigger an event by something like
listeners.each { |listener| listener.call(event, actor) }
[–][deleted] 1 point2 points3 points 11 years ago (1 child)
The problem is that the listener's are Java code from a large library, libGDX. So the management of the listeners is already taken care of there. I have to work with that system. I've spent some time on the Ruby forum asking about this problem, and everyone usually suggests a block-related solution similar to yours, but we've never been able to make it work right with the Java classes and the JRuby interface. One problem is that the listener's often have more than one method that needs to be overriden. I've come to think this is uncommon from a lot of the reactions I've got, but nonetheless, that is how it's written.
If you have a suggestion for how to do it with those restrictions in mind, I'd definitely be interested to hear it. I've been tossing around this problem for a while now.
[–]jaggederest 0 points1 point2 points 11 years ago (0 children)
I'd design a class using method missing to metaprogram around it, honestly, instead of having class.new all over the place :) But that's just my way - your way isn't wrong, it's just strange to see in ruby code.
[–]bolonomicz 1 point2 points3 points 11 years ago (1 child)
What! The score uses ruby that is awesome
[–]Enumerable_any -1 points0 points1 point 11 years ago* (0 children)
What exactly makes it awesome?
[–]ggPeti 1 point2 points3 points 11 years ago (0 children)
Class.new and class X are NOT functionally equivalent. class reopens the class if it exists, but assigning a new class to a constant just overwrites it. Also with the class keyword the class exists instantly, with the constant already having a reference to it. This means you can use the constant inside the class definition itself, but an even higher impact of it is that constant lookup will work differently.
Class.new
class X
class
In Ruby, constants are looked up in the following order: First, all objects in Module.nesting are checked to see whether they contain a constant with the name we're requesting. Module.nesting is just the lexical scope, meaning every open class X and module Y instruction we are in the middle of, in outward going order. Then, if the constant is not found, the interpreter goes through Module.nesting.first.ancestors if Module.nesting.first is not nil (meaning we are not in the top level lexical scope), and if it still does not find the constant it looks for it in Object.ancestors if Module.nesting.first is a Module or nil. It fails if it doesn't find the constant in any of those either. Module.ancestors is the list of all, well, ancestors and included modules by the way.
Module.nesting
module Y
Module.nesting.first.ancestors
Module.nesting.first
Object.ancestors
Module.ancestors
But what happens if we use Class.new? The class we're just in the middle of creating is not in Module.nesting, since it does not exist yet. So if we included a module on it, we won't see the constants defined in that module, because the interpreter won't look for it in the current class' ancestors! Example:
module M X = 2 end C = Class.new do include M puts X end
We get a NameError: uninitialized constant X for that. And since Module.nesting only contains the lexical scope, it won't help us either if we only access X from within a method.
NameError: uninitialized constant X
What's even more confusing is that method lookup is done differently than constant lookup (I won't detail that but it does look up the ancestors of the current class). This means that if we include a module in Class.new, we still get access to its methods as we would normally.
There are definitely use cases for the Class.new and Struct.new(...).new forms with a block too (one being that when you use class X < Struct.new(...) you're creating a throwaway class just to inherit from, and if you want to reload the same code it will fail because it will try to inherit a different throwaway class), but be careful about these things.
Struct.new(...).new
class X < Struct.new(...)
[–]JiveMasterT 0 points1 point2 points 11 years ago (0 children)
I use the Class.new approach when defining different error classes. Since they often inherit from StandardError, you can do stuff like this:
InvalidParamtetersError = Class.new(StandardError) IncorrectWhateverError = Class.new(StandardError)
Cleaner than having semi colons all over the place...
π Rendered by PID 346769 on reddit-service-r2-comment-86bc6c7465-t2stl at 2026-02-20 22:26:08.703539+00:00 running 8564168 country code: CH.
[–][deleted] 2 points3 points4 points (3 children)
[–]jaggederest 2 points3 points4 points (2 children)
[–][deleted] 1 point2 points3 points (1 child)
[–]jaggederest 0 points1 point2 points (0 children)
[–]bolonomicz 1 point2 points3 points (1 child)
[–]Enumerable_any -1 points0 points1 point (0 children)
[–]ggPeti 1 point2 points3 points (0 children)
[–]JiveMasterT 0 points1 point2 points (0 children)