I am trying to dynamically create a class using the eval method. It is working fine except for one small problem. As my code shows I am creating the开发者_开发知识库 Browser class inside the BrowserFactory class. When I do this the Browser class has an added namespace of BrowserFactory. Is there anyway to evaluate the Browser class from a string without the BrowserFactory namespace being attached?
class BrowserFactory
def self.create_browser(browser)
super_class = nil
case browser
when 'IE'
require 'watir'
super_class = 'Watir::IE'
when 'celerity'
require 'celerity'
super_class = 'Celerity::Browser'
end
raise StandardError.new("Browser '#{browser}' is not currentlys supported") if super_class.nil?
eval <<EOS
class Browser < #{super_class}
include Singleton
include BrowserModification
end
EOS
return Browser.instance
end
end
Defining Browser (or ::Browser, to directly answer your question) will prevent you from calling your factory more than once.
I would recommend to use an anonymous class. No need for eval, btw, and you can define the class method to_s if you want to:
class BrowserFactory
def self.create_browser(browser)
super_class = case browser
when 'IE'
require 'watir'
Watir::IE
when 'celerity'
require 'celerity'
Celerity::Browser
else
raise StandardError.new("Browser '#{browser}' is not currentlys supported")
end
klass = Class.new(super_class) do
include Singleton
include BrowserModification
def self.to_s
"Modified#{superclass}"
end
end
klass.instance
end
end
Change
class Browser < #{super_class}
to
class ::Browser < #{super_class}
def BrowserFactory(browser)
case browser
when 'IE'
require 'watir'
Watir::IE
when 'celerity'
require 'celerity'
Celerity::Browser
else
raise ArgumentError, "Browser '#{browser}' is not currently supported"
end.new.extend(BrowserModification)
end
Here's a small testsuite:
module Watir; class IE; def to_s; 'IE' end end end
module Celerity; class Browser; def to_s; 'Celerity' end end end
module BrowserModification; def to_s; "Modified#{super}" end end
require 'test/unit'
class TestBrowserFactory < Test::Unit::TestCase
def test_that_celerity_responds_as_modified_celerity
assert_equal 'ModifiedCelerity', BrowserFactory('celerity').to_s
end
def test_that_internet_explorer_responds_as_modified_internet_explorer
assert_equal 'ModifiedIE', BrowserFactory('IE').to_s
end
def test_that_an_invalid_browser_raises_an_exception
assert_raise ArgumentError do BrowserFactory('xyz') end
end
end
精彩评论