Latar Belakang:
Saya memiliki modul yang menyatakan sejumlah metode contoh
module UsefulThings
def get_file; ...
def delete_file; ...
def format_text(x); ...
end
Dan saya ingin memanggil beberapa metode ini dari dalam kelas. Bagaimana Anda biasanya melakukan ini di ruby adalah seperti ini:
class UsefulWorker
include UsefulThings
def do_work
format_text("abc")
...
end
end
Masalah
include UsefulThings
membawa semua metode dari UsefulThings
. Dalam hal ini saya hanya ingin format_text
dan secara eksplisit tidak mau get_file
dan delete_file
.
Saya dapat melihat beberapa solusi yang mungkin untuk ini:
- Entah bagaimana memohon metode secara langsung pada modul tanpa menyertakannya di mana saja
- Saya tidak tahu bagaimana / jika ini bisa dilakukan. (Karenanya pertanyaan ini)
- Entah bagaimana memasukkan
Usefulthings
dan hanya membawa beberapa metode itu- Saya juga tidak tahu bagaimana / jika ini bisa dilakukan
- Buat kelas proxy, termasuk
UsefulThings
di dalamnya, lalu delegasikanformat_text
ke instance proxy itu- Ini akan berhasil, tetapi kelas proxy anonim adalah peretasan. Yuck.
- Bagi modul menjadi 2 atau lebih modul yang lebih kecil
- Ini juga akan berhasil, dan mungkin merupakan solusi terbaik yang dapat saya pikirkan, tetapi saya lebih memilih untuk menghindarinya karena saya akan berakhir dengan proliferasi puluhan dan lusinan modul - mengelola ini akan memberatkan
Mengapa ada banyak fungsi yang tidak berhubungan dalam satu modul? Itu ApplicationHelper
dari aplikasi rel, yang tim kami telah memutuskan secara de facto sebagai tempat pembuangan untuk sesuatu yang tidak cukup spesifik untuk dimiliki di tempat lain. Sebagian besar metode utilitas mandiri yang digunakan di mana-mana. Saya dapat memecahnya menjadi pembantu yang terpisah, tetapi akan ada 30 dari mereka, semua dengan 1 metode masing-masing ... ini tampaknya tidak produktif
Module#included
panggilan balik untuk memicu yanginclude
lain. Theformat_text
Metode dapat dipindahkan ke dalamnya modul sendiri, karena tampaknya berguna pada itu sendiri. Ini akan membuat manajemen sedikit kurang memberatkan.module UT; def add1; self+1; end; def add2; self+2; end; end
dan ingin menggunakanadd1
tetapi tidakadd2
di kelasFixnum
. Bagaimana bisa membantu untuk memiliki fungsi modul untuk itu? Apakah saya melewatkan sesuatu?Jawaban:
Jika suatu metode pada modul diubah menjadi fungsi modul, Anda cukup membatalkannya dari Mods seolah-olah telah dinyatakan sebagai
Pendekatan module_function di bawah ini akan menghindari pemutusan kelas yang menyertakan semua Mod.
Namun, saya ingin tahu mengapa satu set fungsi yang tidak terkait semuanya ada dalam modul yang sama?
Diedit untuk menunjukkan bahwa termasuk masih berfungsi jika
public :foo
dipanggil setelahmodule_function :foo
sumber
module_function
mengubah metode menjadi pribadi, yang akan memecahkan kode lain - jika tidak ini akan menjadi jawaban yang diterimaFiles.truncate
dan aStrings.truncate
dan saya ingin menggunakan keduanya di kelas yang sama, secara eksplisit. Membuat kelas / instance baru setiap kali saya memerlukan metode khusus atau memodifikasi yang asli bukanlah pendekatan yang baik, meskipun saya bukan seorang dev Ruby.Saya pikir cara terpendek untuk hanya melakukan panggilan tunggal (tanpa mengubah modul yang ada atau membuat yang baru) adalah sebagai berikut:
sumber
Object.new.extend(UsefulThings).get_file
Cara lain untuk melakukannya jika Anda "memiliki" modul ini adalah menggunakannya
module_function
.sumber
ModuleName.method :method_name
untuk mendapatkan objek metode dan memanggilnya viamethod_obj.call
. Kalau tidak, saya harus mengikat metode ke instance dari objek asli, yang tidak mungkin jika objek asli adalah Modul. Menanggapi Orion Edwards,module_function
apakah membuat metode instance asli pribadi. ruby-doc.org/core/classes/Module.html#M001642def self.a; puts 'aaay'; end
Jika Anda ingin memanggil metode ini tanpa menyertakan modul di kelas lain maka Anda perlu mendefinisikannya sebagai metode modul:
dan kemudian Anda dapat memanggil mereka
atau
Tapi bagaimanapun saya akan merekomendasikan agar Anda meletakkan hanya metode terkait dalam satu modul atau dalam satu kelas. Jika Anda memiliki masalah yang ingin Anda sertakan hanya satu metode dari modul maka itu terdengar seperti bau kode yang buruk dan itu bukan gaya Ruby yang baik untuk menggabungkan metode yang tidak terkait.
sumber
Untuk memanggil metode instance modul tanpa menyertakan modul (dan tanpa membuat objek perantara):
sumber
format_text
mengasumsikan adanya metode lain yang disediakan oleh modul, yang (umumnya) tidak ada.Pertama, saya akan merekomendasikan memecah modul menjadi hal-hal berguna yang Anda butuhkan. Tetapi Anda selalu dapat membuat kelas yang diperluas untuk permohonan Anda:
sumber
A. Jika Anda, selalu ingin memanggil mereka dengan cara yang "memenuhi syarat", mandiri (UsefulThings.get_file), maka buatlah statis seperti yang ditunjukkan orang lain,
B. Jika Anda masih ingin mempertahankan pendekatan mixin dalam kasus yang sama, dan juga pemanggilan mandiri satu kali, Anda dapat memiliki modul satu-liner yang diperluas dengan mixin:
Jadi keduanya berfungsi:
IMHO itu lebih bersih daripada
module_function
untuk setiap metode tunggal - kalau-kalau ingin semuanya.sumber
extend self
adalah ungkapan yang umum.Seperti yang saya pahami pertanyaannya, Anda ingin mencampur beberapa metode instance modul ke dalam kelas.
Mari kita mulai dengan mempertimbangkan bagaimana Modul # termasuk bekerja. Misalkan kita memiliki modul
UsefulThings
yang berisi dua metode contoh:dan
Fixnum
include
modul itu:Kami melihat bahwa:
Apakah Anda berharap
UsefulThings#add3
untuk menimpaFixnum#add3
, sehingga1.add3
akan kembali4
? Pertimbangkan ini:Ketika kelas
include
modul, modul menjadi kelas super kelas. Jadi, karena cara kerja warisan, mengirimadd3
ke instanceFixnum
akan menyebabkanFixnum#add3
dipanggil, kembalidog
.Sekarang mari kita tambahkan metode
:add2
keUsefulThings
:Kami sekarang berharap
Fixnum
untukinclude
hanya metodeadd1
danadd3
. Dengan melakukan hal itu, kami berharap mendapatkan hasil yang sama seperti di atas.Misalkan, seperti di atas, kita mengeksekusi:
Apa hasilnya? Metode yang tidak diinginkan
:add2
ditambahkan keFixnum
,:add1
ditambahkan dan, untuk alasan yang saya jelaskan di atas,:add3
tidak ditambahkan. Jadi yang harus kita lakukan adalahundef
:add2
. Kita dapat melakukannya dengan metode pembantu sederhana:yang kami panggil seperti ini:
Kemudian:
yang merupakan hasil yang kita inginkan.
sumber
Tidak yakin apakah seseorang masih membutuhkannya setelah 10 tahun tetapi saya menyelesaikannya menggunakan eigenclass.
sumber
Setelah hampir 9 tahun, inilah solusi generik:
Trik malang yang perlu Anda terapkan adalah memasukkan modul setelah metode telah ditetapkan. Atau Anda juga dapat memasukkannya setelah konteks didefinisikan sebagai
ModuleIncluded.send(:include, CreateModuleFunctions)
.Atau Anda dapat menggunakannya melalui permata reflection_utils .
sumber