Class: LibCLImate::Climate

Inherits:
Object
  • Object
show all
Includes:
Xqsr3::Quality::ParameterChecking
Defined in:
lib/libclimate/climate.rb

Overview

Class used to gather together the CLI specification, and execute it

The standard usage pattern is as follows:

PROGRAM_VERSION = [ 0, 1, 2 ]

program_options = {}

climate = LibCLImate::Climate.new do |cl|

  cl.add_flag('--verbose', alias: '-v', help: 'Makes program output verbose') { program_options[:verbose] = true }

  cl.add_option('--flavour', alias: '-f', help: 'Specifies the flavour') do |o, a|

    program_options[:flavour] = check_flavour(o.value) or cl.abort "Invalid flavour '#{o.value}'; use --help for usage"
  end

  cl.usage_values = '<value-1> [ ... <value-N> ]'
  cl.constrain_values = 1..100000

  cl.info_lines = [

    'ACME CLI program (using libCLImate)',
    :version,
    'An example program',
  ]
end

Defined Under Namespace

Modules: Climate_Constants_

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) {|_self| ... } ⇒ Climate

Creates an instance of the Climate class.

Signature

  • Parameters:

    • options: (Hash) An options hash, containing any of the following options.

  • Options:

    • :no_help_flag (boolean) Prevents the use of the CLASP::Flag.Help flag-specification

    • :no_version_flag (boolean) Prevents the use of the CLASP::Flag.Version flag-specification

    • :program_name (::String) An explicit program-name, which is inferred from $0 if this is nil

    • :version (String, [Integer], [String]) A version specification. If not specified, this is inferred

    • :version_context Object or class that defines a context for searching the version. Ignored if :version is specified

  • Block An optional block that receives the initialising Climate instance, allowing the user to modify the attributes.

Yields:

  • (_self)

Yield Parameters:



447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
# File 'lib/libclimate/climate.rb', line 447

def initialize(options={}, &blk) # :yields: climate

	check_parameter options, 'options', allow_nil: true, type: ::Hash

	options ||=	{}

	check_option options, :no_help_flag, type: :boolean, allow_nil: true
	check_option options, :no_version_flag, type: :boolean, allow_nil: true
	check_option options, :program_name, type: ::String, allow_nil: true

	pr_name		=	options[:program_name]

	unless pr_name

		pr_name	=	File.basename($0)
		pr_name	=	(pr_name =~ /\.(?:bat|cmd|rb|sh)$/) ? "#$`(#$&)" : pr_name
	end

	given_specs			=	options[Climate_Constants_::GIVEN_SPECS_]

	@specifications		=	[]
	@ignore_unknown		=	false
	@exit_on_unknown	=	true
	@exit_on_missing	=	true
	@exit_on_usage		=	true
	@info_lines			=	nil
	set_program_name pr_name
	@stdout				=	$stdout
	@stderr				=	$stderr
	@constrain_values	=	nil
	@flags_and_options	=	flags_and_options
	@usage_values		=	usage_values
	@value_names		=	[]
	version_context		=	options[:version_context]
	@version			=	options[:version] || infer_version_(version_context)

	@specifications << CLASP::Flag.Help(handle: proc { show_usage_ }) unless options[:no_help_flag]
	@specifications << CLASP::Flag.Version(handle: proc { show_version_ }) unless options[:no_version_flag]

	@specifications	=	@specifications + given_specs if given_specs

	yield self if block_given?
end

Instance Attribute Details

#constrain_valuesObject

(Integer, Range) Optional constraint on the values that must be provided to the program



530
531
532
# File 'lib/libclimate/climate.rb', line 530

def constrain_values
  @constrain_values
end

#exit_on_missingObject

(boolean) Indicates whether exit will be called (with non-zero exit code) when a required command-line option is missing. Defaults to true



502
503
504
# File 'lib/libclimate/climate.rb', line 502

def exit_on_missing
  @exit_on_missing
end

#exit_on_unknownObject

(boolean) Indicates whether exit will be called (with non-zero exit code) when an unknown command-line flag or option is encountered. Defaults to true



506
507
508
# File 'lib/libclimate/climate.rb', line 506

def exit_on_unknown
  @exit_on_unknown
end

#exit_on_usageObject

(boolean) Indicates whether exit will be called (with zero exit code) when usage/version is requested on the command-line. Defaults to true



508
509
510
# File 'lib/libclimate/climate.rb', line 508

def exit_on_usage
  @exit_on_usage
end

#flags_and_optionsObject

(String) Optional string to describe the flags and options section. Defaults to “[ ... flags and options ... ]”



532
533
534
# File 'lib/libclimate/climate.rb', line 532

def flags_and_options
  @flags_and_options
end

#ignore_unknownObject

(boolean) Indicates whether unknown flags or options will be ignored. This overrides :exit_on_unknown. Defaults to false



504
505
506
# File 'lib/libclimate/climate.rb', line 504

def ignore_unknown
  @ignore_unknown
end

#info_linesObject

([String]) Optional array of string of program-information that will be written before the rest of the usage block when usage is requested on the command-line



510
511
512
# File 'lib/libclimate/climate.rb', line 510

def info_lines
  @info_lines
end

#program_nameObject

(String) A program name; defaults to the name of the executing script



512
513
514
515
516
517
518
519
520
521
522
# File 'lib/libclimate/climate.rb', line 512

def program_name

	name = @program_name

	if defined?(Colcon) && @stdout.tty?

		name = "#{::Colcon::Decorations::Bold}#{name}#{::Colcon::Decorations::Unbold}"
	end

	name
end

#specificationsObject (readonly)

([CLASP::Specification]) An array of specifications attached to the climate instance, whose contents should be modified by adding (or removing) CLASP specifications



498
499
500
# File 'lib/libclimate/climate.rb', line 498

def specifications
  @specifications
end

#stderr::IO

Returns The output stream for contingent output; defaults to $stderr.

Returns:

  • (::IO)

    The output stream for contingent output; defaults to $stderr



528
529
530
# File 'lib/libclimate/climate.rb', line 528

def stderr
  @stderr
end

#stdout::IO

Returns The output stream for normative output; defaults to $stdout.

Returns:

  • (::IO)

    The output stream for normative output; defaults to $stdout



526
527
528
# File 'lib/libclimate/climate.rb', line 526

def stdout
  @stdout
end

#usage_values::String

Returns Optional string to describe the program values, eg <xyz “[ { <<directory> | &lt;file> } ]”.

Returns:

  • (::String)

    Optional string to describe the program values, eg <xyz “[ { <<directory> | &lt;file> } ]”



534
535
536
# File 'lib/libclimate/climate.rb', line 534

def usage_values
  @usage_values
end

#value_namesObject

([String]) Zero-based array of names for values to be used when that value is not present (according to the :constrain_values attribute)



536
537
538
# File 'lib/libclimate/climate.rb', line 536

def value_names
  @value_names
end

#versionObject

(String, [String], [Integer]) A version string or an array of integers/strings representing the version component(s)



538
539
540
# File 'lib/libclimate/climate.rb', line 538

def version
  @version
end

Class Method Details

.load(source, options = (options_defaulted_ = {}), &blk) ⇒ Object

Loads an instance of the class, as specified by source, according to the given parameters

Signature

  • Parameters:

    • source

      (Hash, IO) The arguments specification, either as a Hash or an instance of an IO-implementing type containing a YAML specification

    • options

      An options hash, containing any of the following options

  • Options:

    • :no_help_flag (boolean) Prevents the use of the CLASP::Flag.Help flag-specification

    • :no_version_flag (boolean) Prevents the use of the CLASP::Flag.Version flag-specification

    • :program_name (::String) An explicit program-name, which is inferred from $0 if this is nil

    • :version (String, [Integer], [String]) A version specification. If not specified, this is inferred

    • :version_context Object or class that defines a context for searching the version. Ignored if :version is specified

  • Block An optional block that receives the initialising Climate instance, allowing the user to modify the attributes.



374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
# File 'lib/libclimate/climate.rb', line 374

def self.load source, options = (options_defaulted_ = {}), &blk

	check_parameter options, 'options', allow_nil: true, type: ::Hash

	options ||= {}

	h = nil

	case source
	when ::IO

		h = YAML.load source.read
	when ::Hash

		h = source
	else

		if source.respond_to?(:to_hash)

			h = source.to_hash
		else

			raise TypeError, "#{self}.#{__method__}() 'source' argument must be a #{::Hash}, or an object implementing #{::IO}, or a type implementing 'to_hash'"
		end
	end

	_libclimate				=	require_element_(h, Hash, 'libclimate', nil)
	_exit_on_missing		=	lookup_element_(_libclimate, :boolean, 'exit_on_missing', 'libclimate')
	_ignore_unknown			=	lookup_element_(_libclimate, :boolean, 'ignore_unknown', 'libclimate')
	_exit_on_unknown		=	lookup_element_(_libclimate, :boolean, 'exit_on_unknown', 'libclimate')
	_exit_on_usage			=	lookup_element_(_libclimate, :boolean, 'exit_on_usage', 'libclimate')
	_info_lines				=	lookup_element_(_libclimate, Array, 'info_lines', 'libclimate')
	_program_name			=	lookup_element_(_libclimate, String, 'program_name', 'libclimate')
	_constrain_values		=	lookup_element_(_libclimate, [ Integer, Range ], 'constrain_values', 'libclimate')
	_flags_and_options		=	lookup_element_(_libclimate, String, 'flags_and_options', 'libclimate')
	_usage_values			=	lookup_element_(_libclimate, String, 'usage_values', 'libclimate')
	_value_names			=	lookup_element_(_libclimate, Array, 'value_names', 'libclimate')
	_version				=	lookup_element_(_libclimate, [ String, [] ], 'version', 'libclimate')

	specs					=	CLASP::Arguments.load_specifications _libclimate, options

	cl						=	Climate.new(options.merge(Climate_Constants_::GIVEN_SPECS_ => specs), &blk)

	cl.exit_on_missing		=	_exit_on_missing unless _exit_on_missing.nil?
	cl.ignore_unknown		=	_ignore_unknown unless _ignore_unknown.nil?
	cl.exit_on_unknown		=	_exit_on_unknown unless _exit_on_unknown.nil?
	cl.exit_on_usage		=	_exit_on_usage unless _exit_on_usage.nil?
	cl.info_lines			=	_info_lines unless _info_lines.nil?
	cl.program_name			=	_program_name unless _program_name.nil?
	cl.constrain_values		=	_constrain_values unless _constrain_values.nil?
	cl.flags_and_options	=	_flags_and_options unless _flags_and_options.nil?
	cl.usage_values			=	_usage_values unless _usage_values.nil?
	cl.value_names			=	_value_names unless _value_names.nil?
	cl.version				=	_version unless _version.nil?

	cl
end

Instance Method Details

#abort(message, options = {}) ⇒ Object

Calls abort() with the given message prefixed by the program_name

Signature

  • Parameters:

    • message (String) The message string

    • options (Hash) An option hash, containing any of the following options

  • Options:

    • :stream optional The output stream to use. Defaults to the value of the attribute stderr

    • :program_name (String) optional Uses the given value rather than the program_name attribute; does not prefix if the empty string

    • :exit optional The exit code. Defaults to 1. Does not exit if nil specified explicitly

Returns

The combined message string, if exit() not called.



855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
# File 'lib/libclimate/climate.rb', line 855

def abort message, options={}

	prog_name	=	options[:program_name]
	prog_name	||=	program_name
	prog_name	||=	''

	stream		=	options[:stream]
	stream		||=	stderr
	stream		||=	$stderr

	exit_code	=	options.has_key?(:exit) ? options[:exit] : 1

	if prog_name.empty?

		msg = message
	else

		msg = "#{prog_name}: #{message}"
	end


	stream.puts msg

	exit(exit_code) if exit_code

	msg
end

#add_alias(name_or_specification, *aliases) ⇒ Object

Adds an alias to specifications

Signature

  • Parameters:

    • name_or_specification (String) The flag/option name or the valued option

    • aliases (*[String]) One or more aliases

Examples

Specification(s) of a flag (single statement)

climate.add_flag('--mark-missing', alias: '-x')

climate.add_flag('--absolute-path', aliases: [ '-abs', '-p' ])

Specification(s) of a flag (multiple statements)

climate.add_flag('--mark-missing')
climate.add_alias('--mark-missing', '-x')

climate.add_flag('--absolute-path')
climate.add_alias('--absolute-path', '-abs', '-p')

Specification(s) of an option (single statement)

climate.add_option('--add-patterns', alias: '-p')

Specification(s) of an option (multiple statements)

climate.add_option('--add-patterns')
climate.add_alias('--add-patterns', '-p')

Specification of a valued option (which has to be multiple statements)

climate.add_option('--verbosity', values: [ 'succinct', 'verbose' ])
climate.add_alias('--verbosity=succinct', '-s')
climate.add_alias('--verbosity=verbose', '-v')

Raises:

  • (ArgumentError)


984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# File 'lib/libclimate/climate.rb', line 984

def add_alias(name_or_specification, *aliases)

	check_parameter name_or_specification, 'name_or_specification', allow_nil: false, types: [ ::String, ::Symbol, ::CLASP::FlagSpecification, ::CLASP::OptionSpecification ]
	raise ArgumentError, "must supply at least one alias" if aliases.empty?

	case name_or_specification
	when ::CLASP::Flag

		self.specifications << name_or_specification
	when ::CLASP::Option

		self.specifications << name_or_specification
	else

		self.specifications << CLASP.Alias(name_or_specification, aliases: aliases)
	end
end

#add_flag(name_or_flag, options = {}, &blk) ⇒ Object

Adds a flag to specifications

Signature

  • Parameters:

    • name_or_flag (String, ::CLASP::FlagSpecification) The flag name or instance of CLASP::FlagSpecification

    • options (Hash) An options hash, containing any of the following options

  • Options:

    • :alias (String) A single alias

    • :aliases ([String]) An array of aliases

    • :help (String) Description string used when writing response to “--help” flag

    • :required (boolean) Indicates whether the flag is required, causing #run to fail with appropriate message if the flag is not specified in the command-line arguments

  • Block An optional block that is invoked when the parsed command-line contains the given flag, receiving the argument and the alias

Examples

Specification(s) of a flag (single statement)



903
904
905
906
907
908
909
910
911
912
913
914
# File 'lib/libclimate/climate.rb', line 903

def add_flag(name_or_flag, options={}, &blk)

	check_parameter name_or_flag, 'name_or_flag', allow_nil: false, types: [ ::String, ::Symbol, ::CLASP::FlagSpecification ]

	if ::CLASP::Flag === name_or_flag

		specifications << name_or_flag
	else

		specifications << CLASP.Flag(name_or_flag, **options, &blk)
	end
end

#add_option(name_or_option, options = {}, &blk) ⇒ Object

Adds an option to specifications

Signature

  • Parameters:

    • name_or_option (String, CLASP::OptionSpecification) The option name or instance of CLASP::OptionSpecification

    • options (Hash) An options hash, containing any of the following options

  • Options:

    • :alias (String) A single alias

    • :aliases ([String]) An array of aliases

    • :help (String) Description string used when writing response to “--help” flag

    • :values_range ([String]) An array of strings representing the valid/expected values used when writing response to “--help” flag. NOTE: the current version does not validate against these values, but a future version may do so

    • :default_value (String) The default version used when, say, for the option --my-opt the command-line contain the argument “--my-opt=

  • Block An optional block that is invoked when the parsed command-line contains the given option, receiving the argument and the alias



933
934
935
936
937
938
939
940
941
942
943
944
# File 'lib/libclimate/climate.rb', line 933

def add_option(name_or_option, options={}, &blk)

	check_parameter name_or_option, 'name_or_option', allow_nil: false, types: [ ::String, ::Symbol, ::CLASP::OptionSpecification ]

	if ::CLASP::Option === name_or_option

		specifications << name_or_option
	else

		specifications << CLASP.Option(name_or_option, **options, &blk)
	end
end

#aliasesObject

DEPRECATED

Instead, use specifications



500
# File 'lib/libclimate/climate.rb', line 500

def aliases; specifications; end

#on_flag(name_or_flag, options = {}, &blk) ⇒ Object

Attaches a block to an already-registered flag

Signature

  • Parameters:

    • name_or_flag (String, ::CLASP::FlagSpecification) The flag name or instance of CLASP::FlagSpecification

    • options (Hash) An options hash, containing any of the following options. No options are recognised currently

  • Options:

  • Block A required block that is invoked when the parsed command-line contains the given flag, receiving the argument and the alias

Raises:

  • (ArgumentError)


1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
# File 'lib/libclimate/climate.rb', line 1014

def on_flag(name_or_flag, options={}, &blk)

	check_parameter name_or_flag, 'name_or_flag', allow_nil: false, types: [ ::String, ::Symbol, ::CLASP::FlagSpecification ]

	raise ArgumentError, "on_flag() requires a block to be given" unless block_given?

	specifications.each do |spec|

		case spec
		when CLASP::FlagSpecification

			if spec == name_or_flag

				spec.action = blk

				return true
			end
		end
	end

	warn "The Climate instance does not contain a FlagSpecification matching '#{name_or_flag}' (#{name_or_flag.class})"

	false
end

#on_option(name_or_option, options = {}, &blk) ⇒ Object

Attaches a block to an already-registered option

Signature

  • Parameters:

    • name_or_option (String, ::CLASP::OptionSpecification) The option name or instance of CLASP::OptionSpecification

    • options (Hash) An options hash, containing any of the following options. No options are recognised currently

  • Options:

  • Block A required block that is invoked when the parsed command-line contains the given option, receiving the argument and the alias

Raises:

  • (ArgumentError)


1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
# File 'lib/libclimate/climate.rb', line 1051

def on_option(name_or_option, options={}, &blk)

	check_parameter name_or_option, 'name_or_option', allow_nil: false, types: [ ::String, ::Symbol, ::CLASP::OptionSpecification ]

	raise ArgumentError, "on_option() requires a block to be given" unless block_given?

	specifications.each do |spec|

		case spec
		when CLASP::OptionSpecification

			if spec == name_or_option

				spec.action = blk

				return true
			end
		end
	end

	warn "The Climate instance does not contain an OptionSpecification matching '#{name_or_option}' (#{name_or_option.class})"

	false
end

#run(argv = ARGV) ⇒ Object

Executes the prepared Climate instance

Signature

  • Parameters:

    • argv ([String]) The array of arguments; defaults to ARGV

Returns

an instance of a type derived from ::Hash with the additional attributes flags, options, values, and argv.

Raises:

  • (ArgumentError)


551
552
553
554
555
556
557
558
# File 'lib/libclimate/climate.rb', line 551

def run argv = ARGV # :yields: customised +::Hash+

	raise ArgumentError, "argv may not be nil" if argv.nil?

	arguments	=	CLASP::Arguments.new argv, specifications

	run_ argv, arguments
end

#set_program_name(name) ⇒ Object

DEPRECATED

This method is now deprecated. Instead use program_name=



492
493
494
495
# File 'lib/libclimate/climate.rb', line 492

def set_program_name name

	@program_name	=	name
end