Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Julia CONFIG dictionary (closes #2430) #2716

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions base/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,14 @@ have_color = false
@windows_only default_color_input = text_colors[:normal]
color_normal = text_colors[:normal]

function answer_color()
c = symbol(get(ENV, "JULIA_ANSWER_COLOR", ""))
return get(text_colors, c, default_color_answer)
end

function input_color()
c = symbol(get(ENV, "JULIA_INPUT_COLOR", ""))
return get(text_colors, c, default_color_input)
end
CONFIG["answer_color", :default, :getter] =
(default_color_answer,
(key,value)->get(text_colors,symbol(get(ENV, "JULIA_ANSWER_COLOR", value)),value))
CONFIG["input_color", :default, :getter] =
(default_color_input,
(key,value)->get(text_colors,symbol(get(ENV, "JULIA_INPUT_COLOR", value)),value))
answer_color() = CONFIG["answer_color"]
input_color() = CONFIG["input_color"]

banner() = print(have_color ? banner_color : banner_plain)

Expand Down
218 changes: 218 additions & 0 deletions base/env.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ end
system_error(:setenv, ret == 0)
end
end
ENV
end

_setenv(var::String, val::String) = _setenv(var, val, true)
Expand Down Expand Up @@ -135,3 +136,220 @@ end

tty_cols() = parse_int(Int32, get(ENV,"COLUMNS","80"), 10)
tty_rows() = parse_int(Int32, get(ENV,"LINES","25"), 10)

type ConfigHashItem
value::Any
hasvalue::Bool
default::Any
hasdefault::Bool
getter::Callback # (key,value) -> value
setter::Callback # (key,value,hadvalue,newvalue)
delete::Callback # (key,value)
ConfigHashItem(v::ANY, hasvalue::Bool, def::ANY, hasdefault::Bool,
getter::Callback, setter::Callback,
delete::Callback) =
new(v,hasvalue,def,hasdefault,getter,setter,delete)
ConfigHashItem(v::ANY) = new(v,true,nothing,false,false,false,false)
end
setindex!(chi::ConfigHashItem, v::ANY, k::String) =
setindex!(chi, v, k, :value)
function setindex!(chi::ConfigHashItem, v::ANY, k::String, what::Symbol)
value = v
if isa(chi.setter, Function) && !(what == :default && chi.hasvalue)
if chi.hasvalue
value = chi.value
hasvalue = true
elseif chi.hasdefault
value = chi.default
hasvalue = true
else
value = nothing
hasvalue = false
end
chi.setter(k, value, hasvalue, v)
end
if what == :default
chi.default = v
chi.hasdefault = true
else
chi.value = v
chi.hasvalue = true
end
chi
end
delete!(chi::ConfigHashItem, k::String) =
delete!(chi, k, :value)
function delete!(chi::ConfigHashItem, k::String, what::Symbol)
if what == :default
if !chi.hasdefault
error("Key $k doesn't have a default")
end
elseif !chi.hasvalue
error("Key $k doesn't have a value")
end
v = getindex(chi, k)
if isa(chi.delete, Function)
if what == :default
if !chi.hasvalue
chi.delete(k, chi.default)
end
else
chi.delete(k, chi.value)
end
end
if what == :default
chi.hasdefault = false
else
chi.hasvalue = false
if isa(chi.setter, Function) && chi.hasdefault
chi.setter(k, chi.value, true, chi.default)
end
end
return v
end
function getindex(chi::ConfigHashItem, k::String)
if chi.hasvalue
value = chi.value
elseif chi.hasdefault
value = chi.default
else
error("Key $k doesn't have a value")
end
if isa(chi.getter, Function)
return chi.getter(k, value)
end
return value
end

type ConfigHash <: Associative{String,Any}
dict::Associative{String,ConfigHashItem}
ConfigHash() = new(Dict{String,ConfigHashItem}())
end
const CONFIG = ConfigHash()

function getindex(ch::ConfigHash, k::String)
return ch.dict[k][k]
end
function get(ch::ConfigHash, k::String, def)
item = get(ch.dict, k, nothing)
if isa(item,ConfigHashItem)
return item[k]
end
return def
end
function has(ch::ConfigHash, k::String)
item = get(ch.dict, k, nothing)
if isa(item,ConfigHashItem)
if item.hasvalue || item.hasdefault
return true
end
return false
end
return false
end
function delete!(ch::ConfigHash, k::String)
item = ch.dict[k]
delete!(item, k)
end
function delete!(ch::ConfigHash, k::String, what::Symbol...)
# example usage:
# delete!(CONFIG, "hamster", :value, :entry)
item = ch.dict[k]
ret = nothing
for x in what
if x == :value || x == :default
ret = delete!(item, k, x)
elseif x == :getter
item.getter = false
elseif x == :setter
item.setter = false
elseif x == :delete
item.delete = false
elseif x == :entry
delete!(ch.dict, k)
else
error("Invalid attribute type $x for ConfigHash")
end
end
return ret
end
delete!(ch::ConfigHash, k::String, def) = has(ch.dict,k) ? delete!(ch,k) : def
function setindex!(ch::ConfigHash, v, k::String)
item = get(ch.dict, k, nothing)
if isa(item,ConfigHashItem)
item[k] = v
else
ch.dict[k] = ConfigHashItem(v)
end
return ch
end
function setindex!(ch::ConfigHash, values, k::String, what::Symbol...)
# example usage:
# CONFIG["hamster",:default,:getter,:setter] = ("pet", getter_f, setter_f)
if !isa(values,Tuple)
values = (values,)
end
v::Tuple = values
if length(v) != length(what)
error("Mismatch in assignment to ConfigHash")
end
itm = get(ch.dict, k, nothing)
if !isa(itm,ConfigHashItem)
itm = ConfigHashItem(nothing)
itm.hasvalue = false
ch.dict[k] = itm
end
item::ConfigHashItem = itm
for i = 1:length(v)
x = what[i]
value = v[i]
if x == :value || x == :default
item[k, x] = value
elseif x == :getter
item.getter = value
elseif x == :setter
item.setter = value
if item.hasvalue
item.setter(k, nothing, false, item.value)
elseif item.hasdefault
item.setter(k, nothing, false, item.default)
end
elseif x == :delete
item.delete = value
else
error("Invalid attribute type $x for ConfigHash")
end
end
return ch
end
#start(ch::ConfigHash) = start(ch.dict)
#done(ch::ConfigHash, i) = done(ch.dict, i)
#function next(ch::ConfigHash, i)
# ((k,item),i) = next(ch.dict, i)
# if isa(item.getter, Function)
# return (item.getter(k, item.value), i)
# end
# return (item.value, i)
#end
#length(ch::ConfigHash) = length(ch.dict)
function show(io::IO, ch::ConfigHash)
println("Julia Configuration:")
ks = sort!(keys(ch.dict))
for k in ks
item = getindex(ch.dict, k)
if item.hasvalue || item.hasdefault
v = getindex(item, k)
print(io, "$k = ")
show(io, v)
println(io)
else
println(io, "$k = <no value>")
end
end
end

CONFIG["OUTPUT_STREAM", :default, :setter] =
(STDOUT,
(key,value,hadvalue,newvalue::IO) -> global OUTPUT_STREAM = newvalue)
CONFIG["gfx/backend", :default] = "gtk"

1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export
# Global constants and variables
ARGS,
C_NULL,
CONFIG,
CPU_CORES,
OS_NAME,
ENDIAN_BOM,
Expand Down
2 changes: 1 addition & 1 deletion test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ include ../Make.inc
TESTS = core numbers strings unicode corelib hashing remote iostring \
arrayops linalg blas fft dct sparse bitarray random math functional bigint \
sorting statistics spawn parallel suitesparse arpack bigfloat file zlib image \
all git pkg
all git pkg env

$(TESTS) ::
$(QUIET_JULIA) $(JULIA_EXECUTABLE) ./runtests.jl $@
Expand Down
63 changes: 63 additions & 0 deletions test/env.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using Test

let
ENV["JULIA ENV TEST VALUE"] = x = randstring(1000)
@test ENV["JULIA ENV TEST VALUE"] == x
@test_fails ENV["julia env test value"]
@test has(ENV,"JULIA ENV TEST VALUE")
@test delete!(ENV,"JULIA ENV TEST VALUE") == x
@test !has(ENV,"JULIA ENV TEST VALUE")
@test_fails ENV["JULIA ENV TEST VALUE"]
@test_fails delete!(ENV,"JULIA ENV TEST VALUE")
count = 0
for (k,v) in ENV
count += 1
end
@test count == length(ENV)
@test get(ENV, "JULIA ENV TEST VALUE", nothing) == nothing
end

let
key = "JULIA ENV TEST VALUE = 2"
try delete!(CONFIG,key,:entry) end
CONFIG[key] = x = (randstring(1000),100,randstring)
@test CONFIG[key] == x
getcnt = 0
setcnt = 0
deletedcnt = 0
expect = x
CONFIG[key, :default, :getter, :setter, :delete] = (42,
(k,v)->(@test(k==key); getcnt+=1; (v,true)),
(k,v,hadv,newv)->(@test(k==key && newv==expect); setcnt+=1; newv),
(k,v)->(@test(k==key); deletedcnt+=1; return true))
@test getcnt == 0
@test setcnt == 1
@test deletedcnt == 0
expect = 42
@test delete!(CONFIG,key) == (x,true)
@test getcnt == 1
@test setcnt == 2
@test deletedcnt == 1
@test CONFIG[key] == (42,true)
@test_fails delete!(CONFIG,key)
@test delete!(CONFIG,key,:default) == (42,true)
@test getcnt == 3
@test setcnt == 2
@test deletedcnt == 2
expect = 1
CONFIG[key, :default] = 1
expect = 2
CONFIG[key] = 2
@test getcnt == 3
@test setcnt == 4
@test deletedcnt == 2
@test delete!(CONFIG,key,:default) == (2,true)
@test getcnt == 4
@test setcnt == 4
@test deletedcnt == 2
@test CONFIG[key] == (2,true)
delete!(CONFIG,key,:getter,:setter,:delete,:value,:entry)
@test getcnt == 5
@test setcnt == 4
@test deletedcnt == 2
end
2 changes: 1 addition & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ testnames = ["core", "numbers", "strings", "unicode", "corelib", "hashing",
"dct", "sparse", "bitarray", "random", "math", "functional",
"bigint", "sorting", "statistics", "spawn", "parallel",
"suitesparse", "arpack", "bigfloat", "file", "zlib", "image",
"perf"]
"perf", "env"]

if ARGS == ["all"]
tests = testnames
Expand Down