joecorcoran/pannier

View on GitHub
lib/pannier/package.rb

Summary

Maintainability
A
3 hrs
Test Coverage
require 'fileutils'
require 'ostruct'
require 'pathname'
require 'set'

require 'pannier/asset'
require 'pannier/concatenator'
require 'pannier/dsl'
require 'pannier/errors'
require 'pannier/logger/package_logger'

module Pannier
  class Package
    extend DSL

    attr_reader :name, :app, :input_assets, :output_assets, :input_path,
                :output_path, :middlewares, :processors

    def initialize(name, app)
      @name, @app = name, app
      @input_assets, @output_assets = SortedSet.new, SortedSet.new
      @middlewares, @processors = [], []
    end

    def set_input(path)
      @input_path = path
    end

    def set_output(path)
      @output_path = path
    end

    def full_input_path
      File.expand_path(File.join(*[@app.input_path, @input_path].compact))
    end

    def full_output_path
      File.expand_path(File.join(*[@app.output_path, @output_path].compact))
    end

    def build_assets_from_paths(paths)
      paths.map do |path|
        pathname = Pathname.new(path)
        Asset.new(pathname.basename.to_s, pathname.dirname.to_s, self)
      end
    end

    def add_input_assets(assets)
      @input_assets.merge(assets)
    end

    def add_output_assets(assets)
      @output_assets.merge(assets)
    end

    def add_modifiers(modifiers)
      @processors += modifiers.map { |m| [:modify!, m] }
    end

    def add_concatenator(concat_name, concatenator = Concatenator.new)
      @processors << [:concat!, concat_name, concatenator]
    end

    def owns_any?(*paths)
      @input_assets.any? { |a| paths.include?(a.path) }
    end

    def package_logger
      @package_logger ||= Logger::PackageLogger.new(@app.logger, self)
    end

    def clobber!
      copy!
      FileUtils.rm_f(@output_assets.map(&:path))
    end

    def process!
      package_logger.wrap do
        copy!
        !@processors.empty? && @processors.each do |instructions|
          send(*instructions)
        end
        write_files!
      end
    end

    def modify!(modifier)
      @output_assets.each do |asset|
        asset.modify!(modifier)
      end
    end

    def concat!(concat_name, concatenator)
      asset = Asset.new(concat_name, full_output_path, self)
      asset.content = concatenator.call(@output_assets.map(&:content))
      @output_assets.replace([asset])
    end

    def copy!
      assets = @input_assets.map do |asset|
        asset.copy_to(full_output_path)
      end
      @output_assets.replace(assets)
    end

    def write_files!
      @output_assets.each(&:write_file!)
    end

    dsl do

      def env
        self.app.env
      end

      def env?(expression, &block)
        self.instance_eval(&block) if env.matches?(expression)
      end

      def input(path)
        set_input(path)
      end

      def output(path)
        set_output(path)
      end

      def behave(*names)
        names.each do |name|
          behavior = self.app.behaviors[name]
          raise MissingBehavior.new(name) if behavior.nil?
          self.instance_eval(&behavior)
        end
      end

      def assets(*patterns)
        patterns.each do |pattern|
          paths = Dir[File.join(full_input_path, pattern)]
          assets = build_assets_from_paths(paths)
          add_input_assets(assets)
        end
      end

      def modify(*modifiers, &block)
        modifiers << block if block_given?
        add_modifiers(modifiers)
      end

      def concat(*args)
        add_concatenator(*args)
      end

    end
  end
end