tmfnll/bonito

View on GitHub
lib/bonito/scope.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

module Bonito
  class Accessor # :nodoc:
    def initialize(scope, symbol)
      @scope = scope
      @symbol = symbol
      @instance_var = :"@#{@symbol.to_s.chomp('=')}"
    end

    def access(*args)
      assignment? ? set(*args) : get
    end

    # :reek:NilCheck
    # String#match? Unavailable for Ruby 2.3
    def assignment?
      !@symbol.to_s.match(/\w+=/).nil?
    end

    private

    def get
      scope = @scope
      while scope
        if scope.instance_variable_defined? @instance_var
          return scope.instance_variable_get @instance_var
        end

        scope = scope.parent
      end
      raise NameError
    end

    def set(value)
      @scope.instance_variable_set @instance_var, value
    end
  end

  class Scope # :nodoc:
    def initialize(parent = nil)
      @parent = parent
    end

    def push
      self.class.new self
    end

    protected

    attr_reader :parent

    private

    def method_missing(symbol, *args)
      Accessor.new(self, symbol).access(*args)
    rescue NameError
      super
    end

    # :reek:BooleanParameter
    # Inherits interface from Object#respond_to_missing?
    def respond_to_missing?(symbol, respond_to_private = false)
      accessor = Accessor.new(self, symbol)
      return true if accessor.assignment?

      accessor.access
      true
    rescue NameError
      super
    end
  end
end