BasicObject 클래스

BasicObject 클래스

BasicObject는 Ruby의 모든 클래스의 조상이에요. 특히 Object 클래스의 부모가 BasicObject이고, 그 Object는 다시 모든 Ruby 클래스의 기본 부모예요. 즉 Ruby에서 가장 뿌리가 되는 클래스라고 생각하면 돼요.

출처: Ruby 4.0 API

본문

BasicObject는 Ruby의 모든 클래스의 부모 클래스예요. 특히 Object 클래스의 부모가 BasicObject이고, Object는 다시 모든 Ruby 클래스의 기본 부모예요:

class Foo; end
Foo.superclass    # => Object
Object.superclass # => BasicObject

부모가 하나도 없는 유일한 클래스가 BasicObject예요:

BasicObject.superclass # => nil

BasicObject 클래스는 Ruby의 객체 계층과 독립적인 객체 계층(예: Delegator 클래스)을 만들 때 쓸 수 있어요. 그런 객체들은:

  • Object 클래스와 그 안에 포함된 Kernel 모듈이 제공하는 많은 메서드에서 오는 "네임스페이스 오염"이 없어요.
  • 흔한 클래스들의 정의가 없어서, 그런 클래스를 참조할 때는 완전히 한정해 줘야 해요(String이 아니라 ::String).

BasicObject의 서브클래스에서 표준 라이브러리의 유용한 부분을 제공하는 방법은 여러 가지예요:

  • 바로 아래 서브클래스에서 include Kernel을 하면 puts, exit 같은 메서드가 정의돼요.
  • 커스텀한 Kernel 유사 모듈을 만들어 include 할 수도 있어요.
  • method_missing으로 위임(delegation)을 쓸 수도 있어요:
class MyObjectSystem < BasicObject
  DELEGATE = [:puts, :p]

  def method_missing(name, *args, &block)
    return super unless DELEGATE.include? name
    ::Kernel.send(name, *args, &block)
  end

  def respond_to_missing?(name, include_private = false)
    DELEGATE.include?(name)
  end
end

BasicObject가 정의하는 메서드

BasicObject에 정의된 메서드들이에요:

  • ::new: 새 BasicObject 인스턴스를 돌려줘요.
  • !: self의 불리언 부정인 true 또는 false를 돌려줘요.
  • !=: self와 주어진 객체가 같지 않은지를 돌려줘요.
  • ==: self와 주어진 객체가 동등한지를 돌려줘요.
  • __id__: self의 정수 객체 식별자를 돌려줘요.
  • __send__: 주어진 심볼이 식별하는 메서드를 호출해요.
  • equal?: self와 주어진 객체가 같은 객체인지를 돌려줘요.
  • instance_eval: 주어진 문자열이나 블록을 self의 컨텍스트에서 평가해요.
  • instance_exec: 주어진 블록을 self의 컨텍스트에서 실행하고 주어진 인자를 전달해요.
  • method_missing: self가 정의하지 않은 메서드로 호출될 때 호출돼요.
  • singleton_method_added: self에 싱글턴 메서드가 추가될 때 호출돼요.
  • singleton_method_removed: self에서 싱글턴 메서드가 제거될 때 호출돼요.
  • singleton_method_undefined: self에서 싱글턴 메서드가 undefine될 때 호출돼요.

Public Instance Methods

new

BasicObject를 돌려줘요.

!obj → true or false

불리언 부정(negation)이에요.

obj != other → true or false

두 객체가 같지 않으면 true, 같으면 false를 돌려줘요.

obj == other → true or false

eql?(other) → true or false

동등성(Equality) — Object 레벨에서 ==objother가 같은 객체일 때만 true를 돌려줘요. 보통 이 메서드는 하위 클래스에서 클래스 고유의 의미로 오버라이드돼요.

==와 달리 equal? 메서드는 객체 동일성(identity)을 판별하는 데 쓰이므로 서브클래스에서 절대 오버라이드하지 않아야 해요. 즉 ab와 같은 객체일 때만 a.equal?(b)true예요:

obj = "a"
other = obj.dup

obj == other      #=> true
obj.equal? other  #=> false
obj.equal? obj    #=> true

eql? 메서드는 objother가 같은 해시 키를 참조하면 true를 돌려줘요. Hash가 멤버 동등성을 검사할 때 사용해요. eql?true를 돌려주는 객체 쌍은 두 객체의 해시 값도 반드시 같아야 해요. 그래서 eql?을 오버라이드하는 서브클래스는 hash도 알맞게 오버라이드해야 해요.

Object 클래스의 객체에서 eql?==와 동의어예요. 서브클래스는 보통 이 전통을 이어받아 eql?을 오버라이드한 ==의 별칭으로 두지만, 예외도 있어요. 예를 들어 Numeric 타입은 ==에서는 타입 변환을 하되 eql?에서는 하지 않으므로:

1 == 1.0     #=> true
1.eql? 1.0   #=> false

==의 별칭이기도 해요.

id → integer

object_id → integer

obj에 대한 정수 식별자를 돌려줘요. 주어진 객체에 대한 모든 object_id 호출에서 같은 숫자가 반환되고, 두 개의 활성 객체가 id를 공유하지 않아요.

주의: 내장 클래스의 일부 객체는 최적화를 위해 재사용돼요. 이는 immediate 값과 frozen 문자열 리터럴의 경우예요.

BasicObject__id__를 구현하고, Kernelobject_id를 구현해요.

immediate 값은 참조가 아니라 값으로 전달돼요: nil, true, false, Fixnum, Symbol, 일부 Float.

Object.new.object_id  == Object.new.object_id  # => false
(21 * 2).object_id    == (21 * 2).object_id    # => true
"hello".object_id     == "hello".object_id     # => false
"hi".freeze.object_id == "hi".freeze.object_id # => true

send(symbol [, args...]) → obj

send(symbol [, args...]) → obj

send(string [, args...]) → obj

send(string [, args...]) → obj

symbol이 식별하는 메서드를, 지정된 인자를 넘겨 호출해요. 문자열로 메서드를 식별하면 문자열이 심볼로 변환돼요.

BasicObject__send__를 구현하고, Kernelsend를 구현해요. objSocket처럼 send와 같은 이름의 메서드를 가질 때는 send보다 __send__가 더 안전해요. public_send도 함께 보세요.

class Klass
  def hello(*args)
    "Hello " + args.join(' ')
  end
end
k = Klass.new
k.send :hello, "gentle", "readers"   #=> "Hello gentle readers"

equal?(other) → true or false

동등성 — Object 레벨에서 ==objother가 같은 객체일 때만 true를 돌려줘요. 보통 하위 클래스에서 클래스 고유 의미로 오버라이드돼요. (==eql?에 대한 설명은 위의 obj == other 항목을 참고하세요.)

==의 별칭이에요.

instance_eval(string [, filename [, lineno]] ) → obj

instance_eval {|obj| block } → obj

Ruby 소스 코드를 담은 문자열 또는 주어진 블록을 수신자(obj)의 컨텍스트 안에서 평가해요. 컨텍스트를 설정하기 위해 코드가 실행되는 동안 변수 selfobj로 설정되어, 코드가 obj의 인스턴스 변수와 private 메서드에 접근할 수 있게 돼요.

instance_eval에 블록을 주면 obj가 블록의 유일한 인자로도 전달돼요.

instance_evalString을 주면, 선택적 두 번째·세 번째 인자가 컴파일 오류를 보고할 때 쓰는 파일명과 시작 줄 번호를 제공해요.

class KlassWithSecret
  def initialize
    @secret = 99
  end
  private
  def the_secret
    "Ssssh! The secret is #{@secret}."
  end
end
k = KlassWithSecret.new
k.instance_eval { @secret }          #=> 99
k.instance_eval { the_secret }       #=> "Ssssh! The secret is 99."
k.instance_eval {|obj| obj == self } #=> true

instance_exec(arg...) {|var...| block } → obj

주어진 블록을 수신자(obj)의 컨텍스트 안에서 실행해요. 컨텍스트를 설정하기 위해 코드가 실행되는 동안 selfobj로 설정되어 코드가 obj의 인스턴스 변수에 접근하게 해 줘요. 인자는 블록 매개변수로 전달돼요.

class KlassWithSecret
  def initialize
    @secret = 99
  end
end
k = KlassWithSecret.new
k.instance_exec(5) {|x| @secret+x }   #=> 104

method_missing(symbol [, *args] ) → result

obj가 처리할 수 없는 메시지를 받았을 때 Ruby가 호출해요. symbol은 호출된 메서드의 심볼이고, args는 그 메서드에 전달된 인자들이에요. 기본적으로 이 메서드가 호출되면 인터프리터가 오류를 발생시켜요. 하지만 이 메서드를 오버라이드해 더 동적인 동작을 제공할 수 있어요. 특정 메서드를 처리하지 않기로 결정했다면 super를 호출해 조상들이 누락된 메서드를 처리하게 해야 해요. 아래 예시는 로마 숫자로 된 이름의 메서드에 응답해 그에 해당하는 정수 값을 돌려주는 클래스 Roman을 만들어요.

class Roman
  def roman_to_int(str)
    # ...
  end

  def method_missing(symbol, *args)
    str = symbol.id2name
    begin
      roman_to_int(str)
    rescue
      super(symbol, *args)
    end
  end
end

r = Roman.new
r.iv      #=> 4
r.xxiii   #=> 23
r.mm      #=> 2000
r.foo     #=> NoMethodError

singleton_method_added(symbol)

수신자에 싱글턴 메서드가 추가될 때마다 콜백으로 호출돼요.

module Chatty
  def Chatty.singleton_method_added(id)
    puts "Adding #{id.id2name}"
  end
  def self.one()     end
  def two()          end
  def Chatty.three() end
end

출력:

Adding singleton_method_added
Adding one
Adding three

singleton_method_removed(symbol)

수신자에서 싱글턴 메서드가 제거될 때마다 콜백으로 호출돼요.

module Chatty
  def Chatty.singleton_method_removed(id)
    puts "Removing #{id.id2name}"
  end
  def self.one()     end
  def two()          end
  def Chatty.three() end
  class << self
    remove_method :three
    remove_method :one
  end
end

출력:

Removing three
Removing one

singleton_method_undefined(symbol)

수신자에서 싱글턴 메서드가 undefine될 때마다 콜백으로 호출돼요.

module Chatty
  def Chatty.singleton_method_undefined(id)
    puts "Undefining #{id.id2name}"
  end
  def Chatty.one()   end
  class << self
     undef_method(:one)
  end
end

출력:

Undefining one