In Ruby you can define a method with any name

This article is the 20th day article of Ruby Part 2 Advent Calendar 2020. https://qiita.com/advent-calendar/2020/ruby2


In Ruby, you can define a method with any name. ...... Speaking of "No, no,def $%^&*I can't write it. ""||Isn't it an operator that can't be redefined? " Both are correct, but Ruby still allows you to define a method with any name.

Let's take a closer look at what that means.

def syntax

Use the def syntax to define methods in Ruby.

#foo method definition
def foo
end

#After the method name!Or?Can be attached
def foo!
end
def foo?
end

# =You can use it like a setter by defining the method name at the end
def foo=(value)
end

#Uppercase letters are also ok
def FOO
end

#Hiragana etc. are also ok
def Hoge
end

#Keywords are also ok
def def
end

#Some operators can be redefined
class Integer
  # 42 -3 is 42+Turn into 3!
  def -(right)
    self + right
  end

  #unary+Method definition
  def +@
  end
end

And both of the codes given in the first example will result in a Syntax Error.

# Syntax Error
def $%^&*
end

# Syntax Error
def ||
end

However, there is a way to define methods with these names. It's the define_method method.

define_method method

First, let's briefly explain the define_method method.

The define_method method, as the name implies, is a method for defining a method. Often used to dynamically construct method names or define multiple similar methods at the same time.

`name`Define method name with capital letters
define_method(name.upcase) {}

# foo, bar,Define baz at once
%i[foo bar baz].each do |name|
  define_method(name) { name }
end

Define a method with any name

Anddefine_methodAccepts any name. In other words$%^&*Or||You can also define a method with a name like. These methods cannot be called with a Syntax Error when calling a method using ., but they can be called using the __send__ method.

#Method definition
define_method('$%^&*') { puts 'method name is $%^&*' }
define_method('||') { puts 'method name is ||' }

#call
__send__ '$%^&*' # => method name is $%^&*
__send__ '||' # => method name is ||

But even||Even if you define a method||The behavior of the operator does not change.

class FalseClass
  #False even if redefined||The result of something does not change
  define_method('||') do
    false
  end
end

p false || true # => true

Of course, you can use the following method names that you can't really define.

define_method('') { puts 'Empty string is also ok' }
__send__ '' # =>Empty string is also ok

#Any byte from 0x00 to 0xff is ok
# (Kernel is included in class C.#To not redefine p)
class C
  (0x00..0xff).each do |n|
    define_method(n.chr) { pp n.chr }
  end
end
C.new.__send__ 0x00.chr # => "\x00"

#It's okay to try defining a method with a random byte sequence
require 'securerandom'
class C2
  10.times do
    define_method(SecureRandom.random_bytes(10)) do
    end
  end
end
p C2.instance_methods(false)
# => [:"4(c\xF4\xBDQ\xD7\xB6\xA0l", :"J&q\xEEZ\x0E\xE3\x9F\"\xC1", :"}\x9F\xCF\x1C\x90\x06o\xFD\x84\xD6", :"U\x8Bc02'\xB4\xF0\xA0\xC4", :"\xEE\x88v\x14\xBA&j\xBE<\x10", :"\a+,\xCD\"\xF4\x83\x80\xE5\xCA", :"4\xC8\xAB/2\x06\f\xF1\xFB\xFA", :"\xBA\xE2E;\xCE\xBC\xB8\xB0b\xD0", :"u [l^q%\xC9\x03\xA2", :"q\xC5O\xAF\xDB\x05t\x86!\x88"]

Summary

In Ruby, you can use the define_method method to define a method with any method name. I think it's a technique you don't use very often, but it might be useful somewhere to remember.

Recommended Posts

In Ruby you can define a method with any name
With Tomcat you can use placeholders ($ {...}) in web.xml
Add a project in any folder with Gradle
Call a method of the parent class by explicitly specifying the name in Ruby
Use Coveralls with GitHub Actions in a Ruby repository
Integer check method with ruby
I searched for a web framework with Gem in Ruby
Multiplication in a Ruby array
Create a method that can retrieve characters from any location
In Redmine you can get the project with Project.find (<identifier>)
[ruby] Method call with argument
With [AWS] CodeStar, you can build a Spring (Java) project running on Lambda in just 3 minutes! !!
I can't create a Java class with a specific name in IntelliJ
Sorting hashes in a Ruby array
[Ruby] Extracting elements with slice method
[Ruby] How to use any? Method
String output method memo in Ruby
Implement a gRPC client in Ruby
[Ruby] undefined method `dark?'occurs in rqr_code
Make a typing game with ruby
What you can do with ruby ​​Quick reference teaching materials (for beginners)
[Rails] How to log in with a name by adding a devise name column
If you want to make a zip file with Ruby, it's rubyzip.
How to reference a column when overriding the column name method in ActiveRecord
How to insert processing with any number of elements in iterative processing in Ruby
A story about an arithmetic overflow that you shouldn't encounter in Ruby
I tried a calendar problem in Ruby
Concurrency Method in Java with basic example
Implemented "Floyd Cycle Detection Method" in Ruby
Let's make a smart home with Ruby!
I made a risky die with Ruby
Extract a part of a string with Ruby
Split a string with ". (Dot)" in Java
Configure a multi-project with subdirectories in Gradle
Use a named format with Ruby's format method
When is it said that you can use try with a Swift error?
Define a new buy method that receives Vehicle type value in Person.java argument.
Notify the build result with slack with CircleCI. You can do it in 5 minutes.
[Ruby] Define the hierarchy at the same time as Hash initialization with tap method
A ruby ​​script that creates an rsa private key that can be used with OpenSSL from any two prime numbers