dynamic include

  • Thread starter Florian Aßmann
  • Start date
F

Florian Aßmann

Hello,

I try to include some modules to a class instance, but I have
problems with the scope, here's what I did:


person.roles.each do |role|
class << person
include role.class.const_get('Functions')
end if role.class.const_defined?('Functions')
end unless person.nil?


As you can see role is not defined when I include it, does anybody
know how I can add some singleton methods to person?

Regards
Florian
 
D

David Vallner

--------------enig7326F7751DEE8E2200C7BDAC
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
As you can see role is not defined when I include it, does anybody know=
how I can add some singleton methods to person?
=20

Maybe the module Functions is the culprit? Are the methods module
functions ("def self.some_method"), or mixin functions ("def
some_method") in the module?

David Vallner


--------------enig7326F7751DEE8E2200C7BDAC
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (MingW32)

iD8DBQFFIA6Wy6MhrS8astoRAkuDAJ98cG+K6cMEWaMIlNXLz1kuHHMd9gCfaW+O
7Mtac/vjj+X6FU/rgEjNfRI=
=70Xc
-----END PGP SIGNATURE-----

--------------enig7326F7751DEE8E2200C7BDAC--
 
F

Florian Aßmann

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


Am 01.10.2006 um 20:53 schrieb David Vallner:
Maybe the module Functions is the culprit? Are the methods module
functions ("def self.some_method"), or mixin functions ("def
some_method") in the module?

David Vallner

Mixin:

class ManagerRole < Role
module Functions
def hire( person )
self.company << person
end
end
end

Florian
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Darwin)

iD8DBQFFIBCMl1R1ZNDW4WgRAhGFAJ4psGPi7gMGGZMgU/pjrOngh1SAFwCeOpgp
vtlL3+rk4E6LJ2v8mzloyIA=3D
=3D7miO
-----END PGP SIGNATURE-----
 
F

Florian Aßmann

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Am 01.10.2006 um 20:53 schrieb David Vallner:
Maybe the module Functions is the culprit? Are the methods module
functions ("def self.some_method"), or mixin functions ("def
some_method") in the module?

David Vallner

To be complete here if the Exception:

NameError: undefined local variable or method `role' for =20
#<Class:#<Person:0x2869aa0>>
/usr/local/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/=20
active_record/base.rb:1129:in `method_missing'
/Users/boof/Documents/Workspaces/rails/comany/config/../app/=20
models/person.rb:63:in `auth'
/usr/local/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/=20
active_record/associations/association_proxy.rb:110:in `each'
/usr/local/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/=20
active_record/associations/association_proxy.rb:110:in `send'
/usr/local/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/=20
active_record/associations/association_proxy.rb:110:in `method_missing'
/usr/local/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/=20
active_record/associations/has_and_belongs_to_many_association.rb:=20
81:in `method_missing'
/Users/boof/Documents/Workspaces/rails/comany/config/../app/=20
models/person.rb:60:in `auth'
test/unit/person_test.rb:37:in `test_4_change_password'


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Darwin)

iD8DBQFFIBD5l1R1ZNDW4WgRAgE3AJ4iG+Mmilp8wl85NJ/vIx7dWCc9LgCcDOL2
mX/zP7k1QDGj7t/KJynFlX8=3D
=3DI3VI
-----END PGP SIGNATURE-----
 
D

David Vallner

--------------enig8BA334A3E1BAE200D6F13945
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
To be complete here if the Exception:
=20
NameError: undefined local variable or method `role' for
#<Class:#<Person:0x2869aa0>>

I smell a Ruby bug / gotcha.

Apparently, in metaclass scope, the surrounding scope just isn't visible.=


Try a workaround:

person.roles.each do |role|
if role.class.const_defined?('Functions')
class << person
self
end.class_eval do
include role.class.const_get('Functions')
end
end
end unless person.nil?

David Vallner

PS: Statement modifiers after whole blocks? Ick.


--------------enig8BA334A3E1BAE200D6F13945
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (MingW32)

iD8DBQFFIBOXy6MhrS8astoRAufoAJ4lgMrk/HCYYhnJL9j8x3UOMtRczwCdGLG0
7tV6V4mk/oWy6lsM8TeKOBY=
=4lJR
-----END PGP SIGNATURE-----

--------------enig8BA334A3E1BAE200D6F13945--
 
D

dblack

---2049402039-1754694657-1159731453=:21214
Content-Type: MULTIPART/MIXED; BOUNDARY="-2049402039-1754694657-1159731453=:21214"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---2049402039-1754694657-1159731453=:21214
Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE

Hi --

I smell a Ruby bug / gotcha.

Apparently, in metaclass scope, the surrounding scope just isn't visible.

The class keyword always creates a new scope, whether you give it a
constant argument or a "<< obj"-style argument.
Try a workaround:

person.roles.each do |role|
if role.class.const_defined?('Functions')
class << person
=09 self
end.class_eval do
include role.class.const_get('Functions')
end
end
end unless person.nil?

You could also use extend, and avoid having to do the thing that won't
be easy until RCR 231 is accepted :)

person.roles.each do |role|
if role.class.const_defined?('Functions')
person.extend role.class.const_get('Functions')
end
end


David

--=20
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
---2049402039-1754694657-1159731453=:21214--
---2049402039-1754694657-1159731453=:21214--
 
D

David Vallner

--=-RWCVu7VJLQvrrCab1jsL
Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable

You could also use extend, and avoid having to do the thing that won't
be easy until RCR 231 is accepted :)

Could've sworn extend was private or protected... On second thought,
that would make the method pretty much useless.

*facewall*

There goes the attempt at remembering the little I can about the messier
meta stuff.

David Vallner

--=-RWCVu7VJLQvrrCab1jsL
Content-Type: application/pgp-signature; name=signature.asc
Content-Description: This is a digitally signed message part

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (GNU/Linux)

iD8DBQBFIB9iy6MhrS8astoRAhTLAJ9vGZ9z9o6trsYbUP5CDh8N7mOaGQCbBnYC
WIf0k+pUfTr8Gr/PgbI21PE=
=Vnrp
-----END PGP SIGNATURE-----

--=-RWCVu7VJLQvrrCab1jsL--
 
F

Florian Aßmann

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


Am 01.10.2006 um 21:14 schrieb David Vallner:
I smell a Ruby bug / gotcha.

Apparently, in metaclass scope, the surrounding scope just isn't =20
visible.

Try a workaround:

person.roles.each do |role|
if role.class.const_defined?('Functions')
class << person
self
end.class_eval do
include role.class.const_get('Functions')
end
end
end unless person.nil?

David Vallner

PS: Statement modifiers after whole blocks? Ick.

Ok, I just tested it, but now even a person with a CustomerRole and =20
no ManagerRole role has the methods once they are included, thanks =20
anyway. :D
dblack, extend works excactly the way I want it to, thank you too :)

Result...

if person =3D self.send( dyn_finder, *find_args )
m_name =3D 'Functions'
functions =3D person.roles.inject([]) do |f,r|
r.class.const_defined?(m_name) and
f << r.class.const_get(m_name)
end and person.extend *functions
end

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Darwin)

iD8DBQFFICUhl1R1ZNDW4WgRAtJUAJ9mHsq/PLfad6hdR8xxFm+Ep6xDKgCggz4D
5NuWkFwTIcalG5cAOnxbP4M=3D
=3D1k6o
-----END PGP SIGNATURE-----
 
D

dblack

---2049402039-1006382877-1159738154=:22266
Content-Type: MULTIPART/MIXED; BOUNDARY="-2049402039-1006382877-1159738154=:22266"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---2049402039-1006382877-1159738154=:22266
Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE

Hi --

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


Am 01.10.2006 um 21:14 schrieb David Vallner:


Ok, I just tested it, but now even a person with a CustomerRole and no=20
ManagerRole role has the methods once they are included, thanks anyway. := D
dblack, extend works excactly the way I want it to, thank you too :)

The two techniques should give you the same results. If you have a
case where they don't, I'd be interested in seeing it.
Result...

if person =3D self.send( dyn_finder, *find_args )
m_name =3D 'Functions'
functions =3D person.roles.inject([]) do |f,r|
r.class.const_defined?(m_name) and
f << r.class.const_get(m_name)
end and person.extend *functions
end

That call to inject will always return an array, so the "and" will
always flip to the right and execute person.extend *functions -- even
if functions is empty, in which case you'll get an error. You'd
probably want to drop the "and" and just do a conditional test:

person.extend *functions unless functions.empty?


David

--=20
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
---2049402039-1006382877-1159738154=:22266--
---2049402039-1006382877-1159738154=:22266--
 
F

Florian Aßmann

After a Test/Unit failed because of an Exception I did: <code>p
functions</code> in my source.
It shows me that at one time <var>functions</var> was False, so I
added the && operator.

Regards
Florian
 

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
474,214
Messages
2,571,112
Members
47,704
Latest member
DavidSuita

Latest Threads

Top