ruby: как загрузить файл .rb в локальном контексте - PullRequest
15 голосов
/ 29 октября 2010

Как эту простую задачу можно выполнить в Ruby?
У меня есть простой файл конфигурации

=== 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, а затем отменить их определение, когда закончу, но я надеюсь, что есть рубиновый способ)

Ответы [ 5 ]

12 голосов
/ 11 октября 2011

Файл конфигурации.

{ 'var' => 'val' }

Загрузка файла конфигурации

class App
  def loader
    config = eval(File.open(File.expand_path('~/config.rb')).read)
    p config['var']
  end
end
7 голосов
/ 28 августа 2014

Как уже говорили другие, для конфигурации лучше использовать YAML или JSON. Оценить файл

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

Этот синтаксис позволит вам увидеть имя файла в следах, что важно. См. Api docs [1].

Обновлена ​​команда eval, чтобы избежать утечек FD (дескриптор файла). Должно быть, я спал или, возможно, должен был спать в это время ночи вместо того, чтобы писать в стеке потока ...

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

5 голосов
/ 29 октября 2010

Вы, конечно, можете взломать решение, используя eval и File.read, но тот факт, что это сложно, должен дать вам сигнал о том, что это не похожий на рубин способ решения вашей проблемы.Два альтернативных варианта будут использовать yaml для вашего config api или задавать простой dsl.

Случай YAML является самым простым, вы просто получите что-то подобное в main.rb:

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

и ваш конфигурационный файл будет выглядеть так:

--- 
var: val
1 голос
/ 29 мая 2013

Мне просто нужно было сделать то же самое, так как я хотел иметь возможность загружать "Ruby DLL", где он возвращает анонимный класс (фабрика для экземпляров вещей), я создал его, который отслеживает уже загруженные элементы и позволяет загруженный файл для возврата значения, которое может быть чем угодно - полностью анонимным классом, модулем, данными и т. д. Это может быть модуль, который можно затем «включить» в объект после его загрузки, и он может предоставить узел « атрибуты "или методы. Вы также можете добавить элемент «unload», чтобы очистить его от загруженного хэша и разыменовать любой загруженный объект.

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");
1 голос
/ 29 октября 2010

Я НЕ рекомендую делать это, кроме как в контролируемой среде.

Сохранение модуля в файл с заранее определенным именем, определяющим методы initialize и run_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

Только потому, что вы можете что-то сделать,значит ты должен.Я не могу придумать причину, по которой я бы сделал это в производстве, и показать это здесь только как любопытство и подтверждение концепции.Сделать это доступным для неизвестных людей было бы хорошим способом взломать вашу машину, потому что код мог делать все, что мог делать владелец аккаунта.

...