rake icon indicating copy to clipboard operation
rake copied to clipboard

Add regexp capturing in rules

Open kndoo opened this issue 6 years ago • 0 comments

This PR allows regexp capturing and backreferencing to task_pattern in rules.

rule task_pattern => source do |task|
  # action
end
  • Regexp.last_match ($~) will be set in Procs at both source and action.
    • Other last_match related special variables, such as $1, $&, $`, and $', will also be set.
  • If source is a String, it may contain backreferences to task_pattern by same format as String#sub.

Here are some examples:

rule /^(.*)-(\d+)x(\d+)\.png$/ => [     # regexp with capture groups
  proc { "#{$1}.svg" }                  # capture variable in a source proc
  # or '\1.svg'                         # backreference in a source string
] do |task|
  basename, width, height = $1, $2, $3  # capture variables in an action proc
  sh "convert #{basename}.svg -resize #{width}x#{height} #{basename}-#{width}x#{height}.png"
end

This can make icon-32x32.png from icon.svg.

rule /-(?<width>\d+)x(?<height>\d+).(?<ext>png|jpg)$/ => [ # regexp with named capture groups
  proc { "#{$`}.#{$~[:ext]}" }                             # matchdata in a source proc
  # or '\`.\k<ext>'                                        # named backreference in a source string
  # or '.\k<ext>'                                          # file extension replacement (already implemented in the current master branch)
] do |task|
  sh "convert #{task.source} -resize #{$~[:width]}x#{$~[:height]} #{task.name}" # accessing named capture groups
end
rule %r{^build/(?<basename>.*?)\.html\.(?<lang>.*?)$} => [
  'doc/\k<lang>/\k<basename>.md'                           # named backreference in a source string
] do
  sh "pandoc -o #{task.name} #{task.source}"
end

This can make build/index.html.en from doc/en/index.md.

Although it passes all the tests, it will break backward compatibility in some cases:

  • Procs that refer to Regexp.last_match related variables assigned outside the rule block
  • String sources that include backslashes (directory separator in Windows?)

Former case example:

options.match(/^CFLAGS=(.*)$/)  # extract a parameter from a multiline text

rule '.o' => '.c' do |task|
  sh "gcc #{$1} -c -o #{task.name} #{task.source}   # $1 will be replaced to nil
end

Any feedback would be appreciated. Thanks.

kndoo avatar Apr 30 '18 06:04 kndoo