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

Add initconfig support for command defaults, allow strings as config keys #257

Open
wants to merge 3 commits into
base: gli-2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 2 additions & 3 deletions features/step_definitions/todo_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@
end

Then /^the config file should contain a section for each command and subcommand$/ do
config = File.open(File.join(ENV['HOME'],'gli_test_todo.rc')) do |file|
YAML::load(file)
end
config_path = File.join(ENV['HOME'],'gli_test_todo.rc')
config = GLI::ConfigLoader.load(config_path)
expect(config.keys).to include(:flag)
expect(config[:flag]).to eq('foo')
config[:flag].tap do |flag|
Expand Down
2 changes: 2 additions & 0 deletions features/support/env.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
# Adds GLI's bin dir to our path
ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
GLI_LIB_PATH = File.expand_path(File.join(File.dirname(__FILE__),'..','..','lib'))
# Adds in GLI's ConfigLoader for indifferent hash access for features that verify config file behavior
require "#{GLI_LIB_PATH}/gli/config_loader.rb"

GLI_GEMSET = 'gli-testing'
TMP_PATH = 'tmp/aruba'
Expand Down
1 change: 1 addition & 0 deletions lib/gli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
require 'gli/commands/initconfig'
require 'gli/commands/rdoc_document_listener'
require 'gli/commands/doc'
require 'gli/config_loader.rb'

module GLI
include GLI::App
Expand Down
5 changes: 2 additions & 3 deletions lib/gli/app_support.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,7 @@ def parse_config # :nodoc:
'commands' => {},
}
if @config_file && File.exist?(@config_file)
require 'yaml'
config.merge!(File.open(@config_file) { |file| YAML::load(file) })
config.merge!(ConfigLoader.load(@config_file))
end
config
end
Expand Down Expand Up @@ -185,7 +184,7 @@ def override_defaults_based_on_config(config)
def override_command_defaults(command_list,config)
command_list.each do |command_name,command|
next if command_name == :initconfig || command.nil?
command_config = (config['commands'] || {})[command_name] || {}
command_config = (config[GLI::InitConfig::COMMANDS_KEY] || {})[command_name] || {}

if @subcommand_option_handling_strategy == :legacy
override_default(command.topmost_ancestor.flags,command_config)
Expand Down
30 changes: 22 additions & 8 deletions lib/gli/commands/initconfig.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,18 @@ def initialize(config_file_name,commands,flags,switches)
private

def create_config(global_options,options,arguments)
config = Hash[(@app_switches.keys + @app_flags.keys).map { |option_name|
config = Hash[(sanitized_global_option_names).map { |option_name|
option_value = global_options[option_name]
if option_value.kind_of?(String) && option_value.respond_to?(:force_encoding)
[option_name,option_value.force_encoding("utf-8")]
[option_name.to_s,option_value.force_encoding("utf-8")]
else
[option_name,option_value]
[option_name.to_s,option_value]
end
}]
config[COMMANDS_KEY] = {}
@app_commands.each do |name,command|
if (command != self) && (name != :rdoc) && (name != :help)
if command != self
config[COMMANDS_KEY][name.to_sym] = config_for_command(@app_commands,name.to_sym)
end
if (command != self) && (name != :rdoc) && (name != :help) && (name != :_doc)
config[COMMANDS_KEY][name.to_s] = config_for_command(@app_commands,name.to_sym)
end
end

Expand All @@ -60,14 +58,30 @@ def create_config(global_options,options,arguments)
end
end

def sanitized_global_option_names
(@app_switches.keys + @app_flags.keys).select do |option_name|
option_name != :help && option_name != :version
end
end

def config_for_command(commands,command_name)
command = commands[command_name]
options = command.switches.merge(command.flags)
{}.tap do |hash|
(options.keys).map { |option_name|
option_value = options[option_name.to_sym].default_value
if option_value.kind_of?(String) && option_value.respond_to?(:force_encoding)
hash[option_name.to_s] = option_value.force_encoding("utf-8")
else
hash[option_name.to_s] = option_value
end
}
subcommands = commands[command_name].commands
subcommands.each do |name,subcommand|
next unless name.kind_of? Symbol
hash[COMMANDS_KEY] ||= {}
puts "#{command_name}:#{name}"
hash[COMMANDS_KEY][name.to_sym] = config_for_command(subcommands,name)
hash[COMMANDS_KEY][name.to_s] = config_for_command(subcommands,name)
end
end
end
Expand Down
25 changes: 25 additions & 0 deletions lib/gli/config_loader.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require 'yaml'

module GLI
class ConfigLoader
def self.load(path)
File.open(path) { |file| apply_indifferent_access_to(YAML::load(file)) }
end

# adapted from https://gist.github.com/Integralist/9503099
def self.apply_indifferent_access_to(obj)
return obj.reduce({}) do |memo, (k, v)|
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry to nitpick, but can you use a more traditional if construct? Trailing ifs for multiple lines is really confusing to me.

memo.tap do |m|
m[k.to_sym] = apply_indifferent_access_to(v)
m[k] = apply_indifferent_access_to(v)
end
end if obj.is_a? Hash

return obj.reduce([]) do |memo, v|
memo << apply_indifferent_access_to(v); memo
end if obj.is_a? Array

obj
end
end
end
39 changes: 38 additions & 1 deletion test/tc_gli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -237,20 +237,36 @@ def test_initconfig_command
@app.flag :bigflag, :bigalias
@app.flag :biggestflag
@app.command :foo do |c|
c.default_value true
c.switch :fooswitch
c.command :subfoo do |s|
s.default_value true
s.switch :absurd
end
end
@app.command :bar do |c|
c.default_value 'yuck'
c.flag :barflag
end
@app.command :blah do |c|
end
@app.switch :version
@app.switch :help
@app.on_error do |ex|
raise ex
end
@app.run(['-f','foo','-s','--bigflag=bleorgh','initconfig'])
assert @fake_stdout.contained?(/written/), @fake_stdout.strings.inspect

written_config = File.open(@config_file) { |f| YAML::load(f) }
# as written
raw_written_config = File.open(@config_file) { |f| YAML::load(f) }
# as loaded by gli in AppSupport#parse_config
written_config = GLI::ConfigLoader.load(@config_file)

assert_equal 'foo',written_config[:f]
# global config keys written out as strings, not symbols
assert_equal 'foo',raw_written_config['f']
assert !raw_written_config[:f]
assert_equal 'bleorgh',written_config[:bigflag]
assert !written_config[:bigalias]
assert written_config[:s]
Expand All @@ -259,8 +275,29 @@ def test_initconfig_command
assert_nil written_config[:biggestflag]
assert written_config[GLI::InitConfig::COMMANDS_KEY]
assert written_config[GLI::InitConfig::COMMANDS_KEY][:foo]
# command config keys written as strings, not symbols
assert written_config[GLI::InitConfig::COMMANDS_KEY]['foo']
assert !raw_written_config[GLI::InitConfig::COMMANDS_KEY][:foo]
assert raw_written_config[GLI::InitConfig::COMMANDS_KEY]['foo']
assert !raw_written_config[GLI::InitConfig::COMMANDS_KEY][:foo]
assert written_config[GLI::InitConfig::COMMANDS_KEY][:foo][:fooswitch]
assert written_config[GLI::InitConfig::COMMANDS_KEY][:foo]['fooswitch']
assert !raw_written_config[GLI::InitConfig::COMMANDS_KEY]['foo'][:fooswitch]
assert written_config[GLI::InitConfig::COMMANDS_KEY][:bar]
assert written_config[GLI::InitConfig::COMMANDS_KEY][:bar][:barflag]
# command config defaults are written
assert_equal written_config[GLI::InitConfig::COMMANDS_KEY][:bar][:barflag],'yuck'
assert written_config[GLI::InitConfig::COMMANDS_KEY][:blah]
# subcommands
assert written_config[GLI::InitConfig::COMMANDS_KEY][:foo][GLI::InitConfig::COMMANDS_KEY]
assert written_config[GLI::InitConfig::COMMANDS_KEY][:foo][GLI::InitConfig::COMMANDS_KEY][:subfoo]
assert written_config[GLI::InitConfig::COMMANDS_KEY][:foo][GLI::InitConfig::COMMANDS_KEY][:subfoo][:absurd]
assert_equal written_config[GLI::InitConfig::COMMANDS_KEY][:foo][GLI::InitConfig::COMMANDS_KEY][:subfoo][:absurd],true
# omit version and help global options
assert !written_config['version']
assert !written_config['help']
assert !written_config[:version]
assert !written_config[:help]

end

Expand Down