루비 모듈에서 인스턴스 메소드를 포함하지 않고 호출할 수 있습니까?
배경:
여러 인스턴스 메서드를 선언하는 모듈이 있습니다.
module UsefulThings
def get_file; ...
def delete_file; ...
def format_text(x); ...
end
그리고 저는 이 방법들 중 몇 가지를 클래스 내에서 부르고 싶습니다.루비에서 일반적으로 이 작업을 수행하는 방법은 다음과 같습니다.
class UsefulWorker
include UsefulThings
def do_work
format_text("abc")
...
end
end
문제
include UsefulThings
에서 모든 방법을 가져옵니다.UsefulThings
이 경우에 나는 단지 원할 뿐입니다.format_text
으로 그고분명원않습다니지하히리를 원하지 않습니다.get_file
그리고.delete_file
.
이에 대한 몇 가지 가능한 솔루션을 확인할 수 있습니다.
- 어떻게든 메소드를 모듈에 포함시키지 않고 직접 호출합니다.
- 이 작업이 어떻게 수행될 수 있는지 모르겠습니다. (따라서 이 질문)
- 든 어게든포다니함합떻다를 합니다.
Usefulthings
그리고 그것의 방법 중 일부만 가지고 옵니다.- 또한 이 작업이 수행될 수 있는지 여부를 모르겠습니다.
- 클래스를 . 를 포함합니다.
UsefulThings
그 안에서, 그 다음에 위임합니다.format_text
그 대리인 인스턴스까지- 이것은 효과가 있겠지만 익명의 프록시 클래스는 해킹입니다.우웩.
- 모듈을 두 개 이상의 작은 모듈로 분할합니다.
- 이것도 효과가 있을 것이고, 아마도 제가 생각할 수 있는 최고의 솔루션일 것입니다. 하지만 결국 수십 개의 모듈이 확산될 것이기 때문에 피하고 싶습니다. 이를 관리하는 것은 부담스러울 것입니다.
하나의 모듈에 관련 없는 기능이 많은 이유는 무엇입니까?그건…ApplicationHelper
우리 팀이 다른 곳에 속할 만큼 구체적이지 않은 것을 위한 쓰레기 매립지로 결정한 레일 앱에서.대부분 모든 곳에서 사용되는 독립형 유틸리티 방법입니다.다른 도우미들로 나눌 수도 있지만 30명이 있을 겁니다 각각 한 가지 방법으로...으로 보입니다.
(기존 모듈을 변경하거나 새 모듈을 만들지 않고) 일회용 단일 통화를 수행하는 가장 빠른 방법은 다음과 같습니다.
Class.new.extend(UsefulThings).get_file
모듈의 메서드가 모듈 기능으로 전환되면 다음과 같이 선언된 것처럼 간단히 모드에서 호출할 수 있습니다.
module Mods
def self.foo
puts "Mods.foo(self)"
end
end
아래의 module_function 접근 방식은 모든 Mod를 포함하는 클래스를 중단하지 않도록 합니다.
module Mods
def foo
puts "Mods.foo"
end
end
class Includer
include Mods
end
Includer.new.foo
Mods.module_eval do
module_function(:foo)
public :foo
end
Includer.new.foo # this would break without public :foo above
class Thing
def bar
Mods.foo
end
end
Thing.new.bar
그런데, 애초에 관련이 없는 함수들의 집합이 같은 모듈 안에 모두 포함되어 있는 이유가 궁금합니다.
다음과 같은 경우 여전히 작업을 포함하도록 편집됨public :foo
다음으로 호출됩니다.module_function :foo
모듈을 "소유"한 경우 이를 수행하는 또 다른 방법은 다음과 같습니다.module_function
.
module UsefulThings
def a
puts "aaay"
end
module_function :a
def b
puts "beee"
end
end
def test
UsefulThings.a
UsefulThings.b # Fails! Not a module method
end
test
다른 클래스에 모듈을 포함하지 않고 이러한 메서드를 호출하려면 모듈 메서드로 정의해야 합니다.
module UsefulThings
def self.get_file; ...
def self.delete_file; ...
def self.format_text(x); ...
end
그리고 나서 그들에게 전화할 수 있습니다.
UsefulThings.format_text("xxx")
또는
UsefulThings::format_text("xxx")
하지만 어쨌든 관련된 방법만 한 모듈이나 한 클래스에 넣는 것이 좋습니다.모듈의 메소드를 하나만 포함하고 싶은 문제가 있다면 코드 냄새가 나쁘고 관련 없는 메소드를 함께 넣는 것은 좋은 루비 스타일이 아닙니다.
모듈을 포함하지 않고(그리고 중간 개체를 만들지 않고) 모듈 인스턴스 메서드를 호출하려면:
class UsefulWorker
def do_work
UsefulThings.instance_method(:format_text).bind(self).call("abc")
...
end
end
10년이 지난 지금도 누군가가 필요한지 모르겠지만, 나는 그것을 고유 클래스를 사용하여 해결했습니다.
module UsefulThings
def useful_thing_1
"thing_1"
end
class << self
include UsefulThings
end
end
class A
include UsefulThings
end
class B
extend UsefulThings
end
UsefulThings.useful_thing_1 # => "thing_1"
A.new.useful_thing_1 # => "thing_1"
B.useful_thing_1 # => "thing_1"
먼저 모듈을 필요한 유용한 것들로 나누는 것을 추천합니다.그러나 언제든지 호출에 대해 클래스를 확장할 수 있습니다.
module UsefulThings
def a
puts "aaay"
end
def b
puts "beee"
end
end
def test
ob = Class.new.send(:include, UsefulThings).new
ob.a
end
test
A. 항상 "정격화된" 독립 실행형 방식(UsusefulThings.get_file)으로 호출한 다음 다른 사람이 지적한 대로 정적으로 만듭니다.
module UsefulThings
def self.get_file; ...
def self.delete_file; ...
def self.format_text(x); ...
# Or.. make all of the "static"
class << self
def write_file; ...
def commit_file; ...
end
end
B. 일회성 독립 실행뿐 아니라 동일한 경우에도 mixin 접근 방식을 유지하려면 mixin과 함께 자체 확장되는 단일 라이너 모듈을 사용할 수 있습니다.
module UsefulThingsMixin
def get_file; ...
def delete_file; ...
def format_text(x); ...
end
module UsefulThings
extend UsefulThingsMixin
end
따라서 두 가지 모두 작동합니다.
UsefulThings.get_file() # one off
class MyUser
include UsefulThingsMixin
def f
format_text # all useful things available directly
end
end
은 IMHO보다 .module_function
모든 방법에 대해 - 모든 방법이 필요할 경우에 대비합니다.
질문을 이해한 바로는 모듈의 인스턴스 메소드 중 일부를 클래스에 혼합하려고 합니다.
먼저 모듈 #include가 작동하는 방식을 고려해 보겠습니다.모듈이 있다고 가정합니다.UsefulThings
에는 두 인스턴스메소드가 되어 있습니다.
module UsefulThings
def add1
self + 1
end
def add3
self + 3
end
end
UsefulThings.instance_methods
#=> [:add1, :add3]
그리고.Fixnum
include
모듈s 당해모듈:
class Fixnum
def add2
puts "cat"
end
def add3
puts "dog"
end
include UsefulThings
end
다음과 같은 것을 확인할 수:
Fixnum.instance_methods.select { |m| m.to_s.start_with? "add" }
#=> [:add2, :add3, :add1]
1.add1
2
1.add2
cat
1.add3
dog
당신은 기대하고 있었습니까?UsefulThings#add3
무시하는Fixnum#add3
, 도록하록1.add3
할 것입니다.4
고려 사항:
Fixnum.ancestors
#=> [Fixnum, UsefulThings, Integer, Numeric, Comparable,
# Object, Kernel, BasicObject]
이 있을 때include
모듈은 클래스의 슈퍼 클래스가 됩니다.그래서, 상속이 어떻게 돌아가는지 때문에,add3
를 들어Fixnum
유할것의 원인이 될 입니다.Fixnum#add3
호됨출, 환됨반 반환dog
.
이제 방법을 해 보겠습니다.:add2
UsefulThings
:
module UsefulThings
def add1
self + 1
end
def add2
self + 2
end
def add3
self + 3
end
end
우리는 이제 소망합니다Fixnum
include
방법들 직오방들법▁the▁methods.add1
그리고.add3
그렇게 해서 위와 같은 결과가 나올 것으로 예상됩니다.
위와 같이 다음을 실행한다고 가정합니다.
class Fixnum
def add2
puts "cat"
end
def add3
puts "dog"
end
include UsefulThings
end
결과는 어떻습니까? 않는 방법은 하지않 방법입니다.:add2
되었습니다.Fixnum
,:add1
로, 추되었고설, 서한이유로명위에가위설이,유,:add3
추가되지 않았습니다.그래서 우리가 해야 할 일은undef
:add2
간단한 도우미 방법으로 이를 수행할 수 있습니다.
module Helpers
def self.include_some(mod, klass, *args)
klass.send(:include, mod)
(mod.instance_methods - args - klass.instance_methods).each do |m|
klass.send(:undef_method, m)
end
end
end
다음과 같이 호출합니다.
class Fixnum
def add2
puts "cat"
end
def add3
puts "dog"
end
Helpers.include_some(UsefulThings, self, :add1, :add3)
end
그러면:
Fixnum.instance_methods.select { |m| m.to_s.start_with? "add" }
#=> [:add2, :add3, :add1]
1.add1
2
1.add2
cat
1.add3
dog
그게 우리가 원하는 결과야
거의 9년 만에 일반적인 솔루션을 소개합니다.
module CreateModuleFunctions
def self.included(base)
base.instance_methods.each do |method|
base.module_eval do
module_function(method)
public(method)
end
end
end
end
RSpec.describe CreateModuleFunctions do
context "when included into a Module" do
it "makes the Module's methods invokable via the Module" do
module ModuleIncluded
def instance_method_1;end
def instance_method_2;end
include CreateModuleFunctions
end
expect { ModuleIncluded.instance_method_1 }.to_not raise_error
end
end
end
적용해야 하는 불행한 트릭은 메소드가 정의된 후 모듈을 포함하는 것입니다.또는 컨텍스트가 다음과 같이 정의된 후에 포함할 수도 있습니다.ModuleIncluded.send(:include, CreateModuleFunctions)
.
또는 reflection_utils 보석을 통해 사용할 수 있습니다.
spec.add_dependency "reflection_utils", ">= 0.3.0"
require 'reflection_utils'
include ReflectionUtils::CreateModuleFunctions
오늘 루비를 공부하다가 흥미를 느꼈을 때 이 오래된 질문이 떠오릅니다.
모듈이 있다고 가정합니다.
module MyModule
def say
'I say'
end
def cheer
'I cheer'
end
end
그럼 수업과 함께, so call.Animal
참을 수 있어요cheer
MyModule로부터의 메소드는 다음과 같습니다.
class Animal
define_method(:happy, MyModule.method(:cheer))
end
이를 바인딩되지 않은 메서드라고 하므로 호출 가능한 개체를 가져와 다른 위치에 바인딩할 수 있습니다.
이때부터 다음과 같은 방법을 일반적으로 사용할 수 있습니다.
my_dog = Animal.new
my_dog.happy # => "I cheer"
저도 오늘 새로운 것을 배웠기 때문에 이것이 도움이 되길 바랍니다.
자세한 내용은 다음을 참조하십시오.irb
Method 개체를 살펴봅니다.
언급URL : https://stackoverflow.com/questions/322470/can-i-invoke-an-instance-method-on-a-ruby-module-without-including-it
'programing' 카테고리의 다른 글
레일 4 인증 토큰 (0) | 2023.06.03 |
---|---|
문자열에서 캐리지 리턴 제거 (0) | 2023.06.03 |
LIMIT/OFFset을 사용하여 쿼리 실행 및 총 행 수 가져오기 (0) | 2023.05.29 |
병합 정렬 알고리즘을 사용하여 내부 정렬하는 방법은 무엇입니까? (0) | 2023.05.29 |
딜러들이 신속하게? (0) | 2023.05.29 |