루비를 아름답게 만드는 것: 메타프로그래밍

11666 단어 rubyrails
Ruby는 현대 개발자들 사이에서 과소평가된 프로그래밍 언어 중 하나입니다. Ruby on Rails 프레임워크와 함께 대중화되었습니다.

Ruby is making developers happy, productive and enjoying programming. - Yukihiro Matsumoto



많은 프레임워크가 있는 JS 세계 또는 Java와 그 모든 복잡성에서 왔을 수 있습니다.
중요한 소프트웨어를 구축하는 데 시간을 낭비하고 가능한 한 빨리 구체적인 결과를 얻고 싶다면 Ruby를 소개하겠습니다.

메타 프로그래밍의 개념을 소개하겠습니다.
루비를 처음 배웠을 때, 이것에 직면했을 때 말 그대로 마음이 흔들렸습니다.

Think about a program that can generate program itself. A program that can generate executable code without the help of a developer.



아니요, 공상 과학이 아니라 Ruby Metaprogramming입니다!

5살짜리에게 설명해야 한다면, 당신이 화창한 도시를 그리고 싶다고 상상해보세요. 펜을 들고 종이에 "Sunny City"라고 쓰세요. 버튼을 누르면 마법이 일어납니다. 그것이 바로 메타프로그래밍입니다.

이제 실제 개발자들에게 설명하겠습니다.

Ruby에서는 메서드에 대한 런타임 검사를 수행할 수 있습니다. 다른 한편으로 객체에 기능(이 방법이 있습니까?), 변수, 상수, 클래스 및 조상에 대해 물어볼 수 있습니다.

이 기사에서 나는 당신에게 respond_to? (?는 부울을 반환하는 메서드에 대한 Ruby 규칙입니다.) send 및 define_method. 그러나 method_missing, remove_method 및 undef_method와 같은 훨씬 더 많은 것이 있습니다.
이 세 가지 방법을 설명하고 마지막으로 놀라운 예를 보여 드리겠습니다.

respond_to?() 메서드



이 메서드는 Ruby를 사용하지 않는 사람들을 위해 특정 메시지를 처리할 수 있는지 클래스를 테스트합니다. 특정 클래스에서 메서드를 호출할 수 있는지 확인합니다.



(Ruby 어휘에서 메시지는 메서드로 알려져 있습니다.)

배송 클래스는 다음과 같습니다.

class Shipment

  def prepare_for_delivery
    @message = 'Shipment is prepared for delivery'
  end

  def tracking_code(code)
    @tracking_code = code
  end

end


react_to?를 사용하세요. prepare_for_delivery 메소드가 존재하는지 확인하는 메소드:

s = Shipment.new 
s.respond_to?(:prepare_for_delivery) 
==> true


이 메시지가 있는 경우 다른 개체에 메시지를 보내는 보다 완전한 예입니다.

s = Shipment.new

if s.respond_to?(:cancel_shipping)
  s.cancel_shipping
else
  puts "Oh no ! Shipment cannot be cancel."
end


모든 수업에 사용할 수 있습니다.

'hello'.respond_to?(:count)
==> true
'world'.respond_to?(:include)
==> false


잡았어?

글쎄, 이 기사의 끝을 염두에 두십시오.

send() 메서드



send() 메서드를 사용하여 클래스의 모든 메서드를 호출할 수 있습니다.

s = Shipment.new

if s.respond_to?(:tracking_code)
  s.send(:tracking_code, '123ABC') # or s.send('cancel_shipping', '123ABC')
else
  puts "Tracking code is not available."
end




(send()의 첫 번째 파라미터로 메시지를 보낸다.)

"우리 방법을 직접 호출하지 않는 이유는 무엇입니까?"라는 말을 듣고 있습니다.

예, 가능하며 이 예는 우리가 사용하는 방법에 대한 실제 예가 아님을 알고 있습니다.

계속합시다.

define_method() 메서드



이제 논리를 알았으므로 설명하기 전에 이 메서드의 동작을 찾을 수도 있습니다.

그것은… 방법을 정의합니다 ? 잘했어요 !

class Shipment
  define_method :cancel do |reason|
    @cancelled = true
    puts reason
  end
end


취소된 인스턴스 변수를 true로 설정하고 이유를 인쇄하여 Shipment 클래스에 대한 새 메서드를 정의했습니다.

당신의 마음을 사로잡을 마지막 예를 들어보세요.

한 가지 예의 메타프로그래밍



Ruby 메타프로그래밍의 기본 사항을 알고 있습니다. 마지막 예제를 살펴보겠습니다.



메타 프로그래밍으로의 바다 여행을 떠나 항해를 시작합시다!

# We create a container class. We only store the product's name at instantiation
class Container

  attr :product_name

  def initialize(name)
    @product_name = name
  end

end

# Apples ! Oranges ! All of theses fruits are contained in FruitContainer extending Container
# For simplification we only have one scanner
class FruitContainer < Container

  def apples_scanner
    puts "Scanning apples..."
  end

end

# Potatoes ! Broccoli ! All of vegetables are contained in VegetableContainer extending Container
# For simplification we only have one scanner
class VegetableContainer < Container

  def potatoes_scanner
    puts "Scanning potatoes..."
  end

end

# The Cargo containing all the containers
class Cargo

  # The constructor accepting multiple parameters
  def initialize(*containers)
    containers.each do |container|
      # self.class.send is used to define singleton methods for our class
      # we could also use define_singleton_method
      self.class.send(:define_method, "inspect_#{container.product_name}") do
        scanner_name = "#{container.product_name}_scanner"
        if container.respond_to?(scanner_name)
          container.send(scanner_name)
        else
          puts "No scanner found."
        end
      end
    end
  end

end

potatoes_container = VegetableContainer.new "potatoes"
apples_container = FruitContainer.new "apples"
cargo = Cargo.new(potatoes_container, apples_container)

cargo.inspect_apples
cargo.inspect_potatoes


우리는 내가 설명한 모든 방법을 사용했습니다. 각 컨테이너 클래스에 대해 제품 이름인 스캐너를 기반으로 메서드(존재하는 경우)를 호출하는 새 메서드를 정의합니다.

출력:

Scanning apples...
Scanning potatoes...



이제 메타프로그래밍이 무엇이며 어떻게 작동하는지 알게 되었습니다. 잘했어요.

메타 프로그래밍의 첫 번째 사용 사례 중 하나는 자체 DSL(도메인 특정 언어)을 만드는 것입니다.

DevOps 사용자를 위한 Ruby DSL(ChefPuppet 기반의 잘 알려진 도구가 있습니다.

이것이 Ruby를 아름답게 만드는 것입니다.

이 주제에 대한 책을 제공할 수 없기 때문에 귀하의 모든 질문과 피드백에 답해 드립니다.

좋은 웹페이지 즐겨찾기