skn_utils 3.5.2 → 3.6.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.
@@ -1,216 +0,0 @@
1
- ##
2
- # File <SknUtils>/lib/skn_utils/lists/linked_commons.rb
3
- #
4
- # Common routines for Linked List:
5
- # #initialize, #first, #next, #current, #last, #at_index,
6
- # #insert, #prepend, #append, #empty?, #clear,
7
- # #each, #to_a, and #sort!
8
- #
9
- # list = SknUtils::Lists::DoublyLinkedList.new(1,2,3,4)
10
- #
11
- # value = list.first
12
- # value = list.next
13
- #
14
- ##
15
- # Node Interface Special Methods called
16
- # from LinkNode to execute regular methods on other nodes
17
- #
18
- # #node_request(method_sym=:current, *vargs, &block) ==> node
19
- # #node_value_request(method_sym=:current, *vargs, &block) ==> value or method return
20
- ##
21
- # node = SknUtils::Lists::DoublyLinkedList.call(1,2,3,4)
22
- #
23
- # node = node.first_node
24
- # value = node.value
25
- # value = node.next_node.value
26
- ##
27
-
28
- module SknUtils
29
- module Lists
30
-
31
- class LinkedCommons
32
- attr_accessor :size
33
-
34
- # Initialize and return first node if nodes are available, else class instance
35
- def self.call(*vargs, &compare_key_proc)
36
- target = self.new(*vargs, &compare_key_proc)
37
- return target.instance_variable_get(:@current) if vargs.size > 1
38
- target
39
- end
40
-
41
- def initialize(*vargs, &compare_key_proc)
42
- @current = nil
43
- @head = nil
44
- @tail = nil
45
- @size = 0
46
-
47
- @match_value = block_given? ? compare_key_proc : lambda {|obj| obj }
48
- @sort_ascending = lambda {|a_obj,b_obj| @match_value.call(a_obj) >= @match_value.call(b_obj)}
49
- @sort_descending = lambda {|a_obj,b_obj| @match_value.call(a_obj) <= @match_value.call(b_obj)}
50
- @sort_condition = @sort_ascending
51
-
52
- vargs.each {|value| insert(value) }
53
- first if vargs.size > 1
54
- end
55
-
56
-
57
- # return values and position current to last node accessed
58
- # prevent @current from nil assignment
59
- def first
60
- @current = self.head if self.head
61
- @current.value rescue nil
62
- end
63
-
64
- def next
65
- @current = @current.next if @current and @current.next
66
- @current.value rescue nil
67
- end
68
-
69
- def current
70
- @current.value rescue nil
71
- end
72
-
73
- def last
74
- @current = self.tail if self.tail
75
- @current.value rescue nil
76
- end
77
-
78
- # return node at positive index from head
79
- def at_index(index)
80
- find_by_index(index)
81
- current
82
- end
83
-
84
- # Access to current node as anchor for Node based operations
85
- # if initialized without vargs, this is only way to access a node
86
- def nodes
87
- @current
88
- end
89
-
90
- def empty?
91
- self.size == 0
92
- end
93
-
94
- # return number cleared
95
- def clear
96
- rc = 0
97
- node = self.head
98
- position = node
99
- while node do
100
- node = node.remove!
101
- rc += 1
102
- break if position.equal?(node)
103
- end
104
-
105
- @current = nil
106
- self.head = nil
107
- self.tail = nil
108
- self.size = 0
109
- rc
110
- end
111
-
112
- # return new size
113
- def prepend(value)
114
- temp = self.head.value rescue nil
115
- insert_before(temp, value)
116
- end
117
-
118
- #
119
- # Enumerate
120
- #
121
-
122
- # perform each() or return enumerator
123
- def each(&block)
124
- @current = self.head
125
- position = @current
126
- if block_given?
127
- while position do
128
- block.call( position.value.dup )
129
- position = position.next
130
- break if position.equal?(@current)
131
- end
132
- else
133
- Enumerator.new do |yielder|
134
- while position do
135
- yielder << position.value.dup
136
- position = position.next
137
- break if position.equal?(@current)
138
- end
139
- end
140
- end
141
- end
142
-
143
- # convert self to a value array
144
- def to_a
145
- @current = self.head
146
- position = self.head
147
- result = []
148
- while position do
149
- result << position.value.dup
150
- position = position.next
151
- break if position.equal?(@current)
152
- end
153
- result
154
- end
155
-
156
- # block format: sort condition : {|a_obj,b_obj| a_obj >= b_obj}
157
- def sort!(direction_sym=:default, &compare_sort_proc)
158
- @active_sort_condition = block_given? ? compare_sort_proc :
159
- case direction_sym
160
- when :asc
161
- @sort_ascending
162
- when :desc
163
- @sort_descending
164
- else
165
- @sort_condition
166
- end
167
- sorted = merge_sort(self.to_a)
168
- clear
169
- sorted.each {|item| insert(item) }
170
- self.size
171
- end
172
-
173
-
174
- protected
175
-
176
- attr_accessor :head, :tail
177
-
178
- # scan for first occurance of matching value
179
- def find_by_value(value)
180
- return nil if value.nil? || self.size == 0
181
- stop_node = self.head
182
- target = stop_node
183
- while target && !target.match_by_value(value)
184
- target = target.next
185
- break if stop_node.equal?(target)
186
- end
187
- target = nil unless target && target.match_by_value(value)
188
- target
189
- end
190
-
191
- # Merged Sort via Ref: http://rubyalgorithms.com/merge_sort.html
192
- # arr is Array to be sorted, sort_cond is Proc expecting a/b params returning true/false
193
- def merge_sort(arr)
194
- return arr if arr.size < 2
195
- middle = arr.size / 2
196
- left = merge_sort(arr[0...middle])
197
- right = merge_sort(arr[middle..arr.size])
198
- merge(left, right)
199
- end
200
-
201
- def merge(left, right)
202
- sorted = []
203
- while left.any? && right.any?
204
- if @active_sort_condition.call(left.first, right.first)
205
- sorted.push right.shift
206
- else
207
- sorted.push left.shift
208
- end
209
- end
210
-
211
- sorted + left + right
212
- end
213
-
214
- end
215
- end # module
216
- end
@@ -1,122 +0,0 @@
1
- ##
2
- # File <SknUtils>/lib/skn_utils/lists/linked_list.rb
3
- #
4
- # ll = SknUtils::Lists::LinkedList.new(*vargs, &compare_key_proc)
5
- # - or -
6
- # ll = SknUtils::Lists::LinkedList.new(1,2,3,4,5) {|element| element[:key] }
7
- # - or -
8
- # ll = SknUtils::Lists::LinkedList.new(
9
- # {key: 'Z'}, {key: 'K'}, {key: 'S'}, {key: 'n'}, {key: 's'}
10
- # ) {|el| el[:key] }
11
- # - or -
12
- # cmp_proc = lambda { |el| el[:key] }
13
- # vargs = [{key: 'Z'}, {key: 'K'}, {key: 'S'}, {key: 'n'}, {key: 's'}]
14
- # ll = SknUtils::Lists::LinkedList.new(*vargs, &cmp_proc)
15
- ###
16
- # value = ll.first
17
- # value = ll.at_index(4)
18
- # count = ll.insert({key: 'anyValue'})
19
- # ...
20
- # count = ll.sort! -- defaults to :asc
21
- # count = ll.sort!(:desc)
22
- # count = ll.sort!() {|a,b| a[:key] <= b[:key] }
23
- ##
24
-
25
- module SknUtils
26
- module Lists
27
- # Singly Linked List
28
- # Forward or #next navigation only
29
- # Head is absolute via #first
30
- # Tail when (next == nil)
31
-
32
- # LinkedCommons provides;
33
- # - #initialize, #first, #next, #current, #last, #at_index,
34
- # #insert, #prepend, #append, #empty?, #clear,
35
- # #each, #to_a, and #sort!
36
- #
37
- class LinkedList < LinkedCommons
38
-
39
- #
40
- # Navigation
41
- #
42
-
43
- # +int position from current node
44
- def nth(index)
45
- node = @current
46
- while index > 1 and node and node.next
47
- node = node.next
48
- index -= 1
49
- @current = node
50
- end
51
- # no reverse or prev for Single List
52
- current
53
- end
54
-
55
- #
56
- # Modifications
57
- #
58
-
59
- def insert(value)
60
- node = @current
61
- @current = LinkNode.call(value, node, :single, self, &@match_value)
62
- self.head = @current if self.head.nil?
63
- self.tail = @current if self.tail.equal?(node)
64
- self.size += 1
65
- end
66
- alias_method :append, :insert
67
-
68
- # return new size
69
- def insert_before(position_value, value)
70
- prior, target = find_by_value(position_value)
71
- node = LinkNode.call(value, prior, :single, self, &@match_value)
72
- node.next = target if target
73
- self.head = node if self.head.equal?(target)
74
- self.tail = node if self.tail.nil?
75
- @current = node
76
- self.size += 1
77
- end
78
-
79
- # return new size
80
- def insert_after(position_value, value)
81
- prior, target = find_by_value(position_value)
82
- node = LinkNode.call(value, target, :single, self, &@match_value)
83
- self.head = node if self.head.nil?
84
- self.tail = node if self.tail.equal?(target)
85
- @current = node
86
- self.size += 1
87
- end
88
-
89
- # return remaining size
90
- def remove(value)
91
- prior, target_node = find_by_value(value)
92
- @current = prior.nil? ? target_node.next : prior
93
- @current.next = target_node.remove! if @current && target_node
94
- self.tail = @current.next if @current && self.tail.equal?(target_node)
95
- self.head = @current.next if @current && self.head.equal?(target_node)
96
- self.size -= 1
97
- end
98
-
99
- protected
100
-
101
- def find_by_value(value)
102
- return [@current, nil] if self.head.nil? || value.nil?
103
- prior = self.head
104
- target = prior
105
- while target && !target.match_by_value(value)
106
- prior = target
107
- target = target.next
108
- end
109
- [prior, target]
110
- end
111
-
112
- def find_by_index(index)
113
- return nil if self.head.nil? || index < 1 || index > self.size
114
- node = self.head
115
- node = node.next while ((index -= 1) > 0 and node.next)
116
- @current = node if node
117
- node
118
- end
119
-
120
- end # end class
121
- end # end module
122
- end # end module
@@ -1,49 +0,0 @@
1
- ##
2
- # spec/lib/skn_utils/node_based_linked_list_spec.rb
3
- #
4
-
5
- RSpec.describe SknUtils::BusinessServices::YearMonth, "Year Month Calculator " do
6
-
7
- let(:basic) { described_class.new(2017, 1) }
8
-
9
- context "Normal Operations " do
10
-
11
- it "No params" do
12
- expect{described_class.new}.to raise_error(ArgumentError)
13
- end
14
- it "With Params" do
15
- expect(basic).to be_a described_class
16
- end
17
- it "#beginning_of month to be correct. " do
18
- expect(basic.beginning_of).to be_a Time
19
- end
20
- it "#end_of month to be correct. " do
21
- expect(basic.end_of).to be_a Time
22
- end
23
- it "#month to equal 3." do
24
- expect(basic.month).to eq(1)
25
- end
26
- it "#year to equal 2017." do
27
- expect(basic.year).to eq(2017)
28
- end
29
- it "#next.month to equal 2." do
30
- expect(basic.next.month).to eq(2)
31
- end
32
- it "Comparisons are correct." do
33
- expect(described_class.new(2017,1)).to eq(described_class.new(2017,1))
34
- expect(described_class.new(2017,2)).to be > (described_class.new(2017,1))
35
- expect(described_class.new(2017,1)).to be < (described_class.new(2017,2))
36
- end
37
- end
38
-
39
- context "Range Operations " do
40
-
41
- it "Can be represented in a Range object. " do
42
- range = described_class.new(2017, 1)..described_class.new(2017, 9)
43
-
44
- expect(range).to include(described_class.new(2017, 2))
45
- expect(range).to include(described_class.new(2017, 7))
46
- end
47
- end
48
-
49
- end
@@ -1,120 +0,0 @@
1
- ##
2
- # spec/lib/skn_utils/converters/hash_to_xml_spec.rb
3
- #
4
-
5
- describe SknUtils::Converters::HashToXml, "Hash to XML Converter Utility " do
6
-
7
- context "Initializers Feature. " do
8
-
9
- it "#new can be called without params or block without error. " do
10
- expect( described_class.new()).to be_a described_class
11
- end
12
-
13
- it "#call can be called without params or block without error. " do
14
- expect( described_class.call()).to be nil
15
- end
16
-
17
- it "#call called with params returns xml string as expected. " do
18
- string = described_class.call({
19
- one: 1,
20
- two: 2,
21
- list: {item: [1,2,3]},
22
- listings: {item: [1,2,3]}
23
- })
24
- puts __method__, string
25
- expect(string).to be_a String
26
- end
27
-
28
- it "#call called with params and block yields xml string as expected. " do
29
- described_class.call({
30
- one: 1,
31
- two: 2,
32
- list: {item: [1,2,3]},
33
- listings: {item: [1,2,3]}
34
- }) do |string|
35
- puts __method__, string
36
- expect(string).to be_a String
37
- end
38
- end
39
-
40
- end
41
-
42
- context "Handles Complex Hashes. " do
43
- let(:array_of_hashes) {
44
- {'resource' => [
45
- { 'name' => 'category1',
46
- 'subCategory' => [
47
- { 'name' => 'subCategory1',
48
- 'product' => [
49
- { 'name' => 'productName1',
50
- 'desc' => 'desc1' },
51
- { 'name' => 'productName2',
52
- 'desc' => 'desc2' } ]
53
- } ]
54
- },
55
- { 'name' => 'category2',
56
- 'subCategory' => [
57
- { 'name' => 'subCategory2.1',
58
- 'product' => [
59
- { 'name' => 'productName2.1.1',
60
- 'desc' => 'desc1' },
61
- { 'name' => 'productName2.1.2',
62
- 'desc' => 'desc2' } ]
63
- } ]
64
- }
65
- ]
66
- }
67
- }
68
-
69
- let(:xml_aware_hash) {
70
- {'xmlAwareHash' =>
71
- {
72
- 'num' => 99,
73
- 'title' => 'something witty',
74
- 'nested' => {
75
- 'total' => [99, 98],
76
- '@attributes' => {'foo' => 'bar', 'hello' => 'world'}
77
- },
78
- 'anothernest' => {
79
- '@attributes' => {'foo' => 'bar', 'hello' => 'world'},
80
- 'date' => [
81
- 'today',
82
- {'day' => 23, 'month' => 'Dec',
83
- 'year' => {'y' => 1999, 'c' => 21},
84
- '@attributes' => {'foo' => 'blhjkldsaf'}
85
- }
86
- ]
87
- }
88
- }
89
- }
90
- }
91
-
92
- it "#call(nested_hash) return an xml string as expected." do
93
- string = described_class.call({
94
- one: 1,
95
- two: 2,
96
- list: {item: [1,2,3]},
97
- listings: {
98
- uri: 'topic/content/topic_value',
99
- '@attributes' => {secured: true}}
100
- })
101
- puts __method__, string
102
- expect( string ).to be_a String
103
- end
104
-
105
- it "#call(array_of_hashes) return an xml string as expected." do
106
- string = described_class.call(array_of_hashes, false)
107
- puts __method__, string
108
- expect( string ).to be_a String
109
- end
110
-
111
- it "#call(xml_aware_hash) return an xml string as expected." do
112
- string = described_class.call(xml_aware_hash)
113
- puts __method__, string
114
- expect( string ).to be_a String
115
- end
116
-
117
- end
118
-
119
-
120
- end
@@ -1,40 +0,0 @@
1
- ##
2
- # spec/lib/skn_utils/exploring/action_service_spec.rb
3
- #
4
-
5
- RSpec.describe SknUtils::Exploring::ActionService, "Example Service Object class with command interface." do
6
- let(:action) {
7
- SknUtils::Exploring::ActionService.new('Thingys')
8
- }
9
-
10
- context "Handles Bad Input. " do
11
- it "Handles invalid string input params" do
12
- expect { action.('Samples') }.to output(/Samples/).to_stdout
13
- end
14
- end
15
-
16
- context "Single Method Invocations. " do
17
- it "Handles a call with no param" do
18
- expect { action.() }.to output(/No Action Taken/).to_stdout
19
- end
20
- it "Handles a call with one param" do
21
- expect { action.(:action_one) }.to output(/Thingys/).to_stdout
22
- end
23
- it "Handles a call with more than one param" do
24
- expect { action.(:action_two, 'Wonderful') }.to output(/Wonderful/).to_stdout
25
- end
26
- end
27
-
28
- context "Chaining Method Invocations. " do
29
- it "Handles calls with no params" do
30
- expect { action.().() }.to output(/No Action Taken/).to_stdout
31
- end
32
- it "Handles a calls with one param" do
33
- expect { action.(:action_one).(:action_one) }.to output(/Thingys/).to_stdout
34
- end
35
- it "Handles a calls with more than one param" do
36
- expect { action.(:action_two, 'Wonderful').(:action_two, 'Marvelous') }.to output(/Wonderful/).to_stdout
37
- end
38
- end
39
-
40
- end
@@ -1,125 +0,0 @@
1
- ##
2
- # spec/lib/skn_utils/commander_spec.rb
3
- #
4
- #
5
-
6
- class Person
7
- extend SknUtils::Exploring::Commander
8
- command [:make_me_a_sandwich, :cook, :blocky] => :@friend
9
- query [:activities, :go, :say_what] => :friend
10
- attr_accessor :friend
11
- end
12
-
13
- class Friend
14
- def make_me_a_sandwich
15
- Table.place "a sandwich!"
16
- end
17
-
18
- def cook(what)
19
- Table.place what
20
- end
21
-
22
- def activities
23
- 'running, biking, hiking'
24
- end
25
-
26
- def go(do_what)
27
- Activities.record do_what
28
- end
29
-
30
- def blocky(text)
31
- Activities.record([yield(self).to_s,text].join(' '))
32
- end
33
-
34
- def say_what(text)
35
- [yield(self).to_s,text].join(' ')
36
- end
37
- end
38
-
39
- module Table
40
- def self.place(text)
41
- contents << text
42
- end
43
- def self.contents
44
- @contents ||= []
45
- end
46
- def self.clear
47
- @contents = []
48
- end
49
- end
50
-
51
- module Activities
52
- def self.record(text)
53
- list << text
54
- end
55
- def self.list
56
- @list ||= []
57
- end
58
- def self.clear
59
- @list = []
60
- end
61
- end
62
-
63
- RSpec.describe SknUtils::Exploring::Commander, 'command' do
64
- let(:friend){ Friend.new }
65
- let(:person){ person = Person.new
66
- person.friend = friend
67
- person
68
- }
69
- before do
70
- Table.clear
71
- Activities.clear
72
- end
73
- it 'forwards a message to another object' do
74
- expect(Table.contents).to eq []
75
- person.make_me_a_sandwich
76
- expect(Table.contents).to include "a sandwich!"
77
- end
78
-
79
- it 'returns the original receiver' do
80
- expect( person).to eq person.make_me_a_sandwich
81
- end
82
-
83
- it 'forwards additional arguments' do
84
- expect(Table.contents).to eq []
85
- person.cook('yum')
86
- expect(Table.contents).to include "yum"
87
- end
88
-
89
- it 'forwards block arguments' do
90
- expect(Activities.list).to eq []
91
- person.blocky('yay!') do |friend|
92
- "Arguments forwarded to #{friend}"
93
- end
94
- expect(Activities.list).to include "Arguments forwarded to #{friend} yay!"
95
- end
96
- end
97
-
98
- RSpec.describe SknUtils::Exploring::Commander, 'query' do
99
- let(:friend){ Friend.new }
100
- let(:person){ person = Person.new
101
- person.friend = friend
102
- person
103
- }
104
- before do
105
- Activities.clear
106
- end
107
-
108
- it 'forwards a message to another object' do
109
- expect(person.activities).to eq "running, biking, hiking"
110
- end
111
-
112
- it 'forwards additional arguments' do
113
- expect(Activities.list).to eq []
114
- person.go('have fun')
115
- expect(Activities.list).to include "have fun"
116
- end
117
-
118
- it 'forwards block arguments' do
119
- expect(Activities.list).to eq []
120
- what_said = person.say_what('yay!') do |friend|
121
- "Arguments forwarded to #{friend}"
122
- end
123
- expect(what_said).to eq "Arguments forwarded to #{friend} yay!"
124
- end
125
- end