/ / ¿Cómo se implementa el método “público / protegido / privado” y cómo puedo emularlo? - Ruby, especificador de acceso

¿Cómo se implementa el método “público / protegido / privado” y cómo puedo emularlo? - Ruby, especificador de acceso

En ruby, puedes hacer esto:

class Thing
public
def f1
puts "f1"
end

private
def f2
puts "f2"
end

public
def f3
puts "f3"
end

private
def f4
puts "f4"
end
end

donde ahora f1 y f3 y público, f2 y f4 esprivado. ¿Qué sucede internamente que le permite invocar un método de clase que luego cambia la definición del método? ¿Cómo puedo implementar la misma funcionalidad (aparentemente para crear mis propias anotaciones de tipo java)?

por ejemplo...

class Thing
fun
def f1
puts "hey"
end

notfun
def f2
puts "hey"
end
end

y fun and notfun cambiaría las siguientes definiciones de funciones.

Gracias

Respuestas

8 para la respuesta № 1

A veces puedes meter a Ruby en una taza de café exprés. Veamos cómo.

Aquí hay un módulo FunNotFun ...

module FunNotFun

def fun
@method_type = "fun"
end

def notfun
@method_type = "not fun"
end

def method_added(id)
return unless @method_type
return if @bypass_method_added_hook
orig_method = instance_method(id)
@bypass_method_added_hook = true
method_type = @method_type
define_method(id) do |*args|
orig_method.bind(self).call(*args).tap do
puts "That was #{method_type}"
end
end
@bypass_method_added_hook = false
end

end

... que puedes usar para extender una clase ...

class Thing

extend FunNotFun

fun
def f1
puts "hey"
end

notfun
def f2
puts "hey"
end
end

... con este resultado:

Thing.new.f1
# => hey
# => That was fun

Thing.new.f2
# => hey
# => That was not fun

Pero ver debajo de la línea para una mejor manera.


Las anotaciones (ver la respuesta de normalocity) son menos problemáticas y, al ser un lenguaje común de Ruby, comunicará más fácilmente la intención de su código. Aquí está cómo hacerlo con anotaciones:

module FunNotFun

def fun(method_id)
wrap_method(method_id, "fun")
end

def notfun(method_id)
wrap_method(method_id, "not fun")
end

def wrap_method(method_id, type_of_method)
orig_method = instance_method(method_id)
define_method(method_id) do |*args|
orig_method.bind(self).call(*args).tap do
puts "That was #{type_of_method}"
end
end
end

end

En uso, la anotación viene después de que se define el método, en lugar de antes:

class Thing

extend FunNotFun

def f1
puts "hey"
end
fun :f1

def f2
puts "hey"
end
notfun :f2

end

El resultado es el mismo:

Thing.new.f1
# => hey
# => That was fun

Thing.new.f2
# => hey
# => That was not fun

1 para la respuesta № 2

Parece que quieres escribir extensiones al lenguaje Ruby, lo cual es posible. No es algo que se pueda explicar brevemente, pero este enlace debería ayudarlo a comenzar:

http://ruby-doc.org/docs/ProgrammingRuby/html/ext_ruby.html

Esta referencia, que tiene que ver con las anotaciones en Ruby, también podría ser útil / relevante:

http://martinfowler.com/bliki/RubyAnnotations.html


1 para la respuesta № 3

Aquí hay una solución de rubí puro para llevarte en la dirección correcta. Depende de method_added. Tenga cuidado de evitar la recursión utilizando una cláusula de guarda.

module Annotations
def fun
@state = :fun
end

def not_fun
@state = :not_fun
end

def inject_label(method_name)
state = @state
define_method(:"#{method_name}_with_label") do |*args, &block|
puts "Invoking #{method_name} in state #{state}"
send(:"#{method_name}_without_label", *args, &block)
end

alias_method :"#{method_name}_without_label", :"#{method_name}"
alias_method :"#{method_name}", :"#{method_name}_with_label"
end

def self.extended(base)
base.instance_eval do
def self.method_added(method_name)
return if method_name.to_s =~ /_with(out)?_labelZ/
@seen ||= {}
unless @seen[method_name]
@seen[method_name] = true
inject_label(method_name)
end
end
end
end
end

class Foo
extend Annotations

fun

def something
puts "I"m something"
end

not_fun

def other
puts "I"m the other"
end
end