29 Haziran 2014 Pazar

Ruby Programlama Dili Deyim ve İfade Kuralları

  1. Fonksiyon Yan Etkisi

Fonksiyon yan etkisi, bir fonksiyon kendisine iki yönlü parametre verilen değişkenin veya yerel olmayan bir değişkenin değerini değiştirdiğinde gerçekleşir [1].


Ruby'de fonksiyona verilen parametrenin değeri değişmez. Çünkü Ruby'de fonksiyona parametrenin sadece değeri geçirilir [2]. Aşağıdaki örnekte a değişkeninin değeri arttir fonksiyonu cagrildiktan sonra bile 1 olarak kalır.


def arttir(deger)
 deger += 1
end

a = 1;
arttir(a);
puts a;


Global bir değişkenin çağrımı durumunda ise Ruby'de operandların nasıl değerlendirileceği (associativity) önceden belirlenmiştir. Aritmetik işlemler için operandlar her zaman soldan sağa değerlendirilir [3]. Yani aşağıdaki örnekte b değişkeninin değeri hesaplanırken önce $a global değişkenin değeri olan 1 alınır. Daha sonra fun metodu cagrilir. fun metodu a'nın degerini 2 olarak değiştirir ve ve bunu döner. En sondaki $a değişkeninin değeri ise 2 olarak hesaplanır. Böylece b=1+2+2=5 olarak hesaplanır. Operandların aritmetik işlemlerde her zaman soldan sağa işleneceği garanti altına alındığı için fonksiyonel yan etki Ruby'de problem değildir.


$a = 1;

def fun
 $a += 1;
 return $a;
end

b = $a + fun + $a;
puts b;


  1. Kısa Devre İfadeleri

Ruby'de kısa devre ifadeleri desteklenmektedir [4,5] Aşağıdaki örnekte “hello” metninin ekrana basılması a && b=1 koşuluna bağlanmıştır. a değişkeni mantıksal (boolean) bir ifadeyken b ise sayı tutar ve ifade içinde b=1 ataması yapılmaktadır. Bu mantıksal ifadede a değişkeni false olduğunda ikinci kısmı yani atamayı işletmeye gerek yoktur. Bu durumda a değişkeni false olduğunda b'ye 1 ataması yapılmaz, true olduğunda ise 1 ataması yapılır.


a = false;
b = 0;

puts "hello" if a && b=1;  # assign b=1 if a is true
puts b; # b is 0

  1. Tip Dönüşümleri



Ruby'de tip dönüşümleri örtülü (implicit,coercion) veya açık (explicit) şekilde olabilir.


    • Örtülü (Implicit) Tip Dönüşümleri


Ruby'de iki farklı tipteki veri tipi üzerinde aritmetik işlem yapılmak istendiğinde otomatik olarak tip dönüşümünü sağlamak için tip üzerinde tanımlı coerce() metodu çağrılır. Tüm numerik tiplerde coerce() metodu dilde tanımlanmıştır. Programcının tanımladığı sınıflarda coerce() metodu tanımlanarak örtülü tip dönüşümleri sağlanabilir [6].


puts 1/2; # sonuc 0 int/int
puts 1/2.0 # sonuc 0.5 int/float. 1 --> 1.0'a donusturulur.


Örtülü tip dönüşümlerinde genlde büyük olan veri tipine doğru bir dönüşüm gerçekleşir.

    • Açık (Explicit) Tip Dönüşümleri


Ruby'de to_s(), to_f(), to_i() gibi metodlarla açık bir şekilde tip dönüşümü desteklenir [6].


puts 125.to_s
puts "12.111".to_i; #12
puts "13".to_f;
puts "12".to_r;
puts "13".to_c;
puts "Jane".to_sym;


Aşağıdaki örnekte ise bir String metni split metodu ile diziye çevrilmektedir.


v = "Ruby Python Tcl PHP Perl".split;
puts v.class;


  1. Operatörler

Operatör, bir ya da daha fazla operand üzerinde gerçekleşecek operasyonu (toplama, karşılaştırma vb.) gösteren bir tokendir [3]


Ruby'deki Operatörler öncelikleri yüksekten alçağa doğru sıralanmış şekilde Tablo-1'de gösterilmiştir. Tabloda N, operatörün kaç değişkenli olduğunu gösterir; A: aynı önceliğe sahip operatörler bulunduğunda değerlendirme (associativity) sırasını belirtir. L soldan sağa, R sağdan sola değerlendirmeyi ifade eder. M ise operatörün tekrar tanımlanıp tanımlanamayacağını (overload) belirtir [3]. Tabloda belirtilmese de parantezlerin önceliği en yüksektir.

Tablo 1: Ruby'de Operatörler [3]


Bu tablodaki öncelikleri dikkate alarak 1+2*3 ifadesini hesaplarsak, iki operand için * operatörünün önceliği +'ya göre daha yüksektir ve 2*3 işlemi toplamadan önce hesaplanır. Daha sonra toplama işlemi yapılır. Bu durumda işlemin sonucu 7 olacaktır. Aşağıda bazı aritmetik işlemler ve sonuçları örnek olarak verilmiştir:

puts 1 + 2*3;    # 7
puts 2**3;       # 8
puts 6%5;        # 1
puts 1==1.0;     # true


  1. Operatör Yeniden Tanımlama (Overloading)

Ruby'de hem standart tipler için hem de programcı tanımlı sınıflar için  operator overloading mümkündür [7,8].  Aşağıdaki örnekte String'lerdeki << operatörünün anlamı değiştirilmiştir.


class String
 def <<(value)
   self.replace(value + self)
 end
end

str = "Hello, ";
str << "World." # World.Hello,
puts str


Aşağıdaki örnekte de String için ** (kare alma) operatörünü tanımlanmıştır.


class String
 def **(value)
   square = self.length**value;
   self*(square/self.length);
 end
end
puts "aa"**3; #aaaaaaaa


[1] Sebesta, R.W., Concepts of Programming Languages, Pearson Education, 2012.


[2] “Ruby - Parameters by reference or by value”, 3 Nisan 2014,  http://stackoverflow.com/a/22827949/878710. [Erişim Tarihi: 27 Nisan 2014].


[3] Flanagan D., Matsumoto Y., The Ruby Programming Language, O'Reilly Media, 2008.


[4] "Short-circuit evaluation”, http://en.wikipedia.org/wiki/Short-circuit_evaluation . [Erişim Tarihi: 27 Nisan 2014].


[5] Kumar R. S., "Short circuit evaluation in ruby", 14 Mayıs 2013, http://blog.revathskumar.com/2013/05/short-circuit-evaluation-in-ruby.html. [Erişim Tarihi: 27 Nisan 2014].


[6] “Ruby Data Types”,  ZetCode, http://zetcode.com/lang/rubytutorial/datatypes/ . [Erişim Tarihi: 24 Nisan 2014].


[7] Robert Klemme, "The Complete Numeric Class", Ruby Best Practices, 20 Şubat 2010, http://blog.rubybestpractices.com/posts/rklemme/019-Complete_Numeric_Class.html. [Erişim Tarihi: 24 Nisan 2014].

[8] Philip De Smedt , "Operator Overloading in Ruby", Ruby Snippets, http://rubysnippets.com/2013/01/25/operator-overloading-in-ruby/. [Erişim Tarihi: 24 Nisan 2014].


NOT: YTÜ - İleri Programlama Dili Dersi 2014 1. Dönem Ödevi Çerçevesinde Hazırlanmıştır.

NOT 2: Ruby 1.9 baz alınmıştır.

28 Haziran 2014 Cumartesi

Ruby'de Tip Tanımları

Tip Tanımları


Değişken tipleri javascript, PHP gibi dillerde olduğu gibi dinamik olarak belirlenir [1]


a = 5
=> 5
a = “5”
=> “5”
a
=> “5”
Ruby dinamik tanımlı (dynamically typed) bir dil olduğundan, tip kontrolü, değişken çalıştırıldığında yapılır [2].
Ruby'de her şey nesne olarak tutulur. Bu yüzden tüm veri tiplerinin bir nesne karşılığı vardır [3].


puts 1.class
=> "Fixnum"
puts true.class
=> "TrueClass"
puts nil.class
=> "NilClass"


Ruby'de tanımlanabilecek temel veri tipleri şunlardır:
  • Boolean
  • Sayı (Number)
  • Karakter Katarı (String)
  • Dizi (Array)
  • Hash
  • Sembol (Symbol)
  • Aralık (Range)

Boolean


Doğru/Yanlış mantıksal ifadelerini tutan değişkenlerdir. “true” veya “false” değer alabilirler [4]. Ruby'de boolean değerler TrueClass ve FalseClass sınıfı olarak tutulurlar [5]. Örneğin aşağıdaki şekilde bir değişkene boolean değer ataması yapılabilir.


bool = true;

Number
Ruby'de Integer, Float ve Rational olmak üzere üç temel sayı veri tipi vardır.


      1. Integer

Ruby'de integer veri tipi de nesnedir: belirli limite kadar Fixnum veya çok büyük sayılar için Bignum olarak tutulurlar. Buradaki limit makine bağımlı bir değerdir. Limiti aşan Fixnum değerleri otomatik olarak Bignum olarak ifade edilirler. Çoğunlukla programcının  sınıf tipi için endişelenmesine gerek yoktur [4].


puts 123; #Fixnum decimal
=> "123"
puts 23_482_345_629; #Bignum with underscores (readability)
=> "23482345629"
puts 0b11; #binary
=> "3"
puts 0x11; #hexadecimal
=> "17"
puts 0172; #octal
=> "122"


      1. Float

Ruby'de kesikli değerler Float veya BigDecimal sınıflarında tutulurlar. Float veri tipinde doğruluk ve tutarlılık problemleri olabilir. Örneğin aşağıdaki kod parçacığı 0.10000000000000184 sonucunu üretir [4].


sum = 0

1000.times do
   sum = sum + 0.0001
end

puts sum
Tam doğru sonuç elde etmek için BigDecimal'dan faydalanılabilir.


require 'bigdecimal'

sum = BigDecimal.new("0")

1000.times do
   sum = sum + BigDecimal.new("0.0001")
end

puts sum


      1. Rational

Ruby'de rasyonel sayılar, rational veri tipi ile desteklenir. Rasyonel sayılar a/b (b!=0) şeklinde ifade edilen sayılardır. Bu sayede bölmelerdeki yuvarlama hataları giderilir [4].


puts 23.to_r
=> "23/1"
puts 2.6.to_r
=> "5854679515581645/2251799813685248"

String
Ruby'de String veri tipi ile karakter katarları yani metinsel veriler tutulur. Ruby'de String'ler 8-bit unicode karakterlerin bir araya gelmesinden oluşur [3,4] Tek tırnak veya çift tırnak kullanılarak tanımlanabilir.


puts "Betty's pie shop"
=> "Betty's pie shop"
puts 'Betty\'s pie shop'
=> "Betty's pie shop"

Array
Ruby'de diziler farklı nesne türlerini de bir arada bulundurabilecek şekilde veri tiplerini grup halinde tutabilirler. Diziler + ile birleştirilebilir, * ile tekrar ettirilebilir, ve negatif indeks ile sondan başa doğru erişilebilirler [6].


nums = [1, 2, 3, 4]
=> [1, 2, 3, 4]
bag = [1, "str", 2.0 ]
=> [1, "str", 2.0]

Hash
Ruby'de hash veri tipi, indisler yerine anahtar kelimeyle erişime olanak sağlayan özelleşmiş dizilerdir [6]


h = {1 => 2, "2" => "4"}
=> {1=>2, "2"=>"4"}
h[1]
=> 2
h["2"]
=> "4"
h[2]
=> nil

Symbol
Ruby'de her şey nesne olduğundan aynı string programın farklı yerlerinde her tanımlandığında/kullanıldığında yeni bir nesne oluşturulur ve hafızada ekstra yer kaplar. Bunu aşağıdaki kodda görebiliriz [3].


puts "my_symbol".object_id;
=> 69851742923000
puts "my_symbol".object_id;
=> 69851742922720
puts :my_symbol.object_id;
=> 396968
puts :my_symbol.object_id;
=> 396968


Ruby'de tüm semboller sembol tablosunda tutulur ve buradan sorgulanabilir. [4].

Range
Ruby'de “..” ile başlangıç ve bitiş değerlerini de içeren bir aralık, “...” ile de başlangıç ve bitiş değerlerini içermeyen bir aralık oluşturulabilir [7]. Örneğin aşağıdaki program 10 11 12 13 14 15 sonucunu üretecektir.


(10..15).each do |n|
  print n, ' '
end

Sınıf Tanımları


Ruby'de her şey bir nesneye karşılık geldiği için programcının kendi tanımladığı sınıflar yeni tip tanımı olarak düşünülebilir. Tanımlanan sınıfta coerce() metodu tanımlanırsa sınıfın değerinin başka bir tipe çevrilmesi sağlanabilir. Ayrıca tanımlanan sınıfta operator overloading yapılabilir [8,9].


class Vec3
 attr_accessor :x,:y,:z

 def initialize(value1, value2, value3)
   @x = value1
   @y = value2
   @z = value3
 end

 def *(a)
   if a.is_a?(Numeric) #multiply by scalar
     return Vec3.new(@x*a, @y*a, @z*a)
   elsif a.is_a?(Vec3) #dot product
     return @x*a.x + @y*a.y + @z*a.z
   end
 end

 def coerce(other)
   return self, other
 end

 def print
   "[" + @x.to_s + ", " + @y.to_s + ", " + @z.to_s + "]"
 end
end

v = Vec3.new(1, 1, 1)
v2 = v*5
v3 = v2*v

puts v.print
puts v2.print
puts v3

Tip Dönüşümleri


Ruby'de tip dönüşümleri örtülü (implicit,coercion) veya açık (explicit) şekilde olabilir.


Ruby'de iki farklı tipteki veri tipi üzerinde aritmetik işlem yapılmak istendiğinde otomatik olarak tip dönüşümünü sağlamak için tip üzeridneki coerce() metodu çağrılır. Tüm numerik tiplerde coerce() metodu dilde tanımlanmıştır. Programcı tanımlı sınıflarda coerce() metodunu tanımlayarak örtülü tip dönüğşümleri sağlanabilir.


Ayrıca Ruby'de to_s(), to_f(), to_i() gibi metodlarla açık bir şekilde tip dönüşümü desteklenir.



[1] “Ruby Programming/Syntax/Literals”,Wikibooks, http://en.wikibooks.org/wiki/Ruby_Programming/Literals . [Erişim Tarihi: 24 Nisan 2014].


[2] Tim Hoolihan, “Static vs. Synamic Scope”, 17 Şubat 2009, http://hoolihan.net/blog-tim/2009/02/17/static-vs-dynamic-scope/ . [Erişim Tarihi: 24 Nisan 2014].


[3] “Ruby Programming/Data Types”, Wikibooks, http://en.wikibooks.org/wiki/Ruby_Programming/Data_types. [Erişim Tarihi: 24 Nisan 2014].


[4] “Ruby Data Types”,  ZetCode, http://zetcode.com/lang/rubytutorial/datatypes/ . [Erişim Tarihi: 24 Nisan 2014].


[5] “Ruby Basics – Data Types”, Ruby Bacon, 2 Kasım 2012, http://www.rubybacon.com/ruby-data-types/. [Erişim Tarihi: 24 Nisan 2014].


[6] M. Slagell and P. Yanardağ, "Ruby Kullanıcı Kılavuzu," 22 Nisan 2003. http://pdf.belgeler.org/uygulamalar/ruby/ruby-ug.pdf. [Erişim Tarihi: 24 Nisan 2014].


[7] “Ruby Quick Reference Guide”, tutorialspoint, http://www.tutorialspoint.com/ruby/ruby_quick_guide.htm. [Erişim Tarihi: 24 Nisan 2014].


[8] Robert Klemme, "The Complete Numeric Class", Ruby Best Practices, 20 Şubat 2010, http://blog.rubybestpractices.com/posts/rklemme/019-Complete_Numeric_Class.html. [Erişim Tarihi: 24 Nisan 2014].

[9] Philip De Smedt , "Operator Overloading in Ruby", Ruby Snippets, http://rubysnippets.com/2013/01/25/operator-overloading-in-ruby/. [Erişim Tarihi: 24 Nisan 2014].


NOT: YTÜ - İleri Programlama Dili Dersi 2014 1. Dönem Ödevi Çerçevesinde Hazırlanmıştır.

NOT 2: Ruby 1.9 baz alınmıştır.