Method
Method
Method 객체는 Object#method로 만들어지고, 단순히 클래스가 아니라 특정 객체와 연결돼요. 그 객체 안에서 메서드를 호출하는 데 쓰이거나, 이터레이터와 함께 블록으로 쓰일 수 있어요. 또한 한 객체에서 떼어내(UnboundMethod) 다른 객체에 다시 묶을 수도 있어요.
출처: Ruby 3.3 API
본문
class Thing
def square(n)
n*n
end
end
thing = Thing.new
meth = thing.method(:square)
meth.call(9) #=> 81
[ 1, 2, 3 ].collect(&meth) #=> [1, 4, 9]
[ 1, 2, 3 ].each(&method(:puts)) #=> prints 1, 2, 3
require 'date'
%w[2017-03-01 2017-03-02].collect(&Date.method(:parse))
#=> [#<Date: 2017-03-01 ((2457814j,0s,0n),+0s,2299161j)>, #<Date: 2017-03-02 ((2457815j,0s,0n),+0s,2299161j)>]
Public Instance Methods
meth << g → a_proc
이 메서드와 주어진 g를 합성(composition)한 proc을 돌려줘요. 돌려받은 proc은 가변 인자를 받아서, 먼저 g를 호출한 뒤 그 결과로 이 메서드를 호출해요.
def f(x)
x * x
end
f = self.method(:f)
g = proc {|x| x + x }
p (f << g).call(2) #=> 16
meth == other_meth → true or false
두 메서드 객체는, 같은 객체에 묶여 있고 같은 메서드 정의를 가리키며 그 메서드를 정의한 클래스가 같은 클래스나 모듈일 때 서로 같다고 판단돼요. (eql?로도 별칭돼 있어요.)
=== 메서드는 call의 별칭이에요.
meth >> g → a_proc
이 메서드와 주어진 g를 합성한 proc을 돌려줘요. 돌려받은 proc은 가변 인자를 받아서, 먼저 이 메서드를 호출한 뒤 그 결과로 g를 호출해요.
def f(x)
x * x
end
f = self.method(:f)
g = proc {|x| x + x }
p (f >> g).call(2) #=> 8
[]는 call의 별칭이에요.
arity → integer
메서드가 받아들이는 인자 개수를 알려줘요. 고정된 개수의 인자를 받는 메서드는 0 이상의 정수를 돌려줘요. 가변 인자를 받는 Ruby 메서드는 -n-1을 돌려주는데, 여기서 n은 필수 인자의 개수예요. 키워드 인자는 추가 인자 하나로 취급되고, 필수 키워드 인자가 있으면 그 인자도 필수로 간주돼요. C로 작성된 메서드에서 가변 인자를 받는 경우에는 -1을 돌려줘요.
class C
def one; end
def two(a); end
def three(*a); end
def four(a, b); end
def five(a, b, *c); end
def six(a, b, *c, &d); end
def seven(a, b, x:0); end
def eight(x:, y:); end
def nine(x:, y:, **z); end
def ten(*a, x:, y:); end
end
c = C.new
c.method(:one).arity #=> 0
c.method(:two).arity #=> 1
c.method(:three).arity #=> -1
c.method(:four).arity #=> 2
c.method(:five).arity #=> -3
c.method(:six).arity #=> -3
c.method(:seven).arity #=> -3
c.method(:eight).arity #=> 1
c.method(:nine).arity #=> 1
c.method(:ten).arity #=> -2
"cat".method(:size).arity #=> 0
"cat".method(:replace).arity #=> 1
"cat".method(:squeeze).arity #=> -1
"cat".method(:count).arity #=> -1
call(args, ...) → obj
주어진 인자로 meth를 호출하고, 메서드의 반환 값을 돌려줘요. (===, []로도 별칭돼 있어요.)
m = 12.method("+")
m.call(3) #=> 15
m.call(20) #=> 32
clone → new_method
이 메서드의 복제본(clone)을 돌려줘요.
class A
def foo
return "bar"
end
end
m = A.new.method(:foo)
m.call # => "bar"
n = m.clone.call # => "bar"
curry → proc, curry(arity) → proc
메서드를 기반으로 커리(curried)된 proc을 돌려줘요. proc이 메서드의 arity보다 적은 개수의 인자로 호출되면, 또 다른 커리된 proc을 돌려줘요. 메서드 시그니처를 만족할 만큼 충분한 인자가 주어졌을 때에만 실제로 메서드가 호출돼요.
가변 인자를 가진 메서드를 커리할 때는, 메서드가 호출되기까지 필요한 인자 개수를 정하기 위해 선택 인자 arity를 지정해야 해요.
def foo(a,b,c)
[a, b, c]
end
proc = self.method(:foo).curry
proc2 = proc.call(1, 2) #=> #<Proc>
proc2.call(3) #=> [1,2,3]
def vararg(*args)
args
end
proc = self.method(:vararg).curry(4)
proc2 = proc.call(:x) #=> #<Proc>
proc3 = proc2.call(:y, :z) #=> #<Proc>
proc3.call(:a) #=> [:x, :y, :z, :a]
eql?(other_meth) → true or false
==의 별칭이에요. 두 메서드 객체는 같은 객체에 묶여 있고 같은 메서드 정의를 가리키며 그 메서드를 정의한 클래스가 같을 때 같다고 판단돼요.
hash → integer
메서드 객체에 대응하는 해시 값을 돌려줘요. Object#hash도 함께 보세요.
inspect → string
메서드의 사람이 읽기 좋은 설명을 돌려줘요. (to_s로도 별칭돼 있어요.)
"cat".method(:count).inspect #=> "#<Method: String#count(*)>"
(1..3).method(:map).inspect #=> "#<Method: Range(Enumerable)#map()>"
두 번째 예시의 설명에는 원래 메서드의 "소유자(owner)"(Range에 포함된 Enumerable 모듈)가 함께 나와요.
inspect는 가능하면 메서드 인자 이름(호출 시퀀스)과 소스 위치도 제공해요.
require 'net/http'
Net::HTTP.method(:get).inspect
#=> "#<Method: Net::HTTP.get(uri_or_host, path=..., port=...) <skip>/lib/ruby/2.7.0/net/http.rb:457>"
인자 정의에서 ...는 그 인자가 선택적(기본값이 있음)이라는 뜻이에요.
C로 정의된 메서드(언어 코어나 확장)에서는 위치와 인자 이름을 추출할 수 없어서, *(임의 개수의 인자)나 _(어떤 위치 인자) 형태의 일반 정보만 제공돼요.
"cat".method(:count).inspect #=> "#<Method: String#count(*)>"
"cat".method(:+).inspect #=> "#<Method: String#+(_)>""
name → symbol
메서드의 이름을 돌려줘요.
original_name → symbol
메서드의 원래 이름을 돌려줘요.
class C
def foo; end
alias bar foo
end
C.instance_method(:bar).original_name # => :foo
owner → class_or_module
이 메서드가 정의된 클래스나 모듈을 돌려줘요. 다시 말해, 메서드가 제거·undefine·교체되지 않는 한 다음이 성립해요. (메서드가 private라면 instance_methods 대신 private_instance_methods를 쓰면 돼요.)
meth.owner.instance_methods(false).include?(meth.name) # => true
Method#receiver도 함께 보세요.
(1..3).method(:map).owner #=> Enumerable
parameters → array
이 메서드의 파라미터 정보를 돌려줘요.
def foo(bar); end
method(:foo).parameters #=> [[:req, :bar]]
def foo(bar, baz, bat, &blk); end
method(:foo).parameters #=> [[:req, :bar], [:req, :baz], [:req, :bat], [:block, :blk]]
def foo(bar, *args); end
method(:foo).parameters #=> [[:req, :bar], [:rest, :args]]
def foo(bar, baz, *args, &blk); end
method(:foo).parameters #=> [[:req, :bar], [:req, :baz], [:rest, :args], [:block, :blk]]
receiver → object
메서드 객체에 묶여 있는 수신자(receiver)를 돌려줘요.
(1..3).method(:map).receiver # => 1..3
source_location → [String, Integer]
이 메서드를 담고 있는 Ruby 소스 파일 이름과 줄 번호를 돌려줘요. 메서드가 Ruby가 아니라 C(네이티브)로 정의되었다면 nil이에요.
super_method → method
super가 사용될 때 호출될 슈퍼클래스의 Method를 돌려줘요. 슈퍼클래스에 해당 메서드가 없으면 nil이에요.
to_proc → proc
이 메서드에 대응하는 Proc 객체를 돌려줘요.
to_s → string
메서드의 사람이 읽기 좋은 설명을 돌려줘요. inspect의 별칭이에요.
"cat".method(:count).inspect #=> "#<Method: String#count(*)>"
(1..3).method(:map).inspect #=> "#<Method: Range(Enumerable)#map()>"
unbind → unbound_method
meth를 현재 수신자에서 떼어내요. 그 결과물인 UnboundMethod는 이후 같은 클래스의 새 객체에 다시 묶을 수 있어요 (UnboundMethod 참고).
더 알아보기
- 객체에서 메서드를 떼어낸
UnboundMethod문서도 함께 살펴보세요. Object#method,Object#public_method,Object#singleton_method로 메서드 객체를 얻는 방법을 확인하세요.