1

私は今、約3日間、これに対して頭をぶつけてきました。HTML ページをモデル化し、キュウリのステップ定義にフォーム データを入力する場所を指示するクラスを作成しました。

class FlightSearchPage

  def initialize(browser, page, brand)
    @browser = browser
    @start_url = page

    #Get reference to config file
    config_file = File.join(File.dirname(__FILE__), '..', 'config', 'site_config.yml')

    #Store hash of config values in local variable
    config = YAML.load_file config_file

    @brand = brand #brand is specified by the customer in the features file

    #Define instance variables from the hash keys
    config.each do |k,v|
      instance_variable_set("@#{k}",v)
    end
  end

  def method_missing(sym, *args, &block)
    @browser.send sym, *args, &block
  end

  def page_title
    #Returns contents of <title> tag in current page.
    @browser.title
  end

  def visit
    @browser.goto(@start_url)
  end

  def set_origin(origin)
    self.text_field(@route[:attribute] => @route[:origin]).set origin
  end

  def set_destination(destination)
    self.text_field(@route[:attribute] => @route[:destination]).set destination
  end

  def set_departure_date(outbound)
    self.text_field(@route[:attribute]  => @date[:outgoing_date]).set outbound
  end

  # [...snip]

end

ご覧のとおり、instance_variable_set を使用して参照をオンザフライで保持する変数を作成しました。変数の名前と値は構成ファイルによって提供されます (これは、必ずしも構成ファイルに精通していない人でも編集できるように設計されています)。ルビー)。

残念ながら、これは大きく毛むくじゃらのクラスであり、新しいフィールドを追加するたびにソース コードを編集する必要があります。これは明らかに設計が悪いため、さらに一歩進んで、 define_method を使用して変数名を動的に設定するメソッドと、これが、ここ数晩、午前 4 時まで起きていた原因です。

これは私がやったことです:

require File.expand_path(File.dirname(__FILE__) + '/flight_search_page')

class SetFieldsByType <  FlightSearchPage
  def text_field(config_hash)
    define_method(config_hash) do |data|
      self.text_field(config_hash[:attribute] => config_hash[:origin]).set data
    end
  end
end

新しいフィールドを追加するために必要なことは、YAML ファイルに新しいエントリを追加することだけであり、define_method は cucumber がデータを入力できるようにするメソッドを作成します。

現在、スコープに問題があります。Ruby は、define_method が @browser のメンバーであると認識しています。しかし、私が知りたいのは、これは実現可能ですか? define_method を完全に誤解していますか?

4

2 に答える 2

2

クラス定義の外でrequireとファイルのロードが見られると期待しているということですか?

いいえ、クラス定義内です。Ruby クラスの宣言は、表示された順序で実行される単なるコードです。のようなものは、それがattr_accessor定義されているように、定義されているクラスに対してたまたま何かを行うクラスメソッドです。これあなたがやりたいことのようです。

あなたのケースでは、代わりに YAML ファイルを読み取り、独自のロジックを実行してアクセサーを作成し、必要なバッキング データを構築します。ユースケースを完全に理解しているわけではありませんが、珍しいことや難しいことではありません。 .

とはいえ、これらの定義を YAML ファイルに入れることで、どの程度の「利便性」が得られるでしょうか? Watir を駆動するために使用したページ インスタンスを作成するために、私がかつて行ったようなことを考えてみましょう。

class SomePage < HeavyWatir
  has_text :fname     # Assumed default CSS accessor pattern
  has_text :whatever, accessor: 'some accessor mechanism', option: 'some other option'
end

インスタンス変数のhas_xxxアクセサーを作成するクラス メソッド (作成したのと同じようattr_accessorに) や、ページ上にあるはずのすべてのものが実際にあることを確認するために使用した他のデータ構造を構築するクラス メソッドなどです。たとえば、非常に大まかに:

page = SomePage.new
page.visit
if page.missing_fields?
  # Do something saying the page isn't complete
end

漠然と似たものが欲しいように思えます:クラス(またはサブクラス、または任意のクラスなどに混ぜることができます)に与えたい「もの」がたくさんあります。

これらの「もの」には追加機能があり、その機能は次のように複数の方法で機能します。

定義中に起こること

たとえば、has_textフィールド名など、ページのメタデータのクラス インスタンス ハッシュに名前を追加します。

使用中に起こること

たとえば、fname=が呼び出されたときに、セッターが呼び出されたことを示すフラグをインスタンスのメタデータに設定します。

于 2012-08-25T17:34:39.083 に答える