modulos - operador modulo en ruby
Extender un módulo de Ruby en otro módulo, incluidos los métodos del módulo (5)
Cada vez que trato de extender un módulo de ruby, pierdo los métodos del módulo. Ni incluir ni extender hará esto. Considera el fragmento:
module A
def self.say_hi
puts "hi"
end
end
module B
include A
end
B.say_hi #undefined_method
Ya sea que B incluya o extienda A, say_hi no estará definido.
¿Hay alguna manera de lograr algo como esto?
No creo que haya una forma simple de hacerlo.
Entonces, aquí hay una forma compleja:
module B
class << self
A.singleton_methods.each do |m|
define_method m, A.method(m).to_proc
end
end
end
Puedes ponerlo en un método de ayuda como este:
class Module
def include_module_methods(mod)
mod.singleton_methods.each do |m|
(class << self; self; end).send :define_method, m, mod.method(m).to_proc
end
end
end
module B
include_module_methods A
end
Si usted es el autor del module A
y lo necesitará con frecuencia, puede volver a crear A así:
module A
module ClassMethods
def say_hi
puts "hi"
end
end
extend ClassMethods
def self.included( other )
other.extend( ClassMethods )
end
end
module B
include A
end
A.say_hi #=> "hi"
B.say_hi #=> "hi"
Use include_complete
gem install include_complete
module A
def self.say_hi
puts "hi"
end
end
module B
include_complete A
end
B.say_hi #=> "hi"
Johnathan, no estoy seguro si todavía te estás preguntando sobre esto, pero hay dos formas diferentes de usar módulos en ruby. A.) usa módulos en su forma autónoma Base :: Tree.entity (params) directamente en su código, o B.) usa módulos como mixins o métodos auxiliares.
A. Le permitirá usar módulos como un patrón de espacio de nombres. Esto es bueno para proyectos más grandes donde existe la posibilidad de conflictos de nombres de métodos
module Base
module Tree
def self.entity(params={},&block)
# some great code goes here
end
end
end
Ahora puede usar esto para crear algún tipo de estructura de árbol en su código, sin tener que instanciar una nueva clase para cada llamada a Base :: Tree.entity.
Otra forma de hacer Namespace-ing es en una clase por clase.
module Session
module Live
class Actor
attr_accessor :type, :uuid, :name, :status
def initialize(params={},&block)
# check params, insert init values for vars..etc
# save your callback as a class variable, and use it sometime later
@block = block
end
def hit_rock_bottom
end
def has_hit_rock_bottom?
end
...
end
end
class Actor
attr_accessor :id,:scope,:callback
def initialize(params={},&block)
self.callback = block if block_given?
end
def respond
if self.callback.is_a? Proc
# do some real crazy things...
end
end
end
end
Ahora tenemos el potencial de superposición en nuestras clases. Queremos saber que cuando creamos una clase Actor es la clase correcta, así que aquí es donde los espacios de nombres son útiles.
Session::Live::Actor.new(params) do |res|...
Session::Actor.new(params)
B. Mix-Ins Estos son tus amigos. Úselos cada vez que crea que tendrá que hacer algo más de una vez en su código.
module Friendly
module Formatter
def to_hash(xmlstring)
#parsing methods
return hash
end
def remove_trailing_whitespace(string,&block)
# remove trailing white space from that idiot who pasted from textmate
end
end
end
Ahora, cada vez que necesite formatear un xmlstring como un hash, o eliminar los espacios en blanco al final en cualquiera de sus códigos futuros, simplemente mezcle.
module Fun
class Ruby
include Friendly::Formatter
attr_accessor :string
def initialize(params={})
end
end
end
Ahora puedes formatear la cadena en tu clase.
fun_ruby = Fun::Ruby.new(params)
fun_ruby.string = "<xml><why><do>most</do><people></people><use>this</use><it>sucks</it></why></xml>"
fun_ruby_hash = fun_ruby.to_hash(fun_ruby.string)
Espero que esta sea una buena explicación. Los puntos planteados anteriormente son buenos ejemplos de formas de extender clases, pero con los módulos, la parte difícil es cuándo usar la palabra clave self . Se refiere al alcance del objeto dentro de la jerarquía de objetos de ruby. Entonces, si desea usar un módulo como mezcla y no desea declarar nada solo, no use la palabra clave auto, sin embargo, si desea mantener el estado dentro del objeto, simplemente use una clase y mezcle. en los módulos que quieras.
No me gusta que todos usen self.included
. Tengo una solución más simple:
module A
module ClassMethods
def a
''a1''
end
end
def a
''a2''
end
end
module B
include A
module ClassMethods
include A::ClassMethods
def b
''b1''
end
end
def b
''b2''
end
end
class C
include B
extend B::ClassMethods
end
class D < C; end
puts D.a
puts D.b
puts D.new.a
puts D.new.b