variable pointers

Discussion in 'Ruby' started by xyz, Dec 6, 2006.

  1. xyz

    xyz Guest

    I have a situation where I'm walking through an unordered sequence of text
    (splitting at newlines) looking for particular patterns. If a particular pattern
    matches then I perform some processing unique to that pattern and assign the
    output to a particular location (the location could be anything, e.g. local
    scalar, a particular array element, an instance variable, etc.).

    WARNING: C syntax approaching. Please restore your seats to their upright and
    locked positions and apply seat belts.

    Using "&" (take address) and "*" (de-reference pointer) from C, conceptually
    what I want to do is:

    template = [
    [ patternRegex, processingProc, &storage ]
    ...
    ]
    textSequence.each { |line|
    template.each { |tuple|
    *tuple[2] = tuple[1].call(line) if line =~ tuple[0]
    }
    }

    Obviously this could be achieved with eval() but that is very heavyweight.

    Are there other options?

    It doesn't seem that using Symbol's will work since they're not addresses (and
    thus can't be de-referenced) and they're scope-independent, i.e. if I use :foo I
    can't distinguish between a local variable foo, a method foo(), etc. even if
    they're not lexically visible within the current scope.

    As a kludge I could change tuple[2] to be an integer that indexes into an array
    and after the main loop is finished manually scatter the array elements to their
    final locations (note the word "kludge" at the beginning). The locations being
    stored may be all over the place so collecting them in a single object would be
    difficult, no less kludgy, and would obfuscate the code.

    Thanx.

    Jake
     
    xyz, Dec 6, 2006
    #1
    1. Advertising

  2. -----BEGIN PGP SIGNED MESSAGE-----

    In article <>,
    xyz <> wrote:
    >
    >I have a situation where I'm walking through an unordered sequence of text
    >(splitting at newlines) looking for particular patterns. If a particular pattern
    >matches then I perform some processing unique to that pattern and assign the
    >output to a particular location (the location could be anything, e.g. local
    >scalar, a particular array element, an instance variable, etc.).


    You are thinking in "C", this just doesn't work well in
    Ruby. Everything in Ruby is an object and every variable is just
    a pointer to that object. When you say

    a = b

    in Ruby, it means in C

    a = &b

    and

    a

    always evaluates to

    *a


    >
    >WARNING: C syntax approaching. Please restore your seats to their upright and
    >locked positions and apply seat belts.
    >
    >Using "&" (take address) and "*" (de-reference pointer) from C, conceptually
    >what I want to do is:
    >
    > template = [
    > [ patternRegex, processingProc, &storage ]
    > ...
    > ]
    > textSequence.each { |line|
    > template.each { |tuple|
    > *tuple[2] = tuple[1].call(line) if line =~ tuple[0]
    > }
    > }
    >
    >Obviously this could be achieved with eval() but that is very heavyweight.
    >
    >Are there other options?
    >


    Just use

    tuple[2] = tuple[1].call(line) if line =~ tuple[0]

    You can't easily pass storage around in Ruby, like you can in
    C. What you pass around is a pointer to an object. The
    processingProc should handle the createtion of the object,
    the storage item is just a name for where you store the pointer
    to the object. If you are managing storage, rather than objects
    you are doing things the hard way in Ruby.

    _ Booker C. Bense


    -----BEGIN PGP SIGNATURE-----
    Version: 2.6.2

    iQCVAwUBRXccaGTWTAjn5N/lAQH8KwQAvIk0tnWmc1aGr3MYFqfg08CBWXa5cBLw
    rQRJEfnxMuW9WyaHBikO2Gb+aB2CLKMaMl3IfaTNSUK0aJtzuJpBi2/RUa6Mbz1j
    EwD5qadlV9ZqQM50buQTUx+gGUVuYjXWSU7HKK0LrFfQlF3cD6Bv47DCuqJNToc7
    PvLGw2n0Qns=
    =FwnP
    -----END PGP SIGNATURE-----
     
    Booker C. Bense, Dec 6, 2006
    #2
    1. Advertising

  3. On 06.12.2006 19:55, xyz wrote:
    > I have a situation where I'm walking through an unordered sequence of text
    > (splitting at newlines) looking for particular patterns. If a particular pattern
    > matches then I perform some processing unique to that pattern and assign the
    > output to a particular location (the location could be anything, e.g. local
    > scalar, a particular array element, an instance variable, etc.).
    >
    > WARNING: C syntax approaching. Please restore your seats to their upright and
    > locked positions and apply seat belts.
    >
    > Using "&" (take address) and "*" (de-reference pointer) from C, conceptually
    > what I want to do is:
    >
    > template = [
    > [ patternRegex, processingProc, &storage ]
    > ...
    > ]
    > textSequence.each { |line|
    > template.each { |tuple|
    > *tuple[2] = tuple[1].call(line) if line =~ tuple[0]
    > }
    > }
    >
    > Obviously this could be achieved with eval() but that is very heavyweight.
    >
    > Are there other options?
    >
    > It doesn't seem that using Symbol's will work since they're not addresses (and
    > thus can't be de-referenced) and they're scope-independent, i.e. if I use :foo I
    > can't distinguish between a local variable foo, a method foo(), etc. even if
    > they're not lexically visible within the current scope.
    >
    > As a kludge I could change tuple[2] to be an integer that indexes into an array
    > and after the main loop is finished manually scatter the array elements to their
    > final locations (note the word "kludge" at the beginning). The locations being
    > stored may be all over the place so collecting them in a single object would be
    > difficult, no less kludgy, and would obfuscate the code.


    I can think of several approaches one of them being:

    class Foo
    INSTRUCTIONS = {
    /(\d+)\s*\+\s*(\d+)/ => lambda {|t, a, b| a.to_i + b.to_i},
    }

    def process (enum)
    result = {}
    enum.each do |line|
    INSTRUCTIONS.each do |rx, fun|
    md = rx.match(line) and result[rx] = fun[*md.to_a]
    end
    end
    result
    end
    end

    irb(main):051:0> Foo.new.process ["1+2", "3"]
    => {/(\d+)\s*\+\s*(\d+)/=>3}

    Of course, you could use a symbol as label in INSTRUCTIONS and use that
    to reference results. And then you might as well store multiple results
    (if it is possible that a pattern matches multiple times).

    class Foo
    INSTRUCTIONS = {
    :sum => [/(\d+)\s*\+\s*(\d+)/, lambda {|t, a, b| a.to_i + b.to_i}],
    }

    def process (enum)
    result = Hash.new {|h,k| h[k]=[]}
    enum.each do |line|
    INSTRUCTIONS.each do |label, (rx, fun)|
    md = rx.match(line) and result[label] << fun[*md.to_a]
    end
    end
    result
    end
    end

    irb(main):087:0> Foo.new.process ["1+2", "3", " 4 + 4"]
    => {:sum=>[3, 8]}

    You can as well hand over the MatchData instance directly to the lambda
    etc. but I guess you get the picture.

    Btw, that method also works with an IO instance.

    Kind regards

    robert
     
    Robert Klemme, Dec 7, 2006
    #3
    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. Phil
    Replies:
    1
    Views:
    660
    llewelly
    Sep 16, 2003
  2. muser
    Replies:
    3
    Views:
    775
    Ron Natalie
    Sep 18, 2003
  3. A
    Replies:
    3
    Views:
    466
    Alan Kelon
    Oct 29, 2003
  4. S?ren Gammelmark
    Replies:
    1
    Views:
    1,929
    Eric Sosman
    Jan 7, 2005
  5. cerr

    pointers, pointers, pointers...

    cerr, Apr 7, 2011, in forum: C Programming
    Replies:
    12
    Views:
    694
Loading...

Share This Page