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

Develop #234

Merged
merged 11 commits into from
Jan 6, 2024
Merged
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
180 changes: 104 additions & 76 deletions lib/wx/core/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ module Interface
def method_missing(sym, *args, &block)
unless block_given? || args.size>1
setter = false
key = sym.to_s.sub(/=\z/) { |s| setter = true; '' }
key = sym.to_s.sub(/=\z/) { |_| setter = true; '' }
if (!setter && args.empty?) || (!has_group?(key) && setter && args.size==1)
if setter
return set(key, args.shift)
Expand Down Expand Up @@ -142,8 +142,8 @@ def read(path_str, output=nil)
when ::TrueClass == output || ::FalseClass == output || output == true || output == false
val.is_a?(Integer) ? val != 0 : !!val
else
raise ArgumentError, "Unknown coercion type #{output.is_a?(::Class) ? output : output.class}" if output
val
raise ArgumentError, "Unknown coercion type #{output.is_a?(::Class) ? output : output.class}" unless output.nil? || output.is_a?(::Proc)
output ? output.call(val) : val
end
end
end
Expand Down Expand Up @@ -330,17 +330,17 @@ module Interface

def each_entry(&block)
if block_given?
@data.select { |_,v| !v.is_a?(::Hash) }.each(&block)
data.select { |_,v| !v.is_a?(::Hash) }.each(&block)
else
::Enumerator.new { |y| @data.each_pair { |k,v| y << [k,v] if !v.is_a?(::Hash) } }
::Enumerator.new { |y| data.each_pair { |k,v| y << [k, expand(v)] unless v.is_a?(::Hash) } }
end
end

def each_group(&block)
if block_given?
@data.select { |_,g| g.is_a?(::Hash) }.each { |k,g| block.call(k, Group.new(self, self.path.dup.push(k), g)) }
data.select { |_,g| g.is_a?(::Hash) }.each { |k,_| block.call(k, Group.new(self, self.path.dup.push(k))) }
else
::Enumerator.new { |y| @data.each_pair { |k,g| y << [k,Group.new(self, self.path.dup.push(k), g)] if g.is_a?(::Hash) } }
::Enumerator.new { |y| data.each_pair { |k,g| y << [k,Group.new(self, self.path.dup.push(k))] if g.is_a?(::Hash) } }
end
end

Expand All @@ -365,11 +365,9 @@ def has_entry?(path_str)
return false if segments.empty?
entry = segments.pop
group_data = if segments.empty?
@data
data
else
unless abs || root?
segments = self.path + segments
end
segments = self.path + segments unless abs || root?
get_group_at(segments)
end
!!(group_data && group_data.has_key?(entry) && !group_data[entry].is_a?(::Hash))
Expand All @@ -378,40 +376,39 @@ def has_entry?(path_str)
def has_group?(path_str)
segments, abs = get_path(path_str)
return root? if segments.empty?
unless abs || root?
segments = self.path + segments
end
segments = self.path + segments unless abs || root?
!!get_group_at(segments)
end

def get(key)
key = key.to_s
raise ArgumentError, 'No paths allowed' if key.index(ConfigBase::SEPARATOR)
elem = @data[key]
elem = data[key]
if elem.is_a?(::Hash)
Group.new(self, self.path.dup.push(key), elem)
Group.new(self, self.path.dup.push(key))
else
elem
expand(elem)
end
end

def set(key, val)
key = key.to_s
raise ArgumentError, 'No paths allowed' if key.index(ConfigBase::SEPARATOR)
exist = @data.has_key?(key)
elem = exist ? @data[key] : nil
hsh = data
exist = hsh.has_key?(key)
elem = exist ? hsh[key] : nil
if val.nil?
@data.delete(key) if exist
hsh.delete(key) if exist
nil
elsif val.is_a?(::Hash)
raise ArgumentError, 'Cannot change existing value entry to group.' if exist && !elem.is_a?(::Hash)
elem = @data[key] = {} unless elem
group = Group.new(self, self.path.dup.push(key), elem)
hsh[key] = {} unless elem
group = Group.new(self, self.path.dup.push(key))
val.each_pair { |k, v| group.set(k, v) }
group
else
raise ArgumentError, 'Cannot change existing group to value entry.' if exist && elem.is_a?(::Hash)
@data[key] = sanitize_value(val)
hsh[key] = val
end
end

Expand All @@ -420,23 +417,21 @@ def delete(path_str)
return nil if segments.empty?
last = segments.pop
group_data = if segments.empty?
@data
data
else
unless abs || root?
segments = self.path + segments
end
segments = self.path + segments unless abs || root?
get_group_at(segments, create_missing_groups: false)
end
raise ArgumentError, "Unable to resolve path #{segments+[last]}" unless group_data
group_data.delete(last)
group_data ? group_data.delete(last) : nil
end

def rename(old_key, new_key)
old_key = old_key.to_s
new_key = new_key.to_s
raise ArgumentError, 'No paths allowed' if old_key.index(ConfigBase::SEPARATOR) || new_key.index(ConfigBase::SEPARATOR)
if @data.has_key?(old_key) && !@data.has_key?(new_key)
@data[new_key] = @data.delete(old_key)
hsh = data
if hsh.has_key?(old_key) && !hsh.has_key?(new_key)
hsh[new_key] = hsh.delete(old_key)
true
else
false
Expand All @@ -448,19 +443,19 @@ def read(path_str, output=nil)
return nil if segments.empty?
last = segments.pop
group_data = if segments.empty?
@data
segments = self.path.dup unless abs || root?
data
else
unless abs || root?
segments = self.path + segments
end
get_group_at(segments, create_missing_groups: true)
segments = self.path + segments unless abs || root?
get_group_at(segments)
end
raise ArgumentError, "Unable to resolve path #{segments+[last]}" unless group_data
val = group_data[last]
val = group_data ? group_data[last] : nil
if val.is_a?(::Hash)
raise TypeError, "Cannot convert group" unless output.nil?
Group.new(self, segments.dup.push(last), val)
Group.new(self, segments.dup.push(last))
else
val = expand(val)
return val unless val && output
case
when ::String == output || ::String === output
val.to_s
Expand All @@ -471,8 +466,8 @@ def read(path_str, output=nil)
when ::TrueClass == output || ::FalseClass == output || output == true || output == false
val.is_a?(::Integer) ? val != 0 : !!val
else
raise ArgumentError, "Unknown coercion type #{output.is_a?(::Class) ? output : output.class}" if output
val
raise ArgumentError, "Unknown coercion type #{output.is_a?(::Class) ? output : output.class}" unless output.nil? || output.is_a?(::Proc)
output ? output.call(val) : val
end
end
end
Expand All @@ -483,11 +478,10 @@ def write(path_str, val)
return false if segments.empty?
last = segments.pop
group_data = if segments.empty?
@data
segments = self.path.dup unless abs || root?
data
else
unless abs || root?
segments = self.path + segments
end
segments = self.path + segments unless abs || root?
get_group_at(segments, create_missing_groups: true)
end
raise ArgumentError, "Unable to resolve path #{segments+[last]}" unless group_data
Expand All @@ -498,13 +492,13 @@ def write(path_str, val)
nil
elsif val.is_a?(::Hash)
raise ArgumentError, 'Cannot change existing value entry to group.' if exist && !elem.is_a?(::Hash)
elem = group_data[last] = {} unless elem
group = Group.new(self, segments.dup.push(last), elem)
group_data[last] = {} unless elem
group = Group.new(self, segments.dup.push(last))
val.each_pair { |k, v| group.set(k, v) }
group
else
raise ArgumentError, 'Cannot change existing group to value entry.' if exist && elem.is_a?(::Hash)
group_data[last] = sanitize_value(val)
group_data[last] = val
end
end
alias :[]= :write
Expand All @@ -514,7 +508,7 @@ def to_s
end

def to_h
@data
data
end

def get_path(path_str)
Expand All @@ -526,21 +520,33 @@ def get_path(path_str)
end
protected :get_path

def sanitize_value(val)
case val
when TrueClass, FalseClass, Numeric, String
val
else
if val.respond_to?(:to_int)
val.to_int
elsif val.respond_to?(:to_f)
val.to_f
else
val.to_s
EXPAND_RE = if Wx::PLATFORM == 'WXMSW'
/(\\)?([$][{(]?|%)(\w+)([})%])?/
else
/(\\)?([$][{(]?)(\w+)([})])?/
end
private_constant :EXPAND_RE

def expand(val)
if root.expanding_env_vars? && ::String === val
val.gsub(EXPAND_RE) do |s|
if $1.nil? &&
(($2[0] == '$' &&
($2.size == 1 && $4.nil?) ||
($2[1] == '(' && $4 == ')') ||
($2[1] == '{' && $4 == '}'))||
($2[0] == '%' && $4 == '%')) &&
ENV[$3]
$1 ? $1+ENV[$3] : ENV[$3]
else
$1 ? s[1,s.size] : s
end
end
else
val
end
end
protected :sanitize_value
protected :expand

end

Expand All @@ -550,12 +556,16 @@ class Group

include Interface

def initialize(parent, path, data)
def initialize(parent, path)
@parent = parent
@path = path.freeze
@data = data
end

def data
self.root.__send__(:get_group_at, @path, create_missing_groups: true, is_pruned: true)
end
protected :data

def root?
false
end
Expand All @@ -573,7 +583,7 @@ def parent
end

def get_group_at(segments, create_missing_groups: false)
root.__send__(:get_group_at, segments)
root.__send__(:get_group_at, segments, create_missing_groups: create_missing_groups)
end
protected :get_group_at

Expand All @@ -582,10 +592,16 @@ def get_group_at(segments, create_missing_groups: false)
include Interface

def initialize(hash = nil)
@expand_env_vars = true
@data = {}
replace(hash) if hash
end

def data
@data
end
protected :data

def root?
true
end
Expand Down Expand Up @@ -614,19 +630,31 @@ def replace(hash)
self
end

def get_group_at(segments, create_missing_groups: false)
# prune segments (process relative segments)
segments = segments.inject([]) do |lst, seg|
case seg
when '..'
lst.pop # remove previous
# forget ..
when '.'
# forget
else
lst << seg
def is_expanding_env_vars
@expand_env_vars
end
alias :expanding_env_vars? :is_expanding_env_vars

def set_expand_env_vars(flag)
@expand_env_vars = !!flag
end
alias :expand_env_vars :set_expand_env_vars

def get_group_at(segments, create_missing_groups: false, is_pruned: false)
unless is_pruned
# prune segments (process relative segments)
segments = segments.inject([]) do |lst, seg|
case seg
when '..'
lst.pop # remove previous
# forget ..
when '.'
# forget
else
lst << seg
end
lst
end
lst
end
# find group matching segments
segments.inject(@data) do |hsh, seg|
Expand Down
22 changes: 21 additions & 1 deletion lib/wx/doc/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def rename(old_key, new_key) end
# By default returns un-coerced value.
# Raises exception if incompatible coercion is specified.
# @param [String] path_str
# @param [Class,nil] output output type to convert to
# @param [Class,Proc,nil] output output type (or converter proc) to convert to (with)
# @return [Boolean,String,Integer,Float,Wx::Config::Group,nil] value entry value
def read(path_str, output=nil) end

Expand Down Expand Up @@ -186,6 +186,16 @@ def clear; end
# @return [self]
def replace(hash) end

# Returns true if we are expanding environment variables in string values, false otherwise.
# @return [Boolean]
def is_expanding_env_vars; end
alias :expanding_env_vars? :is_expanding_env_vars

# Determine whether we wish to expand environment variables in string values.
# @param [Boolean] flag enables expanding environment variables if true, disables otherwise
def set_expand_env_vars(flag) end
alias :expand_env_vars :set_expand_env_vars

end

# Configuration class for wxRuby which stores it's settings in a (possibly nested) Hash.
Expand Down Expand Up @@ -225,6 +235,16 @@ def clear; end
# @return [self]
def replace(hash) end

# Returns true if we are expanding environment variables in string values, false otherwise.
# @return [Boolean]
def is_expanding_env_vars; end
alias :expanding_env_vars? :is_expanding_env_vars

# Determine whether we wish to expand environment variables in string values.
# @param [Boolean] flag enables expanding environment variables if true, disables otherwise
def set_expand_env_vars(flag) end
alias :expand_env_vars :set_expand_env_vars

end

end
Loading