Idiomatic ruby version of this code?

Discussion in 'Ruby' started by Brock Weaver, Aug 18, 2005.

  1. Brock Weaver

    Brock Weaver Guest

    Showing off ruby to a coworker, and I want to emphasize how succinct yet
    clear it can be. So I want to rename all .mp3 files to .temp, or vice vers=
    a
    in the current directory -- in the shortest LOC *that you would actually wr=
    ite*;
    not the "here's a one-liner nobody in their right mind would every write if
    they had to maintain it".

    Here's my first solution:

    Dir.new("./").each do |file|
    =09if file.match(/mp3$/)
    =09=09File.rename(file, file.gsub(/mp3$/, 'temp'))
    =09elsif file.match(/temp$/)
    =09=09File.rename(file, file.gsub(/temp$/, 'mp3'))
    =09end
    end

    Note you can NOT do the following, as it renames mp3 to temp,
    then immediately renames that same file back to mp3...

    Dir.new("./").each do |file|
    =09File.rename(file, file.gsub(/mp3$/, 'temp')) if file.match(/mp3$/)
    =09File.rename(file, file.gsub(/temp$/, 'mp3')) if file.match(/temp$/)
    end

    Any ideas?

    --=20
    Brock Weaver
    [OBC]Technique
    Brock Weaver, Aug 18, 2005
    #1
    1. Advertising

  2. On 18/08/05, Brock Weaver <> wrote:
    > Showing off ruby to a coworker, and I want to emphasize how succinct yet
    > clear it can be. So I want to rename all .mp3 files to .temp, or vice ve=

    rsa
    > in the current directory -- in the shortest LOC *that you would actually =

    write*;
    > not the "here's a one-liner nobody in their right mind would every write =

    if
    > they had to maintain it".
    >=20
    > Here's my first solution:
    >=20
    > Dir.new("./").each do |file|
    > if file.match(/mp3$/)
    > File.rename(file, file.gsub(/mp3$/, 'temp'))
    > elsif file.match(/temp$/)
    > File.rename(file, file.gsub(/temp$/, 'mp3'))
    > end
    > end
    >=20
    > Note you can NOT do the following, as it renames mp3 to temp,
    > then immediately renames that same file back to mp3...
    >=20
    > Dir.new("./").each do |file|
    > File.rename(file, file.gsub(/mp3$/, 'temp')) if file.match(/mp3$/=

    )
    > File.rename(file, file.gsub(/temp$/, 'mp3')) if file.match(/temp$=

    /)
    > end
    >=20
    > Any ideas?
    >=20
    > --
    > Brock Weaver
    > [OBC]Technique
    >=20
    >=20


    If it where a one time solution, I'd do something like this. Though
    maybe I'd extract the file endings into variables, to make it easier
    to change them.

    mp3 =3D Dir['*.mp3']
    temp =3D Dir['*.temp']
    mp3.each do | fn | File.rename(fn, File.basename(fn, '.mp3') + '.temp') end
    temp.each do | fn | File.rename(fn, File.basename(fn, '.temp') + '.mp3') en=
    d

    regards,

    Brian

    --=20
    http://ruby.brian-schroeder.de/

    Stringed instrument chords: http://chordlist.brian-schroeder.de/
    Brian Schröder, Aug 18, 2005
    #2
    1. Advertising

  3. Brock Weaver

    Ben Giddings Guest

    def switch_endings(current_ending, new_ending)
    files = Dir.glob("*.#{current_ending}") do |filename|
    File.rename(filename, filename.gsub(/\.#{current_ending}$/,
    ".#{new_ending}"))
    end
    end

    As for doing both renames at the same time (i.e. swapping the various
    endings) you can't really do that without using a third temporary ending,
    so you could do:

    switch_endings("mp3", "mp3foo")
    switch_endings("temp", "mp3")
    switch_endings("mp3foo", "temp")

    Ben
    Ben Giddings, Aug 18, 2005
    #3
  4. Brock Weaver wrote:
    > Showing off ruby to a coworker, and I want to emphasize how succinct yet
    > clear it can be. So I want to rename all .mp3 files to .temp, or vice versa
    > in the current directory -- in the shortest LOC *that you would actually write*;
    > not the "here's a one-liner nobody in their right mind would every write if
    > they had to maintain it".
    >
    > Here's my first solution:
    >
    > Dir.new("./").each do |file|
    > if file.match(/mp3$/)
    > File.rename(file, file.gsub(/mp3$/, 'temp'))
    > elsif file.match(/temp$/)
    > File.rename(file, file.gsub(/temp$/, 'mp3'))
    > end
    > end


    Dir["*.mp3"].each{ |file|
    new_name = File.basename(file, ".mp3") + ".temp"
    File.rename(file, new_name)
    }

    Regards,

    Dan
    Daniel Berger, Aug 18, 2005
    #4
  5. Brock Weaver

    Zach Dennis Guest

    Brock Weaver wrote:
    > Showing off ruby to a coworker, and I want to emphasize how succinct yet
    > clear it can be. So I want to rename all .mp3 files to .temp, or vice versa
    > in the current directory -- in the shortest LOC *that you would actually write*;
    > not the "here's a one-liner nobody in their right mind would every write if
    > they had to maintain it".
    >
    > Here's my first solution:
    >
    > Dir.new("./").each do |file|
    > if file.match(/mp3$/)
    > File.rename(file, file.gsub(/mp3$/, 'temp'))
    > elsif file.match(/temp$/)
    > File.rename(file, file.gsub(/temp$/, 'mp3'))
    > end
    > end
    >
    > Note you can NOT do the following, as it renames mp3 to temp,
    > then immediately renames that same file back to mp3...
    >
    > Dir.new("./").each do |file|
    > File.rename(file, file.gsub(/mp3$/, 'temp')) if file.match(/mp3$/)
    > File.rename(file, file.gsub(/temp$/, 'mp3')) if file.match(/temp$/)
    > end
    >
    > Any ideas?
    >


    arr1, arr2 = Dir["*.mp3"], Dir["*.temp"]
    arr1.each { |f| File.rename( f, f.sub( /mp3$/, 'temp' ) ) }
    arr2.each { |f| File.rename( f, f.sub( /temp$/, 'mp3' ) ) }

    Zach
    Zach Dennis, Aug 18, 2005
    #5
  6. Brock Weaver

    Brock Weaver Guest

    Perfect! Thank you for your quick response. I decided to take the
    shortcut of parallel variable assignment too, so I'm violating my own
    rule a little I guess.

    Anyway, thanks Brian.

    On 8/18/05, Brian Schr=F6der <> wrote:
    > On 18/08/05, Brock Weaver <> wrote:
    > > Showing off ruby to a coworker, and I want to emphasize how succinct ye=

    t
    > > clear it can be. So I want to rename all .mp3 files to .temp, or vice =

    versa
    > > in the current directory -- in the shortest LOC *that you would actuall=

    y write*;
    > > not the "here's a one-liner nobody in their right mind would every writ=

    e if
    > > they had to maintain it".
    > >
    > > Here's my first solution:
    > >
    > > Dir.new("./").each do |file|
    > > if file.match(/mp3$/)
    > > File.rename(file, file.gsub(/mp3$/, 'temp'))
    > > elsif file.match(/temp$/)
    > > File.rename(file, file.gsub(/temp$/, 'mp3'))
    > > end
    > > end
    > >
    > > Note you can NOT do the following, as it renames mp3 to temp,
    > > then immediately renames that same file back to mp3...
    > >
    > > Dir.new("./").each do |file|
    > > File.rename(file, file.gsub(/mp3$/, 'temp')) if file.match(/mp3=

    $/)
    > > File.rename(file, file.gsub(/temp$/, 'mp3')) if file.match(/tem=

    p$/)
    > > end
    > >
    > > Any ideas?
    > >
    > > --
    > > Brock Weaver
    > > [OBC]Technique
    > >
    > >

    >=20
    > If it where a one time solution, I'd do something like this. Though
    > maybe I'd extract the file endings into variables, to make it easier
    > to change them.
    >=20
    > mp3 =3D Dir['*.mp3']
    > temp =3D Dir['*.temp']
    > mp3.each do | fn | File.rename(fn, File.basename(fn, '.mp3') + '.temp') e=

    nd
    > temp.each do | fn | File.rename(fn, File.basename(fn, '.temp') + '.mp3') =

    end
    >=20
    > regards,
    >=20
    > Brian
    >=20
    > --
    > http://ruby.brian-schroeder.de/
    >=20
    > Stringed instrument chords: http://chordlist.brian-schroeder.de/
    >=20
    >=20



    --=20
    Brock Weaver
    [OBC]Technique
    Brock Weaver, Aug 18, 2005
    #6
  7. Brock Weaver wrote:
    > Here's my first solution:
    >
    > Dir.new("./").each do |file|
    > if file.match(/mp3$/)
    > File.rename(file, file.gsub(/mp3$/, 'temp'))
    > elsif file.match(/temp$/)
    > File.rename(file, file.gsub(/temp$/, 'mp3'))
    > end
    > end
    >

    You could use the tertiary operator to switch file names, but the (exp
    .. and .. or) is also nice for this kind of swapping thing.

    Dir["*.{temp,mp3}"].each do |file|
    File.rename( file, file.gsub( /\w+$/ ) { |ext| ext == 'mp3' and
    'temp' or 'mp3' } )
    end

    If you don't want your extensions hardcoded everywhere, use an array:

    exts = ['temp', 'mp3']
    Dir["*.{#{exts.join ','}}"].each do |file|
    File.rename( file, file.gsub( /(\w+)$/ ) { exts.detect { |x| x != $1
    } } )
    end

    _why
    why the lucky stiff, Aug 18, 2005
    #7
  8. why the lucky stiff wrote:
    > Brock Weaver wrote:
    >
    >> Here's my first solution:
    >>
    >> Dir.new("./").each do |file|
    >> if file.match(/mp3$/)
    >> File.rename(file, file.gsub(/mp3$/, 'temp'))
    >> elsif file.match(/temp$/)
    >> File.rename(file, file.gsub(/temp$/, 'mp3'))
    >> end
    >> end
    >>

    >
    > You could use the tertiary operator to switch file names, but the (exp
    > .. and .. or) is also nice for this kind of swapping thing.
    >
    > Dir["*.{temp,mp3}"].each do |file|
    > File.rename( file, file.gsub( /\w+$/ ) { |ext| ext == 'mp3' and
    > 'temp' or 'mp3' } )
    > end
    >
    > If you don't want your extensions hardcoded everywhere, use an array:
    >
    > exts = ['temp', 'mp3']
    > Dir["*.{#{exts.join ','}}"].each do |file|
    > File.rename( file, file.gsub( /(\w+)$/ ) { exts.detect { |x| x != $1
    > } } )
    > end
    >
    > _why
    >
    >


    gsub and backreferences? Why take that approach when File.basename is
    available?

    def switch(old, new)
    Dir["*.#{old}"].each{ |file|
    new_name = File.basename(file, old) + "." + new
    File.rename(file, new_name)
    }
    end

    Regards,

    Dan
    Daniel Berger, Aug 18, 2005
    #8
  9. Brock Weaver

    Phrogz Guest

    Slightly more DRY (and yes, I'd use this myself):

    mappings = { '.mp3' => '.temp', '.temp' => '.mp3' }
    mappings.each{ |orig_ext, new_ext|
    Dir[ "*#{orig_ext}" ].each{ |filename|
    File.rename( filename, File.basename( filename, orig_ext ) +
    new_ext )
    }
    }
    Phrogz, Aug 18, 2005
    #9
  10. Brock Weaver

    Pit Capitain Guest

    Brock Weaver schrieb:
    > Perfect! Thank you for your quick response. I decided to take the
    > shortcut of parallel variable assignment too, so I'm violating my own
    > rule a little I guess.


    Note that all the offered solutions including your original version
    don't work if there are two files named "x.mp3" and "x.temp".

    Regards,
    Pit
    Pit Capitain, Aug 18, 2005
    #10
  11. Pit Capitain wrote:
    > Brock Weaver schrieb:
    >
    >> Perfect! Thank you for your quick response. I decided to take the
    >> shortcut of parallel variable assignment too, so I'm violating my own
    >> rule a little I guess.

    >
    >
    > Note that all the offered solutions including your original version
    > don't work if there are two files named "x.mp3" and "x.temp".
    >
    > Regards,
    > Pit
    >
    >


    def switch(old, new)
    Dir["*.#{old}"].each{ |file|
    new_name = File.basename(file, old) + "." + new
    File.rename(file, new_name) unless File.exists?(new_name)
    }
    end

    Regards,

    Dan
    Daniel Berger, Aug 18, 2005
    #11
  12. Brock Weaver

    Pit Capitain Guest

    Pit Capitain schrieb:
    > Brock Weaver schrieb:
    >
    >> Perfect! Thank you for your quick response. I decided to take the
    >> shortcut of parallel variable assignment too, so I'm violating my own
    >> rule a little I guess.

    >
    > Note that all the offered solutions including your original version
    > don't work if there are two files named "x.mp3" and "x.temp".


    Sorry, Ben's version works if you choose a non-existing temporary ending.

    Regards,
    Pit
    Pit Capitain, Aug 18, 2005
    #12
  13. Daniel Berger wrote:
    > gsub and backreferences? Why take that approach when File.basename is
    > available?
    >
    > def switch(old, new)
    > Dir["*.#{old}"].each{ |file|
    > new_name = File.basename(file, old) + "." + new
    > File.rename(file, new_name)
    > }
    > end

    You understand he's trying to swap extensions, right? (I think?) Well,
    you've got to get the extension name. And File.extname( file )[1..-1]
    is ugly.

    I always go for short and dirty. I steal second base!

    _why
    why the lucky stiff, Aug 18, 2005
    #13
  14. why the lucky stiff wrote:
    > Daniel Berger wrote:
    >
    >> gsub and backreferences? Why take that approach when File.basename is
    >> available?
    >>
    >> def switch(old, new)
    >> Dir["*.#{old}"].each{ |file|
    >> new_name = File.basename(file, old) + "." + new
    >> File.rename(file, new_name)
    >> }
    >> end

    >
    > You understand he's trying to swap extensions, right? (I think?) Well,
    > you've got to get the extension name. And File.extname( file )[1..-1]
    > is ugly.
    >
    > I always go for short and dirty. I steal second base!
    >
    > _why


    Oh, he wants to switch both. Hm, ok. Still no gsub or backreferences:

    djberge@~/programming/ruby/temp-670>cat switcher.rb
    Dir["*.{mp3,temp}"].each{ |file|
    ext = File.extname(file) == ".mp3" ? ".temp" : ".mp3"
    new_name = File.basename(file, ".*") + ext
    File.rename(file, new_name)
    }
    djberge@~/programming/ruby/temp-671>ls -l
    total 2
    -rw-r--r-- 1 djberge staff 0 Aug 18 13:08 bar.temp
    -rw-r--r-- 1 djberge staff 0 Aug 18 13:08 baz.mp3
    -rw-r--r-- 1 djberge staff 0 Aug 18 13:09 blah.nada
    -rw-r--r-- 1 djberge staff 0 Aug 18 13:08 foo.mp3
    -rw-r--r-- 1 djberge staff 169 Aug 18 13:15 switcher.rb
    djberge@~/programming/ruby/temp-672>ruby switcher.rb
    djberge@~/programming/ruby/temp-673>ls -l
    total 2
    -rw-r--r-- 1 djberge staff 0 Aug 18 13:08 bar.mp3
    -rw-r--r-- 1 djberge staff 0 Aug 18 13:08 baz.temp
    -rw-r--r-- 1 djberge staff 0 Aug 18 13:09 blah.nada
    -rw-r--r-- 1 djberge staff 0 Aug 18 13:08 foo.temp
    -rw-r--r-- 1 djberge staff 169 Aug 18 13:15 switcher.rb
    Daniel Berger, Aug 18, 2005
    #14
  15. Brock Weaver

    Brock Weaver Guest

    Thank you all for your replies. I've chosen to use a cross between
    Zach's and Brian's implementations.

    arr1, arr2 =3D Dir["*.mp3"], Dir["*.temp"]
    arr1.each do | fn | File.rename(fn, File.basename(fn, '.mp3') + '.temp') en=
    d
    arr2.each do | fn | File.rename(fn, File.basename(fn, '.temp') + '.mp3') en=
    d

    Zach's is both concise and clear -- I don't need flexibility per se;
    hardcoding extensions is fine. Brian's use of File.basename instead
    of regex made the script run roughly 5x faster on my XP box (I'm
    renaming about 2,500 files).


    On 8/18/05, Daniel Berger <> wrote:
    > why the lucky stiff wrote:
    > > Daniel Berger wrote:
    > >
    > >> gsub and backreferences? Why take that approach when File.basename is
    > >> available?
    > >>
    > >> def switch(old, new)
    > >> Dir["*.#{old}"].each{ |file|
    > >> new_name =3D File.basename(file, old) + "." + new
    > >> File.rename(file, new_name)
    > >> }
    > >> end

    > >
    > > You understand he's trying to swap extensions, right? (I think?) Well=

    ,
    > > you've got to get the extension name. And File.extname( file )[1..-1]
    > > is ugly.
    > >
    > > I always go for short and dirty. I steal second base!
    > >
    > > _why

    >=20
    > Oh, he wants to switch both. Hm, ok. Still no gsub or backreferences:
    >=20
    > djberge@~/programming/ruby/temp-670>cat switcher.rb
    > Dir["*.{mp3,temp}"].each{ |file|
    > ext =3D File.extname(file) =3D=3D ".mp3" ? ".temp" : ".mp3"
    > new_name =3D File.basename(file, ".*") + ext
    > File.rename(file, new_name)
    > }
    > djberge@~/programming/ruby/temp-671>ls -l
    > total 2
    > -rw-r--r-- 1 djberge staff 0 Aug 18 13:08 bar.temp
    > -rw-r--r-- 1 djberge staff 0 Aug 18 13:08 baz.mp3
    > -rw-r--r-- 1 djberge staff 0 Aug 18 13:09 blah.nada
    > -rw-r--r-- 1 djberge staff 0 Aug 18 13:08 foo.mp3
    > -rw-r--r-- 1 djberge staff 169 Aug 18 13:15 switcher.rb
    > djberge@~/programming/ruby/temp-672>ruby switcher.rb
    > djberge@~/programming/ruby/temp-673>ls -l
    > total 2
    > -rw-r--r-- 1 djberge staff 0 Aug 18 13:08 bar.mp3
    > -rw-r--r-- 1 djberge staff 0 Aug 18 13:08 baz.temp
    > -rw-r--r-- 1 djberge staff 0 Aug 18 13:09 blah.nada
    > -rw-r--r-- 1 djberge staff 0 Aug 18 13:08 foo.temp
    > -rw-r--r-- 1 djberge staff 169 Aug 18 13:15 switcher.rb
    >=20
    >=20



    --=20
    Brock Weaver
    [OBC]Technique
    Brock Weaver, Aug 18, 2005
    #15
  16. Brock Weaver

    Mark Probert Guest

    Hi ..

    On Fri, 2005-08-19 at 01:24 +0900, Brock Weaver wrote:
    > Showing off ruby to a coworker, and I want to emphasize how succinct yet
    > clear it can be. ...
    > Here's my first solution:
    >
    > ...
    > Any ideas?
    >

    I know that this is kind of heretical, but in a situation like this, I'd
    rather use a shell script (I tend to inexpertly use zsh). In this case,
    the simple solution is something like:

    $ a=(*.mp3)
    $ for f in $a; do
    mv $f `basename $f .mp3`.temp
    done

    Pretty easy to read (I'd say more so than the Ruby, IMO) and almost a
    one-liner. An easy idiom to remember, no editing required. If you need
    to reverse it, then up-arrow and change the lines (or use another
    variable, if needed).

    However, if I had to do this as part of a larger project done in Ruby,
    then I would have no hesitation to take the Ruby route (and I have done
    almost exactly this at times).

    My $0.02

    Regards,


    --
    -mark. (probertm at acm dot org)
    Mark Probert, Aug 18, 2005
    #16
  17. Brock Weaver

    pat eyler Guest

    Sorry for being late to the party (and wildly off topic for a ruby-talk thr=
    ead).

    On 8/18/05, Mark Probert <> wrote:
    > Hi ..
    >=20
    > I know that this is kind of heretical, but in a situation like this, I'd
    > rather use a shell script (I tend to inexpertly use zsh). In this case,
    > the simple solution is something like:
    >=20
    > $ a=3D(*.mp3)
    > $ for f in $a; do
    > mv $f `basename $f .mp3`.temp
    > done


    (BTW, my local zsh doesn't like basename.)

    This doesn't really answer the initial requirement though, here's
    an idiomatic bash version ... although the variable mangling's a
    neat trick, a lot of folks here will probably find it too much like
    line noise.

    MP3=3D`echo *.mp3`
    TEMP=3D`echo *.temp`
    for file in $MP3; do mv $file ${file%.mp3}.temp; done
    for file in $TEMP; do mv $file ${file%.temp}.mp3; done

    it's still not safe in terms of overwriting existing files, and there's
    no question in my mind that the Ruby versions are prettier.

    >=20
    > Pretty easy to read (I'd say more so than the Ruby, IMO) and almost a
    > one-liner. An easy idiom to remember, no editing required. If you need
    > to reverse it, then up-arrow and change the lines (or use another
    > variable, if needed).
    >=20
    > However, if I had to do this as part of a larger project done in Ruby,
    > then I would have no hesitation to take the Ruby route (and I have done
    > almost exactly this at times).
    >=20
    > My $0.02
    >=20
    > Regards,
    >=20
    >=20
    > --
    > -mark. (probertm at acm dot org)
    >=20
    >=20
    >=20



    --=20
    thanks,
    -pate
    -------------------------
    We are often unable to tell people what they need to know, because=20
    they want to know something else, and would therefore only=20
    misunderstand what we said
    - the Raven (George MacDonald, Lilith)
    pat eyler, Aug 23, 2005
    #17
    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. Nathan Harmston

    Programming Idiomatic Code

    Nathan Harmston, Jul 3, 2007, in forum: Python
    Replies:
    9
    Views:
    331
    Bruno Desthuilliers
    Jul 4, 2007
  2. V Green
    Replies:
    0
    Views:
    809
    V Green
    Feb 5, 2008
  3. PA Bear [MS MVP]
    Replies:
    0
    Views:
    911
    PA Bear [MS MVP]
    Feb 5, 2008
  4. Iwan van der Kleyn
    Replies:
    5
    Views:
    147
    James Edward Gray II
    Nov 23, 2004
  5. Zed A. Shaw
    Replies:
    2
    Views:
    101
    Zed A. Shaw
    Apr 23, 2005
Loading...

Share This Page