2010-10-29 135 views
14

這個簡單的任務可以在Ruby中完成嗎?
我有一些簡單的配置文件ruby​​:如何在本地文件中加載.rb文件

=== config.rb 
config = { 'var' => 'val' } 

我想一些方法,main.rb文件中定義,以便從config.rb的局部變量成爲該方法的本地變量加載配置文件。
事情是這樣的:

=== main.rb 
Class App 
    def loader 
     load('config.rb') # or smth like that 
     p config['var'] # => "val" 
    end 
end 

我知道我可以在config.rb使用全局變量,然後在完成時取消定義他們,但我希望有你當然可以用砍出一個解決方案紅寶石路)

+3

你可以用EVAL做到這一點,但是這是不是一個好主意(以任何語言)。 – 2010-10-29 12:10:09

+0

有沙箱可以讓你在控制器環境中執行代碼,所以我會投票彌補你的downvote – Papipo 2012-01-31 10:54:35

回答

1

我不推薦除了在受控環境中這樣做。

將模塊保存爲具有預定名稱的文件,該文件定義了initializerun_it方法。在這個例子中我用test.rb作爲文件名:

module Test 
    @@classvar = 'Hello' 
    def initialize 
    @who = 'me' 
    end 

    def get_who 
    @who 
    end 

    def run_it 
    print "#{@@classvar} #{get_who()}" 
    end 
end 

然後寫一個簡單的應用程序加載和執行它:

require 'test' 

class Foo 
    include Test 
end 

END { 
    Foo.new.run_it 
} 

# >> Hello me 

僅僅因爲你可以做一些事情並不意味着你應該。我想不出有什麼理由讓我在製作過程中做到這一點,並且只是將它作爲一種好奇心和概念證明展示出來。將這些提供給未知的人將是一種很好的方式讓你的機器被黑客入侵,因爲代碼可以做任何擁有賬戶可以做的事情。

+0

感謝您的方法,但正如你可以看到自己 - 這是比甚至'PHP風格'更冗餘的解決方案... ... – disfated 2010-10-29 12:30:29

+1

我不是特別熱衷於元編程,但PHP對我來說是一個地獄。我認爲像Ruby這樣強大的動態工具可以完成這樣一項原始任務。壞消息。它不能。 謝謝大家的關注! – disfated 2010-10-29 13:24:08

+0

您可能需要將'require'test''行更改爲'require'。/ test'' – Automatico 2013-04-30 13:05:08

5

eval和File.read,但事實上這很難應該給你一個信號,這不是一種紅寶石般的方式來解決你的問題。兩種替代設計將使用yaml作爲你的配置api,或者定義一個簡單的dsl。

的YAML情況下是最簡單的,你只需有這樣的事情在main.rb的:

Class App 
    def loader 
     config = YAML.load('config.yml') 
     p config['var'] # => "val" 
    end 
end 

和您的配置文件看起來像:

--- 
var: val 
+0

Yaml不會工作:config.rb只是一個例子 - 應該有一些過程 - 不只是序列化數據。實際上,我需要一個簡單的命令「exec_file_as_it_was_typed_here(file)」。順便說一句,PHP可以做到這一點) – disfated 2010-10-29 01:23:49

+0

此外,dsl和尤其是eval不是變種。最起碼到現在。我只是想保持簡單。 – disfated 2010-10-29 01:32:20

+0

簡短的版本是ruby無法做到這一點,更長的版本是,你應該定義和執行一個DSL,而不是依靠一個聰明的黑客與範圍。 – NZKoz 2010-10-29 01:51:27

11

配置文件。

{ 'var' => 'val' } 

加載配置文件

class App 
    def loader 
    config = eval(File.open(File.expand_path('~/config.rb')).read) 
    p config['var'] 
    end 
end 
1

我只是做了類似的事情,我希望能夠加載一個「紅寶石DLL」它返回一個匿名類(一個工廠實例)我創建了這個跟蹤已經加載的項目,並允許加載的文件返回一個值,可以是任何東西 - 一個完全匿名的類,模塊,數據等。它可以是一個模塊,然後你可以「包含」在一個對象被加載後,它可以提供一系列「屬性」或方法。您還可以添加一個「卸載」項目以從加載的哈希中清除它並取消引用它加載的任何對象。

module LoadableModule 

@@loadedByFile_ = {}; 

def self.load(fileName) 
    fileName = File.expand_path(fileName); 
    mod = @@loadedByFile_[fileName]; 
    return mod if mod; 
    begin   
     Thread.current[:loadReturn] = nil; 
     Kernel.load(fileName); 
     mod = Thread.current[:loadReturn]; 
     @@loadedByFile_[fileName] = mod if(mod); 
    rescue => e 
     puts(e); 
     puts(e.backtrace); 
     mod = nil; 
    end 
    Thread.current[:loadReturn] = nil; 
    mod 
end 
def self.onLoaded(retVal) 
    Thread.current[:loadReturn] = retVal; 
end 
end 

加載的文件中:

LoadableModule.onLoaded("a value to return from the loaded file"); 
6

正如其他人所說,配置最好是使用YAML或JSON。要EVAL文件

binding.eval(File.open(File.expand_path('~/config.rb')).read, "config.rb") binding.eval(File.read(File.expand_path('~/config.rb')), "config.rb")

此語法將讓你看到文件名中回溯這是非常重要的。請參閱api文檔[1]。

已更新eval命令以避免FD(文件描述符)泄漏。我一定是睡覺或者也許應該在晚上而不是在計算器寫作的那段時間一直在睡覺..

[1] http://www.ruby-doc.org/core-1.9.3/Binding.html