require 'active_model' require 'quandl/pattern' require 'quandl/pattern/client' require 'quandl/operation' require 'quandl/operation' module Quandl module Command module Tasks class Base class << self def inherited(klass) Tasks.tasks << klass unless Tasks.tasks.include?(klass) end def configure(app) return if disabled? app.command(command_name) do |c| c.syntax = syntax c.description = description c.action{|a,o| call(a,o) } configure_options(c) end end def disabled? @disabled == true end def disable! @disabled = true end def syntax(value=nil) @syntax = value if value.present? @syntax ||= "quandl #{command_name}" end def command_name(value=nil) @command_name = value if value.present? @command_name ||= name.to_s.split("::").last.downcase end def description(value=nil) @description = value if value.present? @description ||= "No description." end def options(value=nil) @options = value if value.present? @options ||= {} end def autoload_client_library before_execute :configure_client end def authenticated_users_only! before_execute :authenticated_users_only! end def disable_in_gem! before_execute :disable_in_gem! end def warn_unauthenticated_users before_execute :warn_unauthenticated_users end def call(args=[], options={}) args = Array(args) options = ensure_options_are_command_options!(options) self.new( args, options ).call end def t(key) key = key.to_s translation = lang key.split('.').each{|m| translation = translation.respond_to?(m) ? translation.send(m) : nil } translation end def lang @lang ||= Quandl::Lang.send(language).quandl.command.tasks.send(command_name) end def language # stub 'en' end protected def ensure_options_are_command_options!(options) return options if options.class == Commander::Command::Options OpenStruct.new(options) end def configure_options(c) options.each do |class_type, options| options.each do |name, desc| c.option "--#{name} #{class_type.to_s.upcase}", class_type, desc end end end end attr_accessor :args, :options, :request_timer include ActiveModel::Validations extend ActiveModel::Callbacks define_model_callbacks :execute before_execute :raise_error_unless_valid!, :check_for_update, :start_request_timer after_execute :log_request_time def call run_callbacks(:execute) do execute end end def initialize(args, options) self.args = args self.options = options end def verbose? options.verbose == true end def force_yes? options.force_yes == true end def ask_yes_or_no ['y','yes'].include?( ask("Are you sure? (y/n)") ) end def summarize(item) return summarize_hash(item) if item.kind_of?(Hash) item end def summarize_hash(item) item.collect do |k,v| next "#{k}: '#{v}'" if v.kind_of?(String) "#{k}: #{v}" end.join(', ') end def table(*args) Array(args).flatten.join(" | ") end def info(*args) logger.info(*args) end def debug(*args) logger.debug(*args) if verbose? end def error(*args) logger.error(*args) end def fatal(*args) logger.fatal("FATAL: #{args.join(" ")}") end def logger Quandl::Logger end def current_user @current_user ||= Quandl::Client::User.info end protected # THREAD POOL def mutex @mutex ||= Mutex.new end def pool @pool ||= Thread.pool( threads ) end def threads options.threads || 4 end def start_request_timer self.request_timer = Time.now end def log_request_time debug("# Started: #{request_timer}. Finished: #{Time.now}. Elapsed: #{request_timer.elapsed_ms}") end def reload_session! @auth_token = nil @current_user = nil configure_client end def authenticated_users_only! if auth_token.blank? fatal("You must authenticate to use #{self.class.command_name}! 'quandl login' OR --token xyz923") false end end def disable_in_gem! if force_yes? info("You have forced update!") true elsif Dir.exists?( File.join( Tasks.root, ".git") ) || File.exists?( File.join( Tasks.root, "Gemfile") ) fatal("#{self.class.command_name} is only permitted when installed as a package! http://quandl.com/help/toolbelt") false end end def warn_unauthenticated_users error("WARN: Authenticate your requests! 'quandl login' OR --token xyz923") if auth_token.blank? end def raise_error_unless_valid! unless valid? error( table(errors.full_messages) ) false end end def configure_client require 'thread/pool' require 'quandl/format' require 'quandl/command/client_ext' Quandl::Client.use( quandl_url ) Quandl::Client.token = auth_token Quandl::Client.request_source = 'quandl_command' Quandl::Client.request_version = Quandl::Command::VERSION end def check_for_update check_time = QConfig.configuration.last_checked_for_update # check time present? if check_time.present? && check_time.is_a?(Time) # has it been more than one day? run_update_check if Time.now - 1.day > check_time || check_time > Time.now else run_update_check end end def run_update_check require 'uri' require 'net/http' require 'open-uri' print("# Checking for updates ... ") uri = URI.parse("https://raw.github.com/quandl/quandl_command/master/lib/quandl/command/version.rb") http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Get.new(uri.request_uri) response = http.request(request) master = response.body master = master.split("\n").detect{|r| r =~ /VERSION/ }.split("'").last if Quandl::Command::VERSION != master info(" A new version of quandl toolbelt has been released. #{master}. Please run 'quandl update'") else info(" you are up to date! #{master}") end rescue => err error("An unexpected error occured while checking for updates ... #{err}") ensure QConfig.configuration.last_checked_for_update = Time.now end def quandl_url return @quandl_url if @quandl_url.present? @quandl_url = options.url if options.try(:url).present? @quandl_url = ENV['QUANDL_URL'] if @quandl_url.blank? @quandl_url = QConfig.configuration.quandl_url if @quandl_url.blank? @quandl_url = 'http://quandl.com/api/' if @quandl_url.blank? @quandl_url end def auth_token return @auth_token if @auth_token.present? @auth_token = options.token if options.try(:token).present? @auth_token = ENV['QUANDL_TOKEN'] if @auth_token.blank? @auth_token = QConfig.configuration.token if @auth_token.blank? @auth_token end end end end end