I know if I subclass the String class and override its capitalize method, I can call the String class' version of capitalize with super. What if instead I reopened the String class and rewrote the capitalize method? Is there a way I can call the previous version of that method?
Not out of the box. A common approach is to rename the existing method to a new name. Then, in your rewritten version, call the old method by the new name.
def String
alias to_i old_to_i
def to_i
#add your own functionality here
old_to_i
end
end
You might also want to look at alias_method_chain, which does some of this for you.
There is also another interesting approach to get super working - if the class to open supports it (e.g. because it's written by yourself):
The methods of the class are not directly defined in the class body, but in another module that is then included. To overwrite a method of the re-opened class, include your own module with the extend version of it (which might use super).
This is, for example, used in the irb-alternative ripl to let plugins implement their own versions of core methods (which call super to get the original behaviour).
Related
As mentioned in this answer, in Ruby 2.1 or later, this code:
class SimpleTest
private
define_method :foo do
42
end
end
will define foo as a private method of SimpleTest instances. (In Ruby 2.0 and earlier it won't be private.) However, I'm looking to do something a little less trivial. I would like to define a DSL that classes can extend, and would like the methods that the DSL defines internally to respect the private/protected visibility of the calling context. That may not be clear, so here's an example:
module Dsl
def has_a(name)
define_method name do
42
end
end
end
class Test
extend Dsl
private
has_a :thing
end
As written, that code will define a public thing method on Test instances. Instead, I would like has_a to be able to reflect on the method visibility where it was called (private in this case), and define thing under that same method visibility.
I'm not familiar with Ruby's C source code, but I took a quick look and found this function which seems like it might do what I want, but I don't think it's accessible from Ruby. (It seems to only be used here.) I also looked up the documentation for define_method (since the first example works as desired) here and it seems like the noex variable declared and set here:
int noex = NOEX_PUBLIC;
const NODE *cref = rb_vm_cref_in_context(mod, mod);
if (cref) {
noex = (int)cref->nd_visi;
}
could be the value I want, but again I don't know how I would get that in Ruby, or even if it would be able to reflect back on the calling scope (in Test). Assuming I had the visibility, then I could simply call private name (or protected name) after the define_method call inside has_a if it wasn't called in a public context.
Thoughts? Is there any way to do this, or am I out of luck?
I think this question has a similar answer to what you are looking for: https://stackoverflow.com/a/28075865/5129208
It looks like the author of that made a custom module to get the behavior you're after.
I was thinking wouldn't it be cool to have a print method defined in the Ruby Object class? Consider the following:
class Object
def print
puts self.to_s
end
end
23.times &:print
Is there any issue in having something like this? Seems like a good feature to have. It also appears easy to read.
There's already Object#inspect defined. Plus, there's already Kernel#print defined as private method in Object class and every class that inherits from it.
This method already exists in the Ruby standard library. However, it has a different name: display.
23.times &:display
# 012345678910111213141516171819202122
As you can see, it does not write a newline after the object's string representation; it is ill-suited for object inspection.
The main issue with adding methods to Object is that they become universal and may clash with similarly named methods in other libraries or in your project.
There are already multiple simple ways to output data or convert to string form in Ruby core, so the risk of a clash (on a very useful method name) likely outweighs any benefits from nicer syntax even in your own code.
If you have a smaller set of classes in your own project, where you feel this would be a useful feature to have, then this is an ideal use case for mix-ins.
Define a module:
module CanPrintSelf
def print
puts self.to_s
end
end
And include it in any class you want to have the feature:
class MyClass
include CanPrintSelf
end
my_object = MyClass.new
my_object.print
So you can have this feature if you like it, and you don't need to modify Object.
Currently reading a Ruby style guide and I came across an example:
def no_op; end
What is the purpose of empty body methods?
There are a number of reasons you might create an empty method:
Stub a method that you will fill in later.
Stub a method that a descendant class will override.
Ensure a class or object will #respond_to? a method without necessarily doing anything other than returning nil.
Undefine an inherited method's behavior while still allowing it to #respond_to? the message, as opposed to using undef foo on public methods and surprising callers.
There are possibly other reasons, too, but those are the ones that leapt to mind. Your mileage may vary.
There may be several reasons.
One case is when a class is expected to implement a specific interface (virtually speaking, given that in Ruby there are no interfaces), but in that specific class that method would not make sense. In this case, the method is left for consistency.
class Foo
def say
"foo"
end
end
class Bar
def say
"bar"
end
end
class Null
def say
end
end
In other cases, it is left as a temporary placeholder or reminder.
There are also cases where the method is left blank on purpose, as a hook for developers using that library. The method it is called somewhere at runtime, and developers using that library can override the blank method in order to execute some custom callback. This approach was used in the past by some Rails libraries.
As a little hobby project, I'm trying to build up my own object system. I was wondering if there is a way of changing the default inheritance of all classes from Object to my base class Entity, so that whenever I create a new class I don't have to explicitly say class Thing < Entity; ideally, I would just be able to say class Thing and have its default superclass be my Entity class.
Sure you could do this by modifying the relevant part of the Ruby source and recompiling Ruby:
VALUE
rb_define_class_id(ID id, VALUE super)
{
VALUE klass;
if (!super) super = rb_cObject; // <-- where the default is set
klass = rb_class_new(super);
// ...
But that’s a huge hassle and requires patching and running a custom Ruby and probably has a lot of gotchas and things that are hard-coded to assume Object is the default.
And, on top of that, what’s the point? If you replace Object with something else as the default superclass, every class—including those in Ruby core—will now inherit from this new default superclass. You could get the same effect (just without the different name) far more easily and without needing a custom Ruby by just changing Object itself. That’s the beauty of being able to reopen classes! For example:
class Object
def foo
'bar!'
end
end
class A; end
A.new.foo #=> 'bar!'
If you wanted to be kind you might even just put all the relevant methods in an Entity module instead of a class and then include it into Object.
No, unfortunately this is not possible in Ruby. Ruby does not have a Meta-Object Protocol like e.g. CLOS that would allow you to manipulate the core semantics of the Object Model. It would be nice, though!
I just started using MongoMapper to manage nested models in a Sinatra app. In this particular case, I just need to check one of the fields when an EmbeddedDocument is initialized, and add a leading slash if one isn't already there.
My idea was to write a check in the initialize method that will take care of it, except writing my own initialize will completely override the default, whereas I want to use the default with my own code added on. I've been trying to find some resources on extending MongoMappers constructors, using super, or anything like that but I haven't found much.
Even if this isn't the best way to solve my current problem (ensuring a leading slash on a String field), I'd also like to know how to extend MongoMapper's default constructor, just for future reference. Thanks in advance.
Edit: I found the MongoMapper Validation docs that solve my current issue of the leading slash.
http://mongomapper.com/documentation/plugins/validations.html
Still curious about the constructor extension though...
The initialize method MongoMapper gives you is in a module, not defined directly on your class. That means that if you define your initialize method, MM's method is still available to you with super.
def initialize(*args)
super
# do your own stuff here
end
MongoMapper's internal plugins uses that pattern extensively. Each plugin sets up its own concerns on initialization, then calls super.