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 +7 -0
- data/.gitignore +21 -0
- data/.gitlab-ci.yml +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +34 -0
- data/Rakefile +2 -0
- data/bin/nodeset.rb +75 -0
- data/bin/nodeset_non_oo_example.rb +66 -0
- data/lib/nodesets/human_sortable_array.rb +42 -0
- data/lib/nodesets/nodeset.rb +61 -0
- data/lib/nodesets/version.rb +3 -0
- data/lib/nodesets.rb +80 -0
- data/nodesets.gemspec +36 -0
- data/spec/nodesets_spec.rb +92 -0
- metadata +104 -0
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
data/Gemfile
ADDED
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
|
+
[](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
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
|
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
|