Private class ruby ​​method

Hi, I am trying to create an assistant for the mass determination of ruby ​​methods as private class methods. In general, a method can be defined as a private class method using the private_class_method key. But I would like to create an assistant in the following style:
class Person define_private_class_methods do def method_one end def method_two end end end 

The way I planned to dynamically determine this is as follows: this does not work:

 class Object def self.define_private_class_methods &block instance_eval do private &block end end end 

any ideas i might be wrong in?

+5
source share
3 answers

You can define methods in an anonymous module by passing the Module.new block, make each instance method in the module private and extend your class with the module

 class Class def define_private_class_methods(&block) mod = Module.new(&block) mod.instance_methods.each { |m| mod.send(:private, m) } extend(mod) end end 

This has the desired result:

 class Person define_private_class_methods do def method_one 123 end end end Person.send(:method_one) #=> 123 Person.method_one #=> private method `method_one' called for Person:Class (NoMethodError) 

... and as a bonus, it also gives you the super method: (perhaps a little used)

 class Person def self.method_one super * 2 end end Person.method_one #=> 456 

Of course, you do not need to use extend , you can also define methods manually manually:

 class Class def define_private_class_methods(&block) mod = Module.new(&block) mod.instance_methods.each do |m| define_singleton_method(m, mod.instance_method(m)) private_class_method(m) end end end 

An important module is an anonymous module, so you have a (temporary) container for defining methods.

+4
source

$ cat /tmp/a.rb

 class Object def self.define_private_class_methods &cb existing = methods(false) instance_eval &cb (methods(false) - existing).each { |m| singleton_class.send :private, m } end end class Person define_private_class_methods do def method_one puts "¡Yay!" end end end Person.send(:method_one) Person.public_send(:method_one) 

$ ruby /tmp/a.rb

 ¡Yay! /tmp/a.rb:18:in `public_send': private method `method_one' called for Person:Class (NoMethodError) Did you mean? method from /tmp/a.rb:18:in `<main>' 

Please note that it’s hard to understand what you are trying to achieve, and there may be a better, cleaner and more reliable way to achieve this functionality.

+5
source

A similar but different (and semantically more correct IMHO) @mudasobwa answer:

 class Class def define_private_class_methods(&definition) class_methods_prior = methods singleton_class.class_eval(&definition) (methods - class_methods_prior).each do |method_name| private_class_method method_name end end end class Person define_private_class_methods do def method_one 1 end end end Person.method_one # !> NoMethodError: private method `method_one' called for Person:Class Person.send :method_one # => 1 

Note This will not change the availability of the class method that you are currently rewriting.

+5
source

Source: https://habr.com/ru/post/1266961/


All Articles