수색…


소개

메타 프로그래밍 은 두 가지 방법으로 설명 할 수 있습니다.

"다른 프로그램 (또는 자체)을 데이터로 쓰거나 조작하는 컴퓨터 프로그램 또는 컴파일 타임에 작업의 일부로 수행되는 컴퓨터 프로그램은 달리 런타임에 수행됩니다."

보다 간단하게 말하자면 : 메타 프로그래밍은 런타임 중에 코드를 작성하여 일상 생활을 더 쉽게 만들어주는 코드를 작성하는 것 입니다.

인스턴스 평가를 사용하여 "with"구현하기

많은 언어에는 프로그래머가 메소드 호출의 수신자를 생략 할 수있는 with 문이 있습니다.

withinstance_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()



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow