Last active
August 29, 2015 14:07
-
-
Save gentoid/8961e7bdbc0c3447ccb1 to your computer and use it in GitHub Desktop.
Environment
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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