class Core::Loader::Context

public

Public Class Methods

load(path:, root:, type:, target:, strict:) click to toggle source
# File lib/core/loader/context.rb, line 13
def load(path:, root:, type:, target:, strict:)
  new(path: path, root: root, type: type, target: target, strict: strict).load
end
new(path:, root:, type:, target:, strict:) click to toggle source
# File lib/core/loader/context.rb, line 18
def initialize(path:, root:, type:, target:, strict:)
  @path = Pathname(path)
  @root = Pathname(root)
  @type = type.to_sym
  @target = target
  @strict = strict
  prepare_to_load!
end

Public Instance Methods

load() click to toggle source
public
# File lib/core/loader/context.rb, line 29
def load
  eval(@path.read, binding, @path.to_s)
end

Private Instance Methods

complete_expression?(string) click to toggle source

Based on github.com/banister/method_source.

# File lib/core/loader/context.rb, line 128
        def complete_expression?(string)
  original_verbose = $VERBOSE
  $VERBOSE = nil

  catch :valid do
    eval "BEGIN{throw :valid}\n#{string}"
  end

  true
rescue ::SyntaxError
  false
ensure
  $VERBOSE = original_verbose
end
extract_block_inner_source(block, path) click to toggle source
# File lib/core/loader/context.rb, line 79
        def extract_block_inner_source(block, path)
  source = extract_block_source(block, path).strip

  if source.end_with?("end")
    scan_to_complete_expression(source, "do", -4, path)
  elsif source.end_with?("}")
    scan_to_complete_expression(source, "{", -2, path)
  else
    # We should never get here, but raise an error just to be clear.
    #
    raise "could not parse inner source of `#{path}`"
  end
end
extract_block_source(block, path) click to toggle source
# File lib/core/loader/context.rb, line 93
        def extract_block_source(block, path)
  lineno = block.source_location[1]
  lines = path.each_line.to_a[(lineno - 1)..]

  lines.count.times do |index|
    possible_source = lines.take(index + 1).join

    if complete_expression?(possible_source)
      return possible_source
    end
  end

  # We should never get here, but raise an error just to be clear.
  #
  raise "could not find a complete expression in `#{path}`"
end
prepare_to_load!() click to toggle source
# File lib/core/loader/context.rb, line 33
              def prepare_to_load!
        @target.makeables.each do |makeable|
          define_singleton_method(makeable) do |*name, **kwargs, &block|
            if @strict && makeable != @type
              raise "expected to define an object of type `#{@type}` but was `#{makeable}` (#{@path})"
            end

            definable_path = Pathname(@path.to_s.gsub(@root.to_s, ""))
            expected_name = definable_path.dirname.join(
              definable_path.basename(definable_path.extname)
            ).to_s.split("/").reject(&:empty?).compact.map(&:to_sym)

            if name.empty?
              name = expected_name
            elsif @strict && name != expected_name
              raise "expected to define an object named `#{expected_name.join(", ")}` but was `#{name.join(", ")}` (#{@path})"
            end

            path, line = caller(1..1).first.split(":", 3)
            location = Core::Define::Location.new(path: path, line: line)
            defined = @target.make(makeable, *name, __location__: location, **kwargs)

            if block
              header = @path.read.each_line.take(block.source_location[1] - 1).join
              source = extract_block_inner_source(block, @path)

              type = case defined
              when ::Class
                "class"
              when ::Module
                "module"
              end

              eval_source = <<~SOURCE
                #{header}#{type} #{defined}#{source}
                end
              SOURCE

              eval(eval_source, TOPLEVEL_BINDING, @path.to_s)
            end

            defined
          end
        end
      end
scan_to_complete_expression(source, matcher, ending_offset, path) click to toggle source
# File lib/core/loader/context.rb, line 110
        def scan_to_complete_expression(source, matcher, ending_offset, path)
  source.scan(matcher) do
    offset = $~.offset(0)[0] + 2

    possible_inner_source = source[offset..ending_offset]

    if complete_expression?(possible_inner_source)
      return possible_inner_source
    end
  end

  # We should never get here, but raise an error just to be clear.
  #
  raise "could not find a complete expression for `#{matcher}` in `#{path}`"
end