skn_utils 3.5.2 → 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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