Reputation: 303
I have this program that basically uses a method called reverse_complement to reverse a string and replaces some characters with other characters; However, if I use the method twice for the same instance it gives me an undefined error. So, puts dna1.reverse_complement.reverse_complement == dna1.nucleotide should give me a true value. However, it gives an undefined method error.
class DNA
attr_reader :nucleotide
def initialize (nucleotide)
@nucleotide = nucleotide
end
def reverse_complement()
@nucleotide.reverse.tr("ATCG", "TAGC")
end
end
dna1 = DNA.new("ATTGCC")
puts dna1.reverse_complement
puts dna1.nucleotide
puts dna2 = dna1.reverse_complement
puts dna1.reverse_complement.reverse_complement == dna1.nucleotide
Upvotes: 0
Views: 278
Reputation: 9497
Would something like this suffice?:
class DNA < String
def reverse_complement
reverse.tr("ATCG", "TAGC")
end
end
dna1 = DNA.new("ATTGCC")
puts dna1
# ATTGCC
puts dna1.reverse_complement
# GGCAAT
puts dna1.reverse_complement.reverse_complement == dna1
# true
def reverse_complement
reverse.tr("ATCG", "TAGC")
end
can be written as:
def reverse_complement
self.reverse.tr("ATCG", "TAGC")
end
where self
is the current object. In the examples above, self
is dna1
which is an instance of DNA.
caveat: inheriting from core classes is a bad idea. This answer will be deleted if OP kindly unaccepts this answer. See link for more details about inheriting from core classes.
Upvotes: 0
Reputation: 369468
Why can't I use the same method twice for one instance in ruby?
Because you aren't using it for one instance. You are calling it on dna1
, which is an instance of DNA
, and then you call it again on the return value of reverse_complement
, which is a completely different instance of class String
.
Personally, I find it very confusing that a method called reverse_complement
would return an object of a completely different type than the one it was called on. I would rather expect it to return a reversed and complementary instance of the same type, i.e. DNA
:
class DNA
def initialize(nucleotide)
self.nucleotide = nucleotide.dup.freeze
end
def reverse_complement
self.class.new(@nucleotide.reverse.tr('ATCG', 'TAGC'))
end
def ==(other)
nucleotide == other.nucleotide
end
def to_s
"DNA: #{nucleotide}"
end
protected
attr_reader :nucleotide
private
attr_writer :nucleotide
end
dna1 = DNA.new('ATTGCC')
puts dna1.reverse_complement
# DNA: GGCAAT
puts dna2 = dna1.reverse_complement
# DNA: GGCAAT
puts dna1.reverse_complement.reverse_complement == dna1
# true
Upvotes: 2
Reputation: 26768
I think your method works but it's your chaining that's the problem:
puts dna1.reverse_complement.reverse_complement
you've defined reverse_complement
to return a string, and you can't call String#reverse_compliment
.
Instead, write this:
dna2 = DNA.new(dna1.reverse_compliment)
puts dna2.reverse_compliment == dna1.nucleotide
Upvotes: 4