【问题标题】:How do you make ruby variables and methods in scope using Thor Templates?如何使用 Thor 模板在范围内创建 ruby​​ 变量和方法?
【发布时间】:2011-07-08 20:12:30
【问题描述】:

我正在尝试使用 Thor::Actions 模板方法生成一些 C++ 测试文件模板,但 erb 一直告诉我我有未定义的变量和方法。

这是调用代码:

def test (name, dir)
  template "tasks/templates/new_test_file", "src/#{dir}/test/#{name}Test.cpp"
  insert_into_file "src/#{dir}/test/CMakeLists.txt", 
       "#{dir}/test/#{name}Test ", :after => "set(Local "
end

这是模板:

<% test_name = name + "Test" %>
#include <gtest/gtest.h>
#include "<%= dir %>/<%= name %>.h"

class <%= test_name %> : public testing::Test {
protected:
    <%= test_name %> () {}
    ~<%= test_name %> () {}
    virtual void SetUp () {}
    virtual void TearDown () {}
};

// Don't forget to write your tests before you write your implementation!
TEST_F (<%= test_name %>, Sample) {
   ASSERT_EQ(1 + 1, 3);
}

我必须怎么做才能将 name 和 dir 纳入范围?我有更复杂的模板,我也需要这个功能。

【问题讨论】:

    标签: ruby templates erb thor


    【解决方案1】:

    我知道你已经解决了这个问题,但我发布这个答案以防其他人出现在寻找你所问问题的解决方案(就像 一样)。

    在#test所属的类中,创建一个attr_accessor,然后在调用模板的同一个方法中设置它的值。

    class MyGenerator < Thor
    
      attr_accessor :name, :dir
    
      def test (name, dir)
        self.name = name
        self.dir = dir
        template "tasks/templates/new_test_file", "src/#{dir}/test/#{name}Test.cpp"
      end
    end
    

    注意:如果您使用#invoke 链接方法,那么每次调用都会使用该类的新实例。因此,您必须使用模板调用在方法中设置实例变量。例如,以下行不通。

    class MyGenerator < Thor
    
      attr_accessor :name
    
      def one (name)
        self.name = name
        invoke :two
      end
    
      def two (name)
        # by the time we get here, this is another instance of MyGenerator, so @name is empty
        template "tasks/templates/new_test_file", "src/#{name}Test.cpp"
      end
    
    end
    

    你应该把self.name = name 放在#two 里面

    为了制作生成器,如果你从 Thor::Group 继承,所有方法都会按顺序调用,并且会为你设置 attr_accessor,并为每个方法设置实例变量。就我而言,我不得不使用 Invocations 而不是 Thor::Group,因为我无法让 Thor::Group 类被识别为可执行文件的子命令。

    【讨论】:

      【解决方案2】:

      ERB 使用 ruby​​ 的绑定对象来检索您想要的变量。 ruby 中的每个对象都有一个绑定,但默认情况下,对绑定的访问仅限于对象本身。您可以解决这个问题,并将您希望的绑定传递到您的 ERB 模板中,方法是创建一个公开对象绑定的模块,如下所示:

      module GetBinding
        def get_binding
          binding
        end
      end
      

      然后您需要使用此模块扩展具有所需变量的任何对象。

      something.extend GetBinding

      并将该对象的绑定传递给erb

      something.extend GetBinding
      some_binding = something.get_binding
      
      erb = ERB.new template
      output = erb.result(some_binding)
      

      有关使用 ERB 的完整示例,请参阅此 wiki 页面了解我的一个项目:https://github.com/derickbailey/Albacore/wiki/Custom-Tasks

      【讨论】:

      • 你的回答并没有直接解决它,但它帮助我弄清楚我无法访问我需要的值,因为它们没有绑定在类中,只是在方法中。让它们成为对象属性就可以了。
      猜你喜欢
      • 2017-03-16
      • 1970-01-01
      • 2016-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-22
      相关资源
      最近更新 更多