I found some unexpected (to me) behavior in Ruby. Is this behavior a bug or a feature? I stumbled on this situation while writing my project.
To put it as succinctly as I can: if a class' name ends with ::File and that class inherits from another class, then the usual File class isn't used with "File", but instead the current class is used.
(Yes, that's as succinct as I could figure out how to make it.)
Consider the following code, which produces the [feature|bug]
class MyClass
end
class MyClass::File < MyClass
def check
File.exist?('./whatever.txt')
end
end
myfile = MyClass::File.new
myfile.check
That code produces the following error:
./dev.rb:8:in `check': undefined method `exist?' for MyClass::File:Class (NoMethodError)
Did you mean? exit
exit!
from ./dev.rb:13:in `<main>'
What's weird (to me, anyway) is that the error doesn't happen if MyClass::File doesn't inherit from MyClass. That is, if you remove the "< MyClass" part then there's no error.
Now, I can just hear some programmers muttering over their latte: you shouldn't end a class name with ::File, that's just bad form. Well, I really want my class called ::File because that's the type of object it represents. I just have this thing that I like to give classes meaningful names.
I found a work around by calling Object::File instead of just File:
Object::File.exist?('./whatever.txt')
I don't even know how I figured that out... I couldn't google anything about this [feature|bug] but I figured it out within 20 guesses. Got lucky, I guess.
So...
1) Is this a feature or a bug?
2) Did I use the right workaround?
Related
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.
I'm including someone else's module, which seems to be split across multiple files. It looks something like this:
alfred.rb:
require 'alfred/ui'
module Alfred
<code>
end
alfred/ui.rb:
module Alfred
class Logger
def info(msg)
logger.info msg
end
end
end
I'm trying to access the info method from my code, which has require "alfred" at the top, using this syntax:
Alfred::Logger.info("my message")
which is not working, and results in #<NameError: uninitialized constant Alfred::Logger>.
Secondly, I would love if someone could explain how exactly Ruby "constructs" a module that is split across several files like this. Does the code from alfred/ui.rb get included at the end of alfred.rb at the beginning where the require line is? Does it all get put together in some other fashion? Maybe it doesn't even matter, but it seems it would help me wrap my head around it better.
The full code of the module I'm using is at Github in case anyone is interested.
Can someone help explain why I can't use the method this way, and what might be done to fix it?
#info is a instance method, meaning it only exists on instances of the Logger class. If you want to call it directly from your code, you'd call Alfred::Logger.new.info "some message", but that seems a bit odd. Usually that type of thing is used internally by the library.
If it had been defined like a class method:
module Alfred
class Logger
def self.info(msg)
logger.info msg
end
end
end
then you would be able to call it as you're attempting.
This is a follow up from Creating a class which inherits from another class in Ruby and m.one + m.two + m.three doesn't work. We are applying for App Academy which is a Learn to Code course for people with little or no experience. As a result, these questions are similar, but I felt the answers in the other two posts did not address an answer, but diverged to explaining tangential concepts (which I did utilize)
To follow up on the first two mentioned links, I am having a problem with inherited classes. I have the Musician class which is inheriting three variables from the Person class. My problem is that when I run the
m.first_name + " " + m.last_name + ": " + m.age.to_s
I get an error: person.rb:31: undefined method `+' for nil:NilClass (NoMethodError). I understand that this error has the answer, but I am not yet adept at understanding what this means.
One point to mention is that the query above, must be the way it is. I can not put Puts in front of it.
I would appreciate any suggestions as to why I am getting this statement regarding + being an undefined method.
Thanks!
edit: Thanks for the quick response. I didnt realize the coding community was so active! This is really amazing. I am going to edit the code to reflect the newest issues, so I dont keep getting the same suggestions.
I get an error: person.rb:31: undefined method `+' for nil:NilClass (NoMethodError). I understand that this error has the answer, but I am not yet adept at understanding what this means.
It means that one of the three variables is nil, i.e., it lacks a value:
m.first_name
m.last_name
This is occurring because you are returning the result of calling the puts function in all of your accessors. You need to return the variables themselves, not print them and return the result of the print function.
Also, since you are already using attr_reader you have get methods created for you already. That's the whole point of using attr_reader; it creates a function which returns an underlying instance variable for you, you simply need to initialize it.
for example, this:
class Foo
def bar
#bar
end
end
is equivalent to
class Foo
attr_reader :bar
end
Your accessors are returning the results of puts, not the instance variable's values.
First, you're already using attr_reader, which generates those methods for you.
Second, first_name, for example, should just return #first_name:
def first_name
#first_name
end
In Ruby, is there a way to get the name of the class that creates an instance of MyClass?
I know that I could pass it in as an argument on my initialize method, but I want to know if any data is already there that has to do with the class that created an instance of MyClass in side of MyClass.
So it would be like
class MyClass
def initialize
#who_called_me = who_called_me.name
end
def who_called_me
puts #who_called_me
end
end
Although this is not portable between implementations and versions, this is a crude solution:
who_made_me=caller[3].split(':')[1][4..-2]
What this does is it gets the current stack, skips the strings for initialize, allocate, and new, and then gets the method name out of the string. Again, this is a total hack, and is based around unspecified behavior. I would not suggest using this unless absolutely necessary.
In general, this is evil. I've seen an equivalent in C#, but it produced violently cruel side effects, not to mention ugly-as-heck code.
In Ruby, if you really had to do this, you'd probably start with Kernel.caller. But please don't do that.
Is it an intended design philosophy? For example if I have a class "Greeter" defined as follow:
1: class Greeter
2: def say_hello
3: puts "Hello"
4: end
5:
6: puts "Goodbye!"
7:
8: end
When I execute the file:
$ ruby greeter.rb
Goodbye!
$
In other languages (e.g. Java, PHP) I will get an error about line 6 is invalid. Ruby's way is somehow different to what I know about OOP, or is it me misunderstand the OOP concept?
I don't understand what this has to do OOP. OOP is all about message sends, and puts "Goodbye!" is a message send. It sends the message :puts with the single argument "Goodbye!" to self.
Indeed, the thing that's not OOP is line 2, which you don't seem to have a problem with, since line 2 is not a message send.
Let's look at it from the opposite view: If the content of a class body were not executed, then how would you define methods? You are obviously not surprised that line 2 gets executed, so why should line 6 be treated any different? That would be horribly inconsistent!
It is an intended design phiolosophy. It comes from:
Is there any better place to implement and invoke class-definition logic than the class body?!
This isn't because it's object-oriented, but because of how Ruby implements OO. That "class" you're defining thereā¦it's an object. It's an object of the type "Class". Your call to puts is considered a "class macro". The scope it is run in is the instance of the Class (not an instance of Greeter). Since Ruby creates an instance of the class definition (so a Class object) when it interprets it, your statement is run immediately at runtime.
You would do well to get a copy of the pickaxe ruby book (Programming Ruby 1.9), and if you're interested in how Ruby works with dynamic stuff like this you might really enjoy Metaprogramming Ruby as well.
Code inside a class definition, but outside any of the methods is a very powerful feature in Ruby, especially considering its dynamic nature. It is actually similar to creating static constructors in other languages. Basically, this is meant for code that should be executed before the methods on your class are ever used. You can use this to actually manipulate your class at runtime. Take a look at methods like attr_accessor to see why this is so useful.
Another way to explain it is:
class Greeter
You have executed a class statement. It defines a class and you are inside that class
2: def say_hello
3: puts "Hello"
4: end
You execute a def a code inside class Greater. This code has created a method
6: puts "Goodbye!"
You are inside class Greeter an another code (a puts) is executed. This code has printed GoodBye! in the console.