I am currently editing a class' to_s method to make it puts out something prettier. At the last line, the object_id is include #<Profile:0x007fde5aadd280>. Any way to remove this object_id from the output without doing so explicitly after calling to_s
You need to write your own #inspect method.
class Foo
def inspect
"<#%s>" % self.class
end
end
Foo.new # => <#Foo>
Read the documentation Object#inspect
Returns a string containing a human-readable representation of obj. By default, show the class name and the list of the instance variables and their values (by calling inspect on each of them). User defined classes should override this method to make better representation of obj. When overriding this method, it should return a string whose encoding is compatible with the default external encoding.
Related
I'd like to convert the constant FOO::BAR to the string "BAR".
This is the opposite of what constantize does and is very similar to demodulize, except I expect a string instead of the actual Module reference.
I was thinking I could make my own helper to do this, but I'm not able to get the "stringified" version of FOO::BAR.
Ideally, I'd like to avoid any 3rd party gems.
Example:
class FOO
BAR = {}
end
# this works
FOO #=> FOO
FOO.name #=> "FOO"
# this doesn't
FOO::BAR #=> {}
FOO::BAR.name #=> NoMethodError: undefined method `name' for {}:Hash
You can't pass constants, you can only pass objects. If you pass FOO::BAR to a method, you're not passing the constant, but the object that has been assigned to FOO::BAR, i.e. the hash.
In order to retrieve the constant's name an object has been assigned-to from the object itself, the object has to store the name somehow.
Modules do store the constant name they have been assigned-to (Ruby sets the name when a module is assigned to a constant for the first time). And because FOO is a module (classes are modules), you can call FOO.name and it returns "FOO". But that only works because the object "knows" its name.
From the built-in objects, only Module (and therefore Class) has a name method that works this way.
You could add a name method to the hash instance FOO::BAR is referring to, although this is probably not what you want:
def (FOO::BAR).name
'FOO::BAR'
end
FOO::BAR.name #=> "FOO::BAR"
Another way is to pass both, the constant (the object actually) and its module to a method:
def find_const(mod, obj)
mod.constants.find { |c| mod.const_get(c).equal?(obj) }
end
find_const(FOO, FOO::BAR) #=> :BAR
The method traverses the module's constants and returns the (first) constant that refers to the passed object.
class FOO
class BAR
end
end
FOO::BAR.to_s.split('::').last
#=> "BAR"
Note that the method Module#to_s "Returns a string representing this module or class. For basic classes and modules, this is the name". Module#name could be used in place of to_s.
Is there a way to bind an existing method to an existing instance of an object if both the method and the instance are passed as symbols into a method that does that if the instance is not a symbol?
For example:
def some_method
#do something
end
some_instance = Klass.new(something)
def method_that_binds(:some_method, to: :some_instance)
#how do I do that?
end
Your requirements are a little unusual, but it is possible to do this mostly as you say:
class Person; end
harry = Person.new
barry = Person.new
def test
puts 'It works!'
end
define_method :method_that_binds do |a_method, to|
eval(to[:to].to_s).singleton_class.send(:define_method, a_method, &Object.new.method(a_method))
end
method_that_binds :test, to: :harry
harry.test
# It works! will be sent to STDOUT
barry.test
# undefined method 'test'
This doesn't actually use a named parameter, but accepts a hash with a to key, but you can see you can call it in the way you want. It also assumes that the methods you are defining are defined globally on Object.
The API you want doesn't easily work, because you have to know from which scope you want to access the local variable. It's not quite clear to me why you want to pass the name of the local variable instead of passing the content of the local variable … after all, the local variable is present at the call site.
Anyway, if you pass in the scope in addition to the name, this can be accomplished rather easily:
def some_method(*args)
puts args
puts "I can access some_instance's ivar: ##private_instance_var"
end
class Foo; def initialize; #private_instance_var = :foo end end
some_instance = Foo.new
def method_that_binds(meth, to:, within:, with: [])
self.class.instance_method(meth).bind(within.local_variable_get(to)).(*with)
end
method_that_binds(:some_method, to: :some_instance, within: binding, with: ['arg1', 'arg2'])
# arg1
# arg2
# I can access some_instance's ivar: foo
As you can see, I also added a way to pass arguments to the method. Without that extension, it becomes even simpler:
def method_that_binds(meth, to:, within:)
self.class.instance_method(meth).bind(within.local_variable_get(to)).()
end
But you have to pass the scope (Binding) into the method.
If you'd like to add a method just to some_instance i.e. it's not available on other instances of Klass then this can be done using define_singleton_method (documentation here.)
some_instance.define_singleton_method(:some_method, method(:some_method))
Here the first use of the symbol :some_method is the name you'd like the method to have on some_instance and the second use as a parameter to method is creating a Method object from your existing method.
If you'd like to use the same name as the existing method you could wrap this in your own method like:
def add_method(obj, name)
obj.define_singleton_method(name, method(name))
end
Let's say we have a class A with a method a and a local variable c.
class A
def a; 10 end
end
c = '5'
And we want to add the method A#a to c.
This is how it can be done
c.singleton_class.send :define_method, :b, &A.new.method(:a)
p c.b # => 10
Explanations.
One way to add a method to an object instance and not to its class is to define it in its singleton class (which every ruby object has).
We can get the c's singleton class by calling the corresponding method c.signleton_class.
Next we need to dynamically define a method in its class and this can usually be accomplished by using the define_method which takes a method name as its first argument (in our case :b) and a block. Now, converting the method into a block might look a bit tricky but the idea is relatively simple: we first transform the method into a Method instance by calling the Object#method and then by putting the & before A.new.method(:a) we tell the interpreter to call the to_proc method on our object (as our returned object is an instance of the Method, the Method#to_proc will be called) and after that the returned proc will be translated into a block that the define_method expects as its second argument.
When you define a method, it returns a symbol with the same name as the method. Is there a point to this? Or is it just there as validation that you created it?
Like so:
def something
...
end
# => :something
IRb always displays the result of calling inspect on the value of the last expression that was evaluated. It doesn't matter whether that expression is a literal expression, a conditional expression, a message send, a class definition expression or a method definition expression.
Everything returns a value in Ruby, i.e. everything is an expression, there is no such thing as a statement in Ruby.
In the past, the return value of a method definition expression was undefined. Most Ruby implementations simply returned nil from a method definition expression, but Rubinius for example returned the CompiledMethod object for the method that was defined.
With Ruby 2.1, the return value of a method definition expression was standardized to be the Symbol corresponding to the method's name. This allows you to use the method definition expression as an argument in methods that expect the name of a method as an argument.
Some examples:
# Before Ruby 2.0:
def foo; end
private :foo
# After Ruby 2.0:
private def foo; end # similar for `protected`, `public`, `module_function`
# Before Ruby 2.0:
def map; end
alias_method :collect, :map
# After Ruby 2.0:
alias_method :collect, def map; end
On a personal note, I would have preferred a method definition expression to evaluate to an UnboundMethod object corresponding to that method, and methods like public, private, protected, alias_method, module_function etc. should be amended to accept UnboundMethods in addition to Symbols and Strings.
The person who proposed this had in mind a usage like this:
private def foo
...
end
protected def bar
...
end
Methods such as public, private, protected take symbols as arguments. The point was to make use of this syntax.
All method defs return symbols in Ruby >=2.1 (not just the ones in IRB).
For example:
class Foo
p def bar; end
end
# => prints :bar
Why is this interesting?
You may have noticed that there are many methods, particularly class-level methods, that take the symbolized name of another method as an argument. You may be familiar with before_filter in Rails controllers. Since method defs return symbols, you could potentially do this:
class MyController < ApplicationController
before_filter def my_filter
# do stuff
end
end
IRB respects the ruby standard “the result of last executed statement is returned from method.” Imagine the code:
def a
def b
# do stuff
end
end
What is the result of execution this code? It follows:
a
# => :b
a.class
# => Symbol < Object
That said, IRB executes the method definition and returns/prints out it’s result. Which is, apparently, a Symbol instance.
I'm learning Ruby and made a class to help:
class WhatImDoing
def initialize
puts "not doing anything"
end
end
with the output of:
not doing anything
#<WhatImDoing:0xb74b14e8>
I'm curious, what is the second line all about? Is it a reference location for the WhatImDoing object I created? Can I access objects through this location(like a pointer or something)? Etc... Just trying to get a better understanding of Ruby, in general.
Thanks.
The second line is the output of irb, showing the return value of the last statement.
If you set something equal to that value:
> class WhatImDoing
def initialize
puts "not doing anything"
end
def ohai
puts "Ohai"
end
end
> tmp = WhatImDoing.new
=> #<WhatImDoing:0x5cd5a2a9>
You could use it:
> tmp.ohai
Ohai
If you had a custom to_s it would show that instead:
> class WhatImDoing
def to_s
"#{super} kthxbai"
end
endt
> tmp = WhatImDoing.new
=> #<WhatImDoing:0x3e389405> kthxbai
I'm assuming that was the output of irb. Irb tried to print your object, i.e. convert it to a string. Since you didn't provide a custom to_s ("to string") method, your object inherited this one:
http://ruby-doc.org/core-1.9.3/Object.html#method-i-to_s
Returns a string representing obj. The default to_s prints the object’s class and an encoding of the object id. As a special case, the top-level object that is the initial execution context of Ruby programs returns “main.”
Further digging into the source code reveals that the hexadecimal number is, indeed, the memory address occupied by that object instance. There isn't really anything fancy you can do with that information, in Ruby. It's just a convenient way to generate an unique identifier for an object instance.
Yes, it is reference to the object you are creating. Yes, you can access that object.
In Ruby, inside a class's instance method, we use a getter by
foo
and we use a setter by
self.foo = something
One doesn't need to have a self. and the other does, is there a way to make them look more similar, and not using something like self.foo as the getter, as it also looks verbose.
(update: note that getter and setter may simply get or set an instance variable, but they might also do a lot of work, such as going into the DB and check the existence of a record and if not, create it, etc)
Since local scope takes precedence, when you say foo = something, a local variable foo will be created and assigned the contents of something.
The reason you can write foo in order to use the getter is because Ruby will move up in scope when it can't find a variable with that name and it will eventually find the method.
If there is a local variable with the same name as the getter method, Ruby will use its value instead:
class Foo
attr_accessor :foo
def initialize
#foo = :one
end
def f
foo = :two
foo
end
end
Foo.new.f
# => :two
In order to make it clear that you want to access the setter, you must write self.foo = something. That will tell Ruby you want to execute the foo= method on the self object with something as parameter.
If you are willing to break the conventions, you can write your setters using jQuery style, using the same method for getter and setter, depending of whether it has arguments or not:
def foo *args
return #foo if args.empty?
#foo = args.first
end
# => nil
foo
# => nil
foo(:bar) # foo = :bar
# => :bar
foo
# => :bar
As far as I know, there isn't a way around this in Ruby. I'm pretty confident this is simply how Ruby evaluates expressions.
When given a value, Ruby will first check if there is a local variable within the context which matches the one being called. If there is (perhaps 'foo' in your case), that will be the value used. If there is no such value, then Ruby will try to look up the value as a method call (falling through to "self" as the caller). If no such method exists in the look up path, an error will be raised.
The need to use "self" in the setter is to avoid Ruby setting the value as a local variable, while the lack of the use of "self" only works in the getter instance when there is no local variable of the same name being used in that context. It is probably better and clearer, albeit slightly more verbose, to be explicit with your use of self as to avoid confusion about where values are coming from.