medcat/liquidscript

View on GitHub
lib/liquidscript/compiler/icr/directives.rb

Summary

Maintainability
A
0 mins
Test Coverage
module Liquidscript
  module Compiler
    class ICR < Base
      module Directives
        module ClassMethods

          def directives
            @_directives ||= {}
          end

          def define_directive(name, body)
            directives[name] = Base::Callable.new(nil, body, "")
          end

        end

        module InstanceMethods

          extend Forwardable

          def handle_directive(directive)
            command, args = directive[:command], directive[:arguments]

            callable = directives.fetch(command)

            callable.bind = self
            callable.call(*args)

          rescue KeyError
            raise UnknownDirectiveError.new(command)
          end

          def directives
            @_directives ||= self.class.directives.dup
          end

          def define_directive(name, body)
            directives[name] = Base::Callable.new(nil, body, "")
          end

          def directive_allow(*args)
            args.each do |a|
              top.context.set(a.value.intern).hidden!
            end

            nil
          end

          def directive_cvar(*args)
            args.each do |a|
              top.context.set(a.value.intern, :class => true).hidden!
            end

            nil
          end

          def directive_todo(comment)
            $stderr.puts "TODO (file: #{@scanner.file}): #{comment[1]}"
            nil
          end

          def directive_include(file)
            file_name = file[1]
            path = include_paths.find do |part|
              File.file?(File.join(part, file_name))
            end

            raise LoadError,
              "cannot load such file -- #{file}" unless path

            full_path = File.join(path, file_name)
            f         = File.open(full_path)
            scanner   = Scanner::Liquidscript.new(f.read, full_path)
            compiler  = Compiler::ICR.new(scanner)
            compiler.top.parent = top
            compiler.top.context.delegate!
            compiler.compile
          end

          def directive_include_path(*paths)
            include_paths.push(*paths.map(&:value))
            nil
          end

          def directive_strict
            top.metadata[:strict] = true

            nil
          end

          private

          def include_paths
            @_include_paths ||= [
              ".",
              File.expand_path("../", @scanner.metadata[:file]),
              *ENV.fetch("LIQUID_PATHS", "").split(':')
            ]
          end

        end

        def self.included(receiver)
          receiver.extend         ClassMethods
          receiver.send :include, InstanceMethods

          InstanceMethods.instance_methods.each do |m|
            if m.to_s =~ /\A_?directive_([A-Za-z0-9\_]+)\z/
              receiver.define_directive($1.gsub(/\_[a-z]/) { |m| m[1].upcase }, m)
            end
          end
        end

      end
    end
  end
end