estum/console_utils

View on GitHub
lib/console_utils.rb

Summary

Maintainability
A
0 mins
Test Coverage
require 'active_support'
require 'active_support/core_ext'
require 'active_support/tagged_logging'
require 'pastel'
require 'console_utils/core_ext/array_to_proc'
require 'console_utils/core_ext/local_values'
require 'console_utils/version'

# = Rails Console Utils
# Collection of utilities to use in Rails Console.
#
# == Modules
#
# [ActiveRecordUtils]
#
#     useful console methods for <tt>ActiveRecord::Base</tt> models
#
# [BenchUtils]
#
#     benchmark shorthands
#
# [RequestUtils]
#
#     tools to make local and remote JSON API requests with
#     json response body formatting and automatic auth
#     (currently supports only token auth).
#
# [OtherUtils]
#
#     uncategorized collection of methods
#
# == Configuration
# Parameters are changable by the <tt>config.console_utils</tt> key inside
# the app's configuration block. It is also available as
# <tt>ConsoleUtils.configure(&block)</tt> in the custom initializer.
module ConsoleUtils
  extend ActiveSupport::Autoload

  JSON_FORMATTERS = [
    :default,
    :jq
  ]

  MODULES = [
    :ActiveRecordUtils,
    :RequestUtils,
    :BenchUtils,
    :OtherUtils
  ]

  MODULES.each { |mod| autoload mod }

  autoload :JSONOutput
  autoload :ReplState


  # :section: Configuration

  # :attr:
  # An array with disabled modules (default: <tt>[]</tt>)
  mattr_accessor(:disabled_modules) { [] }

  # :attr:
  # ID of the user which will be used by default in requests
  # (default: <tt>1</tt>)
  mattr_accessor(:default_uid) { 1 }

  # :attr:
  # A plain string of the default token used to authorize user
  # (default: <tt>nil</tt>)
  mattr_accessor(:default_token)

  # :attr:
  # A name of user's model (default: <tt>:User</tt>)
  mattr_accessor(:user_model_name) { :User }

  # :attr:
  # A primary key of user's model (default: <tt>:id</tt>)
  mattr_accessor(:user_primary_key) { :id }

  # :attr:
  # A column name with a user's token. Using by request tools.
  # (default: <tt>:auth_token</tt>)
  mattr_accessor(:user_token_column) { :auth_token }

  # :attr:
  # A name of the request parameter used to authorize user by a token
  # (default: <tt>:token</tt>)
  mattr_accessor(:token_param) { :token }

  # :attr:
  # JSON formatter used in API request helpers
  # (<tt>:default</tt> or <tt>:jq</tt>)
  mattr_accessor(:json_formatter) { :default }

  # :attr:
  # Command for +jq+ json formatter (default: <tt>"jq . -C"</tt>)
  mattr_accessor(:jq_command) { %w[jq -C] }

  # :attr:
  # Binary path to +curl+ (using in remote requests). (default: <tt>"curl"</tt>)
  mattr_accessor(:curl_bin) { "curl" }

  # :attr:
  # Don't print generated curl command with remote requests.
  # (default: <tt>false</tt>)
  mattr_accessor(:curl_silence) { false }

  # :attr:
  # Remote endpoint used in remote API request helpers
  # (default: <tt>"http://example.com"</tt>)
  mattr_accessor(:remote_endpoint) { "http://example.com" }

  # :attr:
  # Output logger (<tt>Logger.new(STDOUT)</tt> by default)
  mattr_accessor(:logger) { ActiveSupport::TaggedLogging.new(Logger.new(STDOUT)) }

  # :attr:
  # Enable the auth automator with the "exap"
  # (default: <tt>true</tt>)
  mattr_accessor(:request_auto_auth) { true }

  # :attr:
  # Request methods to delegate with requester
  # (default: <tt>[:get, :post, :put, :delete, :patch, :head]</tt>)
  mattr_accessor(:request_methods) {  %i(get post put delete patch head) }

  # :attr:
  # Specifies a callable object, which will hook requests with
  # credentials. There are two built-in implementations: the default
  # one <tt>ConsoleUtils::RequestUtils::DefaultAuthAutomator</tt> and
  # the <tt>ConsoleUtils::RequestUtils::SimpleTokenAutomator</tt>,
  # which is useful when using the +simple_token_automator+ gem.
  mattr_accessor(:auth_automator) { ConsoleUtils::RequestUtils::DefaultAuthAutomator }

  # :attr:
  # Keeps any amount of callable objects to invoke them before each request,
  # with an instance of <tt>ConsoleUtils::RequestUtils::RequestParams</tt>
  # as only the argument.
  # (default: <tt>[]</tt>)
  mattr_accessor(:request_hooks) { [] }

  # :section: Class Methods

  class << self
    alias_method :config, :itself

    # :method: self.configure
    def configure # :yields:
      yield(config)
    end

    def enabled_modules # :yields:
      unless block_given?
        return to_enum(__method__) { ConsoleUtils::MODULES.size - disabled_modules.size }
      end

      (ConsoleUtils::MODULES - disabled_modules).each do |mod|
        yield(const_get(mod))
      end
    end

    # Returns User's class set in the <tt>:user_class_name</tt>
    def user_model
      Object.const_get(user_model_name)
    end
    alias_method :user_class, :user_model

    def user_scope(scope = nil)
      case scope
      when nil    then user_model
      when Symbol then user_model.public_send(scope)
                  else user_model.all.merge(scope)
      end
    end

    # Finds +user_model+ by +user_primary_key+.
    # If the first argument is <tt>:any</tt>, gets a random user.
    def find_user(id, scope: nil)
      if id == :any
        user_scope(scope).anyone.tap do |u|
          puts "random user #{user_primary_key}: #{u.public_send(user_primary_key)}"
        end
      else
        user_scope(scope).where(user_primary_key => id).first!
      end
    end

    def auto_token_for(id)
      user = find_user(id, scope: user_model.select([:id, user_token_column]))
      user.public_send(user_token_column)
    end

    # Setup enabled modules for Pry context
    def pry!
      setup_modules_to(TOPLEVEL_BINDING.eval('self'))
    end

    # Setup enabled modules by extending given context
    def setup_modules_to(context = nil)
      ReplState.setup(context)
    end

    def pastel
      @pastel ||= Pastel.new
    end
  end

  ActiveSupport.run_load_hooks(:console_utils, self)
end

if defined? Rails
  require "console_utils/railtie"
end