为什么我的define_method不起作用?

时间:2014-09-30 05:11:28

标签: ruby-on-rails ruby metaprogramming

我的Designer课程中有两种方法(在我的rails应用程序中):

  def add_specialty(specialty)
    specialty_list.add(specialty)
    save
  end

  def add_qualification(qualification)
    qualification_list.add(qualification)
    save
  end

以下是我传给他们的规格:

  context 'adding specialties' do
    it "can add a new specialty" do
      expect { designer.add_specialty("interior design") }.to change {designer.specialty_list.count}.by(1)
      expect(designer.specialty_list).to include("interior design")
    end
  end

  context 'adding qualifications' do
    it "can add a new qualification" do
      expect { designer.add_qualification("architect") }.to change {designer.qualification_list.count}.by(1)
      expect(designer.qualification_list).to include("architect")
    end
  end

现在我想重构这个实现:

  ["specialty", "qualification"].each do |attr|
    define_method("add_#{attr}") do |arg|
      "#{attr}_list".add(arg)
      save
    end
  end

这失败了。我失败了:

  1) Designer adding qualifications can add a new qualification
     Failure/Error: expect { designer.add_qualification("architect") }.to change {designer.qualification_list.count}.by(1)
     NoMethodError:
       undefined method `add' for "qualification_list":String
     # ./app/models/designer.rb:93:in `block (2 levels) in <class:Designer>'
     # ./spec/models/designer_spec.rb:79:in `block (4 levels) in <top (required)>'
     # ./spec/models/designer_spec.rb:79:in `block (3 levels) in <top (required)>'
     # -e:1:in `<main>'

  2) Designer adding specialties can add a new specialty
     Failure/Error: expect { designer.add_specialty("interior design") }.to change {designer.specialty_list.count}.by(1)
     NoMethodError:
       undefined method `add' for "specialty_list":String
     # ./app/models/designer.rb:93:in `block (2 levels) in <class:Designer>'
     # ./spec/models/designer_spec.rb:72:in `block (4 levels) in <top (required)>'
     # ./spec/models/designer_spec.rb:72:in `block (3 levels) in <top (required)>'
     # -e:1:in `<main>'

我的define_method实施中我做错了什么?

2 个答案:

答案 0 :(得分:1)

"#{attr}_list"本身只是字符串"specialty_list""qualification_list",字符串没有add方法。我想你想要send specialty_list方法,例如

%w{ specialty qualification }.each do |attr|
  define_method("add_#{attr}") do |arg|
    send("#{attr}_list").add(arg)
    save
  end
end

答案 1 :(得分:0)

好的:我的工作方式如下:

  ["specialty", "qualification"].each do |attr|
    define_method("add_#{attr}") do |arg|
      instance_eval("#{attr}_list").send(:add, arg)
      save
    end
  end

不确定为什么会这样,或者是否正确的方法。有人愿意为更好的理解做出贡献吗?