Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 1060 Vote(s) - 3.53 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Detect new method visibility in class method

#1
Here's a code example:

class Foo
def self.create_method
def example_method
"foo"
end
end

private

create_method
end

Foo.public_instance_methods(false) # => [:example_method]

Is it possible to detect that class method `create_method` was called from class `Foo` private area?

In the above example, that information could be used to make `example_method` public or private depending on the place where `create_method` was invoked from.
Reply

#2
I wrote more unified solution, it's able to find out a visibility scope of any caller.

My main idea was to identify 2 things:

- caller object(`self` binding of caller)
- method name of caller object

I used [binding_of_caller][1] gem to achieve this.

class Foo
class << self
def visibility_scope
binding_of_caller = binding.of_caller(1)
caller_method = binding_of_caller.eval('__method__')
caller_object = binding_of_caller.eval('self')

# It's asking if caller is a module, since Class is inherited from Module
if caller_object.is_a?(Module)
return visibility_scope_for(caller_object.singleton_class, caller_method)
end


# First we should check object.singleton_class, since methods from there are called before
# class instance methods from object.class
visibility = visibility_scope_for(caller_object.singleton_class, caller_method)
return visibility if visibility

# Then we check instance methods, that are stored in object.class
visibility = visibility_scope_for(caller_object.class, caller_method)
return visibility if visibility

fail 'Visibility is undefined'
end

private

def visibility_scope_for(object, method_name)
%w(public protected private).each do |scope|
if object.send("#{scope}_method_defined?", method_name)
return scope
end
end
nil
end
end
end


Add some methods to test:

class Foo
class << self
# This method is private in instance and public in class
def twin_method
visibility_scope
end

def class_public_method
visibility_scope
end

protected

def class_protected_method
visibility_scope
end

private

def class_private_method
visibility_scope
end
end

def instance_public_method
self.class.visibility_scope
end

protected

def instance_protected_method
self.class.visibility_scope
end

private

def twin_method
self.class.visibility_scope
end

def instance_private_method
self.class.visibility_scope
end
end

# singleton methods
foo = Foo.new
foo.singleton_class.class_eval do
def public_singleton_method
Foo.visibility_scope
end

protected

def protected_singleton_method
Foo.visibility_scope
end

private

def private_singleton_method
Foo.visibility_scope
end
end

class Bar
class << self
private

def class_private_method
Foo.visibility_scope
end
end

protected

def instance_protected_method
Foo.visibility_scope
end
end

Test

# check ordinary method
Foo.class_public_method
=> "public"
Foo.send(:class_protected_method)
=> "protected"
Foo.send(:class_private_method)
=> "private"
Foo.new.instance_public_method
=> "public"
Foo.new.send(:instance_protected_method)
=> "protected"
Foo.new.send(:instance_private_method)
=> "private"

# check class and instance methods with the same name
Foo.twin_method
=> "public"
Foo.new.send(:twin_method)
=> "private"

# check methods from different objects
Bar.send(:class_private_method)
=> "private"
Bar.new.send(:instance_protected_method)
=> "protected"

# check singleton methods
foo.public_singleton_method
=> "public"
foo.send(:protected_singleton_method)
=> "protected"
foo.send(:private_singleton_method)
=> "private"


[1]:

[To see links please register here]

Reply

#3
Just to be sure, I double checked with ruby code, but I might be missing something. I couldn’t find any way to get the currently declared visibility scope from the class. As it appears if visibility methods (private, public or protected) are declared without method name argument it will set the current scope as a class wide declaration unless we declare other visibility scope on the subsequent statements.

You can check this code for further investigation -

[To see links please register here]


I couldn’t find any method which directly refers to cref->visi, You can check this code for the reference -

[To see links please register here]


Here is also the similar answer from one of the earliest post on Stackoverflow -

[To see links please register here]


So this is the simplified solution, I came up with -

class Foo
def self.create_method
def example_method
"foo"
end

visibility = if self.private_method_defined? :test_method
:private
elsif self.public_method_defined? :test_method
:public
elsif self.protected_method_defined? :test_method
:protected
end

send visibility, :example_method
end

private

# As Ruby doesn't associate visibility flag along with the caller
# reference rather with the actual method which are subsequently
# declared. So we can take that as an advantage and create a test method
# and later from :create_method scope check that particular method
# visibility and change the generated method visibility accordingly.
# Create a test method to verify the actual visibility when calling 'create_method' method
def test_method; end

create_method
end

puts "Public methods: #{Foo.public_instance_methods(false)}"
# []
puts "Private methods: #{Foo.private_instance_methods(false)}"
# [:test_method, :example_method]
puts "Protected methods: #{Foo.protected_instance_methods(false)}"
# []
Reply

#4
Though it’s a bit hacky, it is possible:

class Foo
def self.create_method
define_method :example_method do
visibility = case caller(0).first[/block in (\w+)'/, 1].to_sym
when ->(m) { Foo.private_methods.include? m }
:private
when ->(m) { Foo.protected_methods.include? m }
:protected
when ->(m) { Foo.public_methods.include? m }
:public
else :unknown
end
puts "Visibility: #{visibility}"
end
end

private_class_method :create_method
end

Foo.send :create_method
Foo.new.example_method

#⇒ Visibility: private

Here we check the visibility of caller by `case` block. Please note, that you can’t simply move the case into another helper method without any modifications, since it relies on `caller`. Hope it helps.
Reply

#5
Try

[To see links please register here]


There is feature :

> Call tree profiles - outputs results in the calltree format suitable
> for the KCacheGrind profiling tool.

That might help you
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through