I have recently written a block of code to perform some limited validation on a series of DocBook XML files. Specifically, this does things like check for uniqueness of "id" attributes (which the tools I use only does within files, not between them), check for broken references, etc.
The chunk of code that prompts this post is the following:
Code:
# Get xml files to validate:
files = Dir.new('.').to_a.collect { |f|
retval = nil # Default: we don't want this file
retval = f if f =~ /\.xml$/ # Actually, we do if it's xml
excluded_files.each { |ef|
retval = nil if f == ef
}
retval
}.compact
This got me thinking, there has to be an easier way. A little digging and consulting with the office Ruby expert led me to find_all, reject and partition. Thus, I could craft a cunning expression that returns either f or nil. While these will work in this case, consider a something like following, for which I can find no more elegant alternative:
Code:
# Perform some filtering and manipulation
def fixfile(file)
return nil if not f =~ /\.xml$/
return f if good_files.include? f
return some_manipulation(f) if bad_files.include? f
end
files = Dir.new('.').to_a.collect { |f| fixfile(f) }.compact
The obvious solution would be to return early from a block, but this is not possible (return in a block is a LocalJumpError). The other obvious (but slightly less elegant) solution would be to pass a function instead of a block. but I don't think there is a way to do this.
Am I fighting the language rather than working with it here? Does Ruby have an idiom for this? Have I completely lost what little bits of my mind remain?