Skip to content

Object (Nesne)

Ruby, Object Oriented Programming'in dibidir :) Her şey nesnelerden oluşur. Nasıl mı? hemen basit bir değişken oluşturup içine bir tekst yazalım.

mesaj = "Merhaba"

mesaj değişkeninin türü ne?

mesaj.class # => String

Bu değişken String nesnesinden türemiş. Peki, String nereden geliyor?

mesaj.class.superclass # => Object

Dikkat ettiyseniz burada superclass kullandık. Yani bu hiyerarşideki bir üst sınıfı arıyoruz. Karşımıza ne çıktı? Object. Peki acaba Object nereden türemiş?

mesaj.class.superclass.superclass # => BasicObject

Hmmm.. Peki BasicObject nereden geliyor?

mesaj.class.superclass.superclass.superclass # => nil

İşte şu anda dibi bulduk :) Demek ki hiyerarşi;

BasicObject > Object > String

şeklinde bir hiyerarşi söz konusu.

Peki, sayılarda durum ne?

numara = 1
numara.class # => Fixnum
numara.class.superclass # => Integer
numara.class.superclass.superclass # => Numeric
numara.class.superclass.superclass.superclass # => Object
numara.class.superclass.superclass.superclass.superclass # => BasicObject
numara.class.superclass.superclass.superclass.superclass.superclass # => nil

Ufff... bir an için bitmeyecek sandım :) Çok basit bir sayı tanımlası yaptığımızda bile, arka plandaki işleyiş yukarıdaki gibi oluyor. Yani

BasicObject > Object > Numeric > Integer > Fixnum

şeklinde yine ana nesne BasicObject olmak koşuluyla uzun bir hiyerarşi söz konusu.

Her şey BasicObject den türüyor, bu yüzden de aslında her şey bir Class dolayısıyla bu durum dile çok ciddi esneklik kazandırıyor.

Nesne Metodları (Object Instance Methods)

Şimdi boş bir nesne oluşturalım. Class bölümünde daha detaylı göreceğimiz instantiate işlemiyle new methodunu kullanarak;

o = Object.new # => #<Object:0x007fe552099a68>
o.__id__       # => 70311450299700

yaptığımızda, oluşan nesnenin hafızada unique (yani bundan sadece bir tane) bir identifier'ı (kabaca buna kimlik diyelim) yani ID'si olduğunu görürüz. __id__ yerine object_id yani o.object_id şeklinde de kullanabiliriz.

Eğer hash method’unu çağırırsak, Ruby bize ilgili objenin Fixnum türünde sayısal değerini üretir ve verir.

o = Object.new # => #<Object:0x007f8c3b0a3420>
o.__id__       # => 70120131336720
o.object_id    # => 70120131336720
o.hash         # => -229260864779029724

Neticede String de bir nesne ve;

t = String.new("Hello")  # => "Hello"
t.__id__                 # => 70170408456140
t.methods                # => [:<=>, :==, :===, :eql?, :hash, :casecmp, :+, :*, :%, :[], :[]=, :insert, :length, :size, :bytesize, :empty?, :=~, :match, :succ, :succ!, :next, :next!, :upto, :index, :rindex, :replace, :clear, :chr, :getbyte, :setbyte, :byteslice, :scrub, :scrub!, :freeze, :to_i, :to_f, :to_s, :to_str, :inspect, :dump, :upcase, :downcase, :capitalize, :swapcase, :upcase!, :downcase!, :capitalize!, :swapcase!, :hex, :oct, :split, :lines, :bytes, :chars, :codepoints, :reverse, :reverse!, :concat, :<<, :prepend, :crypt, :intern, :to_sym, :ord, :include?, :start_with?, :end_with?, :scan, :ljust, :rjust, :center, :sub, :gsub, :chop, :chomp, :strip, :lstrip, :rstrip, :sub!, :gsub!, :chop!, :chomp!, :strip!, :lstrip!, :rstrip!, :tr, :tr_s, :delete, :squeeze, :count, :tr!, :tr_s!, :delete!, :squeeze!, :each_line, :each_byte, :each_char, :each_codepoint, :sum, :slice, :slice!, :partition, :rpartition, :encoding, :force_encoding, :b, :valid_encoding?, :ascii_only?, :unpack, :encode, :encode!, :to_r, :to_c, :>, :>=, :<, :<=, :between?, :nil?, :!~, :class, :singleton_class, :clone, :dup, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :extend, :display, :method, :public_method, :singleton_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]

t.method(:upcase).call   # => "HELLO"

t.methods ise String'den türeyen t ye ait tüm method’ları listeledik. Sonuç Array (Dizi) olarak geldi ve bu dizinin tüm elemanları : işaretiyle başlıyor. Çünkü bu elemanlar birer Symbol.

t.method(:upcase).call da ise, t'nin :upcase method’unu call ile çağırdır. Aslında yaptığımız iş: "hello".upcase ile birebir aynı.

Acaba bu nesne ne?

t.is_a?(String) # => true is_a? method’u ile nesnenin türünü kontrol edebiliriz.

Diğer dillerin pek çoğunda (özellikle Python) bir işi yapmanın bir ya da en fazla iki yolu varken, Ruby bu konuda çok rahattır. Bir işi yapmanın her zaman birden fazla yolu olur ve bunların neredeyse hepsi doğrudur. (Kullanıldığı yere ve amaca bağlı olarak)

is_a? yerine kind_of? da kullanabiliriz!

Bir nesneye ait hangi method'ların olduğunu;

o = Object.new
o.methods # => [:nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :to_s, :inspect, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :extend, :display, :method, :public_method, :singleton_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :==, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]

o.public_methods # => [:nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :to_s, :inspect, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :extend, :display, :method, :public_method, :singleton_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :==, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]

o.private_methods # => [:initialize_copy, :initialize_dup, :initialize_clone, :sprintf, :format, :Integer, :Float, :String, :Array, :Hash, :warn, :raise, :fail, :global_variables, :__method__, :__callee__, :__dir__, :eval, :local_variables, :iterator?, :block_given?, :catch, :throw, :loop, :respond_to_missing?, :trace_var, :untrace_var, :at_exit, :syscall, :open, :printf, :print, :putc, :puts, :gets, :readline, :select, :readlines, :`, :p, :test, :srand, :rand, :trap, :exec, :fork, :exit!, :system, :spawn, :sleep, :exit, :abort, :load, :require, :require_relative, :autoload, :autoload?, :proc, :lambda, :binding, :caller, :caller_locations, :Rational, :Complex, :set_trace_func, :gem, :gem_original_require, :initialize, :singleton_method_added, :singleton_method_removed, :singleton_method_undefined, :method_missing]

o.protected_methods # => []

o.public_methods(false) # => []

public_methods default olarak public_methods(all=true) şeklinde çalışır. Eğer parametre olarak false geçersek ve bu bizim oluşturduğumuz bir nesne ise, sadece ilgili nesnenin public_method'ları geri döner.

Başta belirttiğimiz gibi, basit bir nesne bile Object'den türediği için ve default olarak bu türeme esnasında tüm özellikler diğerine geçtiği için, sadece sizin method'larınızı görüntülemek açısından false olayı çok işe yarar.

Method Missing

Bence Ruby'nin en süper özelliklerinden biridir. Olmayan bir method'u çağırdığınız zaman tetiklenen method method_missing method'udur. Ruby on Rails framework'ü neredeyse bu mekanizma üzerine kurulmuştur. 3 parametre alır; çağırılan method, eğer parametre geçilmişse parametreler, eğer block geçilmişse block.

class User
  def method_missing(method_name, *args, &block)
    if method_name == :show_user_info
      "This user has no information"
    else
      "You've called #{method_name}, You've passed: #{args}"
    end
  end
end

u = User.new
u.show_user_info # => "This user has no information"
u.show_user_age  # => "You've called show_user_age, You've passed: []"

User adında bir Class'ımız var. İçinde hiçbir method tanımlı değil. u.show_user_info satırında, olmayan bir method'u çağırıyoruz. Tanımladığımız method_missing method'u ile olmayan method çağırılmasını yakalıyoruz.

Eğer show_user_info diye bir method çağrılırsa yakalıyoruz, bunun dışında bir şey olursa da method adını ve geçilen parametreleri gösteriyoruz.

Bu sayede NoMethodError hatası almadan işimize devam edebiliyoruz.

Anlamak açısından, Roman rakamları için bir sınıf yaptığınızı düşünün. Sadece örnek olması için gösteriyorum, C,X ve M için;

class Roman
  def roman_to_str(str)
    case str
    when "x", "X"
      10
    when "c", "C"
      100
    when "m", "M"
      1000
    end
  end
  def method_missing(method)
    roman_to_str method.id2name
  end
end

r = Roman.new
r.x # => 10
r.X # => 10
r.C # => 100
r.M # => 1000

Bunu geliştirip "MMCX" ya da "III" gibi gerçek dönüştürme işini yapabilirsiniz.

respond_to_missing?

Yukarıdaki örnekte, olmayan method'ları ürettik. Peki, acaba bu olmayan method'ları nasıl çağırabilir ya da kontrol edebiliriz? Normalde, bir Class'ın hangi method'u olduğunu respond_to? ile öğreniyorduk. Örneğe uygulayalım;

r.C derken aslında :C method'unu çağırıyoruz. Peki böyle bir method var mı?

r.method(:C)      # => `method': undefined method `C' for class `Roman' (NameError)

Nasıl yani? peki kontrol edelim?

r.respond_to?(:C) # => false

Çünkü biz :C yi dinamik olarak ürettik ama öylece ortada bıraktık. Yapmamız gereken respond_to_missing? ile gereken cevabı vermekti:

class Roman
  def roman_to_str(str)
    case str
    when "x", "X"
      10
    when "c", "C"
      100
    when "m", "M"
      1000
    end
  end
  def method_missing(method)
    roman_to_str method.id2name
  end
  def respond_to_missing?(method_name, include_private = false)
    [:x, :X, :c, :C, :m, :M].include?(method_name) || super
  end
end

r.method(:C)      # => #<Method: Roman#C>
r.respond_to?(:C) # => true
r.respond_to?(:Q) # => false # olmayan method