Ruby koan 280 - where is the reference to to_str? - ruby

I've had a look around and can't find this question:
For ruby koan 280 it's telling me the following underscore section should be false:
def test_to_str_allows_objects_to_be_treated_as_strings
assert_equal __, File.exist?(CanBeTreatedAsString.new) # test passes, if __ is changed to false
end
OK, fine. But how does this test that to_str allows objects to be treated as Strings? Here is the CanBeTreatedAsString class, which DOES include a to_str method:
class CanBeTreatedAsString
def to_s
"string-like"
end
def to_str
to_s
end
end
...but how is that relevant to the assert_equal code above? Is it that .exist? expects a String?
This page:
http://www.ruby-doc.org/core-2.2.0/File.html#method-c-exist-3F
says the parameter can be an IO object. Are some methods specific about the parameter types they receive? And if so, how do I tell?

File.exist? takes a string or an IO. Part of how it does that is by calling to_str on the object. A string returns itself for to_str. Otherwise, it's only supposed to be implemented on objects that can be used as a string.
Due to Ruby's duck typing conventions, there isn't an easy way to tell. However, usually, if a method accepts a string, then it will call String.try_convert (which uses to_str) to allow duck typing. In a similar fashion, many objects that expect an int call Integer.try_convert (which calls to_int) to convert the argument.
Here's more information on the various conversion protocols: http://pivotallabs.com/messages-not-types-exploring-rubys-conversion-protocols/
EDIT: Forgot to add the how can you tell

Related

Ruby to_s a special method? [duplicate]

I'm learning Ruby and I've seen a couple of methods that are confusing me a bit, particularly to_s vs to_str (and similarly, to_i/to_int, to_a/to_ary, & to_h/to_hash). What I've read explains that the shorter form (e.g. to_s) are for explicit conversions while the longer form are for implicit conversions.
I don't really understand how to_str would actually be used. Would something other than a String ever define to_str? Can you give a practical application for this method?
Note first that all of this applies to each pair of “short” (e.g. to_s/to_i/to_a/to_h) vs. “long” (e.g. to_str/to_int/to_ary/to_hash) coercion methods in Ruby (for their respective types) as they all have the same semantics.
They have different meanings. You should not implement to_str unless your object acts like a string, rather than just being representable by a string. The only core class that implements to_str is String itself.
From Programming Ruby (quoted from this blog post, which is worth reading all of):
[to_i and to_s] are not particularly strict: if an object has some kind of decent representation as a string, for example, it will probably have a to_s method… [to_int and to_str] are strict conversion functions: you implement them only if [your] object can naturally be used every place a string or an integer could be used.
Older Ruby documentation from the Pickaxe has this to say:
Unlike to_s, which is supported by almost all classes, to_str is normally implemented only by those classes that act like strings.
For example, in addition to Integer, both Float & Numeric implement to_int (to_i's equivalent of to_str) because both of them can readily substituted for an Integer (they are all actually numbers). Unless your class has a similarly tight relationship with String, you should not implement to_str.
To understand if you should use/implement to_s/to_str, let's look at some exemples. It is revealing to consider when these method fail.
1.to_s # returns "1"
Object.new.to_s # returns "#<Object:0x4932990>"
1.to_str # raises NoMethodError
Object.new.to_str # raises NoMethodError
As we can see, to_s is happy to turn any object into a string. On the other hand, to_str raises an error when its parameter does not look like a string.
Now let us look at Array#join.
[1,2].join(',') # returns "1,2"
[1,2].join(3) # fails, the argument does not look like a valid separator.
It is useful that Array#join converts to string the items in the array (whatever they really are) before joining them, so Array#join calls to_s on them.
However, the separator is supposed to be a string -- someone calling [1,2].join(3) is likely to be making a mistake. This is why Array#join calls to_str on the separator.
The same principle seems to hold for the other methods. Consider to_a/to_ary on a hash:
{1,2}.to_a # returns [[1, 2]], an array that describes the hash
{1,2}.to_ary # fails, because a hash is not really an array.
In summary, here is how I see it:
call to_s to get a string that describes the object.
call to_str to verify that an object really acts like a string.
implement to_s when you can build a string that describes your object.
implement to_str when your object can fully behave like a string.
I think a case when you could implement to_str yourself is maybe a ColoredString class -- a string that has a color attached to it. If it seems clear to you that passing a colored comma to join is not a mistake and should result in "1,2" (even though that string would not be colored), then do implement to_str on ColoredString.
Zverok has a great easily understandable article about when to use what (explained with to_h and to_hash).
It has to do whether your Object implementing those methods can be converted to a string
-> use to_s
or it is a type of some (enhanced) string
-> use to_str
I've seen a meaningful usage of to_hash in practice for the Configuration class in the gem 'configuration' (GitHub and Configuration.rb)
It represents -- as the name says -- the provided configuration, which in fact is a kind of hash (with additional features), rather than being convertible to one.

How can Ruby transform a method into a symbol as argument?

The respond_to? method takes as argument, a method to be checked, but as a symbol.
Why as symbol? And how does ruby convert the method into a symbol?
There's no magic. Methods are attached to objects by their name, which is a symbol. In fact, Math.sin(2) is basically a shorthand for Math.send(:sin, 2) ("send message :sin to Math object, with parameter 2"). You can also access methods itself: Math.method(:sin) will give you the associated Method object (whose name, Math.method(:sin).name, is of course :sin), and Math.methods will list all implemented methods' names. Math.respond_to?(:sin) can basically be rewritten as Math.methods.include?(:sin) (this is simplified, as it ignores respond_to_missing?, but... close enough for this discussion).
Think of it this way. You go to a friend's house, and their mother answers the door. You ask, "Hello, is Tim here?" You don't need to actually drag your friend to the door and ask "Hello, is this individual here?" The name works just as well. :)
EDIT:
Hmmm that's confusing right now for me. What does named mean exactly? I mean maybe with a little example. I call it with array.each. When does the "name" :each come into play then?
I am not sure how to explain it better. Methods have names, just like people have names. When you say array.each, it is sending the message :each to the object that is contained in the variable array, pretty much exactly what array.send(:each) would do. Methods are pieces of code attached to objects via their names: when an object receives a message, it runs the piece of code that is associated with that message.
Specifically, in the standard Ruby implementation, objects of class Array, when they receive the message :each, will invoke the C function rb_ary_each that is defined in the Ruby source code, and linked to the message :each using rb_define_method(rb_cArray, "each", rb_ary_each, 0) (also in the Ruby source code).
Inside Ruby, there are basically two equivalent ways to define methods. These two are equivalent:
class Foo
def bar
puts "hello"
end
end
class Foo
define_method(:bar) do
puts "hello"
end
end
Both of them do the same thing: associate the message :bar with the piece of code do puts "hello" end. When :bar is received by a Foo (whether through Foo.send(:bar) or by Foo.bar), this piece of code is run.

Why does `gsub` call `to_hash`?

I am writing a DSL. I don't want users to have to quote the arguments to pass strings, therefore I overwrite method_missing to convert an unknown method to a string. In the following example, create is the DSL method, and I wanted user to type arg1 and arg2 without the quotes.
def method_missing(m, *arg)
m.to_s
end
def create(*args)
arg1.gsub(#do something here)
end
create arg1 arg2
However, this raises and error when I use gsub on the 'string':
'gsub': can't convert String to Hash (String#to_hash gives String) (TypeError)
I guess the method_missing overwriting is messed it up since it looks like gsub is calling String#to_hash, which is not a method in String, thus it is routed to method_missing.
I am wondering why gsub calls String#to_hash, or whether there is any other way to let users of the DSL not have to type quotes, without overwriting method_missing.
String#gsub does different things depending on the argument count and types, and if a block was given:
gsub(pattern, replacement) → new_str
gsub(pattern, hash) → new_str
gsub(pattern) {|match| block } → new_str
gsub(pattern) → enumerator
The second one is documented as:
If the second argument is a Hash, and the matched text is one of its keys, the corresponding value is the replacement string.
But how to distinguish it from the first? Both take two arguments! That's a little bit complicated but in your case Ruby (well, the reference implementation called CRuby or MRI to be exact) starts with checking if the second argument has the internal type T_HASH (it doesn't as it's most likely T_STRING due to #to_s), then it checks if #to_hash can be called. Either because it responds to it or #method_missing can instead. You have defined it so Ruby calls it. However it doesn't return a T_HASH and that is the cause of the exception you've posted.
A possible solution is defining main.method_missing and not Object#method_missing (as String inherits from Object):
def self.method_missing(m, *arg)
m.to_s
end
However I recommend sticking to quotes or writing your own small parser for this kind of file if it shouldn't adhere to Ruby's syntax. Using *_missing may be the cause of confusing or unhelpful error messages. Or even none (I guess create arg1 arg2 should've been create arg1, arg2).
gsub probably uses method_missing itself somewhere, so it seems that defining it globally there is causing internal issues with the method call. If you're going to use method_missing make sure you always define it in a module or a class:
module CoolDSL
def self.method_missing(m, *arg)
m.to_s
end
def self.create(*args)
args[0].gsub(/1/, "2")
end
def self.do_thing
create arg1 arg2
end
end
CoolDSL.do_thing
Naturally, that's not exactly useful as a DSL, so you'll want to learn the power of instance_eval and yield. I like this guide.

ruby Array.inspect vs. Array[element].to_s

I'm working with an array, which we'll call books, of complex objects, which we'll call Book. The problem is when I call puts "#{books.inspect}", ruby outputs a stream of binary (unreadable utf8 characters). However, when I call puts #{books[0].to_str}", I get a brief, pretty output that describes the book in question. Not sure if it is relevant, but Book is a subclass (we can call it's parent class Item), and books.length=1
Ruby implies that .to_s and .inspect are synonymous, but they are clearly providing different results in practice. Does anyone know why this is happening and can you provide a suggestion for how to get the nice output I want out of the whole books collection?
Misc info:
[chk ~ ]$ ruby -v
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux]
class Myclass
def to_s
'my string representation'
end
def inspect
'my inspection'
end
end
a= [Myclass.new]
p a
puts a
outputs ::
[my inspection]
my string representation
The inspect method is called for each element inside the array. If that method is not defined you get the default class representation. You will just need to define inspect.
You could always just do :
def inspect
self.to_s
end
books.inspect and books[0].to_s are absolutely NOT the same.
The first is a call to inspect method of book object, which is an array. The second is a call to to_s method of books[0] object, whatever it is that is contained inside the array.
As you didn't specify what exactly is books[0], I'm afraid I can't tell anything more.
books is an array so calling books.inspect is calling Array#inspect. That method works by calling .inspect on the elements, so in this case Book#inspect.
Doing string-interpolation "Here's some info #{value}" calls .to_s on the value object whatever its class may be.
Putting these together as an example "Books #{books}" would call Array#to_s (which is an alias for Array#inspect) that calls Book#inspect to produce the output string.
When you want things to work consistently, you should define inspect and make to_s an alias of inspect as is done in the Array class as an example. e.g.
class MyClass
def inspect
'my string representation'
end
alias_method :to_s, :inspect
end
There may be times when you want them to be different where .inspect is useful for debugging and .to_s for more usual output. In that case you would define each of them with different code.

Are "begin" and "end" reserved words or not?

I'm kind of confused about reserved words in Ruby.
"The Ruby Programming Language", co-authored by Matz, says that begin and end are reserved words of the language. They're certainly used syntactically to mark out blocks.
However, range objects in the language have methods named begin and end, as in
(1..10).end
=> 10
Now, testing this out, I find that, indeed, I can define methods named "begin" and "end" on objects, though if I try to name a variable "begin" it fails. (Here's a sample of using it as a method name, it actually works...:)
class Foo
def begin
puts "hi"
end
end
Foo.new.begin
So, I suppose I'm asking, what actually is the status of reserved words like this? I would have imagined that they couldn't be used for method names (and yet it seems to work) or that at the very least it would be terrible style (but it is actually used in the core language for the Range class).
I'm pretty confused as to when they're allowed to be used and for what. Is there even documentation on this?
Yes, they are reserved words. Yes, they can be used for method names. No, you can't call them without an explicit receiver. It's probably not a good idea anyway.
class Foo
def if(foo)
puts foo
end
end
Foo.new.if("foo") # outputs foo, returns nil
Update: Here's a quote from "The Ruby Programming Language", by Matz (the creator of Ruby) himself:
In most languages, these words would be called “reserved words” and
they would be never allowed as identifiers. The Ruby parser is
flexible and does not complain if you prefix these keywords with #,
##, or $ prefixes and use them as instance, class, or global variable
names. Also, you can use these keywords as method names, with the
caveat that the method must always be explicitly invoked through an
object.
When they are given in a form that is unambiguously a method call, you can use them. If you have a period in front of it .begin or have parentheses after is begin(), then it is unambiguously a method call. When you try to use it as a variable begin, it is ambiguous (in principle).
Actually, as Perry, notes, begin() might be tricky. I checked with irb with Ruby 1.9.3, and the following strange thing happens:
irb(main):001:0> def begin(foo)
irb(main):002:1> puts 'a'
irb(main):003:1> end
=> nil
irb(main):004:0> begin(3)
irb(main):005:1>
irb(main):006:1* end
=> 3
It is not defined, and what looks like a method call might be just a block returning the last-evaluated 3. But the lines around def begin(foo) remains mystery.

Resources