nodesets 0.0.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6973b486464e08befc4f99114654eb52e25db997
4
+ data.tar.gz: a954a9e38efe4dd85c0141cc2ce91d8fd50b3a05
5
+ SHA512:
6
+ metadata.gz: d424f0036f276b841063335467b3176245689f4384eb432cdb044e4076f4f7eb8c10f4aad07084ed95caab23762a9455422a530bc32c44a2a66e9fad9ae82fa5
7
+ data.tar.gz: f32ae6d788e7fcbfdaa4254a1058d80282aed4911682173a5b928c81e1e99d6e98e49b059f5e9a048cdb4e77193c4e1632f65d59298e303cec674363a522f883
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ # Vim swap files
16
+ [._]*.s[a-v][a-z]
17
+ [._]*.sw[a-p]
18
+ [._]s[a-v][a-z]
19
+ [._]sw[a-p]
20
+ #Gem itself
21
+ #*.gem
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,18 @@
1
+ image: "ruby:2.0"
2
+
3
+ stages:
4
+ - setup
5
+ - test
6
+
7
+ before_script:
8
+ - bundle install
9
+
10
+ rspec:
11
+ stage: test
12
+ cache:
13
+ key: gems
14
+ policy: pull
15
+ script:
16
+ - bundle exec rspec spec
17
+ tags:
18
+ - docker
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in nodesets.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2017 Adam Spencer
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ [![pipeline status](https://git.computecanada.ca/cc-provisioning/nodesets/badges/master/pipeline.svg)](https://git.computecanada.ca/cc-provisioning/nodesets/commits/master)
2
+ # Nodesets
3
+
4
+ Nodeset rubygem, includes sample, as well as usable, executables. Fold, expand or count nodesets. Allows exclude, intersection or XOR from the specified nodesets.
5
+ Attempts to follows Slurm Nodeset (NodeName) conventions, possibly more if extensions are added.
6
+ Not as feature filled as ClusterShell NodeSet written in Python, but faster at the moment and does the job in ruby.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'nodeset'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install nodesets
23
+
24
+ ## Usage
25
+
26
+ TODO: Write usage instructions here
27
+
28
+ ## Contributing
29
+
30
+ 1. Fork it ( https://git.computecanada.ca/cc-provisioning/nodesets/fork )
31
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
32
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
33
+ 4. Push to the branch (`git push origin my-new-feature`)
34
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/nodeset.rb ADDED
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'nodesets'
5
+
6
+ options = {
7
+ :field_separator => ' ',
8
+ }
9
+
10
+ optparse = OptionParser.new do|opts|
11
+ opts.banner = "Usage: nodeset.rb [options]"
12
+ opts.on( '--debug', 'Support pry for debugging' ) do
13
+ options[:debug] = true
14
+ end
15
+ opts.on( '-v', '--verbose', 'Output a lot of job information' ) do
16
+ options[:verbose] = true
17
+ end
18
+ opts.on( '-f', '--fs \'separator...\'', 'Field separator to use between nodes, defaults to space' ) do |fs|
19
+ options[:field_separator] = fs.gsub(/(#{SEPARATORS.keys.map{|x|Regexp.escape(x)}.join('|')})/,SEPARATORS)
20
+ end
21
+ opts.on( '-e', '--expand [NodeSet]', 'Expand NodeSet to a list' ) do |nodes|
22
+ options[:expand] = nodes ? nodes : ''
23
+ end
24
+ opts.on( '-f', '--fold [Nodes]', 'Fold a node list of most forms into a proper NodeSet' ) do |nodes|
25
+ options[:fold] = nodes ? nodes : ''
26
+ end
27
+ opts.on( '-c', '--count [Nodes]', 'Count a node list of most forms of NodeSet' ) do |nodes|
28
+ options[:count] = nodes ? nodes : ''
29
+ end
30
+ opts.on( '-x', '--exclude Nodes', 'Exclude specified NodeSet from inputted NodeSet' ) do |nodes|
31
+ options[:exclude] = nodes
32
+ end
33
+ opts.on( '-i', '--intersection Nodes', 'Calculate specified NodeSet intersection from inputted NodeSet' ) do |nodes|
34
+ options[:intersection] = nodes
35
+ end
36
+ opts.on( '-X', '--xor Nodes', 'Calculate symmetric difference between this NodeSet and inputted NodeSet' ) do |nodes|
37
+ options[:xor] = nodes
38
+ end
39
+ end
40
+ begin optparse.parse!
41
+ rescue OptionParser::InvalidOption => e
42
+ puts e
43
+ puts optparse
44
+ exit 1
45
+ end
46
+
47
+ if ARGF.filename != "-" or (not STDIN.tty? and not STDIN.closed?)
48
+ input = ARGF.read.gsub("\n", ',').chomp(',')
49
+ end
50
+
51
+ fail 'Can only set either --fold or --expand, not both' if options[:fold] && options[:expand]
52
+ fail 'Can only set one or none of --exclude, --intersection or --xor' if [options[:exclude],options[:intersection],options[:xor]].compact.count > 1
53
+
54
+ nodeset = Nodesets::Nodeset.new
55
+ [options[:expand], options[:fold], options[:count], input].each do |nodes|
56
+ nodeset.merge(nodes) if not nodes.nil? || nodes.empty?
57
+ end
58
+
59
+ out = []
60
+ to_out = []
61
+ if options[:exclude]
62
+ nodeset = nodeset - options[:exclude]
63
+ elsif options[:intersection]
64
+ nodeset = nodeset & options[:intersection]
65
+ elsif options[:xor]
66
+ nodeset = nodeset ^ options[:xor]
67
+ end
68
+ out << nodeset.count if options[:count]
69
+ if options[:expand]
70
+ out.concat(nodeset.to_a)
71
+ elsif options[:fold]
72
+ out << nodeset.fold
73
+ end
74
+ to_out << out.join(options[:field_separator]) if out
75
+ puts to_out
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'nodesets'
5
+
6
+ options = {
7
+ :field_separator => ' ',
8
+ }
9
+
10
+ optparse = OptionParser.new do|opts|
11
+ opts.banner = "Usage: nodeset_oo_example.rb [options]"
12
+ opts.on( '--debug', 'Support pry for debugging' ) do
13
+ options[:debug] = true
14
+ end
15
+ opts.on( '-v', '--verbose', 'Output a lot of job information' ) do
16
+ options[:verbose] = true
17
+ end
18
+ opts.on( '-f', '--fs \'separator...\'', 'Field separator to use between nodes, defaults to space' ) do |fs|
19
+ options[:field_separator] = fs.gsub(/(#{SEPARATORS.keys.map{|x|Regexp.escape(x)}.join('|')})/,SEPARATORS)
20
+ end
21
+ opts.on( '-e', '--expand [NodeSet]', 'Expand NodeSet to a list' ) do |nodes|
22
+ options[:expand] = nodes ? nodes : ''
23
+ end
24
+ opts.on( '-f', '--fold [Nodes]', 'Fold a node list of most forms into a proper NodeSet' ) do |nodes|
25
+ options[:fold] = nodes ? nodes : ''
26
+ end
27
+ opts.on( '-c', '--count [Nodes]', 'Count a node list of most forms of NodeSet' ) do |nodes|
28
+ options[:count] = nodes ? nodes : ''
29
+ end
30
+ end
31
+ begin optparse.parse!
32
+ rescue OptionParser::InvalidOption => e
33
+ puts e
34
+ puts optparse
35
+ exit 1
36
+ end
37
+
38
+ if ARGF.filename != "-" or (not STDIN.tty? and not STDIN.closed?)
39
+ input = ARGF.read
40
+ end
41
+
42
+ fail 'Can only set either --fold or --expand, not both' if options[:fold] && options[:expand]
43
+
44
+ node_out = []
45
+ to_out = []
46
+ expanded = nil
47
+ expanded_of_folded = nil
48
+ if not options[:expand].nil?
49
+ options[:expand] = options[:expand]+','+input if input
50
+ expanded = Nodesets.parse_nodeset(options[:expand])
51
+ node_out << expanded
52
+ elsif not options[:fold].nil?
53
+ options[:fold] = options[:fold]+','+input if input
54
+ expanded_of_folded = Nodesets.parse_nodeset(options[:fold])
55
+ node_out << [Nodesets.make_nodeset(expanded_of_folded)]
56
+ end
57
+ if not options[:count].nil?
58
+ incl_input = nil
59
+ incl_count = nil
60
+ incl_count = count if not options[:count].empty?
61
+ incl_input = input if not options[:expand] && options[:fold]
62
+ nodes = [expanded, expanded_of_folded, incl_count, incl_input].compact.join(',')
63
+ to_out << Nodesets.parse_nodeset(nodes).count
64
+ end
65
+ to_out << node_out.join(options[:field_separator]) if node_out
66
+ puts to_out.flatten
@@ -0,0 +1,42 @@
1
+ module Nodesets
2
+ # http://www.zenspider.com/ruby/2012/01/array-natural_sort.html
3
+ # https://dzone.com/articles/convert-ruby-array-ranges
4
+ # This has been improved since the posting
5
+ # a.to_ranges.map { |x| x.count > 1 ? x.to_s.gsub!(/([[:digit:]]+)[.]{2}[[:alpha:]]+([[:digit:]]+)/,'[\1-\2]') : x.first }
6
+ class HumanSortableArray < Array
7
+ #def initialize(arr, compact_uniq = false, sorted = false)
8
+ # @compact_uniq = compact_uniq
9
+ # @sorted = sorted
10
+ # super(arr)
11
+ #end
12
+ def human_sort
13
+ self.sort_by { |item| item.to_s.split(/(\d+)/).map { |e| [e.to_i, e] } }
14
+ end
15
+ def to_ranges
16
+ array = self
17
+ #array = HumanSortableArray.new(self).human_sort
18
+ #array = if not @compact_uniq && @sorted
19
+ # HumanSortableArray.new(self.compact.uniq, true, true).human_sort_simple
20
+ #else
21
+ # self
22
+ #end
23
+ #array = HumanSortableArray.new(self.compact.uniq, true, true).human_sort
24
+ ranges = []
25
+ if !array.empty?
26
+ # Initialize the left and right endpoints of the range
27
+ left, right = array.first, nil
28
+ array.each do |obj|
29
+ # If the right endpoint is set and obj is not equal to right's successor
30
+ # then we need to create a range.
31
+ if right && obj != right.succ
32
+ ranges << (left == right ? left : Range.new(left,right))
33
+ left = obj
34
+ end
35
+ right = obj
36
+ end
37
+ ranges << (left == right ? left : Range.new(left,right))
38
+ end
39
+ ranges
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,61 @@
1
+ require 'set'
2
+
3
+ module Nodesets
4
+ class Nodeset < Set
5
+ attr_reader :sorted
6
+ def initialize(nodes = nil, sorted = false)
7
+ @sorted = sorted
8
+ nodes = Nodesets.parse_nodeset(nodes) if nodes && nodes.is_a?(String)
9
+ #nodes = Nodesets.parse_nodeset(nodes) if nodes && (! nodes.is_a?(Set))
10
+ super(nodes)
11
+ end
12
+ def merge(nodes)
13
+ @sorted = false
14
+ if nodes && (! nodes.is_a?(Set))
15
+ nodes = if nodes.is_a?(Array)
16
+ nodes.map {|x| Nodesets.parse_nodeset(x) }.flatten
17
+ else
18
+ Nodesets.parse_nodeset(nodes)
19
+ end
20
+ end
21
+ super(nodes)
22
+ end
23
+ def subtract(nodes)
24
+ @sorted = false
25
+ nodes = Nodesets.parse_nodeset(nodes) if nodes && (! nodes.is_a?(Set))
26
+ super(nodes)
27
+ end
28
+ def &(nodes)
29
+ nodes = Nodesets.parse_nodeset(nodes) if nodes && (! nodes.is_a?(Set))
30
+ super(nodes)
31
+ end
32
+ def ^(nodes)
33
+ nodes = Nodesets.parse_nodeset(nodes) if nodes && (! nodes.is_a?(Set))
34
+ self.class.new(super(nodes))
35
+ end
36
+ def human_sort
37
+ if @sorted
38
+ self
39
+ else
40
+ Nodesets::Nodeset.new(Nodesets::HumanSortableArray.new(self.to_a).human_sort, true)
41
+ end
42
+ end
43
+ def human_sort!
44
+ self.replace(human_sort)
45
+ #replaced = self.replace(human_sort)
46
+ #@sorted = true
47
+ #replaced
48
+ end
49
+ def [](pos)
50
+ self.human_sort! unless @sorted
51
+ self.to_a[pos]
52
+ end
53
+ def fold
54
+ Nodesets.make_nodeset(self)
55
+ end
56
+ def expand(sort: true)
57
+ self.human_sort! if (! @sorted) && sort
58
+ self.to_a
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ module Nodesets
2
+ VERSION = "0.0.2"
3
+ end
data/lib/nodesets.rb ADDED
@@ -0,0 +1,80 @@
1
+ require "nodesets/version"
2
+ require "nodesets/human_sortable_array"
3
+ require "nodesets/nodeset"
4
+
5
+ module Nodesets
6
+
7
+ SEPARATORS = {
8
+ '\n' => "\n",
9
+ '\r' => "\r",
10
+ '\t' => "\t",
11
+ '\0' => "\0",
12
+ }
13
+ Nodeset_split = /,(?=(?:[^\]]*\[[^\[]*\])*[^\]]*\z)/.freeze
14
+ Nodeset_single_split = /\[(.+?)\]$/.freeze
15
+ SCONTROL_ALLOCGPU_REGEX = /NodeName=(?<nodename>\S+)(?:.*)AllocTRES=\S+?gpu=(?<gpucount>\S+)/.freeze
16
+
17
+ class << self
18
+ # require "#{File.expand_path('../nodeset_gem', __FILE__)}/human_sortable_array"
19
+ # require "#{File.expand_path('../nodeset_gem', __FILE__)}/nodeset"
20
+ def parse_nodeset(nodeset)
21
+ nodeset = nodeset.split(Nodeset_split).map do |set|
22
+ match = /(\d.*)/.match(set) if not set.include?('[')
23
+ set = "#{match.pre_match}[#{match[0]}]" if match
24
+ prefix, digits = set.split(Nodeset_single_split)
25
+ post_digits = digits.split(',').map do |x|
26
+ if x.include?('-')
27
+ first, _, last = x.partition('-')
28
+ (first.to_i..last.to_i).to_a.map do |y|
29
+ name = "#{prefix}#{y}"
30
+ name = yield name if block_given?
31
+ name
32
+ end
33
+ else
34
+ name = "#{prefix}#{x}"
35
+ name = yield name if block_given?
36
+ name
37
+ end
38
+ end.flatten
39
+ end.flatten.uniq
40
+ ## FIXME: Probably not the parsers job to do the sorting, removed it for now
41
+ ## expensive call and breaks test predictability
42
+ #Nodesets::HumanSortableArray.new(nodeset).human_sort
43
+ end
44
+ def parse_nodeset_arr(nodeset_arr)
45
+ nodeset_arr.each_with_object([]) do |nodeset, node_arr|
46
+ node_arr.concat(parse_nodeset(nodeset))
47
+ end
48
+ end
49
+ def make_nodeset(node_arr)
50
+ # For speed, and because we only currently support a single prefix in a nodeset
51
+ # we will assume that the first items prefix is the same as all the rest
52
+ node_arr = node_arr.to_a
53
+ node_prefix = node_arr[0].partition(/^([-_A-Za-z]+)/)[1]
54
+ node_prefix_length = node_prefix.length
55
+ num_w_ranges = node_arr.map do |x|
56
+ x[node_prefix_length..-1].to_i
57
+ end
58
+ ## Old, less efficient method
59
+ #node_prefix = ''
60
+ #num_w_ranges = node_arr.map do |x|
61
+ # name_split = x.partition(/^([-_A-Za-z]+)/)
62
+ # node_prefix = name_split[1] if node_prefix.empty?
63
+ # name_split.last
64
+ #end
65
+ num_w_ranges = Nodesets::HumanSortableArray.new(num_w_ranges.sort).to_ranges.map do |x|
66
+ ## Old, less efficient method
67
+ #x.to_s.sub('..','-')
68
+ begin
69
+ y = x.to_s
70
+ y[/\.\./] = '-'
71
+ y
72
+ rescue IndexError
73
+ x
74
+ end
75
+ end.join(',')
76
+ node_arr.length > 1 ? "#{node_prefix}[#{num_w_ranges}]" : "#{node_prefix}#{num_w_ranges}"
77
+ end
78
+ end
79
+
80
+ end
data/nodesets.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'nodesets/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'nodesets'
8
+ spec.version = Nodesets::VERSION
9
+ spec.summary = "Nodeset parsing the way that Slurm tends to handle, folding or expanding"
10
+ spec.description = %q(
11
+ Allows parsing nodenames or Nodesets in the way that Slurm generally handles,
12
+ you can either fold an array of names into a nodeset, or you can expand a nodeset into
13
+ an array of separate node names.
14
+ )
15
+ spec.authors = ["Adam Spencer"]
16
+ spec.email = 'adam.spencer@sfu.ca'
17
+ #s.executables = [
18
+ # "nodeset_gem.rb",
19
+ #]
20
+ #s.files = [
21
+ # "lib/nodeset_gem.rb",
22
+ # "lib/nodeset_gem/nodeset.rb",
23
+ # "lib/nodeset_gem/human_sortable_array.rb",
24
+ #]
25
+ spec.homepage = 'http://rubygems.org/gems/nodesets'
26
+ spec.license = 'MIT'
27
+
28
+ spec.files = `git ls-files -z`.split("\x0")
29
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
30
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_development_dependency "bundler", "~> 1.7"
34
+ spec.add_development_dependency "rake", "~> 10.0"
35
+ spec.add_development_dependency "rspec", "~> 3.2"
36
+ end
@@ -0,0 +1,92 @@
1
+ require 'nodesets'
2
+
3
+ # TODO: Add further tests
4
+ # Fix the :human_sort, :human_sort! test
5
+ describe Nodesets do
6
+ it "Nodeset pre-ordered contains iam1,iam9,iam10,iam11,iam20" do
7
+ arr = ['iam1','iam9','iam10','iam11','iam20']
8
+ expect(Nodesets::Nodeset.new(arr.join(',')).to_a).to eql(arr)
9
+ end
10
+
11
+ it "Nodeset pre-unordered contains iam9,iam10,iam11,iam20,iam1" do
12
+ arr = ['iam9','iam10','iam11','iam20','iam1']
13
+ expect(Nodesets::Nodeset.new(arr.join(',')).to_a).to eql(arr)
14
+ end
15
+
16
+ it "Nodeset human_sorted" do
17
+ unsorted_arr = ['iam9','iam10','iam11','iam20','iam1']
18
+ sorted_arr = ['iam1','iam9','iam10','iam11','iam20']
19
+ expect(Nodesets::Nodeset.new(unsorted_arr.join(',')).human_sort.to_a).to eql(sorted_arr)
20
+ end
21
+
22
+ it "Nodeset human_sort and human_sort! to return the same sorted array when to_a" do
23
+ unsorted_arr = ['iam9','iam10','iam11','iam20','iam1']
24
+ initial = Nodesets::Nodeset.new(unsorted_arr.join(','))
25
+ human_sort_wo_dup = initial.human_sort
26
+ human_sort_w_dup = initial.human_sort!
27
+ expect(human_sort_wo_dup.to_a == human_sort_w_dup.to_a).to be true
28
+ end
29
+
30
+ ### TODO: FIXME: This test currently does not work
31
+ ## The purpose of this test is to verify that :human_sort returns a new object, and
32
+ ## :human_sort! replaces the current object with a new object, unsure of how to test this...
33
+ #it "Nodeset human_sort! (duplicate, new, object returned rather than the same object)" do
34
+ # unsorted_arr = ['iam9','iam10','iam11','iam20','iam1']
35
+ # initial = Nodesets::Nodeset.new(unsorted_arr.join(','))
36
+ # human_sort_wo_dup = initial.human_sort
37
+ # human_sort_w_dup = initial.human_sort!
38
+ # expect(human_sort_wo_dup == human_sort_w_dup).to be true
39
+ # expect(human_sort_wo_dup.object_id == human_sort_w_dup.object_id).to be false
40
+ #end
41
+
42
+ it "Nodeset after value merge to contain the same values(not order specific) as array" do
43
+ arr = ['iam1','iam9','iam10','iam11','iam20']
44
+ initial = Nodesets::Nodeset.new(arr.join(','))
45
+ to_adjust = 'iam3'
46
+ adjusted_arr = (arr << to_adjust)
47
+ adjusted_nodeset_arr = initial.merge(to_adjust).to_a
48
+ expect(adjusted_nodeset_arr & adjusted_arr == adjusted_arr && adjusted_nodeset_arr - adjusted_arr == []).to be true
49
+ end
50
+
51
+ it "Nodeset after value subtraction to contain the same values(not order specific) as array" do
52
+ arr = ['iam1','iam9','iam10','iam11','iam20']
53
+ initial = Nodesets::Nodeset.new(arr.join(','))
54
+ to_adjust = 'iam11'
55
+ adjusted_arr = arr - [to_adjust]
56
+ adjusted_nodeset_arr = initial.subtract(to_adjust).to_a
57
+ expect(adjusted_nodeset_arr & adjusted_arr == adjusted_arr && adjusted_nodeset_arr - adjusted_arr == []).to be true
58
+ end
59
+
60
+ it "Nodeset :& intersection converted back to array to match array intersection(not order specific)" do
61
+ arr = ['iam1','iam9','iam10','iam11','iam20']
62
+ intersection = ['iam9','iam11','iam400']
63
+ initial = Nodesets::Nodeset.new(arr.join(','))
64
+ adjusted_arr = arr & intersection
65
+ adjusted_nodeset_arr = (initial & Nodesets::Nodeset.new(intersection.join(','))).to_a
66
+ expect(adjusted_nodeset_arr & adjusted_arr == adjusted_arr && adjusted_nodeset_arr - adjusted_arr == []).to be true
67
+ end
68
+
69
+ it "Nodeset fold properly" do
70
+ arr = ['iam1','iam9','iam10','iam11','iam20']
71
+ expect(Nodesets::Nodeset.new(arr.join(',')).fold).to eql('iam[1,9-11,20]')
72
+ end
73
+
74
+ it "Nodeset expand properly and be :human_sort'ed" do
75
+ arr = ['iam13','iam1','iam9','iam10','iam11','iam20']
76
+ human_sorted_arr = ['iam1','iam9','iam10','iam11','iam13','iam20']
77
+ expect(Nodesets::Nodeset.new(arr.join(',')).expand).to eql(human_sorted_arr)
78
+ end
79
+
80
+ it "Nodeset XOR properly" do
81
+ arr = ['iam1','iam9','iam10','iam11','iam20']
82
+ xor_arr = ['iam1','iam10','iam11']
83
+ shouldbe_arr = ['iam9','iam20']
84
+ expect((Nodesets::Nodeset.new(arr.join(',')) ^ Nodesets::Nodeset.new(xor_arr.join(','))).to_a).to eql(shouldbe_arr)
85
+ end
86
+
87
+ it "Nodeset unsorted array to sorted subset :[] properly" do
88
+ arr = ['iam1','iam15','iam9','iam10','iam11','iam20']
89
+ expect(Nodesets::Nodeset.new(arr.join(','))[2..4]).to eql(['iam10','iam11','iam15'])
90
+ end
91
+
92
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nodesets
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Adam Spencer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-11-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '3.2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3.2'
55
+ description: "\nAllows parsing nodenames or Nodesets in the way that Slurm generally
56
+ handles,\nyou can either fold an array of names into a nodeset, or you can expand
57
+ a nodeset into\nan array of separate node names.\n "
58
+ email: adam.spencer@sfu.ca
59
+ executables:
60
+ - nodeset.rb
61
+ - nodeset_non_oo_example.rb
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - .gitignore
66
+ - .gitlab-ci.yml
67
+ - Gemfile
68
+ - LICENSE.txt
69
+ - README.md
70
+ - Rakefile
71
+ - bin/nodeset.rb
72
+ - bin/nodeset_non_oo_example.rb
73
+ - lib/nodesets.rb
74
+ - lib/nodesets/human_sortable_array.rb
75
+ - lib/nodesets/nodeset.rb
76
+ - lib/nodesets/version.rb
77
+ - nodesets.gemspec
78
+ - spec/nodesets_spec.rb
79
+ homepage: http://rubygems.org/gems/nodesets
80
+ licenses:
81
+ - MIT
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.0.14.1
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: Nodeset parsing the way that Slurm tends to handle, folding or expanding
103
+ test_files:
104
+ - spec/nodesets_spec.rb