Getting around access control


#1

i know there is a way to do this - but how

class C
protected
def meth
42
end
end

c = C::new

c.instance_eval{ p meth }

this throws an error, of course, but i’m too tired to remember how to
work
around it.

-a


#2

Ara.T.Howard wrote:

c = C::new

c.instance_eval{ p meth }

this throws an error, of course, but i’m too tired to remember how to work
around it.

-a

These are probably not helpful:

irb(main):012:0> c.instance_eval{ p send(:meth) }
42
=> nil
irb(main):013:0> c.instance_eval " p meth "
42
=> nil

The strange thing is that s/protected/private/ avoids the error:

irb(main):014:0> class C
irb(main):015:1> private
irb(main):016:1> def m2; 43; end
irb(main):017:1> end
=> nil
irb(main):018:0> c.instance_eval{ p m2 }
43

(ruby-1.8.2, anyway)

The original error (in the protected case) seem uncalled for…


#3

On Tue, 6 Dec 2005, Joel VanderWerf wrote:

The original error (in the protected case) seem uncalled for…
yeah - it’s quite strange. unfortunately the ‘send’ approach won’t work
because the actual usage is something like

class Controller
def method
handler = Handler::new self
handler.encode ‘42’
end
end

class Handler
def initialize controller
@controller = controller
end
def encode msg
@controller.instance_eval do
#
# many things which need to be insider the controller
#
end
end
end

that ‘private’ methods are allowed is really strange indeed.

regards.

-a


#4

removed_email_address@domain.invalid wrote:

def encode msg
  @controller.instance_eval do
    #
    # many things which need to be insider the controller
    #
  end
end

You could delegate:

     delegate(@controller).instance_eval do ... end

In the delegate object, make sure everything is public and that it uses
#send to delegate. The cost is bouncing messages around a bit more and
not having access to instance vars…


#5

On Tue, 06 Dec 2005 07:33:10 -0000, removed_email_address@domain.invalid wrote:

(ruby-1.8.2, anyway)

The original error (in the protected case) seem uncalled for…

[… snip …]

that ‘private’ methods are allowed is really strange indeed.

I actually really like Ruby’s notion of private - just that you can’t
call
the method with a receiver. When I first started with IRB I’d often look
for methods using Something.methods.sort . It took me ages to realise
why
I was missing so many very common ones - because they’re ‘private’ so
that
they can only be called on self.

I think it’s really flexible :slight_smile:


#6

yeah - it’s quite strange. unfortunately the ‘send’ approach won’t work
because the actual usage is something like

Anyway, i think the ‘send’ of private methods is / will be changed in
1.9 so you can’t do it anymore. Don’t know about the other access
control runaround, where you can subclass a class with private meths
and declare them public (p 393 of pickax), if that will/is changed in
1.9


#7

Hi,

At Tue, 6 Dec 2005 16:04:39 +0900,
Ara.T.Howard wrote in [ruby-talk:169057]:

c.instance_eval{ p meth }

this throws an error, of course, but i’m too tired to remember how to work
around it.

Hmmm, it seems to have changed unintentionally, together with
rb_funcall2(), at Dec 1. Should I fix it?

Index: eval.c

RCS file: /cvs/ruby/src/ruby/eval.c,v
retrieving revision 1.616.2.135
diff -U2 -p -u -r1.616.2.135 eval.c
— eval.c 30 Nov 2005 15:51:05 -0000 1.616.2.135
+++ eval.c 6 Dec 2005 08:46:32 -0000
@@ -5901,11 +5901,11 @@ rb_call(klass, recv, mid, argc, argv, sc
}

  • if (mid != missing && scope == 0) {
  • if (mid != missing) {
    /* receiver specified form for private method */
  • if (noex & NOEX_PRIVATE)
  • if ((noex & NOEX_PRIVATE) && && scope == 0)
    return method_missing(recv, mid, argc, argv, CSTAT_PRIV);

    /* self must be kind of a specified form for protected method */

  • if (noex & NOEX_PROTECTED) {
  • if ((noex & NOEX_PROTECTED) && scope < 3) {
    VALUE defined_class = klass;

#8

On Wed, 7 Dec 2005, Ross B. wrote:

Or have I missed something ?

try your example with ‘protected’.

-a


#9

On Tue, 06 Dec 2005 15:01:48 -0000, Gene T. removed_email_address@domain.invalid
wrote:

yeah - it’s quite strange. unfortunately the ‘send’ approach won’t work
because the actual usage is something like

Anyway, i think the ‘send’ of private methods is / will be changed in
1.9 so you can’t do it anymore. Don’t know about the other access
control runaround, where you can subclass a class with private meths
and declare them public (p 393 of pickax), if that will/is changed in
1.9

Isn’t access control kind of advisory anyway? Hopefully this isn’t about
to change???

irb(main):001:0> class Clz
irb(main):002:1> def amethod
irb(main):003:2> “amethod”
irb(main):004:2> end
irb(main):005:1> private :amethod
irb(main):006:1> end
=> Clz

irb(main):007:0> Clz.new.amethod
NoMethodError: private method `amethod’ called for #Clz:0xb7eddc18
from (irb):7

irb(main):008:0> class Clz
irb(main):009:1> public :amethod
irb(main):010:1> end
=> Clz

irb(main):011:0> Clz.new.amethod
=> “amethod”

</possible stupid question>

Or have I missed something ?


#10

On Tue, 6 Dec 2005, nobuyoshi nakada wrote:

rb_funcall2(), at Dec 1. Should I fix it?
}

  • if ((noex & NOEX_PROTECTED) && scope < 3) {
    VALUE defined_class = klass;

i personally think instance_eval should be able to call both protected
and
private methods…

it’s just too hard to decide once and for all what should be private in
an api

  • this gives uses a way out.

take now for instance though - it seems i’m stuck since i cannot call
the
methods i need without altering the source of rails… ;-(

-a


#11

On Wed, 7 Dec 2005, Gene T. wrote:

yeah - it’s quite strange. unfortunately the ‘send’ approach won’t work
because the actual usage is something like

Anyway, i think the ‘send’ of private methods is / will be changed in 1.9 so
you can’t do it anymore. Don’t know about the other access control
runaround, where you can subclass a class with private meths and declare
them public (p 393 of pickax), if that will/is changed in 1.9

doesn’t look like it…

harp:~ > ruby -e’ p RUBY_VERSION; Class::new{ private; def meth() p 42
end }::new.instance_eval{ meth } ’
“1.9.0”
42

-a


#12

On 12/6/05, removed_email_address@domain.invalid removed_email_address@domain.invalid wrote:

c.instance_eval{ p meth }

i personally think instance_eval should be able to call both protected and
private methods…

it’s just too hard to decide once and for all what should be private in an api

  • this gives uses a way out.

take now for instance though - it seems i’m stuck since i cannot call the
methods i need without altering the source of rails… ;-(

Well, one thing you can do for now is not worry about altering the
rails sources, but just reopen the class in a personal library to
unprotect the needed method. Right?

Jacob F.


#13

On Dec 6, 2005, at 10:25 AM, removed_email_address@domain.invalid wrote:

i personally think instance_eval should be able to call both
protected and
private methods…

I agree.

James Edward G. II


#14

On Tue, 06 Dec 2005 16:21:12 -0000, removed_email_address@domain.invalid wrote:

On Wed, 7 Dec 2005, Ross B. wrote:

Or have I missed something ?

try your example with ‘protected’.

-a

irb(main):025:0> class ClzThree
irb(main):026:1> protected
irb(main):027:1> def amethod
irb(main):028:2> “amethod”
irb(main):029:2> end
irb(main):030:1> end
=> nil

irb(main):031:0> ClzThree.new.amethod
NoMethodError: protected method `amethod’ called for
#ClzThree:0xb7f48018
from (irb):31
from :0

irb(main):032:0> class ClzThree
irb(main):033:1> public :amethod
irb(main):034:1> end
=> ClzThree

irb(main):037:0> ClzThree.new.amethod
=> “amethod”

?


#15

On 12/6/05, removed_email_address@domain.invalid removed_email_address@domain.invalid wrote:

yeah… technically that works. what i’m doing is having handlered register
with a controller to process requests based on mime_type. the handler really
needs to be run in the context of the controller to access all the good stuff
there but which ‘good stuff’ is not know a priori so i can’t really use this
approach. also, it’s probably bad mojo to start making methods public that
should be private on an object that’s directly exposed to the web :wink:

Good points, especially the last one. Since all public methods of a
controller are exposed as actions that can be invoked (assuming a
route exists) from outside, you probably don’t want them public. :slight_smile:
And upgrading the protection from protected to private (since your
code would work with private methods) could possibly cause problems
with other code that should have access but wouldn’t. I guess you’re
stuck for now.

:frowning:

Jacob F.


#16

On Wed, 7 Dec 2005, Ross B. wrote:

   from (irb):31

?
yeah… technically that works. what i’m doing is having handlered
register
with a controller to process requests based on mime_type. the handler
really
needs to be run in the context of the controller to access all the good
stuff
there but which ‘good stuff’ is not know a priori so i can’t really use
this
approach. also, it’s probably bad mojo to start making methods public
that
should be private on an object that’s directly exposed to the web :wink:

cheers.

-a


#17

On Tue, 06 Dec 2005 16:47:45 -0000, removed_email_address@domain.invalid wrote:

irb(main):031:0> ClzThree.new.amethod
irb(main):037:0> ClzThree.new.amethod
there but which ‘good stuff’ is not know a priori so i can’t really use
this
approach. also, it’s probably bad mojo to start making methods public
that
should be private on an object that’s directly exposed to the web :wink:

cheers.

-a

Phew - I was worried I’d missed a huge part of that section for a moment
:slight_smile:

I understand that it’s probably not the solution you wanted. It quite
worries me sometimes that it’s doable at all, but then I remember my
arguments in the past with Java, about the difference between protecting
for robust design and protecting for protection’s sake.

(Of course this time it’s probably a case of the former :slight_smile: I think it’s
good that it’s your decision with Ruby though…)