首页 > 解决方案 > 限制命名空间内定义的规则范围

问题描述

我有以下 Rakefile(这是一个简化的示例):

namespace :green do
  rule(/^build:/) do |t|
    puts "[green] #{t}"
  end

  task :start do
    puts '[green] start'
  end

  task run: ['build:app', :start]
end

namespace :blue do
  rule(/^build:/) do |t|
    puts "[blue] #{t}"
  end

  task :start do
    puts '[blue] start'
  end

  task run: ['build:app', :start]
end

我希望每个“构建”规则仅适用于定义它的命名空间。换句话说,这就是我想要发生的事情:

$ rake blue:run
[blue] build:app
[blue] start

但实际发生的是这样的(使用 Rake 12.3.1):

$ rake blue:run
[green] build:app
[blue] start

有没有办法限制“构建”规则的范围,以便无法从“蓝色”命名空间访问“绿色”命名空间中定义的规则?

标签: rubyrake

解决方案


看起来 Rake 本身并不支持这一点。任务的范围限定在它们定义的命名空间中(通过添加范围路径作为前缀),但规则没有这样的前缀。

我能够通过猴子修补 Rake 来使其工作,这并不理想:

# Monkey-patch rake
module Rake
  module TaskManager
    # Copied from rake 12.3.1 and enhanced for scoped rules
    def lookup_in_scope(name, scope)
      loop do
        tn = scope.path_with_task_name(name)
        task = @tasks[tn]
        return task if task
        break if scope.empty?
        # BEGIN ADDED LINES
        task = enhance_with_matching_rule(tn)
        return task if task
        # END ADDED LINES
        scope = scope.tail
      end
      nil
    end
  end

  module DSL
    # Create a rule inside a namespace scope
    def scoped_rule(name, &block)
      pattern = "^#{Rake.application.current_scope.path}:#{name}:"
      Rake.application.create_rule(Regexp.new(pattern), &block)
    end
  end
end

namespace :green do
  scoped_rule :build do |t|
    puts t
  end

  task :start do |t|
    puts t
  end

  task run: ['build:app', :start]
end

namespace :blue do
  scoped_rule :build do |t|
    puts t
  end

  task :start do |t|
    puts t
  end

  task run: ['build:app', :start]
end

输出:

$ rake green:run
green:build:app
green:start
$ rake blue:run
blue:build:app
blue:start

推荐阅读