How do you do polymorphism in Ruby?
edit: added more code for your updated question
disclaimer: I haven't used Ruby in a year or so, and don't have it installed on this machine, so the syntax might be entirely wrong. But the concepts are correct.
The exact same way, with classes and overridden methods:
class Animal
def MakeNoise
return ""
end
def Sleep
print self.class.name + " is sleeping.\n"
end
end
class Dog < Animal
def MakeNoise
return "Woof!"
end
end
class Cat < Animal
def MakeNoise
return "Meow!"
end
end
animals = [Dog.new, Cat.new]
animals.each {|a|
print a.MakeNoise + "\n"
a.Sleep
}
how to do polymorphism in Ruby
You almost made it :) In ruby you can't return an arbitrary object from a constructor. Well, you can, but that return value is ignored. Instead use a Factory Method (in OOP speak).
class Human
def move
p 'Human move: X'
end
end
class Computer
def move
p 'Computer move: O'
end
end
class Player
def self.get_player(letter)
if letter == 'X'
return Human.new
else
return Computer.new
end
end
end
bob = Player.get_player('X')
bob.move
# >> "Human move: X"
How to access a variable in Polymorphism with Ruby?
You're running it in wrong way. You should create instances of concrete shapes and then call methods on them:
[8] pry(main)> circle = Circle.new
=> #<Circle:0x0000563ed7328770>
[9] pry(main)> circle.size = 5
=> 5
[10] pry(main)> circle.calculate_area
=> 12.566370614359172
Does polymorphism exist in Ruby?
Yes, Ruby does support polymorphism.
Consider the case of simple class inheritance where an instance of a derived class "is a" instance of both the child and parent classes:
class Parent; end
class Child < Parent; end
o = Child.new
o.is_a?(Child) # => true
o.is_a?(Parent) # => true
Note that this example is also valid for included modules:
a = Array.new
a.is_a?(Array) # => true
a.is_a?(Enumerable) # => true
Of course, Ruby also encourages duck typing, which may be the source of confusion regarding the question of properly supporting polymorphism.
Is it possible to do polymorphism by doing overloading?
If the addition is what you're after, you can do it more simply as:
def add(*numbers)
numbers.inject(&:+)
end
add(1) # => 1
add(1, 3, 5) # => 9
If you're looking for a more general solution to the problem of how to provide behavior dependent on the number of arguments, then you use *args
in the signature and then branch based on args.size
:
def foo(*args)
case args.size
when 1
# do something
when 2
# do something else
when (3..5)
# do another thing
end
end
Change polymorphic type in ruby
After some more thought, this just wants to be a state_machine, which is nearly like a case or branching ifs. However, we were able to implement a way to handle this without conditionals that feels pretty good:
class Folder
def initialize(name)
@name = name
@state = ClosedFolderState.new(self)
end
attr_reader :name
attr_accessor :state
def pretty_name
"#{@state.icon} #{@name}"
end
def left_click
@state.left_click
end
end
class ClosedFolderState
def initialize(folder)
@folder = folder
end
def icon
'+'
end
def left_click
@folder.state = OpenFolderState.new(@folder)
end
end
class OpenFolderState
def initialize(folder)
@folder = folder
end
def icon
'-'
end
def left_click
@folder.state = ClosedFolderState.new(@folder)
end
end
This may be overkill, but this seems to meet our goal of just seeing if we can move away from conditionals, and here using a decorator seems to work. I am not saying this would be everyone's preferred solution, but I think this answers my question.
Ruby on Rails - Create polymorphic comment through partial
When you pass a record to a form builder rails uses the polymorphic route helpers* to lookup the url for the action attribute.
To route to a nested resource you need to pass the parent and child(ren) in an array:
bootstrap_form_for([@commentable, @comment])
# or
bootstrap_form_for([@comment.commentable, @comment])
This would give the path /images/:image_id/comments
for a new record and /images/:image_id/comments/:id
if it has been persisted.
Get specific type of polymorphic association
According to APIdock:
:foreign_type
Specify the column used to store the associated object’s type, if this is a polymorphic association. By default this is guessed to be
the name of the association with a “_type” suffix. So a class that
defines a belongs_to :taggable, polymorphic: true association will use
“taggable_type” as the default :foreign_type.
So, you should use foreign_type
in the source
association to specify what column stores the associated object's type.
I think you want two methods html
and pdf
, so you can use it when the source is either Html
or Pdf
. In this case, I think you should create two methods for it, for example:
def html
source if source_type == "Html"
end
def pdf
source if source_type == "Pdf"
end
Related Topics
How to Get a JSON String from Url
ASP.NET MVC Get Textbox Input Value
How to Flatten an Expandoobject Returned via JSONresult in ASP.NET MVC
Is There an Equivalent to the Scanner Class in C# for Strings
C# Namespace Alias - What's the Point
Best Way to Tackle Global Hotkey Processing in C#
Main Method Code Entirely Inside Try/Catch: Is It Bad Practice
SQL Error: Incorrect Syntax Near the Keyword 'User'
Sqldataadapter VS SQLdatareader
Copy Constructor Versus Clone()
How to Get the HTML Output of a Usercontrol in .Net (C#)
Webbrowser Control IE8 Compatibility Mode On/Off Switch
Asp.Net-Mvc: Razor '@' Symbol in Js File
How to Read a .Net Guid into a Java Uuid
Using Reflection in C# to Get Properties of a Nested Object