getting around access control

A

Ara.T.Howard

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
--
===============================================================================
| ara [dot] t [dot] howard [at] noaa [dot] gov
| all happiness comes from the desire for others to be happy. all misery
| comes from the desire for oneself to be happy.
| -- bodhicaryavatara
===============================================================================
 
J

Joel VanderWerf

Ara.T.Howard said:
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

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....
 
A

ara.t.howard

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....


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
--
===============================================================================
| ara [dot] t [dot] howard [at] noaa [dot] gov
| all happiness comes from the desire for others to be happy. all misery
| comes from the desire for oneself to be happy.
| -- bodhicaryavatara
===============================================================================
 
J

Joel VanderWerf

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....
 
N

nobuyoshi nakada

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;
 
R

Ross Bamford

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....

[.. 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 :)
 
G

Gene Tani

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
 
R

Ross Bamford

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

<possible stupid question>

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 ?
 
A

ara.t.howard

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
--
===============================================================================
| ara [dot] t [dot] howard [at] noaa [dot] gov
| all happiness comes from the desire for others to be happy. all misery
| comes from the desire for oneself to be happy.
| -- bodhicaryavatara
===============================================================================
 
A

ara.t.howard

Or have I missed something ?

try your example with 'protected'.


-a
--
===============================================================================
| ara [dot] t [dot] howard [at] noaa [dot] gov
| all happiness comes from the desire for others to be happy. all misery
| comes from the desire for oneself to be happy.
| -- bodhicaryavatara
===============================================================================
 
A

ara.t.howard

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;


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
--
===============================================================================
| ara [dot] t [dot] howard [at] noaa [dot] gov
| all happiness comes from the desire for others to be happy. all misery
| comes from the desire for oneself to be happy.
| -- bodhicaryavatara
===============================================================================
 
R

Ross Bamford

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"

?
 
J

Jacob Fugal

i personally think instance_eval should be able to call both protected an= d
private methods...

it's just too hard to decide once and for all what should be private in a= n 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 Fugal
 
A

ara.t.howard

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"

?

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 ;-)

cheers.

-a
--
===============================================================================
| ara [dot] t [dot] howard [at] noaa [dot] gov
| all happiness comes from the desire for others to be happy. all misery
| comes from the desire for oneself to be happy.
| -- bodhicaryavatara
===============================================================================
 
J

Jacob Fugal

yeah... technically that works. what i'm doing is having handlered regi= ster
with a controller to process requests based on mime_type. the handler re= ally
needs to be run in the context of the controller to access all the good s= tuff
there but which 'good stuff' is not know a priori so i can't really use t= his
approach. also, it's probably bad mojo to start making methods public th= at
should be private on an object that's directly exposed to the web ;-)

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. :)
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.

:(

Jacob Fugal
 
R

Ross Bamford

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 ;-)

cheers.

-a

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

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 :) I think it's
good that it's your decision with Ruby though...)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,906
Latest member
SkinfixSkintag

Latest Threads

Top