Idiomatic ruby version of this code?

B

Brock Weaver

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
 
B

Brian Schröder

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/
 
B

Ben Giddings

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
 
D

Daniel Berger

Brock said:
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
 
Z

Zach Dennis

Brock said:
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
 
B

Brock Weaver

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.

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?
=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
 
W

why the lucky stiff

Brock said:
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
 
D

Daniel Berger

why said:
Brock said:
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
 
P

Phrogz

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 )
}
}
 
P

Pit Capitain

Brock said:
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
 
D

Daniel Berger

Pit said:
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
 
P

Pit Capitain

Pit said:
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
 
W

why the lucky stiff

Daniel said:
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
 
D

Daniel Berger

why said:
Daniel said:
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
 
B

Brock Weaver

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).


why said:
Daniel said:
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
 
M

Mark Probert

Hi ..

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,
 
P

pat eyler

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

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
 

Members online

Forum statistics

Threads
473,744
Messages
2,569,479
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top