Ruby Language
메타 프로그래밍
수색…
소개
메타 프로그래밍 은 두 가지 방법으로 설명 할 수 있습니다.
"다른 프로그램 (또는 자체)을 데이터로 쓰거나 조작하는 컴퓨터 프로그램 또는 컴파일 타임에 작업의 일부로 수행되는 컴퓨터 프로그램은 달리 런타임에 수행됩니다."
보다 간단하게 말하자면 : 메타 프로그래밍은 런타임 중에 코드를 작성하여 일상 생활을 더 쉽게 만들어주는 코드를 작성하는 것 입니다.
인스턴스 평가를 사용하여 "with"구현하기
많은 언어에는 프로그래머가 메소드 호출의 수신자를 생략 할 수있는 with
문이 있습니다.
with
는 instance_eval
사용하여 Ruby에서 쉽게 에뮬레이트 될 수 있습니다 :
def with(object, &block)
object.instance_eval &block
end
with
메서드는 객체에서 메서드를 원활하게 실행하는 데 사용할 수 있습니다.
hash = Hash.new
with hash do
store :key, :value
has_key? :key # => true
values # => [:value]
end
동적으로 메소드 정의하기
Ruby를 사용하면 실행 시간에 프로그램의 구조를 수정할 수 있습니다. 이를 수행하는 한 가지 방법은 메소드 method_missing
사용하여 메소드를 동적으로 정의하는 것입니다.
숫자가 777.is_greater_than_123?
구문을 사용하여 다른 숫자보다 큰지 테스트 할 수 있기를 원한다고 가정 해 봅시다 777.is_greater_than_123?
.
# open Numeric class
class Numeric
# override `method_missing`
def method_missing(method_name,*args)
# test if the method_name matches the syntax we want
if method_name.to_s.match /^is_greater_than_(\d+)\?$/
# capture the number in the method_name
the_other_number = $1.to_i
# return whether the number is greater than the other number or not
self > the_other_number
else
# if the method_name doesn't match what we want, let the previous definition of `method_missing` handle it
super
end
end
end
method_missing
을 사용할 때 기억해야 할 중요한 사항 중 하나는 respond_to?
를 재정의해야한다는 것입니다 respond_to?
방법:
class Numeric
def respond_to?(method_name, include_all = false)
method_name.to_s.match(/^is_greater_than_(\d+)\?$/) || super
end
end
이를 잊어 버리면 600.is_greater_than_123
성공적으로 호출 할 수있는 상황이 불일치하지만 600.respond_to(:is_greater_than_123)
는 false를 반환합니다.
인스턴스에 메서드 정의
루비에서는 모든 클래스의 기존 인스턴스에 메소드를 추가 할 수 있습니다. 이렇게하면 해당 클래스의 나머지 인스턴스의 비헤이비어를 변경하지 않고 클래스에 비헤이비어를 추가 할 수 있습니다.
class Example
def method1(foo)
puts foo
end
end
#defines method2 on object exp
exp = Example.new
exp.define_method(:method2) {puts "Method2"}
#with method parameters
exp.define_method(:method3) {|name| puts name}
send () 메소드
send()
는 메시지를 object
에 전달하는 데 사용됩니다. send()
는 Object
클래스의 인스턴스 메서드입니다. send()
의 첫 번째 인수는 객체에 보내는 메시지, 즉 메소드의 이름입니다. string
또는 symbol
있지만 기호 가 선호됩니다. 그런 다음 메소드에서 전달해야하는 인수가 send()
의 나머지 인수가됩니다.
class Hello
def hello(*args)
puts 'Hello ' + args.join(' ')
end
end
h = Hello.new
h.send :hello, 'gentle', 'readers' #=> "Hello gentle readers"
# h.send(:hello, 'gentle', 'readers') #=> Here :hello is method and rest are the arguments to method.
더 자세한 설명이있는 예는 다음과 같습니다.
class Account
attr_accessor :name, :email, :notes, :address
def assign_values(values)
values.each_key do |k, v|
# How send method would look a like
# self.name = value[k]
self.send("#{k}=", values[k])
end
end
end
user_info = {
name: 'Matt',
email: '[email protected]',
address: '132 random st.',
notes: "annoying customer"
}
account = Account.new
If attributes gets increase then we would messup the code
#--------- Bad way --------------
account.name = user_info[:name]
account.address = user_info[:address]
account.email = user_info[:email]
account.notes = user_info[:notes]
# --------- Meta Programing way --------------
account.assign_values(user_info) # With single line we can assign n number of attributes
puts account.inspect
참고 : send()
자체는 더 이상 권장되지 않습니다. private 메소드를 호출 할 수있는 public_send()
__send__()
를 사용하거나 public_send()
를 호출하여 (권장 public_send()