简体   繁体   中英

Ruby: How to make custom DSL accept variables

I have this class:

class Items
    def initialize &block
      (block.arity < 1 ?  (instance_eval &block) : block.call(self)) if block_given?
    end

    def button_id button_id=nil
      unless @button_id.present?
        raise "button_id must be supplied" if button_id.nil?
        @button_id = button_id
      end
      @button_id
    end
end

Now, when I do this it works:

Items.new do
   button_id 1
end

But when I do this, it fails because I think it is not on the same scope:

@button = Button.find(params[:button_id]
Items.new do
   button_id @button.id
end

How can fix this to take arguments outside the scope?

Thanks!

Try this:

class Items
  def self.dsl
    new.tap do |item|
      yield item
    end
  end

  def button_id(button_id)
    @button_id = button_id
  end
end

@button = Button.find(params[:button_id])

item = Items.dsl do |item|
  item.button_id(@button.id)
end

puts item.inspect

Turns out all I needed to do was to pass the arguments to the block like this:

Items.new do |item|
   item.button_id @button.id
end

Less beautiful DSL but works.

I don't think this is the right use case of DSL, when you can simply assign the attributes by arguments.

class Item
  attr_accessor: :button_id

  def initialize(args)
    button_id = args[:button_id]
  end
end

Another problem is in your usage. The instance would be of little value if you don't assign it to a variable

item = Item.new button_id: button_id

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