动态加载Ruby Gem的Thor选项

时间:2014-03-30 08:56:51

标签: ruby dsl thor

在尝试开发一个简单的宝石来学习这个过程时,我偶然发现了这个问题: Thor DSL将选项带入命令使用语法:option :some_option, :type => :boolean,就在方法定义之前。

我正在尝试从文件中加载一组动态选项。我在构造函数中执行此文件读取操作,但似乎 Thor 类的option关键字在initialize方法之前得到处理。

有什么想法来解决这个问题?如果有人可以解释选项关键字如何工作,那也很棒?我的意思是option方法调用?我没有得到设计。 (这是我尝试的第一个DSL,并且是Ruby Gems的新手)

#!/usr/bin/env ruby

require 'thor'
require 'yaml'
require 'tinynews'

class TinyNewsCLI < Thor
  attr_reader :sources
  @sources = {}

  def initialize *args
    super
    f = File.open( "sources.yml", "r" ).read
    @sources = YAML::load( f )
  end

  desc "list", "Lists the available news feeds."
  def list
    puts "List of news feed sources: "
    @sources.each do |symbol, source|
      puts "- #{source[:title]}"
    end
  end

  desc "show --source SOURCE", "Show news from SOURCE feed"
  option :source, :required => true
  def show
    if options[:source]
      TinyNews.print_to_cli( options[:source].to_sym )
    end
  end

  desc "tinynews --NEWS_SOURCE", "Show news for NEWS_SOURCE"
  @sources.keys.each do |source_symbol| # ERROR: States that @sources.keys is nil
    #[:hindu, :cnn, :bbc].each do |source_symbol| # I expected the above to work like this
    option source_symbol, :type => :boolean
  end
  def news_from_option
    p @sources.keys
    TinyNews.print_to_cli( options.keys.last.to_sym )
  end

  default_task :news_from_option

end

TinyNewsCLI.start( ARGV )

1 个答案:

答案 0 :(得分:4)

经过一些调整后,我认为我找到了一个看起来不太糟糕的解决方案。但不确定将代码放在模块中是不是一个好习惯。但无论如何:

#!/usr/bin/env ruby

require 'thor'
require 'yaml'
require 'tinynews'


module TinyNews

  # ***** SOLUTION *******
  f = File.open( "../sources.yml", "r" ).read
  SOURCES = YAML::load( f )

  class TinyNewsCLI < Thor

    default_task :news_from_source

    desc "list", "Lists the available news feeds."
    def list
      puts "List of news feed sources: "
      SOURCES.each do |symbol, source|
        puts "- #{source[:title]}"
      end
    end

    desc "--source NEWS_SOURCE", "Show news for NEWS_SOURCE"
    option :source, :required => true, :aliases => :s
    def news_from_source
      TinyNews.print_to_cli( options[:source].to_sym )
    end
  end

end

TinyNews::TinyNewsCLI.start( ARGV )