Ruby way to update file lines

Discussion in 'Ruby' started by Mark Probert, Aug 19, 2004.

  1. Mark Probert

    Mark Probert Guest

    Hi.

    I have a need to update a config file. It uses '#' as a line comment
    marker. The config file looks like:

    # file comment
    #
    name1:foo1:bar:eek:ther
    name2:foo2:bar:eek:ther
    name3:foo3:bar:eek:ther
    name4:foo4:bar:eek:ther

    The name:foo combination is unique.

    What is the most efficient way to read in the file, update the line, and
    then write it back to the file. One update would be to place a '#' in col
    1

    #name3:foo3:bar:eek:ther

    Any thoughts appreciated.

    -mark.
    Mark Probert, Aug 19, 2004
    #1
    1. Advertising

  2. Mark Probert

    Kirk Haines Guest

    On Thu, 19 Aug 2004 10:45:54 +0900, Mark Probert wrote

    >
    > What is the most efficient way to read in the file, update the line,
    > and then write it back to the file. One update would be to place a
    > '#' in col 1
    >
    > #name3:foo3:bar:eek:ther
    >
    > Any thoughts appreciated.


    Unless the file is very large, my initial thought is just to read the file
    to an array. Edit, then rewrite the file.


    Kirk Haines
    Kirk Haines, Aug 19, 2004
    #2
    1. Advertising

  3. "Mark Probert" <> schrieb im Newsbeitrag
    news:Xns9549BE97C59B0probertmnospamacmorg@198.161.157.145...
    > Hi.
    >
    > I have a need to update a config file. It uses '#' as a line comment
    > marker. The config file looks like:
    >
    > # file comment
    > #
    > name1:foo1:bar:eek:ther
    > name2:foo2:bar:eek:ther
    > name3:foo3:bar:eek:ther
    > name4:foo4:bar:eek:ther
    >
    > The name:foo combination is unique.
    >
    > What is the most efficient way to read in the file, update the line, and
    > then write it back to the file. One update would be to place a '#' in col
    > 1
    >
    > #name3:foo3:bar:eek:ther
    >
    > Any thoughts appreciated.
    >
    > -mark.


    Some code thoughts below

    Regards

    robert


    # match keys
    COMMENT = lambda {|key, val| "# #{key}:#{val}"}
    DELETE = lambda { nil }

    tasks = {
    "foo:bar" => COMMENT,
    "foo1:bar1" => DELETE,
    }

    conf = File.readlines("conf.txt")

    # manipulate
    conf.map! do |line|
    if /^([^:]+:[^:]+):(.*)$/ =~ line && (fun = tasks[$1])
    fun.call $1, $2
    else
    line
    end
    end

    # remove deleted lines
    conf.compact!

    File.open("conf-1.txt", "w") {|io| io.puts conf }

    #
    # alternative -----------------------------------------
    #

    # use regexp as line matcher
    tasks = {
    /^foo1:bar1:/ => lambda {|line| "# #{line}"},
    /^\s*#\s*foo.bar:/ => lambda {|line| line.sub(/^\s*#\s*/, '' )},
    }


    conf = File.readlines("conf-1.txt")

    # manipulate
    conf.map! do |line|
    p,f = tasks.find {|patt, fun| patt =~ line}
    f ? f.call( line ) : line
    end

    # remove deleted lines
    conf.compact!

    File.open("conf-2.txt", "w") {|io| io.puts conf }
    Robert Klemme, Aug 19, 2004
    #3
  4. On Thu, 19 Aug 2004 01:44:10 +0000, Mark Probert wrote:

    > Hi.
    >
    > I have a need to update a config file. It uses '#' as a line comment
    > marker. The config file looks like:
    >
    > # file comment
    > #
    > name1:foo1:bar:eek:ther
    > name2:foo2:bar:eek:ther
    > name3:foo3:bar:eek:ther
    > name4:foo4:bar:eek:ther
    >
    > The name:foo combination is unique.
    >
    > What is the most efficient way to read in the file, update the line, and
    > then write it back to the file. One update would be to place a '#' in col
    > 1
    >
    > #name3:foo3:bar:eek:ther
    >
    > Any thoughts appreciated.
    >
    > -mark.


    You could use inplace edit. This can make ruby work like awk.
    For example:

    ruby -aF: -ni.bak -e 'print "#" if $F[0] == "name3"' configfile

    KB
    Kristof Bastiaensen, Aug 19, 2004
    #4
  5. Mark Probert

    Mark Probert Guest

    "Robert Klemme" <> wrote:

    >
    > Some code thoughts below
    >
    > Regards
    >
    > robert
    >
    >
    > # match keys
    > COMMENT = lambda {|key, val| "# #{key}:#{val}"}
    > DELETE = lambda { nil }
    >
    > tasks = {
    > "foo:bar" => COMMENT,
    > "foo1:bar1" => DELETE,
    > }
    >
    > conf = File.readlines("conf.txt")
    >
    > # manipulate
    > conf.map! do |line|
    > if /^([^:]+:[^:]+):(.*)$/ =~ line && (fun = tasks[$1])
    > fun.call $1, $2
    > else
    > line
    > end
    > end
    >
    > # remove deleted lines
    > conf.compact!
    >
    > File.open("conf-1.txt", "w") {|io| io.puts conf }
    >


    I liked this one :) Thanks.

    One minor correction: COMMENT and DELETE should be lower case. Ruby 1.8
    spits and error about constants otherwise.

    -mark.
    Mark Probert, Aug 21, 2004
    #5
  6. "Mark Probert" <> schrieb im Newsbeitrag
    news:Xns954C7C2A261F8probertmnospamtelusn@198.161.157.145...
    > "Robert Klemme" <> wrote:
    >
    > >
    > > Some code thoughts below
    > >
    > > Regards
    > >
    > > robert
    > >
    > >
    > > # match keys
    > > COMMENT = lambda {|key, val| "# #{key}:#{val}"}
    > > DELETE = lambda { nil }
    > >
    > > tasks = {
    > > "foo:bar" => COMMENT,
    > > "foo1:bar1" => DELETE,
    > > }
    > >
    > > conf = File.readlines("conf.txt")
    > >
    > > # manipulate
    > > conf.map! do |line|
    > > if /^([^:]+:[^:]+):(.*)$/ =~ line && (fun = tasks[$1])
    > > fun.call $1, $2
    > > else
    > > line
    > > end
    > > end
    > >
    > > # remove deleted lines
    > > conf.compact!
    > >
    > > File.open("conf-1.txt", "w") {|io| io.puts conf }
    > >

    >
    > I liked this one :) Thanks.


    Thanks, too! :)

    > One minor correction: COMMENT and DELETE should be lower case. Ruby 1.8
    > spits and error about constants otherwise.


    They are meant to be constants because they *are* constant. I just put both
    variants into a single file but you'll likely need only one of them, don't
    you?

    Regards

    robert
    Robert Klemme, Aug 21, 2004
    #6
  7. Mark Probert

    Mark Probert Guest

    "Robert Klemme" <> wrote in
    news::
    >
    > They are meant to be constants because they *are* constant. I just
    > put both variants into a single file but you'll likely need only one
    > of them, don't you?
    >

    When I leave them as constants, Ruby complains with the following error:

    deln.rb:37: dynamic constant assignment
    COMMENT = lambda {|key, val| "# #{key}:#{val}" }
    ^

    In the end, it worked out well. My code snippet looks like:

    # create a function map for the items we want to delete
    comment = lambda {|key, val| "# #{key}:#{val}" }
    delete = lambda {|key, val| nil }
    checkmap = {}
    @nodelist.each do |n|
    key = "#{n.name}:#{n.ip}"
    checkmap[key] = (@remove) ? delete : comment
    end

    Where I now have the option of making the deletion permanent or just
    commenting it out. Which is perfect for my application.

    Regards,

    -mark.
    Mark Probert, Aug 21, 2004
    #7
  8. "Mark Probert" <> schrieb im Newsbeitrag
    news:Xns954CA02966DD9probertmnospamtelusn@198.80.55.250...
    > "Robert Klemme" <> wrote in
    > news::
    > >
    > > They are meant to be constants because they *are* constant. I just
    > > put both variants into a single file but you'll likely need only one
    > > of them, don't you?
    > >

    > When I leave them as constants, Ruby complains with the following error:
    >
    > deln.rb:37: dynamic constant assignment
    > COMMENT = lambda {|key, val| "# #{key}:#{val}" }
    > ^


    Then you got the scoping wrong. Constants should be defined on top level or
    class / module scope, otherwise they are of not much use: what do you gain
    by reevaluationg and assigning an expression on each method invocation?
    That's not what constants are intended for. You probably did something like
    this:

    >> def foo() FOO = "bar" end

    SyntaxError: compile error
    (irb):2: dynamic constant assignment
    def foo() FOO = "bar" end
    ^
    from (irb):2

    While it should be

    FOO = "bar"
    def foo() ... end
    # use FOO
    or

    class Any
    FOO = "bar"
    # use FOO
    end

    Both of them don't trigger warnings unless you do multiple assignments to
    the same constant:

    >> FOO = "bar"

    => "bar"
    >> FOO = "bar"

    (irb):2: warning: already initialized constant FOO
    => "bar"

    > In the end, it worked out well. My code snippet looks like:
    >
    > # create a function map for the items we want to delete
    > comment = lambda {|key, val| "# #{key}:#{val}" }
    > delete = lambda {|key, val| nil }
    > checkmap = {}
    > @nodelist.each do |n|
    > key = "#{n.name}:#{n.ip}"
    > checkmap[key] = (@remove) ? delete : comment
    > end
    >
    > Where I now have the option of making the deletion permanent or just
    > commenting it out. Which is perfect for my application.


    Fine.

    robert
    Robert Klemme, Aug 22, 2004
    #8
  9. Mark Probert

    Mark Probert Guest

    "Robert Klemme" <> wrote in
    news::

    >
    > Then you got the scoping wrong.
    >

    You are correct. Thank you for the clarification.

    -mark.
    Mark Probert, Aug 22, 2004
    #9
    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. Joe Wright
    Replies:
    0
    Views:
    511
    Joe Wright
    Jul 27, 2003
  2. Murali
    Replies:
    2
    Views:
    559
    Jerry Coffin
    Mar 9, 2006
  3. WuyaSea Operator
    Replies:
    48
    Views:
    1,467
    Ben Phillips
    Sep 24, 2007
  4. Lew
    Replies:
    0
    Views:
    404
  5. blnukem
    Replies:
    7
    Views:
    117
    Joe Smith
    Sep 6, 2004
Loading...

Share This Page