defining methods dynamically

Discussion in 'Ruby' started by Venkat Bagam, Oct 30, 2007.

  1. Venkat Bagam

    Venkat Bagam Guest

    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, Oct 30, 2007
    #1
    1. Advertising

  2. 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/.
     
    Michael Linfield, Oct 30, 2007
    #2
    1. Advertising

  3. Venkat Bagam

    Robert Dober Guest

    On 10/30/07, 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...


    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
    --
    what do I think about Ruby?
    http://ruby-smalltalk.blogspot.com/
     
    Robert Dober, Oct 30, 2007
    #3
  4. Venkat Bagam

    Robert Dober Guest

    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/
     
    Robert Dober, Oct 30, 2007
    #4
  5. Venkat Bagam

    Dan Yoder Guest

    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 :mad: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" <> 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/
     
    Dan Yoder, Oct 30, 2007
    #5
  6. Venkat Bagam

    Drew Olson Guest

    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/.
     
    Drew Olson, Oct 30, 2007
    #6
  7. Venkat Bagam

    Guest

    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/.
     
    , Nov 3, 2007
    #7
  8. Venkat Bagam

    Guest

    On Oct 30, 2007 6:45 PM, Dan Yoder <> wrote:
    > 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 :mad: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 ;)
    >
    > Dan
    >
    > ---
    > Dan Yoder
    > http://dev.zeraweb.com/
    > Ruby and JavaScript Consulting


    Robert

    --
    what do I think about Ruby?
    http://ruby-smalltalk.blogspot.com/
     
    , Nov 3, 2007
    #8
  9. Venkat Bagam

    Guest

    , Nov 3, 2007
    #9
  10. Venkat Bagam

    brainopia Guest

    > 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.
     
    brainopia, Nov 3, 2007
    #10
  11. Venkat Bagam

    Guest

    On Nov 3, 2007 7:10 PM, brainopia <> 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.

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

    R.
    --
    what do I think about Ruby?
    http://ruby-smalltalk.blogspot.com/
     
    , Nov 4, 2007
    #11
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jasper Pearlman

    Defining methods outside of script tags

    Jasper Pearlman, Aug 16, 2004, in forum: ASP .Net
    Replies:
    3
    Views:
    351
  2. johny smith
    Replies:
    8
    Views:
    421
    Peter Koch Larsen
    Jul 2, 2004
  3. Kenneth McDonald

    defining methods dynamically?

    Kenneth McDonald, Aug 2, 2007, in forum: Ruby
    Replies:
    5
    Views:
    114
    Peña, Botp
    Aug 3, 2007
  4. Kenneth McDonald
    Replies:
    5
    Views:
    127
    Kenneth McDonald
    Aug 5, 2007
  5. Kenneth McDonald
    Replies:
    5
    Views:
    324
    Kenneth McDonald
    Sep 26, 2008
Loading...

Share This Page