Codes316
Codes316

Reputation: 303

Why can't I use the same method twice for one instance in ruby?

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

Answers (3)

Sagar Pandya
Sagar Pandya

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

Notes

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

J&#246;rg W Mittag
J&#246;rg W Mittag

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

max pleaner
max pleaner

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

Related Questions