简体   繁体   中英

DSL class initialization having issues with number of arguments using instance_eval or block.call

I am writing a DSL based on a pattern I have successfully used in the past. I thought this would work out of the box but I am getting an error that I just can't figure out, so any help is appreciated.

Here is the method to add a test:

module PPEKit
  module Tests
    def add_test(id, &block)
      @_tests ||= {}
      @_tests[id] = Test.new(id, &block) unless @_tests.include? id
    end
  end
end

Here is the Test class definition:

  module Tests
    class Test
      attr_accessor :id, :description, :conditions, :platforms

      def initialize(id, &block)
        @id = id
        (block.arity < 1 ? (instance_eval(&block)) : block.call(self)) if block_given? # ERROR occurs here
      end
    end
  end

The Tests module is included in a PPEKit::Product class as so:

module PPEKit
  class Product
    include Tests

I am not showing method_missing because the error I am getting happens during the instance_eval call. I have tried initializing the Test object using both types of block arity with the same result:

    add_test :my_test_id do
      description 'my test description'
      conditions  [:minvdd, :maxvdd, :bin1_1300Mhz, :bin2_1200Mhz]
      platforms   [:v93k, :j750]
      meta1       'dkwew'
      meta2       'jkjejkf'
    end

    add_test :my_test_id do |t|
      t.description 'my test description'
      t.conditions  [:minvdd, :maxvdd, :bin1_1300Mhz, :bin2_1200Mhz]
      t.platforms   [:v93k, :j750]
      t.meta1       'dkwew'
      t.meta2       'jkjejkf'
    end

Both of the definitions above give the following error:

    COMPLETE CALL STACK
    -------------------
    wrong number of arguments (given 1, expected 0)
    /users/user/origen/ppekit/lib/ppekit/test_list.rb:6:in `block in instantiate_tests'

Here is a peek at the Test class in pry right before calling instance_eval:

    [1] pry(#<PPEKit::Tests::Test>)> id
    => :my_test_id
    [2] pry(#<PPEKit::Tests::Test>)> self
    => #<PPEKit::Tests::Test:0x002b42673ab158>
    [3] pry(#<PPEKit::Tests::Test>)> cd self
    [4] pry(#<PPEKit::Tests::Test>)> block.arity
    => 0
    [5] pry(#<PPEKit::Tests::Test>)> block
    => #       <Proc:0x002ab7aff4cab8@/users/user/origen/ppekit/lib/ppekit/test_list.rb:5>
    [6] pry(#<PPEKit::Tests::Test>):1> ls
    PPEKit::Tests::Test#methods:
      conditions  conditions=  description  description=  id  id=  method_missing  platforms  platforms=
    self.methods: __pry__
    locals: _  __  _dir_  _ex_  _file_  _in_  _out_  _pry_

Again, thanks in advance.

regards

You don't have description(arg) , only a getter description() and a setter description=(arg) . And so when you do description 'my test description' it calls the getter with an argument it doesn't expect and you get wrong number of arguments (given 1, expected 0) .

In the tutorial they don't use attr_accessor , but regular methods.

You could use description= or change your code:

module PPEKit
  module Tests
    def add_test(id, &block)
      @tests ||= {}
      @tests[id] = Test.new(id, &block)
    end

    class Test
      def initialize(id, &block)
        @id = id
        @description = nil
        block.arity < 1 ? instance_eval(&block) : block.call(self)
      end

      def description(description)
        @description = description
      end
    end
  end
end

include PPEKit::Tests

add_test :create_article do
  description 'creating article'
end

add_test :delete_article do |t|
  t.description 'deleting article'
end

puts @tests
# {:create_article=>#<Test:0x00000000d91ac0 @id=:create_article, @description="creating article">,
#  :delete_article=>#<Test:0x00000000d919d0 @id=:delete_article, @description="deleting article">}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM