I know in Ruby that I can use respond_to? to check if an object has a certain method.
But, given the class, how can I check if the instance has a certain method?
i.e, something like
Foo.new.respond_to?(:bar)
But I feel like there's gotta be a better way than instantiating a new instance.
I don't know why everyone is suggesting you should be using instance_methods and include? when method_defined? does the job.
class Test
def hello; end
end
Test.method_defined? :hello #=> true
NOTE
In case you are coming to Ruby from another OO language OR you think that method_defined means ONLY methods that you defined explicitly with:
def my_method
end
then read this:
In Ruby, a property (attribute) on your model is basically a method also. So method_defined? will also return true for properties, not just methods.
For example:
Given an instance of a class that has a String attribute first_name:
<instance>.first_name.class #=> String
<instance>.class.method_defined?(:first_name) #=> true
since first_name is both an attribute and a method (and a string of type String).
You can use method_defined? as follows:
String.method_defined? :upcase # => true
Much easier, portable and efficient than the instance_methods.include? everyone else seems to be suggesting.
Keep in mind that you won't know if a class responds dynamically to some calls with method_missing, for example by redefining respond_to?, or since Ruby 1.9.2 by defining respond_to_missing?.
Actually this doesn't work for both Objects and Classes.
This does:
class TestClass
def methodName
end
end
So with the given answer, this works:
TestClass.method_defined? :methodName # => TRUE
But this does NOT work:
t = TestClass.new
t.method_defined? : methodName # => ERROR!
So I use this for both classes and objects:
Classes:
TestClass.methods.include? 'methodName' # => TRUE
Objects:
t = TestClass.new
t.methods.include? 'methodName' # => TRUE
The answer to "Given a class, see if instance has method (Ruby)" is better. Apparently Ruby has this built-in, and I somehow missed it. My answer is left for reference, regardless.
Ruby classes respond to the methods instance_methods and public_instance_methods. In Ruby 1.8, the first lists all instance method names in an array of strings, and the second restricts it to public methods. The second behavior is what you'd most likely want, since respond_to? restricts itself to public methods by default, as well.
Foo.public_instance_methods.include?('bar')
In Ruby 1.9, though, those methods return arrays of symbols.
Foo.public_instance_methods.include?(:bar)
If you're planning on doing this often, you might want to extend Module to include a shortcut method. (It may seem odd to assign this to Module instead of Class, but since that's where the instance_methods methods live, it's best to keep in line with that pattern.)
class Module
def instance_respond_to?(method_name)
public_instance_methods.include?(method_name)
end
end
If you want to support both Ruby 1.8 and Ruby 1.9, that would be a convenient place to add the logic to search for both strings and symbols, as well.
Try Foo.instance_methods.include? :bar
Not sure if this is the best way, but you could always do this:
Foo.instance_methods.include? 'bar'
I think there is something wrong with method_defined? in Rails. It may be inconsistent or something, so if you use Rails, it's better to use something from attribute_method?(attribute).
"testing for method_defined? on ActiveRecord classes doesn't work until an instantiation" is a question about the inconsistency.
If you're checking to see if an object can respond to a series of methods, you could do something like:
methods = [:valid?, :chase, :test]
def has_methods?(something, methods)
methods & something.methods == methods
end
the methods & something.methods will join the two arrays on their common/matching elements. something.methods includes all of the methods you're checking for, it'll equal methods. For example:
[1,2] & [1,2,3,4,5]
==> [1,2]
so
[1,2] & [1,2,3,4,5] == [1,2]
==> true
In this situation, you'd want to use symbols, because when you call .methods, it returns an array of symbols and if you used ["my", "methods"], it'd return false.
klass.instance_methods.include :method_name or "method_name", depending on the Ruby version I think.
class Foo
def self.fclass_method
end
def finstance_method
end
end
foo_obj = Foo.new
foo_obj.class.methods(false)
=> [:fclass_method]
foo_obj.class.instance_methods(false)
=> [:fclass_method]
Hope this helps you!
While respond_to? will return true only for public methods, checking for "method definition" on a class may also pertain to private methods.
On Ruby v2.0+ checking both public and private sets can be achieved with
Foo.private_instance_methods.include?(:bar) || Foo.instance_methods.include?(:bar)
On my case working with ruby 2.5.3 the following sentences have worked perfectly :
value = "hello world"
value.methods.include? :upcase
It will return a boolean value true or false.
Related
Simple question:
In java you can define :
void myFunction<T>(T value) { //do stuff }
Is there an equivalent in ruby, and if not, how can I achieve a similar result (passing class types?)
You can pass a class to a method just like passing normal objects. For example
def create_object(klass, *args)
klass.new(*args)
end
create_object(String) #=> ""
create_object(Hash) #=> {}
create_object(Array, 3, :hello) #=> [:hello, :hello, :hello]
First a few definitions
Generics is an abstraction over types
Polymorphism is a sum-type pattern
Composition is a product-type pattern
Most OO languages lean towards polymorphism
Ruby is an OO language. Polymorphism is at the core of its design. The type system in Ruby is only getting strong in Ruby 3. So we may see more interesting generics at that point; but until now, I haven't heard that to be a feature.
To achieve this, we technically need to figure out a way of applying a method on separate types without knowing the type. It's a lot of code duplication is possible.
Your Java example…
void myFunction<T>(T value) { //do stuff }
…can be translated into Ruby as
def myFunction(value)
raise "Only works with T types" unless value.is_a? T
# do stuff
end
Where the magic now has to happen is in defining the possible set of T. I'm thinking something like…
class T
def _required_for_MyFunction()
raise "T is abstract!"
end
end
class Something < T
def _required_for_MyFunction()
# does something
end
end
class Nothing < T
def _required_for_MyFunction()
# does nothing
end
end
The painful part of polymorphism is that you have to define your type space from the get-go. The good parts of this is you have total control of the domain space.
Ruby follows duck typing. You can pass arguments of any class to any method (which is the original reason why you might need generics). If you want to get the class of said argument, you can still use #class
def foo(bar)
bar.class
end
foo 'baz' # => String
foo 42 # => Fixnum
The number 1 contains 109 additional methods above and beyond the Fixnum class it inherits from.
1.methods - Fixnum.methods => [:%, :&, :*, :**, :+, :+#, :-, :-#, ...]
(1.methods - Fixnum.methods).count => 109
1.is_a? Fixnum => true
So from my understanding, I would say the number 1 is an instance of Fixnum. But why does the number 1 have so many more methods than Fixnum? And where do they come from? How would I write my own method for the number 1?
When you call .methods, it gives the methods defined on that instance. So when you ask for Fixnum.methods, you get the methods you can call on Fixnum the class, not on objects of type Fixnum.
As to your last question, Ruby allows you to extend a class like so:
class Fixnum
def plus9
return self + 9
end
end
They can come from Fixnum's parent classes as well as any modules mixed in along the way. You can use 1.method('<method name>').inspect to find out where exactly does the method originate.
method#source_location is good as well, but it doesn't work for native methods, which is almost everything on 1.
Fixnum itself is an instance of Class, when you call Fixnum.methods, it returns the methods that the Class class and its ancestors have.
So 1.methods - Fixnum.methods has little sense as you are comparing the methods of Fixnum class and the methods of Class class.
Fixnum.class
# => Class
1.class
# => Fixnum
How would I write my own method for the number 1
You can implement your own methods in Fixnum or any of its ancestor classes: Integer, Numeric, etc, depending on which class this method makes sense.
You may misunderstand the Object#methods method.
According to the Ruby API,
methods(regular=true) → Returns a list of the names of public and protected methods of obj.
So Fixnum.methods returns the methods from the perspective of the object, not the class.
Module#instance_methods is what you want
1.methods.count == Fixnum.instance_methods.count # => true
To get the right method list in Ruby is kind of a confusing thing, Idiosyncratic Ruby has a detailed post about method-lists. It helps me sort things up, and hope this can help you, too.
To extend the Fixnum class and add/modify your own methods. You can use this code:
class Fixnum
def newNum_method
puts self.methods
end
end
Also you can modify existing methods the same way. Many times the 'to_s' is modified to produce specific results for example:
class Array
def to_s
puts self.join(":")
end
end
This code ONLY modifies what you specify.
You can also add class specific code for example:
def Array.newMethod
puts Array.methods
end
This allows you to call:
puts Array.newMethod
(Which would technically be the same as "puts Array.methods")
but you can customize this to say or do whatever with the 'Array' class
You could even create a method for the Fixnum class itself to Iterate over its parents and list EACH method from them.
def Fixnum.listParentMethods
.....
end
Try
1.methods - Fixnum.instance_methods
and you'll get an empty array.
In ruby, classes are objects of type Class.
When you call obj.methods, it returns all public methods of obj.
So what if obj is a class?
In Rails (version 3.2 at least; I don't have 4 to be able to try there), ActiveRecord::Base#find chokes if given a SimpleDelegator, even if the object it delegates would otherwise work properly.
The reason for this is that AR::Base#find passes values into AR::ConnectionAdapters::Quoting#quote while creating an SQL statement, and since it doesn't know what to do with SimpleDelegator, it tries to pass it to YAML.dump, which raises an exception. AR determines how to quote by a case statement of classes (ie. String === value, etc.).
Now, of course, even if a SimpleDelegator contains a String, its class is SimpleDelegator, so the above check will fail. However, SimpleDelegator has a __getobj__ method, which provides access to the actual object being delegated to:
> s = SimpleDelegator.new("test")
#=> "test"
> String === s
#=> false
> String === s.__getobj__
#=> true
In order to get around this problem, I could override Class#=== to take SimpleDelegator into account:
class Class
def ===(other)
return super(other.__getobj__) if other.is_a?(SimpleDelegator)
super
end
end
> String === s
#=> true
However, this clearly does not look like a safe way to go about doing this (I don't know if this will negatively impact anything, but at the least, class equality to SimpleDelegator will be broken). On the other hand, this makes it easier to handle other instances of code like that in AR::ConnectionAdapters::Quoting#quote which I'm not yet aware of (as opposed to specifically monkey patching quote to know about SimpleDelegator, for instance).
Module#=== is a native C method in MRI, and makes use of a method called rb_obj_is_kind_of. I had hoped that overriding SimpleDelegator#kind_of? might allow me to do what I want to here in a safer manner, but it seemed to have no impact (I guess rb_obj_is_kind_of doesn't really have anything to do with Object#kind_of?).
Is there any way to do this in a "safe" manner, or am I just stuck monkey patching individual cases as they come up?
It looks like you may hack around and to cheat the AR. It tries to YAML.dump? Well, we’ll help it:
class A < SimpleDelegate
def initialize *args
#s = 'voilá'
end
# required by YAML (Psych)
def encode_with coder
coder.tag = nil
coder.represent_scalar(nil, #s)
end
end
require 'yaml'
puts YAML.dump(A.new)
# ⇒ --- voilá
Now AR should be able to dump it and voilá. The encode_with method might be put into CheatModule to include it whereever you need to cheat AR:
module DelegateYamler
def encode_with coder
coder.tag = nil
coder.represent_scalar(nil, __getobj__)
end
end
Hope it helps.
As the title suggests, I would like to assign all the instance methods defined on one class to another. I know at I can get a list of the methods that I want to copy from ClassA to ClassB like this:
ClassA.instance_methods(false)
And I think I can define them on ClassB like this:
ClassA.instance_methods(false).each do |method_name|
ClassB.method_define(method_name, [body here??])
end
Is there a way to get the corresponding method body, and if so, will this method work? If not, is there even a way to do this?
Others already told you to subclass. But to answer your literal question, we would be getting involved with UnboundMethod objects:
class Object
def kokot; 'kokot' end
end
o = Object.new
o.kokot
#=> kokot
3.kokot
#=> kokot
So far so good. Now let's redefine kokot method on Numeric:
class Numeric
def kokot; 'pica' end
end
o.kokot
#=> kokot
3.kokot
#=> pica
But what if we decide, that new kokot method is great for numerics, but just complex numbers should keep using the old kokot method. We can do it like this:
um = Object.instance_method :kokot
#=> #<UnboundMethod: Object#kokot>
Complex( 2, 3 ).kokot # gives the redefined kokot method
#=> pica
Complex.module_exec { define_method :kokot, um }
# Now we've just bound the old kokot to Complex
Complex( 2, 3 ).kokot
#=> kokot
In short, there is a way to "copy and paste" methods among related classes. It is required that the target be a subclass of the unbound method source. Method #source_location shows the file and the line where #kokot has been defined:
um.source_location
#=> ["(irb)", 2]
For built-in methods, #source_location returns nil. In Ruby 2.0, RubyVM class has method #disassemble:
RubyVM::InstructionSequence.disassemble( um )
#=> ( program listing goes here )
In any case, Ruby bytecode is not that beautiful to look at. Going back to your original needs, not even #define_method or UnboundMethod#bind can bind methods to incompatible objects. This cannot be cheated by tricks like redefining #kind_of?, one would have to cheat CLASS_OF() function in the native code...
From the available gems, Sourcify, RubyParser and Sorcerer are of interest. (Thanks, #Casper.) Using these, one could theoretically transplant code between incompatible objects via #eval-ling extracted method source. Long way as it goes, this technique would still fall short of realiable method transfer, as it fails whenever the source is not available at runtime (eg. self-modifying source).
It seems like what you might want is mix-ins:
Taken from http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_modules.html
module Debug
def whoAmI?
"#{self.type.name} (\##{self.id}): #{self.to_s}"
end
end
class Phonograph
include Debug
# ...
end
class EightTrack
include Debug
# ...
end
ph = Phonograph.new("West End Blues")
et = EightTrack.new("Surrealistic Pillow")
ph.whoAmI? » "Phonograph (#537766170): West End Blues"
et.whoAmI? » "EightTrack (#537765860): Surrealistic Pillow"
In ruby 2.0 you can use modules. Matz explicitly forbade this behavior from classes.
But you can use instance_methods from modules.
ModuleA.instance_methods(false).each do |name|
meth = ModuleA.instance_method(name)
ClassB.send(:define_method, name, meth)
end
define_method is a private method, so that's why you use send here.
But why do this? Just include the module.
If you want to just apply behavior to an object you can unbind a method from any module and bind it to any object.
ModuleA.instance_method(:something).bind(some_object).call(args)
If this is what you want, take a look at casting, a gem that adds a convenience to doing delegation like this as well as adding methods to an object only for the life of a block.
In that case, classB should inherit classA.
Learning ruby. I'm under the impression that boolean attributes should be named as follows:
my_boolean_attribute?
However, I get syntax errors when attempting to do the following:
class MyClass
attr_accessor :my_boolean_attribute?
def initialize
:my_boolean_attribute? = false
end
end
Apparently ruby is hating the "?". Is this the convention? What am I doing wrong?
Edit: three-years later; the times, they are a-changin'…
Julik's answer is the simplest and best way to tackle the problem these days:
class Foo
attr_accessor :dead
alias_method :dead?, :dead # will pick up the reader method
end
My answer to the original question follows, for posterity…
The short version:
You can't use a question mark in the name of an instance variable.
The longer version:
Take, for example, attr_accessor :foo — it's simply conceptually a bit of syntactic sugar for the following:
def foo
#foo
end
def foo=(newfoo)
#foo = newfoo
end
Furthermore, the question-mark suffix is mostly just a convention to indicate that the return value of a method is a boolean.
The best approximation I can make of what you're going for here…
class MyClass
def initialize
#awesome = true
end
def awesome?
#awesome
end
end
In this case, there may be a case to be made for using attr_accessor — after all, it may be explicit that you're working directly with a boolean attribute. Generally, I save the question-mark suffix for when I am implementing a method whose boolean return value is based on slightly more complex conditions than just the value of an attribute.
Cheers!
Edit, two years later, after a recent comment:
Ruby enforces certain naming conventions. Symbols in Ruby can't have question marks. Thus invocations of :my_boolean_attribute? both will fail with a NameError. Edit: not correct, just use the quoted syntax for a symbol, e.g., :"my_attribute?"
Symbols are immutable, attempting to assign to one will throw a SyntaxError.
The easiest way to quickly add a "question method" is to use aliasing for your reader method
class Foo
attr_accessor :dead
alias_method :dead?, :dead # will pick up the reader method
end
The attr_accessor symbol implies that the variable name is #my_boolean_attribute, so that's what you should be setting (not the symbol).
Also, you can't use ? for variables, just method names.
? is convention for methodnames, not variables. You can't use an instance variable named #foo?, however you could use a variable named #foo and name the (manually created) getter method foo? if you wanted to.
Monkey-patching metaprogramming - maybe it can be made more elegant, this is only a quick draft, and I haven't done metaprogramming for a little while...
# inject the convenience method into the definition of the Object class
class Object
def Object::bool_attr(attrname)
class_eval { define_method(attrname.to_s,
lambda { instance_variable_get('#' + attrname.to_s.chop) }) }
class_eval { define_method(attrname.to_s.chop+"=",
lambda { |x| instance_variable_set('#'+attrname.to_s.chop, x) }) }
end
end
### somewhere later
class MyClass
bool_attr :my_boolean_attribute?
def initialize
#my_boolean_attribute = true
end
end
# yet even more later
foo = MyClass.new
bar = MyClass.new
foo.my_boolean_attribute = 1
puts foo.my_boolean_attribute?
puts bar.my_boolean_attribute?
With this approach, you can be DRY and get the nice questionmark too. You just might need to pick a better name than "bool_attr", like, "bool_attr_accessor" or something similar.
The definitions that I made are a bit cranky, in a sense that the question mark is present in the original symbol. Probably a cleaner approach would be to avoid the questionmark in the symbol name and append it during the definition of the method - should be less confusing.
Oh, and almost forgot to include the obligatory link: Seeing metaclasses clearly
I looked through the answers, and while the accepted answer is on-target, it introduces "extra" noise in the class. The way I'd suggest solving this issue is:
class Animal
attr_writer :can_swim
def initialize(animal_type_name)
#can_swim = true
#animal_type_name = animal_type_name
end
def can_swim?
#can_swim
end
def to_s
#animal_type_name
end
end
dog = Animal.new('Dog in a bag')
dog.can_swim = false
puts "Can this #{dog} Swim? --- [#{dog_without_legs.can_swim? ? 'YEP!' : 'NOPE!'}]"