Defining methods dynamically

Hi Folks,

I have an array has_roles = %w[admin employee ...] which is a subset of
application_roles = ["admin", "employee", "manager"...]
Now I would define a method for each role in application roles where i
would call methods like

       @logged_in_user.admin which returns true because has_roles
includes "admin"
       @logged_in_user.employee which returns true because has_roles
includes
           "employee"
       @logged_in_user.manager which returns false because has_roles
doesnot
           include "manager"

I came accross using define_method in class Module for this purpose but
went wrong some where. Can any one there achieve this using
define_method. Its very urgent any help appreciated..thanks in
advance...

···

--
Posted via http://www.ruby-forum.com/.

Venkat Bagam wrote:

Hi Folks,

I have an array has_roles = %w[admin employee ...] which is a subset of
application_roles = ["admin", "employee", "manager"...]
Now I would define a method for each role in application roles where i
would call methods like

       @logged_in_user.admin which returns true because has_roles
includes "admin"
       @logged_in_user.employee which returns true because has_roles
includes
           "employee"
       @logged_in_user.manager which returns false because has_roles
doesnot
           include "manager"

I came accross using define_method in class Module for this purpose but
went wrong some where. Can any one there achieve this using
define_method. Its very urgent any help appreciated..thanks in
advance...

If I'm understanding you right...

class Roles
class << self

def admin
puts "This person is an admin"
end

def employee
puts "This person is an employee"
end

end

Of course you probably wouldnt use this very example to achieve what
your going for, but this is one of the approaches you would take using
the define method.

- Mac

···

--
Posted via http://www.ruby-forum.com/\.

Sure that is the hammer for your nail:
Not tested
ar.each do | role |
   define_method role do |*args|
      @logged_in_usr.send( role )
   end
end
Cheers
Robert

···

On 10/30/07, Venkat Bagam <bagam_venkat@hotmail.com> wrote:

Hi Folks,

I have an array has_roles = %w[admin employee ...] which is a subset of
application_roles = ["admin", "employee", "manager"...]
Now I would define a method for each role in application roles where i
would call methods like

       @logged_in_user.admin which returns true because has_roles
includes "admin"
       @logged_in_user.employee which returns true because has_roles
includes
           "employee"
       @logged_in_user.manager which returns false because has_roles
doesnot
           include "manager"

I came accross using define_method in class Module for this purpose but
went wrong some where. Can any one there achieve this using
define_method. Its very urgent any help appreciated..thanks in
advance...

--
what do I think about Ruby?
http://ruby-smalltalk.blogspot.com/

Venkat Bagam wrote:

Hi Folks,

I have an array has_roles = %w[admin employee ...] which is a subset of
application_roles = ["admin", "employee", "manager"...]

I personally like this approach. It's all a matter of taste:

class Application
  @@possible_roles = [:admin, :employee, :manager]

  def self.roles *args
    args.each do |role|
      class_eval do
        define_method(role) do
          true
        end
      end
    end

    (@@possible_roles - args).each do |non_role|
      class_eval do
        define_method(non_role) do
          false
        end
      end
    end
  end
end

class MyApplication < Application
  roles :admin, :employee
end

my_app = MyApplication.new
puts my_app.admin # => true
puts my_app.manager # => false

···

--
Posted via http://www.ruby-forum.com/\.

sorry hit this send button agaiiin

however this seems simple enough for some sort of delegation

HTH
Robert

···

--
what do I think about Ruby?
http://ruby-smalltalk.blogspot.com/

Drew Olson wrote:

Venkat Bagam wrote:

Hi Folks,

I have an array has_roles = %w[admin employee ...] which is a subset of
application_roles = ["admin", "employee", "manager"...]

I personally like this approach. It's all a matter of taste:

class Application
  @@possible_roles = [:admin, :employee, :manager]

  def self.roles *args
    args.each do |role|
      class_eval do
        define_method(role) do
          true
        end
      end
    end

    (@@possible_roles - args).each do |non_role|
      class_eval do
        define_method(non_role) do
          false
        end
      end
    end
  end
end

class MyApplication < Application
  roles :admin, :employee
end

my_app = MyApplication.new
puts my_app.admin # => true
puts my_app.manager # => false

Hi thanks for the reply... Its working well but I just need some
illustration.

1. whats happening when the my_app object is created.?
2. whats happening here def self.roles *args
    I mean, how come *args take :admin, :employee into it?

thanks and regards
Venkat

···

--
Posted via http://www.ruby-forum.com/\.

You can definitely do this with define_method:

      1 class Person
      2 class << self
      3 attr_accessor :roles
      4 end
      5 Person.roles = %w( admin manager employee )
      6
      7 attr_accessor :roles
      8 def initialize
      9 @roles =
     10 end
     11
     12 Person.roles.each do |role|
     13 define_method( role ) { || roles.include? role }
     14 end
     15
     16 end

john = Person.new
john.admin # false
john.roles << 'admin'
john.admin # true

Robert mentions delegation as an option, which would also work:

      1 require 'forwardable'
      2 class Person
      3 extend Forwardable
      4 class << self
      5 attr_accessor :roles
      6 end
      7 Person.roles = %w( admin manager employee )
      8
      9 attr_accessor :roles
     10 def initialize
     11 @roles =
     12 end
     13
     14 Person.roles.each do |role|
     15 def_delegator :@roles, role, :include?
     16 end
     17
     18 end

One difficulty with either implementation is that you need to make
sure that you add (or remove) the appropriate method whenever
Person.roles is changed. If Person.roles isn't going to change, then
just change the singleton's attr_accessor for roles to attr_reader.
Otherwise, you are going to need singleton methods like 'add_role' and
'remove_role', which will define or undefine your role methods.

Hope that helps.

Dan

···

---
Dan Yoder
http://dev.zeraweb.com/
Ruby and JavaScript Consulting

On Oct 30, 8:49 am, "Robert Dober" <robert.do...@gmail.com> wrote:

sorry hit this send button agaiiin

however this seems simple enough for some sort of delegation

HTH
Robert

--
what do I think about Ruby?http://ruby-smalltalk.blogspot.com/

You can definitely do this with define_method:

      1 class Person
      2 class << self
      3 attr_accessor :roles
      4 end
      5 Person.roles = %w( admin manager employee )
      6
      7 attr_accessor :roles
      8 def initialize
      9 @roles =
     10 end
     11
     12 Person.roles.each do |role|
     13 define_method( role ) { || roles.include? role }
     14 end
     15
     16 end

john = Person.new
john.admin # false
john.roles << 'admin'
john.admin # true

Robert mentions delegation as an option, which would also work:

      1 require 'forwardable'
      2 class Person
      3 extend Forwardable
      4 class << self
      5 attr_accessor :roles
      6 end
      7 Person.roles = %w( admin manager employee )
      8
      9 attr_accessor :roles
     10 def initialize
     11 @roles =
     12 end
     13
     14 Person.roles.each do |role|
     15 def_delegator :@roles, role, :include?
     16 end
     17
     18 end

One difficulty with either implementation is that you need to make
sure that you add (or remove) the appropriate method whenever
Person.roles is changed.

Exactly that was why I thaught of delegation, as I am not familiar
with the delegation idioms please forgive me that I handcoded it

class Person
  @roles = %w{ a b c d }
  class << self; attr_reader :roles end
  def method_missing name,*args,&blk
     super unless @roles.map.to_s.include? name
     ### do delegation here
     @some_obj.send name, *args, &blk
  end

Hope that helps.

Idem :wink:

Dan

---
Dan Yoder
http://dev.zeraweb.com/
Ruby and JavaScript Consulting

Robert

···

On Oct 30, 2007 6:45 PM, Dan Yoder <dan@zeraweb.com> wrote:

--
what do I think about Ruby?
http://ruby-smalltalk.blogspot.com/

Erratuml

   unless @roles.map.to_s

-->
   unless self.class.roles.map.to_s

Cheers
Robert

···

--
what do I think about Ruby?
http://ruby-smalltalk.blogspot.com/

Exactly that was why I thaught of delegation, as I am not familiar
with the delegation idioms please forgive me that I handcoded it

class Person
  @roles = %w{ a b c d }
  class << self; attr_reader :roles end
  def method_missing name,*args,&blk
     super unless @roles.map.to_s.include? name
     ### do delegation here
     @some_obj.send name, *args, &blk
  end

method_missing - is awfully slow, so if there is other option (like two from Dan Yoder) than better to use them at the cost of a few more lines.

I was showing the concept and I asked to imagine that delegation was
used, did I not?
However I do not think that the speed of method missing might be an
issue and dynamic delegation would probably be slow too.
Now if speed really is an issue you could of course do something like
the following
class DynamicDefiners
  def initialize klass
  @klass = klass
  @names = # not used in this simple usecase
  end
  def add *names
  @names += names
  names.each do | name |
    @klass.module_eval do
    attr_accessor name # or more sophisticated stuff as defining delegators
    end
  end
  end
  def del *names
  @names -= names
  names.each do | name |
    @klass.module_eval do
    remove_method name # or more sophisticated stuff as deleting delegators
    end
  end
    
  end
end
class Person
  @roles = DynamicDefiners.new self
  @roles.add *%w{ foo bar }
  class << self; attr_reader :roles end
  def initialize
    @foo = 22
    @bar = 32
    @baz = 42
  end
end

p = Person.new
puts( p.foo )
puts( p.bar ) rescue puts "no bar"
puts( p.baz ) rescue puts "no baz"

Person.roles.add "baz"
Person.roles.del "bar"

puts( p.foo )
puts( p.bar ) rescue puts "no bar"
puts( p.baz ) rescue puts "no baz"

I do not think one would need this stuff but who knows :wink:

R.

···

On Nov 3, 2007 7:10 PM, brainopia <ravwar@gmail.com> wrote:

> Exactly that was why I thaught of delegation, as I am not familiar
> with the delegation idioms please forgive me that I handcoded it
>
> class Person
> @roles = %w{ a b c d }
> class << self; attr_reader :roles end
> def method_missing name,*args,&blk
> super unless @roles.map.to_s.include? name
> ### do delegation here
> @some_obj.send name, *args, &blk
> end

method_missing - is awfully slow, so if there is other option (like two
from Dan Yoder) than better to use them at the cost of a few more lines.

--
what do I think about Ruby?
http://ruby-smalltalk.blogspot.com/