Skip to content

Instantly share code, notes, and snippets.

@gentoid
Last active August 29, 2015 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gentoid/8961e7bdbc0c3447ccb1 to your computer and use it in GitHub Desktop.
Save gentoid/8961e7bdbc0c3447ccb1 to your computer and use it in GitHub Desktop.
Environment
class Environment
attr_reader :vars, :parent
def initialize(parent = nil)
@parent = parent
@vars = parent ? parent.vars.clone : {}
end
def extend_env
Environment.new self
end
def lookup(name)
scope = self
while scope
return scope if scope.vars.include?(name)
scope = scope.parent
end
end
def set(name, value)
scope = lookup(name) || self
scope.vars[name] = value
end
def get(name)
raise("Undefined variable: #{name}") unless @vars.include?(name)
@vars[name]
end
def def(name, value)
@vars[name] = value
end
end
require 'rails_helper'
describe Environment do
describe '#initialize' do
context 'when no args passed' do
it 'creates empty env when no parent env passed' do
expect(subject.vars).to eq({})
end
end
context 'when parent passed' do
let(:parent_env) { Environment.new }
let(:subject) { Environment.new parent_env }
before :each do
parent_env.set :x, 71
end
it 'creates env with vars from parent' do
expect(subject.vars).to eq parent_env.vars
end
end
end
describe '#extend' do
it 'returns env' do
expect(subject.extend_env).to be_instance_of Environment
end
it 'returns env with vars from subject' do
subject.set :x, 45
expect(subject.extend_env.vars).to eq(subject.vars)
end
end
describe '#lookup' do
context 'when var exists in subject itself' do
before :each do
subject.set :x, 34
end
it 'returns subject itself' do
expect(subject.lookup :x).to eq(subject)
end
end
context 'when var exists in any parent scope' do
let(:parent_env) { Environment.new }
let!(:subject) { Environment.new parent_env }
before :each do
parent_env.set :x, 56
end
it 'returns env contain var' do
expect(subject.lookup :x).to eq(parent_env)
end
end
context 'when var not exists in any scope' do
it 'returns nil' do
expect(subject.lookup :x).to eq nil
end
end
end
describe '#set' do
let(:parent_env) { Environment.new }
let!(:subject) { Environment.new parent_env }
context 'when a var is in current scope' do
before :each do
subject.vars[:x] = 12
end
it 'set value of the var in current scope' do
subject.set :x, 'qwerty'
expect(subject.vars[:x]).to eq('qwerty')
end
end
context 'when a var is in any of parent scopes' do
before :each do
parent_env.set :x, 34
end
it 'set value of the var in that scope' do
subject.set :x, 89
expect(parent_env.vars[:x]).to eq 89
end
end
context 'when a var not exists in any scope' do
it 'creates var in current scope' do
subject.set :t, 58
expect(subject.vars[:t]).to eq 58
end
end
end
describe '#get' do
context 'when var is in current scope' do
it 'returns value ot the var' do
subject.set :x, 'e'
expect(subject.get :x).to eq 'e'
end
it 'returns false if var equals false' do
subject.set :q, false
expect(subject.get :q).to eq false
end
end
context 'when var not exists in current scopes' do
it 'rise an error' do
expect{ subject.get :q }.to raise_error
end
end
end
describe '#def' do
it 'creates var in current scope' do
subject.def :d, 'rty'
expect(subject.get :d).to eq 'rty'
end
it 'override var in current scope' do
subject.def :f, 1
subject.def :f, 6
expect(subject.get :f).to eq 6
end
it "shadows parent's var" do
parent_scope = Environment.new
parent_scope.def :g, 'g'
current_scope = Environment.new parent_scope
current_scope.def :g, 'h'
expect(current_scope.get :g).to eq 'h'
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment