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.
Related
Having reading through The Ruby programming language I found an example of using alias keyword for augmenting the methods.
def hello # A nice simple method
puts 'Hello world' # Suppose we want to augment it...
end
alias original_hello hello # Give the method a backup name
def hello # Now we define a new method with the old name
puts "Your attention please" # That does some stuff
original_hello # Then calls the original method
puts "This has been a test" # Then does some more stuff
end
Indeed original hello preserves the old behavior even after the method the it had been referencing to was redefined.
But, to my mind, this example hardly clarifies the real benefit of this technique. Cannot the same be achieved in traditional way (e.g. by providing the block)? Then why applying this idiom? Can anyone provide an example from the real world when augmenting with alias really makes sense?
Rails code is full of those. Imagine the original hello method does not belong to your code base. Somewhere in 3rd-party library there is do_stuff(stuff) method declared on the class Stuffer.
You want to e.g. debug this method. You reopen the class, define an alias and, voilà:
class Stuffer
alias original_do_stuff do_stuff
def do_stuff(stuff)
puts stuff.inspect
original_do_stuff(stuff)
end
end
Now all the code, including original 3rd party code you might be even not aware about, would print out the parameter passed to every single call to do_stuff.
Real-life example (don’t try this at home and in the school :)
class String
alias _inspect inspect
def inspect
puts "I am a string: “#{_inspect}”"
end
end
"abc".inspect
#⇒ I am a string: “"abc"”
Can anyone provide an example from the real world when augmenting with alias really makes sense?
Not really. Today, you would do this (example taken from #mudasobwa's answer):
module WeirdInspectRefinement
module WeirdInspectExtension
def inspect
"I am a string: “#{super}”"
end
end
refine String do
prepend WeirdInspectExtension
end
end
using WeirdInspectRefinement
p 'abc'.inspect
#⇒ 'I am a string: “"abc"”'
But even before Module#prepend and Refinements existed, there was never a reason to use alias for this, which leaves unused methods around polluting the namespace, and Rails abandoned it quite a while ago:
class String
old_inspect = instance_method(:inspect)
define_method(:inspect) do
"I am a string: “#{old_inspect.bind(self).()}”"
end
end
'abc'.inspect
#⇒ 'I am a string: “"abc"”'
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.
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
I'm trying to use the steam-condenser gem to pull a list of games for a particular user (myself). So far I have the following:
require 'steam-condenser'
id = SteamId.new 'tamachan87'
games_owned = id.games
games_owned is now a hash, containing keys and arrays.
If I call games_owned.values in IRB I will get a result that contains all the information of those games, from it's ID number to the name to its logo hash.
However, when I use the following:
games_owned.each do |key, array|
puts "==== #{key} ===="
puts array
end
I get just the first value of the array such as:
==== 200260 ====
#<SteamGame:0x00000100beb0a8>
Each value/array thing has an #name variable which is the only thing I want to pull.
Could someone please help me to better understand these hashes and how I can pull specific data (#name) from them?
Thanks in advance.
The return value of SteamId#games is not a hash of arrays, it's a hash of SteamGame objects.
Your example code could be written like that:
games_owned.each do |app_id, game|
puts "==== #{app_id} ===="
puts game.name
end
See the documentation of SteamId for more information.
The reason you get an unfriendly class name and memory value is that the SteamGame class does not define an inspect method. However if all you're interested is printing the names of the games, use puts key.name
If you want to print your Steamgame object in a pretty way by using "puts"
you should overwrite "to_s" in your Steamgame class.
The reason you are getting different results is puts uses to_s method to print its argument (which is
steamgame object itself in your case with specific id).
If you use "p" or "puts array.inspect" instead of "puts", it will debug your object and you will see irb like results.
If you have an attribute like #name in your Steamgame class, you should be able to get it just by saying:
games_owned.values[i].name or puts array.name.
did you try that?
is there a way in Ruby to find the calling method name inside of a method?
For example:
class Test
def self.foo
Fooz.bar
end
end
class Fooz
def self.bar
# get Test.foo or foo
end
end
puts caller[0]
or perhaps...
puts caller[0][/`.*'/][1..-2]
In Ruby 2.0.0, you can use:
caller_locations(1,1)[0].label
It's much faster than the Ruby 1.8+ solution:
caller[0][/`([^']*)'/, 1]
Will get included in backports when I get the time (or a pull request!).
Use caller_locations(1,1)[0].label (for ruby >= 2.0)
Edit: My answer was saying to use __method__ but I was wrong, it returns the current method name.
I use
caller[0][/`([^']*)'/, 1]
How about
caller[0].split("`").pop.gsub("'", "")
Much cleaner imo.
Instead you can write it as library function and make a call wherever needed. The code goes as follows :
module CallChain
def self.caller_method(depth=1)
parse_caller(caller(depth+1).first).last
end
private
# Copied from ActionMailer
def self.parse_caller(at)
if /^(.+?):(\d+)(?::in `(.*)')?/ =~ at
file = Regexp.last_match[1]
line = Regexp.last_match[2].to_i
method = Regexp.last_match[3]
[file, line, method]
end
end
end
To trigger the above module method you need to call like this:
caller = CallChain.caller_method
code reference from
In order to see the caller and callee information in any language, whether it be ruby or java or python, you would always want to look at the stack trace. In some languages, such as Rust and C++, there are options built into the compiler to turn on some sort of profiling mechanism you can view during run time. I do belive one exists for Ruby called ruby-prof.
And as mentioned above, you could look into the execution stack for ruby. This execution stack is an array containing backtrace location objects.
Essentially all you need to know about this command is as follows:
caller(start=1, length=nil) → array or nil