libclimate-ruby 0.12.2 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4b097608f416fda5a16bf34588903e669cd37abc259c8e971c65087de88dbd1e
4
- data.tar.gz: 3dd3938b2ea4fc8f8b2d632787b048d8c8a75fd575a1df4262c60007fea989fb
3
+ metadata.gz: 6c5040323c276e22e2dcf86fbebf1e66bf159904d9a28e764ff913aed1d9a508
4
+ data.tar.gz: 9551c44bc9ca7bb1f69783d8c6b1e5ae0288548140dcd86023cd80df6fa98c14
5
5
  SHA512:
6
- metadata.gz: 23fa6d636ea3bc4bae684ab3adaae3abb12ea3c6dc634c48fd69098016f7fad816b87e07c50291a136e0ea4e9bb4ec41d816f7a155428ae6a213db184cd45705
7
- data.tar.gz: 17ae81db2053520808553a12cabf97c96369ffbf027039bc53c689ea05c1933ec4aff888b957f262432209cd980f6da3c28557c24874cb759d29c31a5a8a3c8d
6
+ metadata.gz: 158c64020110e066c1f57be6c4820e9519bed9fccee5883b903dd8d8f4c49d91f971bcfef8e2ff3fd416e6074be0149562098305b56a7cd705aa2619199c7620
7
+ data.tar.gz: 7672ba94c8724a7504f12d589ff20e703b31eb5ae5e27e6f1878ba8136a8ab2f0749e307b5d00ef11cfca277641c3c3479808c0a2d2406be1247abe887ae3f93
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # examples/flag_and_option_specifications.from_DATA.rb
4
+
5
+
6
+ # requires
7
+
8
+ require 'libclimate'
9
+
10
+
11
+ # constants
12
+
13
+ PROGRAM_VERSION = '0.0.1'
14
+
15
+
16
+ # Specify aliases, parse, and checking standard flags
17
+
18
+ options = {}
19
+ climate = LibCLImate::Climate.load DATA do |cl|
20
+
21
+ cl.on_flag('--debug') { options[:debug] = true }
22
+
23
+ cl.on_option('--verbosity') { |o, a| options[:verbosity] = o.value }
24
+ end
25
+
26
+ r = climate.run ARGV
27
+
28
+
29
+ # Program-specific processing of flags/options
30
+
31
+ if options[:verbosity]
32
+
33
+ $stdout.puts "verbosity is specified as: #{options[:verbosity]}"
34
+ end
35
+
36
+ if options[:debug]
37
+
38
+ $stdout.puts 'Debug mode is specified'
39
+ end
40
+
41
+
42
+ __END__
43
+ ---
44
+ libclimate:
45
+ clasp:
46
+ specifications:
47
+ - flag:
48
+ name: --debug
49
+ alias: -d
50
+ help: runs in Debug mode
51
+ required: false
52
+ - option:
53
+ name: --verbosity
54
+ help: specifies the verbosity
55
+ values:
56
+ - silent
57
+ - quiet
58
+ - terse
59
+ - chatty
60
+ - verbose
61
+ - alias:
62
+ resolved: --verbosity=chatty
63
+ aliases:
64
+ - --chatty
65
+ - -c
66
+ constrain_values: !ruby/range 1..2
67
+ exit_on_missing: true
68
+ flags_and_options: "[... flags/options ...]"
69
+ usage_values: "<directory-1> [ <directory-2> ]"
70
+ value_names:
71
+ - directory-1
72
+ - directory-2
73
+ info_lines:
74
+ - libCLImate.Ruby examples
75
+ - :version
76
+ - Illustrates use of libCLImate.Ruby's specification of flags, options, and aliases, from DATA
77
+ -
78
+ version:
79
+ - 0
80
+ - 3
81
+ - "4"
82
+
@@ -44,6 +44,8 @@ require 'clasp'
44
44
  require 'xqsr3/extensions/io'
45
45
  require 'xqsr3/quality/parameter_checking'
46
46
 
47
+ require 'yaml'
48
+
47
49
  =begin
48
50
  =end
49
51
 
@@ -166,6 +168,11 @@ class Climate
166
168
  #:stopdoc:
167
169
 
168
170
  private
171
+ module Climate_Constants_
172
+
173
+ GIVEN_SPECS_ = "_Given_Specs_01B59422_8407_4c89_9432_8160C52BD5AD"
174
+ end # module Climate_Constants_
175
+
169
176
  def show_usage_
170
177
 
171
178
  options = {}
@@ -262,10 +269,166 @@ class Climate
262
269
 
263
270
  nil
264
271
  end
272
+
273
+ def self.check_type_(v, types)
274
+
275
+ return true if v.nil?
276
+
277
+ types = [ types ] unless Array === types
278
+
279
+ return true if types.empty?
280
+
281
+ types.each do |type|
282
+
283
+ if false
284
+
285
+ ;
286
+ elsif :boolean == type
287
+
288
+ return true if [ TrueClass, FalseClass ].include? v.class
289
+ elsif type.is_a?(Class)
290
+
291
+ return true if v.is_a?(type)
292
+ elsif type.is_a?(Array)
293
+
294
+ t0 = type[0]
295
+
296
+ if t0
297
+
298
+ #return true if v.is_a?
299
+ else
300
+
301
+ # Can be array of anything
302
+
303
+ return true if v.is_a?(Array)
304
+ end
305
+ else
306
+
307
+ warn "Cannot validate type of '#{v}' (#{v.class}) against type specification '#{type}'"
308
+ end
309
+ end
310
+
311
+ false
312
+ end
313
+
314
+ def self.lookup_element_(h, types, name, path)
315
+
316
+ if h.has_key?(name)
317
+
318
+ r = h[name]
319
+
320
+ unless self.check_type_(r, types)
321
+
322
+ raise TypeError, "element '#{name}' is of type '#{r.class}' and '#{types}' is required"
323
+ end
324
+
325
+ return r
326
+ end
327
+
328
+ nil
329
+ end
330
+
331
+ def self.require_element_(h, types, name, path)
332
+
333
+ unless h.has_key?(name)
334
+
335
+ if (path || '').empty?
336
+
337
+ raise ArgumentError, "missing top-level element '#{name}' in load configuration"
338
+ else
339
+
340
+ raise ArgumentError, "missing element '#{path}/#{name}' in load configuration"
341
+ end
342
+ else
343
+
344
+ r = h[name]
345
+
346
+ unless self.check_type_(r, types)
347
+
348
+ raise TypeError, "element '#{name}' is of type '#{r.class}' and '#{types}' is required"
349
+ end
350
+
351
+ return r
352
+ end
353
+ end
265
354
  #:startdoc:
266
355
 
267
356
  public
268
357
 
358
+ # Loads an instance of the class, as specified by +source+, according to the given parameters
359
+ #
360
+ # === Signature
361
+ #
362
+ # * *Parameters:*
363
+ # - +source+:: (+Hash+, +IO+) The arguments specification, either as a Hash or an instance of an IO-implementing type containing a YAML specification
364
+ # - +options+:: An options hash, containing any of the following options
365
+ #
366
+ # * *Options:*
367
+ # - +:no_help_flag+ (boolean) Prevents the use of the +CLASP::Flag.Help+ flag-specification
368
+ # - +:no_version_flag+ (boolean) Prevents the use of the +CLASP::Flag.Version+ flag-specification
369
+ # - +:program_name+ (::String) An explicit program-name, which is inferred from +$0+ if this is +nil+
370
+ # - +:version+ (String, [Integer], [String]) A version specification. If not specified, this is inferred
371
+ # - +:version_context+ Object or class that defines a context for searching the version. Ignored if +:version+ is specified
372
+ #
373
+ # * *Block* An optional block that receives the initialising Climate instance, allowing the user to modify the attributes.
374
+ def self.load source, options = (options_defaulted_ = {}), &blk
375
+
376
+ check_parameter options, 'options', allow_nil: true, type: ::Hash
377
+
378
+ options ||= {}
379
+
380
+ h = nil
381
+
382
+ case source
383
+ when ::IO
384
+
385
+ h = YAML.load source.read
386
+ when ::Hash
387
+
388
+ h = source
389
+ else
390
+
391
+ if source.respond_to?(:to_hash)
392
+
393
+ h = source.to_hash
394
+ else
395
+
396
+ raise TypeError, "#{self}.#{__method__}() 'source' argument must be a #{::Hash}, or an object implementing #{::IO}, or a type implementing 'to_hash'"
397
+ end
398
+ end
399
+
400
+ _libclimate = require_element_(h, Hash, 'libclimate', nil)
401
+ _exit_on_missing = lookup_element_(_libclimate, :boolean, 'exit_on_missing', 'libclimate')
402
+ _ignore_unknown = lookup_element_(_libclimate, :boolean, 'ignore_unknown', 'libclimate')
403
+ _exit_on_unknown = lookup_element_(_libclimate, :boolean, 'exit_on_unknown', 'libclimate')
404
+ _exit_on_usage = lookup_element_(_libclimate, :boolean, 'exit_on_usage', 'libclimate')
405
+ _info_lines = lookup_element_(_libclimate, Array, 'info_lines', 'libclimate')
406
+ _program_name = lookup_element_(_libclimate, String, 'program_name', 'libclimate')
407
+ _constrain_values = lookup_element_(_libclimate, [ Integer, Range ], 'constrain_values', 'libclimate')
408
+ _flags_and_options = lookup_element_(_libclimate, String, 'flags_and_options', 'libclimate')
409
+ _usage_values = lookup_element_(_libclimate, String, 'usage_values', 'libclimate')
410
+ _value_names = lookup_element_(_libclimate, Array, 'value_names', 'libclimate')
411
+ _version = lookup_element_(_libclimate, [ String, [] ], 'version', 'libclimate')
412
+
413
+ specs = CLASP::Arguments.load_specifications _libclimate, options
414
+
415
+ cl = Climate.new(options.merge(Climate_Constants_::GIVEN_SPECS_ => specs), &blk)
416
+
417
+ cl.exit_on_missing = _exit_on_missing unless _exit_on_missing.nil?
418
+ cl.ignore_unknown = _ignore_unknown unless _ignore_unknown.nil?
419
+ cl.exit_on_unknown = _exit_on_unknown unless _exit_on_unknown.nil?
420
+ cl.exit_on_usage = _exit_on_usage unless _exit_on_usage.nil?
421
+ cl.info_lines = _info_lines unless _info_lines.nil?
422
+ cl.program_name = _program_name unless _program_name.nil?
423
+ cl.constrain_values = _constrain_values unless _constrain_values.nil?
424
+ cl.flags_and_options = _flags_and_options unless _flags_and_options.nil?
425
+ cl.usage_values = _usage_values unless _usage_values.nil?
426
+ cl.value_names = _value_names unless _value_names.nil?
427
+ cl.version = _version unless _version.nil?
428
+
429
+ cl
430
+ end
431
+
269
432
  # Creates an instance of the Climate class.
270
433
  #
271
434
  # === Signature
@@ -280,8 +443,8 @@ class Climate
280
443
  # - +:version+ (String, [Integer], [String]) A version specification. If not specified, this is inferred
281
444
  # - +:version_context+ Object or class that defines a context for searching the version. Ignored if +:version+ is specified
282
445
  #
283
- # * *Block* An optional block which receives the constructing instance, allowing the user to modify the attributes.
284
- def initialize(options={}) # :yields: climate
446
+ # * *Block* An optional block that receives the initialising Climate instance, allowing the user to modify the attributes.
447
+ def initialize(options={}, &blk) # :yields: climate
285
448
 
286
449
  check_parameter options, 'options', allow_nil: true, type: ::Hash
287
450
 
@@ -299,6 +462,8 @@ class Climate
299
462
  pr_name = (pr_name =~ /\.(?:bat|cmd|rb|sh)$/) ? "#$`(#$&)" : pr_name
300
463
  end
301
464
 
465
+ given_specs = options[Climate_Constants_::GIVEN_SPECS_]
466
+
302
467
  @specifications = []
303
468
  @ignore_unknown = false
304
469
  @exit_on_unknown = true
@@ -318,6 +483,8 @@ class Climate
318
483
  @specifications << CLASP::Flag.Help(handle: proc { show_usage_ }) unless options[:no_help_flag]
319
484
  @specifications << CLASP::Flag.Version(handle: proc { show_version_ }) unless options[:no_version_flag]
320
485
 
486
+ @specifications = @specifications + given_specs if given_specs
487
+
321
488
  yield self if block_given?
322
489
  end
323
490
 
@@ -386,6 +553,13 @@ class Climate
386
553
  raise ArgumentError, "argv may not be nil" if argv.nil?
387
554
 
388
555
  arguments = CLASP::Arguments.new argv, specifications
556
+
557
+ run_ argv, arguments
558
+ end
559
+
560
+ private
561
+ def run_ argv, arguments # :nodoc:
562
+
389
563
  flags = arguments.flags
390
564
  options = arguments.options
391
565
  values = arguments.values.to_a
@@ -594,7 +768,7 @@ class Climate
594
768
  message = "wrong number of values: #{values.size} given, #{values_constraint} required; use --help for usage"
595
769
  end
596
770
 
597
- if exit_on_unknown
771
+ if exit_on_missing
598
772
 
599
773
  self.abort message
600
774
  else
@@ -619,7 +793,7 @@ class Climate
619
793
  message = "wrong number of values: #{values.size} givens, #{values_constraint.begin} - #{values_constraint.end - (values_constraint.exclude_end? ? 1 : 0)} required; use --help for usage"
620
794
  end
621
795
 
622
- if exit_on_unknown
796
+ if exit_on_missing
623
797
 
624
798
  self.abort message
625
799
  else
@@ -661,6 +835,7 @@ class Climate
661
835
 
662
836
  results
663
837
  end
838
+ public
664
839
 
665
840
  # Calls abort() with the given message prefixed by the program_name
666
841
  #
@@ -719,20 +894,22 @@ class Climate
719
894
  # - +:help+ (String) Description string used when writing response to "+--help+" flag
720
895
  # - +: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
721
896
  #
897
+ # * *Block* An optional block that is invoked when the parsed command-line contains the given flag, receiving the argument and the alias
898
+ #
722
899
  # === Examples
723
900
  #
724
901
  # ==== Specification(s) of a flag (single statement)
725
902
  #
726
- def add_flag(name_or_flag, options={}, &block)
903
+ def add_flag(name_or_flag, options={}, &blk)
727
904
 
728
- check_parameter name_or_flag, 'name_or_flag', allow_nil: false, types: [ ::String, ::Symbol, ::CLASP::Flag ]
905
+ check_parameter name_or_flag, 'name_or_flag', allow_nil: false, types: [ ::String, ::Symbol, ::CLASP::FlagSpecification ]
729
906
 
730
907
  if ::CLASP::Flag === name_or_flag
731
908
 
732
909
  specifications << name_or_flag
733
910
  else
734
911
 
735
- specifications << CLASP.Flag(name_or_flag, **options, &block)
912
+ specifications << CLASP.Flag(name_or_flag, **options, &blk)
736
913
  end
737
914
  end
738
915
 
@@ -750,16 +927,19 @@ class Climate
750
927
  # - +:help+ (String) Description string used when writing response to "+--help+" flag
751
928
  # - +: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
752
929
  # - +:default_value+ (String) The default version used when, say, for the option +--my-opt+ the command-line contain the argument "+--my-opt=+"
753
- def add_option(name_or_option, options={}, &block)
930
+ #
931
+ # * *Block* An optional block that is invoked when the parsed command-line contains the given option, receiving the argument and the alias
932
+ #
933
+ def add_option(name_or_option, options={}, &blk)
754
934
 
755
- check_parameter name_or_option, 'name_or_option', allow_nil: false, types: [ ::String, ::Symbol, ::CLASP::Option ]
935
+ check_parameter name_or_option, 'name_or_option', allow_nil: false, types: [ ::String, ::Symbol, ::CLASP::OptionSpecification ]
756
936
 
757
937
  if ::CLASP::Option === name_or_option
758
938
 
759
939
  specifications << name_or_option
760
940
  else
761
941
 
762
- specifications << CLASP.Option(name_or_option, **options, &block)
942
+ specifications << CLASP.Option(name_or_option, **options, &blk)
763
943
  end
764
944
  end
765
945
 
@@ -803,7 +983,7 @@ class Climate
803
983
  # climate.add_alias('--verbosity=verbose', '-v')
804
984
  def add_alias(name_or_specification, *aliases)
805
985
 
806
- check_parameter name_or_specification, 'name_or_specification', allow_nil: false, types: [ ::String, ::Symbol, ::CLASP::Flag, ::CLASP::Option ]
986
+ check_parameter name_or_specification, 'name_or_specification', allow_nil: false, types: [ ::String, ::Symbol, ::CLASP::FlagSpecification, ::CLASP::OptionSpecification ]
807
987
  raise ArgumentError, "must supply at least one alias" if aliases.empty?
808
988
 
809
989
  case name_or_specification
@@ -818,6 +998,80 @@ class Climate
818
998
  self.specifications << CLASP.Alias(name_or_specification, aliases: aliases)
819
999
  end
820
1000
  end
1001
+
1002
+ # Attaches a block to an already-registered flag
1003
+ #
1004
+ # === Signature
1005
+ #
1006
+ # * *Parameters:*
1007
+ # - +name_or_flag+ (String, ::CLASP::FlagSpecification) The flag name or instance of CLASP::FlagSpecification
1008
+ # - +options+ (Hash) An options hash, containing any of the following options. No options are recognised currently
1009
+ #
1010
+ # * *Options:*
1011
+ #
1012
+ # * *Block* A required block that is invoked when the parsed command-line contains the given flag, receiving the argument and the alias
1013
+ #
1014
+ def on_flag(name_or_flag, options={}, &blk)
1015
+
1016
+ check_parameter name_or_flag, 'name_or_flag', allow_nil: false, types: [ ::String, ::Symbol, ::CLASP::FlagSpecification ]
1017
+
1018
+ raise ArgumentError, "on_flag() requires a block to be given" unless block_given?
1019
+
1020
+ specifications.each do |spec|
1021
+
1022
+ case spec
1023
+ when CLASP::FlagSpecification
1024
+
1025
+ if spec == name_or_flag
1026
+
1027
+ spec.action = blk
1028
+
1029
+ return true
1030
+ end
1031
+ end
1032
+ end
1033
+
1034
+ warn "The Climate instance does not contain a FlagSpecification matching '#{name_or_flag}' (#{name_or_flag.class})"
1035
+
1036
+ false
1037
+ end
1038
+
1039
+ # Attaches a block to an already-registered option
1040
+ #
1041
+ # === Signature
1042
+ #
1043
+ # * *Parameters:*
1044
+ # - +name_or_option+ (String, ::CLASP::OptionSpecification) The option name or instance of CLASP::OptionSpecification
1045
+ # - +options+ (Hash) An options hash, containing any of the following options. No options are recognised currently
1046
+ #
1047
+ # * *Options:*
1048
+ #
1049
+ # * *Block* A required block that is invoked when the parsed command-line contains the given option, receiving the argument and the alias
1050
+ #
1051
+ def on_option(name_or_option, options={}, &blk)
1052
+
1053
+ check_parameter name_or_option, 'name_or_option', allow_nil: false, types: [ ::String, ::Symbol, ::CLASP::OptionSpecification ]
1054
+
1055
+ raise ArgumentError, "on_option() requires a block to be given" unless block_given?
1056
+
1057
+ specifications.each do |spec|
1058
+
1059
+ case spec
1060
+ when CLASP::OptionSpecification
1061
+
1062
+ if spec == name_or_option
1063
+
1064
+ spec.action = blk
1065
+
1066
+ return true
1067
+ end
1068
+ end
1069
+ end
1070
+
1071
+ warn "The Climate instance does not contain an OptionSpecification matching '#{name_or_option}' (#{name_or_option.class})"
1072
+
1073
+ false
1074
+ end
821
1075
  end # class Climate
822
1076
  end # module LibCLImate
823
1077
 
@@ -43,7 +43,7 @@
43
43
  module LibCLImate
44
44
 
45
45
  # Current version of the libCLImate.Ruby library
46
- VERSION = '0.12.2'
46
+ VERSION = '0.13.0'
47
47
 
48
48
  private
49
49
  VERSION_PARTS_ = VERSION.split(/[.]/).collect { |n| n.to_i } # :nodoc:
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libclimate-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.2
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Wilson
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.18'
19
+ version: '0.19'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.18'
26
+ version: '0.19'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: xqsr3
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -46,6 +46,7 @@ extra_rdoc_files: []
46
46
  files:
47
47
  - LICENSE
48
48
  - README.md
49
+ - examples/flag_and_option_specifications.from_DATA.rb
49
50
  - examples/flag_and_option_specifications.md
50
51
  - examples/flag_and_option_specifications.rb
51
52
  - examples/show_usage_and_version.md