svoop/rodbot

View on GitHub
lib/rodbot/generator.rb

Summary

Maintainability
A
25 mins
Test Coverage
# frozen-string-literal: true

require 'fileutils'
require 'erb'
require 'pastel'

module Rodbot

  # Generators for new bots, deployments and such
  #
  # All files inside the +templates_path+ are honoured provided they match the
  # {GLOB}. Files with the extension ".gerb" are parsed like ERB files, however,
  # GERB tags must use square brackets.
  #
  #   ERB:  <%= 'foobar' %>
  #   GERB: [%= 'foobar' %]
  #
  # It's therefore possible to generate ERB files such as +index.erb.gerb+.
  #
  # Helpers available in GERB templates have to be defined in
  # {Rodbot::Generator::Helpers}.
  class Generator

    # Glob to filter relevant template files
    GLOB = "**/{*,.ruby-version*,.gitignore,.keep}"

    # Colors used by +info+ to color part of the output
    TAG_COLORS = {
      create: :green
    }.freeze

    # @param templates_path [Pathname] root path of the templates to generate from
    def initialize(templates_path)
      @templates_path = templates_path
      @helpers_binding = Helpers.new.instance_eval('binding')
      @pastel = Pastel.new
    end

    # Print the interpolated template to STDOUT
    def display
      puts
      each_template_path do |template_path, target_path, content|
        puts "### #{target_path} ###", (content || template_path.read), nil
      end
    end

    # Write the interpolated template to directory
    #
    # @param directory [Pathname] where to write the files to
    def write(directory)
      fail(Rodbot::GeneratorError, "cowardly refusing to write to existing #{directory}") if directory.exist?
      each_template_path do |template_path, target_path, content|
        absolute_target_path = directory.join(target_path)
        absolute_target_path.dirname.mkpath
        puts tag(:create, target_path)
        if content
          absolute_target_path.write(content)
        else
          FileUtils.copy(template_path, absolute_target_path)
        end
      end
    end

    private

    def each_template_path
      @templates_path.glob(GLOB).each do |template_path|
        next unless template_path.file?
        target_path = template_path.relative_path_from(@templates_path)
        content = if template_path.extname == '.gerb'
          target_path = target_path.dirname.join(target_path.basename('.gerb'))
          eval_gerb(template_path.read)
        end
        yield(template_path, target_path, content)
      end
    end

    def eval_gerb(string)
      ungerbify(ERB.new(gerbify(string), trim_mode: '-').result(@helpers_binding))
    end

    def gerbify(string)
      string.gsub('<%', '{%').gsub('%>', '%}').gsub('[%', '<%').gsub('%]', '%>')
    end

    def ungerbify(string)
      string.gsub('{%', '<%').gsub('%}', '%>')
    end

    def tag(tag, string)
      padded_tag = '[' + tag.to_s.ljust(6, ' ') + '] '
      @pastel.decorate(padded_tag, TAG_COLORS[tag]) + string.to_s.strip
    end

    class Helpers
      def time_zone
        Rodbot.config(:time_zone)
      end

      def relay_extensions
        Rodbot.plugins.extend_relay
        Rodbot.plugins.extensions[:relay].to_h do |name, _|
          [name, URI(Rodbot::Services::Relay.url(name)).port]
        end
      end
    end

  end
end