如何在Ruby中创建和使用由字符串值动态命名的变量? 关于发送:警告!

问题描述

我正在使用SitePrism创建一些POM测试。我的页面类别之一如下:

class HomePage < SitePrism::Page
    set_url '/index.html'
    element :red_colour_cell,"div[id='colour-cell-red']"
    element :green_colour_cell,"div[id='colour-cell-green']"
    element :blue_colour_cell,"div[id='colour-cell-blue']"

    def click_colour_cell(colour)
        case colour
            when 'red'
                has_red_colour_cell?
                red_colour_cell.click
            when 'green'
                has_green_colour_cell?
                green_colour_cell.click
            when 'blue'
                has_blue_colour_cell?
                blue_colour_cell.click
        end
    end
end

方法click_colour_cell()从调用此方法的Capybara测试步骤获取其字符串值。 如果将来我需要创建其他类似的方法,那么用这么多的大小写开关来确定代码流可能会变得很繁琐和笨拙。

是否可以通过某种方式创建由另一个变量的字符串值动态命名的变量?例如,我想为click_colour_cell()做一些类似于以下的事情:

    def click_colour_cell(colour)
        has_@colour_colour_cell?
        @colour_colour_cell.click
    end

其中@colour表示传递的值colour的值,将由Ruby解释:

    def click_colour_cell('blue')
        has_blue_colour_cell?
        blue_colour_cell.click
    end

这不是用于什么实例变量的吗?我尝试了上述建议作为解决方案,但收到了模棱两可的错误:

syntax error,unexpected end,expecting ':'
    end
    ^~~ (SyntaxError)

如果它是我需要使用的实例变量,那么我不确定是否正确使用了它。如果我还需要使用其他东西,请告知。

解决方法

使用实例变量定义对象的属性。

相反,您可以通过方法send和字符串插值来实现。

请尝试以下操作:

def click_colour_cell(colour)
  send("has_#{colour}_colour_cell?")
  send("#{colour}_colour_cell").click
end

关于发送:

sendObject类(所有类的父类)中定义的方法。

正如documentation所说,它调用由给定的String或Symbol标识的方法。您还可以将参数传递给尝试调用的方法。

在下面的代码段中,send将搜索名为testing的方法并调用它。

class SendTest
  def testing
    puts 'Hey there!'
  end
end


obj = SendTest.new
obj.send("testing")
obj.send(:testing)

输出

Hey there!
Hey there!

在您的情况下,考虑为colour传递的参数为blue

"has_#{colour}_colour_cell?"将返回字符串"has_blue_colour_cell?",并且send将动态调用名为has_blue_colour_cell?的方法。方法blue_colour_cell

也是这样 ,

直接回答您的问题

您可以使用以下方法动态获取/设置实例变量:

instance_variable_get("@build_string_as_you_see_fit")
instance_variable_set("@build_string_as_you_see_fit",value_for_ivar)

但是...

警告!

我认为在此处动态创建变量和/或在send中使用字符串构建方法名称之类的方法是一个坏主意,它将极大地阻碍将来的可维护性。

这样想:每次您看到这样的方法名称:

click_blue_button
click_red_button
click_green_button

这和做的事情是一样的

add_one_to(1)   // instead of 1 + 1,i.e. 1.+(1)
add_two_to(1)   // instead of 1 + 2,i.e. 1.+(2)
add_three_to(1) // instead of 1 + 3,i.e. i.+(3)

您没有将有意义的参数传递给方法,而是将值硬编码为方法名称!继续此操作,最终您的整个代码库将不得不处理已硬编码到方法名称中的“值”。

更好的方法

这是您应该做的:

class HomePage < SitePrism::Page
  set_url '/index.html'

  elements :color_cells,"div[id^='colour-cell-']"

  def click_cell(color)
    cell = color_cells.find_by(id: "colour-cell-#{color}") # just an example,I don't know how to do element queries in site-prism
    cell.click
  end
end

或者如果您必须将它们作为单独的元素:

class HomePage < SitePrism::Page
  set_url '/index.html'

  COLORS = %i[red green blue]

  COLORS.each do |color|
    element :"#{color}_colour_cell","div[id='colour-cell-#{color}']"
  end

  def cell(color:)                 # every other usage should call this method instead
    @cells ||= COLORS.index_with do |color|
      send("#{color}_colour_cell") # do the dynamic `send` in only ONE place
    end
    @cells.fetch(color)
  end
end

home_page.cell(color: :red).click

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...