Determining Method's Visibility on the Fly

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



Leave a reply



Submit