Dynamic code generation

Discussion in 'Ruby' started by Thiago Arrais, Apr 1, 2006.

  1. I have been trying to do some simple dynamic code generation in Ruby.
    What I am specifically trying is to redefine a class level method on
    the subclasses. I know I may achieve that by using a simple def, but I
    would like come up with a simpler syntax, something like this:

    ----
    class Parent
    def self.redefinable_method
    return "This is the default string returned when the method
    isn't redefined"
    end

    def redefinable_method
    return self.class.redefinable_method
    end
    end

    class FirstChild < Parent
    redefine "This is the custom string for the FirstChild class"
    end

    class SecondChild < Parent; end

    fst =3D FirstChild.new
    fst.redefinable_method =3D> "This is the custom string for the FirstChild c=
    lass"

    snd =3D SecondChild.new
    snd.redefinable_method =3D> "This is the default string returned when
    the method isn't redefined"
    ----

    In this example you can see two points: (a) I am a total newbie, (b)
    the method 'redefine' should be defined on the parent class, but I
    don't have a clue on how it should be written. I have taken a look at
    ActiveRecord's associations, but it seems like overkill to use the
    exact same approach.

    Two questions:

    Is it possible to do that?
    Can the client code (child classes) be made any simpler/shorter?

    Cheers,

    Thiago Arrais
    Thiago Arrais, Apr 1, 2006
    #1
    1. Advertising

  2. On Apr 1, 2006, at 12:03 PM, Thiago Arrais wrote:

    > I have been trying to do some simple dynamic code generation in Ruby.
    > What I am specifically trying is to redefine a class level method on
    > the subclasses. I know I may achieve that by using a simple def, but I
    > would like come up with a simpler syntax, something like this:
    >
    > ----
    > class Parent
    > def self.redefinable_method
    > return "This is the default string returned when the method
    > isn't redefined"
    > end
    >
    > def redefinable_method
    > return self.class.redefinable_method
    > end
    > end
    >
    > class FirstChild < Parent
    > redefine "This is the custom string for the FirstChild class"
    > end
    >
    > class SecondChild < Parent; end
    >
    > fst = FirstChild.new
    > fst.redefinable_method => "This is the custom string for the
    > FirstChild class"
    >
    > snd = SecondChild.new
    > snd.redefinable_method => "This is the default string returned when
    > the method isn't redefined"
    > ----
    >
    > In this example you can see two points: (a) I am a total newbie, (b)
    > the method 'redefine' should be defined on the parent class, but I
    > don't have a clue on how it should be written. I have taken a look at
    > ActiveRecord's associations, but it seems like overkill to use the
    > exact same approach.
    >
    > Two questions:
    >
    > Is it possible to do that?
    > Can the client code (child classes) be made any simpler/shorter?
    >
    > Cheers,
    >
    > Thiago Arrais
    >


    This seems to be a solution looking for a problem
    class Parent
    def redefinable_method
    "This is the default string returned when the method isn't
    redefined"
    end
    end

    class FirstChild < Parent
    def redefinable_method
    "This is the custom string for the FirstChild class"
    end
    end

    class SecondChild < Parent; end

    I don;t see what you gain by meta-programming here
    Logan Capaldo, Apr 1, 2006
    #2
    1. Advertising

  3. Firstly you confuse things too much by using the same name as an
    instance and class method. There's probably an easier way but try this:

    class ParentClass
    def self.say
    "This is a message"
    end

    def self.make_it_say(message)
    class_methods = Module.new do
    define_method :say do
    message
    end
    end
    self.extend(class_methods)
    end
    end

    class ChildClass < ParentClass
    make_it_say "I've been redefined!"
    end

    puts ParentClass.say
    puts ChildClass.say
    Timothy Goddard, Apr 2, 2006
    #3
  4. On 4/1/06, Timothy Goddard <> wrote:
    > Firstly you confuse things too much by using the same name as an
    > instance and class method.


    I thought too, code just seems too cluttered. The effect I was trying
    to achieve was calling class methods from instances, but Ruby doesn't
    allow it. Maybe just calling class methods from instances is bad form.

    Anyway, your idea helped me to solve my problem. I don't think I will
    even need the class method anymore. define_method is exactly what I
    was looking for.

    By the way, we don't need to do the module thing. define_method can be
    called inside make_it_say directly, like this:

    ----
    class Parent
    def self.make_it_say(message)
    define_method :say do
    message
    end
    end

    def say
    'This is the default message'
    end
    end
    ----

    Child and Parent code seem pretty clean to me now. Thanks.

    Cheers,

    Thiago Arrais
    Thiago Arrais, Apr 2, 2006
    #4
  5. On 4/1/06, Logan Capaldo <> wrote:
    > I don;t see what you gain by meta-programming here


    I need a method to identify the child classes, something like
    Class#name, just more detailed. All instances of subclasses of the
    parent class need to respond to that method, but the method returns
    the same thing for all instances: a class identifier. Most classes
    will respond in mostly the same way, but some will need customization.

    Maybe a (almost) real example will help:

    ----
    class Parent

    def identifier
    return "This is class #{self.class.name}"
    end

    end

    class ChildUsingDefaultIdentifier; end

    class ChildUsingCustomIdentifier

    def identifier
    return 'Instances of this class identify them on a totally
    different way'
    end

    end
    ----

    Sure we could just override the method in the subclasses that needed
    to override it (like we did above), but it is just an identifier and a
    whole def block seemed too much.

    Regards,

    Thiago Arrais
    Thiago Arrais, Apr 2, 2006
    #5
  6. On Apr 1, 2006, at 11:15 PM, Thiago Arrais wrote:

    > On 4/1/06, Logan Capaldo <> wrote:
    >> I don;t see what you gain by meta-programming here

    >
    > I need a method to identify the child classes, something like
    > Class#name, just more detailed. All instances of subclasses of the
    > parent class need to respond to that method, but the method returns
    > the same thing for all instances: a class identifier. Most classes
    > will respond in mostly the same way, but some will need customization.
    >
    > Maybe a (almost) real example will help:
    >
    > ----
    > class Parent
    >
    > def identifier
    > return "This is class #{self.class.name}"
    > end
    >
    > end
    >
    > class ChildUsingDefaultIdentifier; end
    >
    > class ChildUsingCustomIdentifier
    >
    > def identifier
    > return 'Instances of this class identify them on a totally
    > different way'
    > end
    >
    > end
    > ----
    >
    > Sure we could just override the method in the subclasses that needed
    > to override it (like we did above), but it is just an identifier and a
    > whole def block seemed too much.
    >
    > Regards,
    >
    > Thiago Arrais
    >


    This seems like a job for class constants:

    % cat identifiers.rb
    class A
    ID = "Class A"
    end

    class B < A # uses default id
    end

    class C < A # uses a custom id
    ID = "Class C"
    end

    puts A::ID
    puts B::ID
    puts C::ID
    puts A::ID

    % ruby identifiers.rb
    Class A
    Class A
    Class C
    Class A
    Logan Capaldo, Apr 2, 2006
    #6
  7. On 4/2/06, Logan Capaldo <> wrote:
    > This seems like a job for class constants:


    This is what it seemed at first to me too. But I would like the
    instances to respond to a method, not the classes.

    The expected behavior is like this

    $ tail identifiers.rb

    # calling the identifier method on the instances, not the classes
    puts A.new.name
    puts B.new.name
    puts C.new.name
    puts A.new.name

    $ ruby identifiers.rb
    Class A
    Class A
    Class C
    Class A

    I wouldn't like to override a method just for returning a different
    ID. I have solved the problem with the approach described on the
    previous message. The question is: is there a simpler way? Maybe using
    class constants?

    Cheers,

    Thiago Arrais
    Thiago Arrais, Apr 3, 2006
    #7
  8. Take with a grain of salt, because I don't really understand this
    stuff. But, couldn't you do:

    irb(main):003:0> t =3D Time.at(0)
    =3D> Wed Dec 31 19:00:00 Eastern Standard Time 1969
    irb(main):004:0> t
    =3D> Wed Dec 31 19:00:00 Eastern Standard Time 1969
    irb(main):005:0> t.class
    =3D> Time
    irb(main):006:0> t.class.now
    =3D> Mon Apr 03 12:53:14 Eastern Standard Time 2006
    irb(main):007:0>

    I'm calling the class level method of the instance variable. Is that
    what you're looking for?

    Michael
    Michael Trier, Apr 3, 2006
    #8
  9. On 4/3/06, Michael Trier <> wrote:
    > Take with a grain of salt, because I don't really understand this
    > stuff. But, couldn't you do:
    >
    > irb(main):003:0> t =3D Time.at(0)
    > =3D> Wed Dec 31 19:00:00 Eastern Standard Time 1969
    > irb(main):004:0> t
    > =3D> Wed Dec 31 19:00:00 Eastern Standard Time 1969
    > irb(main):005:0> t.class
    > =3D> Time
    > irb(main):006:0> t.class.now
    > =3D> Mon Apr 03 12:53:14 Eastern Standard Time 2006
    > irb(main):007:0>
    >
    > I'm calling the class level method of the instance variable.


    No, you are calling the class level method of the _class_ variable.
    The message `now` goes to the object returned by t.class (the Time
    class), not the object 't'. You would be calling the class level
    method of the instance variable if you did something like this

    irb(main):005:0> t =3D Time.now
    =3D> Mon Apr 03 14:07:59 BRT 2006
    irb(main):006:0> t.now
    NoMethodError: undefined method `now' for Mon Apr 03 14:07:59 BRT 2006:Time
    from (irb):6
    from :0

    Which, indeed, fails miserably. But if we think a little, this is
    actually a feature, not a bug. In order to call a method on the class
    object, we need to send a message directly to it. Messages to the
    instances are handled by them.

    Other languages actually allow this kind of auto-delegation. It would
    be interesting to know what people think about it.

    > Is that
    > what you're looking for?


    It was one of the solutions I came up with, but it didn't survive very
    long. See previous posts.

    Thanks,

    Thiago Arrais
    Thiago Arrais, Apr 3, 2006
    #9
  10. Got it. I misunderstood what you were trying to achieve.

    Michael
    Michael Trier, Apr 3, 2006
    #10
  11. --Apple-Mail-21-429504684
    Content-Transfer-Encoding: 7bit
    Content-Type: text/plain;
    charset=US-ASCII;
    format=flowed


    On Apr 3, 2006, at 10:55 AM, Thiago Arrais wrote:

    > The question is: is there a simpler way? Maybe using
    > class constants?


    Is this simpler enough?

    % cat identifiers.rb
    class A
    ID = "Class A"
    def name
    self.class::ID
    end
    end

    class B < A # uses default id
    end

    class C < A # uses a custom id
    ID = "Class C"
    end

    puts A.new.name
    puts B.new.name
    puts C.new.name

    % ruby identifiers.rb
    Class A
    Class A
    Class C


    --Apple-Mail-21-429504684--
    Logan Capaldo, Apr 3, 2006
    #11
  12. On 4/3/06, Logan Capaldo <> wrote:
    > Is this simpler enough?


    Yup. I think I am going with this one.

    Thanks,

    Thiago Arrais
    Thiago Arrais, Apr 3, 2006
    #12
    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. Mike Treseler

    [Fwd: Vhdl dynamic generation]

    Mike Treseler, Jun 25, 2003, in forum: VHDL
    Replies:
    2
    Views:
    2,232
    abida
    Apr 17, 2011
  2. Stephen Walch

    Dynamic page generation page examples?

    Stephen Walch, Oct 6, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    654
    Stephen Walch
    Oct 6, 2003
  3. Frank
    Replies:
    1
    Views:
    495
    Roedy Green
    Aug 28, 2003
  4. John W. Long

    HTML Generation (Next Generation CGI)

    John W. Long, Nov 22, 2003, in forum: Ruby
    Replies:
    4
    Views:
    331
    John W. Long
    Nov 24, 2003
  5. Iwan van der Kleyn
    Replies:
    5
    Views:
    156
    James Edward Gray II
    Nov 23, 2004
Loading...

Share This Page