How to change instance method's visibility
ooo = Object.new
def ooo.some_public; 'woot' end
ooo.respond_to?(:some_public) # => true
ooo.singleton_class.class_eval{private :some_public}
ooo.respond_to?(:some_public) # => false
Avoid class pollution while including module
You can wrap a class into the module and use private methods within the class, like so:
module Bar
def call
BarClass.new.call
end
class BarClass
def call
hide_me
end
private
def hide_me
puts "invisible"
end
end
end
class Foo
include Bar
def call_bar
call
end
def this_method_fails
hide_me
end
end
Keep visibility of abstract method in subclass
No, there's not really a way to restrict that. are you worried about malicious developers or clueless coworkers? if the latter then you just need to establish coding conventions like "don't increase the visibility of methods" and put some javadoc on the abstract method indicating proper usage. if the former, then you probably need to design your code differently (possibly using the strategy pattern).
public methods in package-private classes
If the class is not going to be extended by another, more visible subclass*, the only difference is clarity of intent. Declaring all methods package private makes it more difficult for future readers to determine which of the methods are meant to be called by other classes in the same package.
*which would not make much sense as a design solution to me, but technically is possible nevertheless.
Customizing a Ruby Struct with pre-defined definitions and a custom block
In Ruby there is the notion of a current class which is the target of keywords such as def
.
When you use instance_eval
, the current class is set to self.singleton_class
. In other words, def x
and def self.x
are equivalent. In your code, custom_instance_method
is defined on the singleton class of the newly created Struct
, making it a class method.
When you use class_eval
, the current class is set to self
. Since this method is only available on classes, it will set the current class to the one you called the method on. In other words, def x
will define a method that's available to all objects of that class. This is what you wanted.
For more details, see my other answer.
Dynamically set parameters in define_method
So as advised I went to class_eval
.
class Whatever
class << self
def add_method(name, parameters = {})
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{name}(#{method_parameters(parameters)})
#{method_body(parameters)}
end
RUBY
end
# method_parameters({
# foo: { required: false, default: 0 },
# bar: { required: true }
# })
# => "foo: 0, bar:"
def method_parameters(parameters)
parameters.map do |key, options|
value = options[:required] ? '' : " #{options[:default] || 'nil'}"
"#{key}:#{value}"
end.join(', ')
end
# method_parameters({
# foo: { required: false, default: 0 },
# bar: { required: true }
# })
# => "[foo, bar]"
def method_body(parameters)
"[#{parameters.keys.map(&:to_s).join(', ')}]"
end
end
end
params = {
foo: { required: false, default: 0 },
bar: { required: true }
}
Whatever.add_method(:hello, params)
Whatever.new.hello(bar: true) # => [0, true]
Whatever.new.hello(foo: 42, bar: true) # => [42, true]
Whatever.new.hello # missing keyword: bar (ArgumentError)
Related Topics
Rails: Allowing a Partial to Only Be Rendered Once
Capture Webcam's Image with Ruby
Can't Find a Route with an Underscore or Doesn't Treat It Properly
Count Iteration on the Enumerable Cycle
What Is the Fastest Way to Sort a Hash
Increase Timeout for Net::Http
Why Do I Get a Encoding::Compatibilityerror with #Inspect
Openuri Causing 401 Unauthorized Error with Https Url
Filter Activeadmin with Hstore
Reading Parameters on Sinatra Post
How to Pass Value from One Resource to Another Resource in Chef Recipe
Jekyll Liquid - Accessing _Config.Yml Dynamically
Why Are Parenthesis Sometimes Required in Ruby
Ruby/Rails Actionmailer Not Working with Ntlm
Why Capypara + Rspect Tests Still Pass Even Though I Delete Application.Js File