Module: Cliffy::Internal
- Defined in:
- lib/cliffy/internal/run.rb,
lib/cliffy/internal/wrapper.rb,
lib/cliffy/internal/validate.rb,
lib/cliffy/internal/generate_help_data.rb
Defined Under Namespace
Classes: Wrapper
Class Method Summary collapse
- .generate_help_data(command, command_name, executable_name) ⇒ Object
- .run(command, arguments, command_name, executable_name) ⇒ Object
- .validate(command) ⇒ Object
Class Method Details
.generate_help_data(command, command_name, executable_name) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/cliffy/internal/generate_help_data.rb', line 3 def self.generate_help_data command, command_name, executable_name usage_tokens = [executable_name, command_name] parameter_names_and_descriptions = {} = {} command.method(:run).parameters.each do |parameter| symbol = parameter[1] description = command.signature[symbol][:description] symbol_name = parameter[1].to_s.gsub '_', '-' case parameter.first when :req usage_tokens << "<#{symbol_name}>" parameter_names_and_descriptions[symbol_name] = description when :rest usage_tokens << "<#{symbol_name}...>" parameter_names_and_descriptions[symbol_name] = description when :key option = "--#{symbol_name}" type = command.signature[symbol][:type] case type when :boolean usage_tokens << "[#{option}]" when :integer, :float, :string usage_tokens << "[#{option} value]" when Hash sub_symbol_names = type.keys.map { |sub_symbol| sub_symbol.to_s.gsub '_', '-' }.join ' ' usage_tokens << "[#{option} #{sub_symbol_names}]" end [option] = description end end usage = usage_tokens.join ' ' titles_and_contents = { 'Description' => command.description, 'Usage' => usage } unless parameter_names_and_descriptions.empty? titles_and_contents.merge! 'Parameters' => parameter_names_and_descriptions end unless .empty? titles_and_contents.merge! 'Options' => end if command.respond_to? :notes titles_and_contents.merge! 'Notes' => command.notes end titles_and_contents end |
.run(command, arguments, command_name, executable_name) ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/cliffy/internal/run.rb', line 5 def self.run command, arguments, command_name, executable_name unless command.respond_to? :signature command.run return end true_values = ['yes', 'true', '1'] false_values = ['no', 'false', '0'] = "Invalid arguments. Run `#{executable_name} help #{command_name}` for help." run_method = command.method :run signature = command.signature remaining_arguments = arguments.dup keyword_parameters = {} optional_symbols_and_data = signature.filter { |symbol, data| data[:kind] == :optional } unless optional_symbols_and_data.empty? = optional_symbols_and_data.to_h do |symbol, data| option_name = symbol.to_s.gsub '_', '-' option = "--#{option_name}" [option, symbol] end = .keys.to_set = optional_symbols_and_data.keys.map { |key| "--#{key.to_s.gsub '_', '-'}" }.to_set queued_arguments = [] while ! remaining_arguments.empty? argument = remaining_arguments.pop if argument.start_with?('--') && .include?(argument) symbol = [argument] data_type = optional_symbols_and_data[symbol][:type] value = nil case data_type when :boolean if queued_arguments.empty? value = true end when :integer, :float, :string if queued_arguments.count == 1 queued_argument = queued_arguments.first case data_type when :integer value = Integer queued_argument, exception: false when :float value = Float queued_argument, exception: false when :string value = queued_argument end end when Hash if queued_arguments.count == data_type.count sub_symbols_and_values = {} queued_arguments.zip(data_type).each do |queued_argument, sub_type| sub_value = nil case sub_type[1] when :boolean sub_value = true if true_values.include? argument sub_value = false if false_values.include? argument when :integer sub_value = Integer queued_argument, exception: false when :float sub_value = Float queued_argument, exception: false when :string sub_value = queued_argument end raise if sub_value == nil sub_symbols_and_values[sub_type.first] = sub_value end value = sub_symbols_and_values end end raise if value === nil keyword_parameters[symbol] = value .delete argument queued_arguments = [] else queued_arguments.unshift argument end end remaining_arguments = queued_arguments end strict_parsing = true if command.respond_to?(:configuration) && command.configuration.include?(:strict_parsing) strict_parsing = command.configuration[:strict_parsing] end if strict_parsing if remaining_arguments.any? { |argument| argument.start_with? '--' } raise end end required_parameters = [] run_method.parameters.each do |parameter| next unless parameter.first == :req data = signature[parameter[1]] argument = remaining_arguments.shift raise if argument == nil value = nil case data[:type] when :boolean value = true if true_values.include? argument value = false if false_values.include? argument when :integer value = Integer argument, exception: false when :float value = Float argument, exception: false when :string value = argument end raise if value == nil required_parameters << value end variadic_parameters = [] variadic_data = signature.values.find { |data| data[:kind] == :variadic } if variadic_data data_type = variadic_data[:type] while ! remaining_arguments.empty? argument = remaining_arguments.shift value = nil case data_type when :boolean value = true if true_values.include? argument value = false if false_values.include? argument when :integer value = Integer argument, exception: false when :float value = Float argument, exception: false when :string value = argument end raise if value == nil variadic_parameters << value end variadic_count = variadic_parameters.count minimum = variadic_data[:minimum] raise if minimum && variadic_parameters.count < minimum maximum = variadic_data[:maximum] raise if maximum && variadic_parameters.count > maximum else raise unless remaining_arguments.empty? end positional_parameters = required_parameters + variadic_parameters command.run *positional_parameters, **keyword_parameters end |
.validate(command) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/cliffy/internal/validate.rb', line 3 def self.validate command prefix = "Error validating '#{command.class}' command:" raise "#{prefix} No run method." unless command.respond_to? :run raise "#{prefix} No description." unless command.respond_to? :description description = command.description unless description.is_a?(String) && ! description.empty? && description.lines.count == 1 raise "#{prefix} Invalid description." end if command.respond_to? :notes notes = command.notes raise "#{prefix} Notes is not an array." unless notes.is_a?(Array) notes.each_with_index do |note, index| unless note.is_a?(String) && ! note.empty? && note.lines.count == 1 raise "#{prefix} Invalid note at index #{index}." end end end parameters = command.method(:run).parameters return if parameters.empty? unless command.respond_to?(:signature) && command.signature.is_a?(Hash) raise "#{prefix} Signature missing or not defined correctly." end command.signature.each do |symbol, data| raise "#{prefix} signature key '#{symbol}' is not a symbol." unless symbol.is_a? Symbol data_prefix = "#{prefix} Signature data for '#{symbol}'" raise "#{data_prefix} is not a hash." unless data.is_a? Hash raise "#{data_prefix} does not have a kind." unless data.include? :kind raise "#{data_prefix} does not have a type." unless data.include? :type raise "#{data_prefix} does not have a description." unless data.include? :description data_kind = data[:kind] data_type = data[:type] data_description = data[:description] case data_kind when :required, :optional valid_data_keys = [:kind, :description, :type] when :variadic valid_data_keys = [:kind, :description, :type, :minimum, :maximum] else raise "#{data_prefix} has an invalid kind." end unless data.keys.to_set.subset? valid_data_keys.to_set raise "#{data_prefix} contains an unrecognized key." end unless data_description.is_a?(String) && ! data_description.empty? && data_description.lines.count == 1 raise "#{data_prefix} does not have a valid description." end primitives = [:string, :integer, :float, :boolean] case data_kind when :required, :variadic unless primitives.include? data_type raise "#{data_prefix} is of kind '#{data_kind}' and must have a valid primitive type." end when :optional case data_type when :string, :integer, :float, :boolean when Hash unless data_type.keys.all? { |key| key.is_a? Symbol } raise "#{data_prefix} contains an invalid key in the value hash." end unless data_type.values.all? { |value| primitives.include? value } raise "#{data_prefix} contains an invalid value in the value hash." end else raise "#{data_prefix} is of kind 'optional' and must have a valid primitive or hash type." end end if data_kind == :variadic if data.include? :minimum minimum = data[:minimum] unless minimum.is_a?(Integer) && minimum >= 0 raise "#{data_prefix} has an invalid minimum value." end else minimum = 0 end if data.include? :maximum maximum = data[:maximum] unless maximum.is_a?(Integer) && maximum >= 0 && maximum > minimum raise "#{data_prefix} has an invalid maximum value." end end end end method_symbols = parameters.map { |parameter| parameter[1] }.to_set signature_symbols = command.signature.keys.to_set missing_method_symbols = signature_symbols - method_symbols missing_signature_symbols = method_symbols - signature_symbols unless missing_method_symbols.empty? raise "#{prefix} Symbols missing from run method that are in signature: #{missing_method_symbols.join ', '}" end unless missing_signature_symbols.empty? raise "#{prefix} Symbols missing from signature that are in run method: #{missing_signature_symbols.join ', '}" end found_req = false found_rest = false found_key = false parameters.each do |parameter| parameter_prefix = "#{prefix} '#{parameter[1]}'" case parameter.first when :req kind = :required found_req = true raise "#{prefix} Required positional after variadic." if found_rest raise "#{prefix} Required positional after required keyword." if found_key when :rest kind = :variadic found_rest = true raise "#{prefix} Variadic after required keyword." if found_key when :key kind = :optional found_key = true else raise "#{parameter_prefix} is not a supported kind of method parameter." end unless command.signature[parameter[1]][:kind] == kind raise "#{parameter_prefix} should have a kind of '#{kind}', in the signature." end end end |