Question

While trying to develop a simple gem to learn the process, I happened to stumble on this issue: Thor DSL takes in options to a command using the syntax: option :some_option, :type => :boolean, just prior to the method definition.

I am trying to have a dynamic set of options loaded from a file. I do this file read operation in the constructor, but it seems the option keyword for the Thor class is getting processed before the initialize method.

Any ideas to resolve this? Also it would be great if someone can explain how the option keyword works? I mean is option a method call? I don't get the design. (This is the first DSL I am trying out and am a total newbie to 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 )
Was it helpful?

Solution

After a bit of tweaking, I think I ended upon a solution that doesn't look too bad. But not sure placing code in module like that is a good practice. But anyways:

#!/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 )
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top