Дефинират се с class
. Методите, дефинирани в тялото на класа,
стават методи на инстанциите му. Инстанцират се се с ИмеНаКласа.new
.
class Bacon
def chunky?
'yes, of course!'
end
end
bacon = Bacon.new
bacon.chunky? # "yes, of course!"
Полетата (още: instance variables) имат представка @
.
class Vector
def initialize(x, y)
@x = x
@y = y
end
def length
(@x * @x + @y * @y) ** 0.5
end
end
vector = Vector.new 2.0, 3.0
vector.length() # 3.605551275463989
vector.length # 3.605551275463989
По подразбиране имат стойност nil
.
class Person
def heh
@something
end
end
person = Person.new
person.heh # nil
В метод на може да извикате друг със self.име_на_метод
или просто име_на_метод
:
class Person
def initialize(name) @name = name end
def say_hi() puts "My name is #{@name}!" end
def sound_smart() puts "1101000 1101001" end
def talk
self.say_hi
sound_smart
end
end
mel = Person.new 'Mel'
mel.talk
Такова подравняване на методи е гадно, но пък се събира в слайд
В методите на класа, self
е референция към обекта,
на който е извикан методът. Като this
в Java.
class Person
def me
self
end
end
person = Person.new
person # #<Person:0x9db4008>
person.me # #<Person:0x9db4008>
person.me.me # #<Person:0x9db4008>
Полетата не са публично достъпни. Може да ги достигнете само чрез метод.
class Person
def initialize(age)
@age = age
end
def age
@age
end
def set_age(age)
@age = age
end
end
person = Person.new(33)
person.age # 33
person.set_age 20
person.age # 20
Разбира се, set_age
е гадно име на метод. Може и по-добре:
class Person
def age
@age
end
def age=(value)
@age = value
end
end
person = Person.new
person.age = 33 # Същото като person.age=(33)
person.age # 33
Последното е досадно за писане. Затова:
class Person
attr_accessor :age
end
person = Person.new
person.age = 33
person.age # 33
Ако ви трябва само getter или setter, може така:
class Person
attr_reader :name
attr_writer :grade
attr_accessor :age, :height
end
attr_accessor
е метод, който генерира два метода — #foo
и #foo=
. Достъпен е в дефинициите на класове. Неформален термин за такива
методи е "class macro".
Има ги в изобилие.
Обърнете внимание, че следните два реда правят едно и също:
person.age()
person.age
Няма разлика между достъпване на атрибут и извикване на метод, който го изчислява. Това се нарича Uniform Access Principle и като цяло е хубаво нещо.
Тялото на класа е напълно изпълним код:
class Something
a = 1
b = 2
a + b # 3
end
Понякога дори е полезно:
class Object
if RUBY_VERSION <= '1.8.6'
def tap
yield self
self
end
end
end
В Ruby важат следните конвенции.
UpperCamelCase
plain_snake_case
Във всеки момент може да "отворите" клас и да му добавите методи.
class Person
def name
'River'
end
end
class Person
def say_hi
"Hi, I am #{name}."
end
end
Person.new.say_hi # "Hi, I am River."
Person.new.name # "River"
Ако дефинирате един метод два пъти, втората дефиниция измества първата.
class Something
def name
'Tom Baker'
end
def name
'Colin Baker'
end
end
Something.new.name # => 'Colin Baker'
Въпреки името си, alias
прави копие на метод.
class Array
alias old_inject inject
def inject(*args, &block)
puts "I see you are using #inject. Let me help!"
old_inject(*args, &block) * 0.01
end
end
[1, 2, 3, 4, 5, 6].inject { |a, b| a + b } # 0.21
Ако викнете #methods
на нещо, ще получите масив от символи
с имената на методите му.
Помните ли Array#-
?
class Person
def foo() end
def bar() end
end
Person.new.methods - Object.new.methods # [:foo, :bar]
Много интуитивно.
class Vector
attr_accessor :x, :y
def initialize(x, y)
@x, @y = x, y
end
def +(other)
Vector.new(x + other.x, y + other.y)
end
def inspect
"Vector.new(#@x, #@y)"
end
end
Vector.new(1, 5) + Vector.new(3, 10) # Vector.new(4, 15)
class Person
def say_hi
"Hello! I am #{name}"
end
private
def name
'the Doctor'
end
end
person = Person.new
person.say_hi # "Hello! I am the Doctor"
person.name # error: NoMethodError
Ако един метод е private
, не може да го викате с явен получател.
Дори със self.
class Person
def say_hi
"Hello! I am #{self.name}"
end
private
def name
'the Doctor'
end
end
person = Person.new
person.say_hi # error: NoMethodError
Ще разгледаме:
class Integer
def prime_divisors
2.upto(abs).select { |n| remainder(n).zero? and n.prime? }
end
def prime?
2.upto(pred).all? { |n| remainder(n).nonzero? }
end
end
class Range
def fizzbuzz
map do |n|
if n % 15 == 0 then :fizzbuzz
elsif n % 3 == 0 then :fizz
elsif n % 5 == 0 then :buzz
else n
end
end
end
end
class Hash
def group_values
each_with_object({}) do |(key, value), result|
result[value] ||= []
result[value] << key
end
end
end
class Array
def densities
map { |item| count item }
end
end
p
, res
, tmp
, cur_num
и прочее
{}
когато блока е на един ред, do/end
когато е на няколко
snake_case
, а не с lowerCamelCase
. Методи също
n % 3
map { |item| count item }
class Range
def fizzbuzz
fizzbuzzed = Array.new
# ...
end
end
[]
, а не Array.new
{}
, а не Hash.new
fizzbuzzed
?Редовно виждаме:
output = []
input.each do |item|
output << do_something_with(item)
end
output
map
и/или select
Enumerable
current = 2
divisors = []
while current <= self.abs / 2
divisors << current if self.abs % current == 0 and prime? current
current += 1
end
divisors << self.abs if divisors.empty?
divisors
while
и until
се ползват много рядко в Ruby.def fizzbuzz
to_a.tap do |result|
each_with_index.select { |n, i| (n % 3).zero? or (n % 5).zero? }.map do |n, i|
result[i] = :"#{ "fizz" if (n % 3).zero? }#{ "buzz" if (n % 5).zero? }"
end
end
end
tap do |result|
? Можеше просто да се присвои
def fizzbuzz
map do |n|
if n % 15 == 0 then :fizzbuzz
elsif n % 5 == 0 then :fizz
elsif n % 3 == 0 then :buzz
else n
end
end
end
Това е твърде много код за Ruby. Ако вашия изглежда така, правите нещо грешно. Отделно, имената пак са гадни.
def prime_divisors
div = []
num = self
num = num < 0 ? num * (-1) : num
2.upto(num) do |cur|
isprime = true
2.upto(cur - 1) do |check|
if (cur % check) == 0
isprime = false
break
end
end
if (num % cur) == 0 and isprime
div << cur
end
isprime = true
end
div
end
(n % 3 == 0) ? ((n % 5 == 0) ? :fizzbuzz : :fizz) : ((n % 5 == 0) ? :buzz : n)
each_with_object({}) do |(key, val), memo|
memo[val] ? memo[val] << key : memo[val] = [key]
end
memo
. Речниковата дефиниция е: