Alter String base class to perform new (private methods) beforereturning itself when called by print

Discussion in 'Ruby' started by Steven G. Harms, Feb 16, 2008.

  1. class String
    def summon
    puts "You summon: " + self
    end
    def summon2
    puts "You summon: " + self.gsub('x','y')
    end
    def to_s
    return "Atreyu"
    end
    end

    "Artax".summon
    "Artax".summon2

    puts "Artax".to_s # reference 1
    puts "Artax" # reference 2

    This produces...

    You summon: Artax
    You summon: Artay
    Atreyu
    Artax

    Now the "summon" methods indicate to me that by referencing self in
    methods added to the String class, you can alter the string from
    within itself. The question is, how can I get `puts "Artax" ` to
    produce the same results as `puts "Artax"`. They are both Strings
    and, as far as I understand it, to_s is what is used to get a String's
    display value.

    Question #1: Is there a way to references 1 and 2, supra, to do the
    same thing?

    Question #2: I thought perhaps I could do the magic on the assignment
    operation. I'm not having too much luck with that, as yet.

    If this is the best solution, could the responding individual please
    be so gracious as to provide example code of how to override
    assignment? I'm muddling about with my re-defined initialize
    expecting an optional argument, but I've not figured out how to access
    it properly.

    Thanks,

    Steven
    Steven G. Harms, Feb 16, 2008
    #1
    1. Advertising

  2. On 16.02.2008 07:26, Steven G. Harms wrote:
    > class String
    > def summon
    > puts "You summon: " + self
    > end
    > def summon2
    > puts "You summon: " + self.gsub('x','y')
    > end
    > def to_s
    > return "Atreyu"
    > end
    > end
    >
    > "Artax".summon
    > "Artax".summon2
    >
    > puts "Artax".to_s # reference 1
    > puts "Artax" # reference 2
    >
    > This produces...
    >
    > You summon: Artax
    > You summon: Artay
    > Atreyu
    > Artax
    >
    > Now the "summon" methods indicate to me that by referencing self in
    > methods added to the String class, you can alter the string from
    > within itself.


    Actually your summon methods do not alter self.

    > The question is, how can I get `puts "Artax" ` to
    > produce the same results as `puts "Artax"`.


    ??? It's the same statement so I would expect the same output (module
    changes of the instance in between invocations).

    > They are both Strings
    > and, as far as I understand it, to_s is what is used to get a String's
    > display value.


    It's generally not a good idea to mess with such basic classes like
    String in this way (i.e. make to_s return something else than self).
    Since your example does not contain context it's difficult to come up
    with appropriate suggestions. What are you *really* trying to achieve?

    > Question #1: Is there a way to references 1 and 2, supra, to do the
    > same thing?


    Not sure what you mean here. Can you explain?

    > Question #2: I thought perhaps I could do the magic on the assignment
    > operation. I'm not having too much luck with that, as yet.


    You cannot change the semantics of assignment. You can however define
    methods that look like assignment, i.e. def foo=(x)...end. I doubt
    though that this is helpful for you in this context.

    > If this is the best solution, could the responding individual please
    > be so gracious as to provide example code of how to override
    > assignment? I'm muddling about with my re-defined initialize
    > expecting an optional argument, but I've not figured out how to access
    > it properly.


    Again, what problem are you trying to solve?

    Kind regards

    robert
    Robert Klemme, Feb 16, 2008
    #2
    1. Advertising

  3. Steven G. Harms

    Todd Benson Guest

    Re: Alter String base class to perform new (private methods) before returning itself when called by print statements

    On Feb 16, 2008 12:29 AM, Steven G. Harms <> wrote:
    > class String
    > def summon
    > puts "You summon: " + self
    > end
    > def summon2
    > puts "You summon: " + self.gsub('x','y')
    > end


    Keep in mind that these methods output what you want in irb, but
    return nil. In my irb session it looks something like this...
    irb(main):001:0> class String
    irb(main):002:1> def summon
    irb(main):003:2> puts "You summon: " + self
    irb(main):004:2> end
    irb(main):005:1> end
    => nil
    irb(main):006:0> s = "hello".summon
    You summon: hello
    => nil
    irb(main):007:0> s
    => nil

    > def to_s
    > return "Atreyu"
    > end
    > end
    >
    > "Artax".summon
    > "Artax".summon2
    >
    > puts "Artax".to_s # reference 1
    > puts "Artax" # reference 2
    >
    > This produces...
    >
    > You summon: Artax
    > You summon: Artay
    > Atreyu
    > Artax
    >
    > Now the "summon" methods indicate to me that by referencing self in
    > methods added to the String class, you can alter the string from
    > within itself.


    Yes, this is possible.

    > The question is, how can I get `puts "Artax" ` to
    > produce the same results as `puts "Artax"`. They are both Strings
    > and, as far as I understand it, to_s is what is used to get a String's
    > display value.
    >
    > Question #1: Is there a way to references 1 and 2, supra, to do the
    > same thing?


    Look at these two (using the previous code)...

    puts s.to_s
    puts(s).to_s

    >
    > Thanks,
    >
    > Steven


    Todd
    Todd Benson, Feb 16, 2008
    #3
  4. Steven G. Harms

    Todd Benson Guest

    Re: Alter String base class to perform new (private methods) before returning itself when called by print statements

    On Feb 16, 2008 7:37 AM, Todd Benson <> wrote:
    > Look at these two (using the previous code)...
    >
    > puts s.to_s
    > puts(s).to_s


    No, no , no!! Not using all the previous code! My bad. More "after"
    code for you (BTW, Robert's right, you shouldn't really mess with
    #to_s)...

    class String
    def to_s
    "hi"
    end
    end

    puts "hello".to_s
    puts("hello").to_s

    Todd
    Todd Benson, Feb 16, 2008
    #4
  5. Robert, Todd, et. al.,

    I apologize if my first post was missing some of the larger context, I
    didn't want to have to give too much information about the problem
    domain lest that deter replies ;).

    The code I'm working on is used for storing Strings which contain
    conjugations of Latin verbs ( I mean, people who lived near the
    Mediterranean, not people south of the Rio Grande ).

    Classical Latin words contain macrons on certain vowels ( the long bar
    that signifies a "long" sound ). When following conjugation rules
    occasionally the "macron-ized" character needs to be "shortened" and
    the macron thus removed. Thus, for example "they love" is the stem of
    the infinitive remove_ending("am\={a}re") + "nt" (I'm using LaTeX
    style macron representation).

    The rules dictate that you should chop off the "re" and add the "nt",
    thus giving you "am\={a}nt".

    BUT here's the rule, a macronized vowel before 'nt' or 'nd' anywhere
    in the string must be shortened, thus the word is *actually* "amant".
    There are other conditions that shorten a macron (comes before another
    vowel, etc.).

    Here's the output (at top) and code (at bottom): http://stevengharms.com/?page_id=1159

    While I have the code that produces the "right" output, I'm trying to
    refactor the code to be more Ruby-like, cleaner, and more organized.
    So the code that I link to here is still functional, but not final
    draft!

    As it is currently, you enter a verb characterization from the CLI, a
    Verb.new object is created with that string as the input. Those
    pieces are broken up and you have a Verb object. You can then issue:

    demo_verb=Verb.new( verb characterization string )
    puts demo_verb.active_present

    In 'active_present" 6 strings are created and returned in an array.
    Each of these strings are passed to a "check_macron" routine which
    removes macrons where needed.

    Point #1 ( Original Question, effectively)

    My idea was "Well, what if *every* string, in the duration of this
    program, knows to check_macron itself at time of assignment OR at time
    of being used for output" -- my idea being to "smarten" up String so
    that I didn't have to go around invoking check_macron all over the
    place. Further, I wouldn't have to change my ( heavy! ) use of the
    String assignment idioms ( heavily used ).

    Point #2:

    I was against the idea of subclassing String because, as i understand
    it, my assignments would take the look of:

    aLatinString = LatinString.new("something")

    instead of the very short and pleasant:

    aRegularString = "razzle"

    Perhaps I am mistaken in this?

    Well, so that's the full story, likely full of a lot of extra details,
    but hopefully you will make it through and be able to guide me to more
    Ruby like constructions!

    Steven
    Steven G. Harms, Feb 16, 2008
    #5
  6. On 16.02.2008 18:10, Steven G. Harms wrote:
    > Robert, Todd, et. al.,
    >
    > I apologize if my first post was missing some of the larger context, I
    > didn't want to have to give too much information about the problem
    > domain lest that deter replies ;).


    No problem at all. Sometimes it's hard to see where one should draw the
    line between too much and too few information to help people understand
    what's going on.

    > The code I'm working on is used for storing Strings which contain
    > conjugations of Latin verbs ( I mean, people who lived near the
    > Mediterranean, not people south of the Rio Grande ).


    :) My Latin is very rusty nowadays but this brings back memories (our
    first sentence in class five was "agricola arat")... :)

    > Classical Latin words contain macrons on certain vowels ( the long bar
    > that signifies a "long" sound ). When following conjugation rules
    > occasionally the "macron-ized" character needs to be "shortened" and
    > the macron thus removed. Thus, for example "they love" is the stem of
    > the infinitive remove_ending("am\={a}re") + "nt" (I'm using LaTeX
    > style macron representation).
    >
    > The rules dictate that you should chop off the "re" and add the "nt",
    > thus giving you "am\={a}nt".
    >
    > BUT here's the rule, a macronized vowel before 'nt' or 'nd' anywhere
    > in the string must be shortened, thus the word is *actually* "amant".
    > There are other conditions that shorten a macron (comes before another
    > vowel, etc.).
    >
    > Here's the output (at top) and code (at bottom): http://stevengharms.com/?page_id=1159


    Where exactly? I could neither see code nor latin words on that page.

    > While I have the code that produces the "right" output, I'm trying to
    > refactor the code to be more Ruby-like, cleaner, and more organized.
    > So the code that I link to here is still functional, but not final
    > draft!
    >
    > As it is currently, you enter a verb characterization from the CLI, a
    > Verb.new object is created with that string as the input. Those
    > pieces are broken up and you have a Verb object. You can then issue:
    >
    > demo_verb=Verb.new( verb characterization string )
    > puts demo_verb.active_present
    >
    > In 'active_present" 6 strings are created and returned in an array.
    > Each of these strings are passed to a "check_macron" routine which
    > removes macrons where needed.


    Personally I find this naming a bit unfortunate: checking is usually a
    read only operation while you are actually manipulating something.

    > Point #1 ( Original Question, effectively)
    >
    > My idea was "Well, what if *every* string, in the duration of this
    > program, knows to check_macron itself at time of assignment OR at time
    > of being used for output" -- my idea being to "smarten" up String so
    > that I didn't have to go around invoking check_macron all over the
    > place. Further, I wouldn't have to change my ( heavy! ) use of the
    > String assignment idioms ( heavily used ).


    That's double "heavy" - man this must be really heavy. :)

    I can see where your motivation comes from. Generally I'd opt for not
    putting this into class String because it is too specialized (i.e
    functionality that does make sense in context of your application only).

    One possible solution that might not too bad from your point of view:
    add a class and define a conversion method, e.g.

    LatinString = Struct.new :string do
    def remove_macron
    ...
    end

    def to_s
    # for printing...
    end
    end

    class String
    def to_latin
    LatinString.new self
    end
    end

    now you can do

    die = "alea".to_latin

    Another alternative (modifying assignment) could be this:

    class LatinVocabulary
    def initialize
    @vars = {}
    end

    def method_missing(sym, *args, &b)
    name = sym.to_s

    case
    when /^(.*)=$/ =~ name && args.length == 1
    # assignment
    @vars[$1] = remove_macron(args.first)
    when args.empty? && @vars.has_key? name
    # getter
    @vars[name]
    else
    super
    end
    end

    def remove_macron(str)
    ...
    end
    end

    And then

    voc = LatinVocabulary.new
    voc.die = "alea"
    voc.peasant = "agricola"

    > Point #2:
    >
    > I was against the idea of subclassing String because, as i understand
    > it, my assignments would take the look of:
    >
    > aLatinString = LatinString.new("something")
    >
    > instead of the very short and pleasant:
    >
    > aRegularString = "razzle"
    >
    > Perhaps I am mistaken in this?


    No, you are not. How should the interpreter know that "..." suddenly
    creates a LatinString and not a String? This is really hard coded into
    the language. And it's good that way because otherwise all sorts of
    nasty things could happen if anybody could change this.

    > Well, so that's the full story, likely full of a lot of extra details,
    > but hopefully you will make it through and be able to guide me to more
    > Ruby like constructions!


    I am still a bit unsure about when those conversions need to be done
    because I did not find the code where you indicated. From what you
    write method Verb#active_present generates this list you mentioned.
    Now, should this list be a list of plain Strings or do you need
    LatinStrings to be returned, i.e. does the result of this method call
    have to be modified already or do you need to be able to do it later?
    If the former, then you can apply the conversion in Verb#active_present,
    if the latter you can return a LatinString (as shown above).

    But generally, if you need a String with particular properties, create
    your own class for this. There are enough options to make handling and
    printing of anything as convenient as printing Strings. My 0.03EUR...

    Kind regards

    robert
    Robert Klemme, Feb 17, 2008
    #6
  7. Robert,

    Thank you for such a connsidered reply.

    On Feb 17, 4:57 am, Robert Klemme <> wrote:
    > :)  My Latin is very rusty nowadays but this brings back memories (our
    > first sentence in class five was "agricola arat")... :)


    It's always about the farmers, isn't it?

    > > Here's the output (at top) and code (at bottom):http://stevengharms.com/?page_id=1159

    >
    > Where exactly? I could neither see code nor latin words on that page.


    I *believe* you can now see the code at:
    http://stevengharms.com/improving-the-latin-command-line-verb-conjugator

    I just changed my 'slug' type and failed to understand that the
    preview was for admin-eyes-only.

    > > In 'active_present" 6 strings are created and returned in an array.
    > > Each of these strings are passed to a "check_macron" routine which
    > > removes macrons where needed.

    >
    > Personally I find this naming a bit unfortunate: checking is usually a
    > read only operation while you are actually manipulating something.

    I see your point on check_macron not being optimally named, let me
    keep the old name for purposes of this thread but I'll act on that
    recommendation.

    > I can see where your motivation comes from.  Generally I'd opt for not
    > putting this into class String because it is too specialized (i.e
    > functionality that does make sense in context of your application only).

    [ code snip ]

    That's sensible. I've never seen this Struct.new syntax so I'll be
    eager to try it out. I think i ( perhaps cumbersomely? ) wind up
    going more-or-less along this design pattern ( now that you can see
    the code ).


    > Another alternative (modifying assignment) could be this:
    >
    > class LatinVocabulary
    >    def initialize
    >      @vars = {}
    >    end
    >
    >    def method_missing(sym, *args, &b)
    >      name = sym.to_s
    >
    >      case
    >      when /^(.*)=$/ =~ name && args.length == 1
    >        # assignment
    >        @vars[$1] = remove_macron(args.first)
    >      when args.empty? && @vars.has_key? name
    >        # getter
    >        @vars[name]
    >      else
    >        super
    >      end
    >    end
    >
    >    def remove_macron(str)
    >      ...
    >    end
    > end
    >
    > And then
    >
    > voc = LatinVocabulary.new
    > voc.die = "alea"
    > voc.peasant = "agricola"


    This feels very "intro to metaprogramming" - the use of the
    method_missing method could, in principle, be used to expand the
    class. i.e.(pseudocode) "if method_missing :)active_present) do the
    active_present build with macron_sanitization routine". This may be
    where my code goes to once I get a bit more cleaned up.

    > > instead of the very short and pleasant:

    >
    > > aRegularString = "razzle"

    >
    > > Perhaps I am mistaken in this?

    >
    > No, you are not.  How should the interpreter know that "..." suddenly
    > creates a LatinString and not a String?  This is really hard coded into
    > the language.  And it's good that way because otherwise all sorts of
    > nasty things could happen if anybody could change this.


    Heh, well I suppose I was a bit overwhelmed by the idea of open
    classes and figured that Ruby would let me saw my hand off on this
    point, if I wanted to. That said, I agree it's probably a good thing
    that this can't get mucked about with.

    > LatinStrings to be returned, i.e. does the result of this method call
    > have to be modified already or do you need to be able to do it later?
    > If the former, then you can apply the conversion in Verb#active_present,
    > if the latter you can return a LatinString (as shown above).


    I think I wind up doing the former

    Thank you for your illuminating replies,

    Steven
    Steven G. Harms, Feb 17, 2008
    #7
  8. On 17.02.2008 15:00, Steven G. Harms wrote:
    > Thank you for such a connsidered reply.


    You're welcome!

    > On Feb 17, 4:57 am, Robert Klemme <> wrote:
    >> :) My Latin is very rusty nowadays but this brings back memories (our
    >> first sentence in class five was "agricola arat")... :)

    >
    > It's always about the farmers, isn't it?


    :))

    >>> Here's the output (at top) and code (at bottom):http://stevengharms.com/?page_id=1159

    >> Where exactly? I could neither see code nor latin words on that page.

    >
    > I *believe* you can now see the code at:
    > http://stevengharms.com/improving-the-latin-command-line-verb-conjugator


    I can confirm that. :)

    Few remarks: your type checking can be simplified:

    case input
    when Array
    ....
    when String
    ....
    else
    raise ArgumentError, "wrong type: #{input.inspect}"
    end

    Same for the conjugation, for which I would introduce symbols as names
    (not "1", "2" etc.).

    Same in evaluate_conjugation.

    def evaluate_conjugation
    case @infinitive
    when /\?re$/ # what exactly should your regexp look like?
    # question mark without escaping backslash
    # is not so good
    "1" # or rather a symbol denoting the name
    when /...
    ...
    else
    end
    end


    >> I can see where your motivation comes from. Generally I'd opt for not
    >> putting this into class String because it is too specialized (i.e
    >> functionality that does make sense in context of your application only).

    > [ code snip ]
    >
    > That's sensible. I've never seen this Struct.new syntax so I'll be
    > eager to try it out. I think i ( perhaps cumbersomely? ) wind up
    > going more-or-less along this design pattern ( now that you can see
    > the code ).


    Struct.new is actually just a convenient way to create a new class with
    a set of properties that are honored during #hash, #eql? and #== so
    instances can be easily compared and used as Hash keys.

    [...]

    > This feels very "intro to metaprogramming" - the use of the
    > method_missing method could, in principle, be used to expand the
    > class. i.e.(pseudocode) "if method_missing :)active_present) do the
    > active_present build with macron_sanitization routine". This may be
    > where my code goes to once I get a bit more cleaned up.


    If you know the method beforehand it is more efficient to define it
    right away.

    >> LatinStrings to be returned, i.e. does the result of this method call
    >> have to be modified already or do you need to be able to do it later?
    >> If the former, then you can apply the conversion in Verb#active_present,
    >> if the latter you can return a LatinString (as shown above).

    >
    > I think I wind up doing the former
    >
    > Thank you for your illuminating replies,


    You're welcome! I'm glad I could help.

    Kind regards

    robert
    Robert Klemme, Feb 17, 2008
    #8
    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. vijay
    Replies:
    6
    Views:
    392
    vijay
    Aug 22, 2003
  2. Alf P. Steinbach
    Replies:
    6
    Views:
    531
    John Carson
    Sep 3, 2005
  3. Replies:
    4
    Views:
    464
    Zeppe
    Sep 12, 2008
  4. -berlin.de
    Replies:
    0
    Views:
    135
    -berlin.de
    Jun 30, 2007
  5. Robert
    Replies:
    16
    Views:
    184
Loading...

Share This Page