Top Level Namespace
Instance Method Summary collapse
-
#hostlist_expression(expression, separator = [":", "-"]) ⇒ Array<String>
Expand hostlist expression.
Instance Method Details
#hostlist_expression(expression, separator = [":", "-"]) ⇒ Array<String>
Expand hostlist expression
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 |
# File 'lib/hostlist_expression.rb', line 17 def hostlist_expression(expression, separator = [":", "-"]) # Validate range separator if separator.class == Array separator = separator.join("") end if not separator.class == String raise "Error: Range separator must be either of type String or Array. given: #{separator.class}" elsif separator.length == 0 raise "Error: Range separator is empty" end # Prepeare separator for use in regular expressions separator = Regexp.escape(separator) # Return input, if this is not a hostlist expression return expression if not expression.match(/\[(?:[\da-z]+(?:[#{separator}][\da-z]+)?,?)+\]/i) # hosts array will hold all expanded results, it as well is the working array where partially resolved results are stored hosts = Array.new hosts.push(expression) # Iterate over all range definitions, e.g. [0:10] or [A:Z] expression.scan(/\[([\da-z#{separator},]+)\]/i).each do|match| # Will hold replacements for each match replacements = Array.new # The pattern may be a sequence with multiple ranges. Split... match[0].split(",").each do |range| # Split ranges by range separator range_items = range.split(/[#{separator}]/) # If it's not really a range, duplicate the single item if range_items.length == 1 range_items.push(range_items[0]) end # Get lower and higher value of range if range_items[0] < range_items[1] from = range_items[0] to = range_items[1] else from = range_items[1] to = range_items[0] end # Numeric range if from.match(/^[0-9]+$/) and to.match(/^[0-9]+$/) isnum = true from = from.to_i to = to.to_i # Uppercase alphabetic range elsif from.length == 1 and to.length == 1 and /^[[:upper:]]+$/.match(from) and /^[[:upper:]]+$/.match(to) alphabet = ('A'..'Z').to_a from = alphabet.index(from) to = alphabet.index(to) # Lowercase alphabetic range elsif from.length == 1 and to.length == 1 and /^[[:lower:]]+$/.match(from) and /^[[:lower:]]+$/.match(to) alphabet = ('a'..'z').to_a from = alphabet.index(from) to = alphabet.index(to) else raise "Error: Invalid host range definition #{expression}" end # Iterate over all hosts and store the resolved patterns in "replacements" hosts.each do |host| # Iterate over the range (from..to).each do |i| if isnum # Formatting number with leading zeros replacements.push("#{i}".rjust(range_items[0].length, "0")) else # Select correct letter from alphabet replacements.push(alphabet[i]) end end end end # We clone the hosts array, because we can't modify it while iterating over its elements. So we iterate over the clone instead hosts.clone.each do |host| # Remove the original element hosts.delete(host) # Iterate over previously stored replacements replacements.each do|replacement| # Adding replacement to hosts array hosts.push(host.sub(/\[#{match[0]}\]/, replacement)) end end end # Return uniqe results return hosts.uniq end |