skn_utils 3.2.1 → 3.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3e5f35b9cb8f4d40e5450210986430079a3dc62b
4
- data.tar.gz: 165cb18c3053dedaa3f72a96c007a4b1d2170d3a
3
+ metadata.gz: aec86482b36e3dc0625a89641a5220417cbb4761
4
+ data.tar.gz: dd1e2519bf5d407deb7c05f1d7454e2b2db2e9e1
5
5
  SHA512:
6
- metadata.gz: 6ad5ece92556a9124e64178cf0d51b47a146fd338fdbd07fdfe97b44d8dcd217857308a4e31b963b54bbef2c401ee1191b94fda25f300744aeb042cef58a70d0
7
- data.tar.gz: 879e7b4feb2b76ebfd0ba5ff540e8deb96fa52d198050b8402b4906a10a8dbea65164ebe997a15c45b8591176c9b336295a03e136392d32aec4299635ed5ba30
6
+ metadata.gz: 1f8b4978cd8bdf65eece11e09f400ba65f1b3904fc61e7c6f88889b968a9802cad5155b3bb9dea96ad960f5d147b81bf00ca1a04e742e86fe6863afdafa6ef54
7
+ data.tar.gz: f61b021c403bf7dcade30dab45625078e0e8e19c48f41d3f1a73820e7996f48663683a1a16bca40997630ced0bfce38ae57640d4b86b37aff4a703f498a551ed
data/README.md CHANGED
@@ -16,6 +16,10 @@ Ruby Gem containing a Ruby PORO (Plain Old Ruby Object) that can be instantiated
16
16
 
17
17
 
18
18
  ## New Features
19
+ 08/2017 V3.3.0
20
+ Added Linked List classes which implement value based Singular, Doubly, and Circular linked lists patterns. Value based implies
21
+ the internal nodes of a linked list are never returned through the public interface, only node contents or values.
22
+
19
23
  07/2017 V3.1.5
20
24
  Added SknSettings class for use as a replacement to the popular, but obsolete, Config.gem
21
25
  SknSettings.load_configuration_basename!(config_file_name-only) or 'Rails.env.to_s' value, will load all the yml files in this order:
@@ -48,10 +52,56 @@ Ruby Gem containing a Ruby PORO (Plain Old Ruby Object) that can be instantiated
48
52
  Last Version to depend on Rails (ActiveModel) for #to_json and #to_xml serialization
49
53
 
50
54
 
55
+ ## Public Components
56
+ SknUtils::NestedResult # >= V 3.0.0 Primary Key/Value Container with Dot/Hash notiation support.
57
+ SknSettings # Application Configuration class, Key/Value Container with Dot/Hash notiation support.
58
+
59
+ SknHash # Wrapper for name only, WITHOUT SknUtils namespace, inherits from SknUtils::NestedResult
60
+ SknUtils::ResultBean # Wrapper for name only, inherits from SknUtils::NestedResult
61
+ SknUtils::PageControls # Wrapper for name only, inherits from SknUtils::NestedResult
62
+
63
+ SknUtils::List::LinkedList # List with forward (#next) navigation, and tail/open
64
+ SknUtils::List::DoublyLinkedList # List with forward (#next) and backward (#prev) navigation, and head/tail open
65
+ SknUtils::List::CircularLinkedList # List with forward (#next) and backward (#prev) navigation, and head/tail wrapping
66
+
67
+
51
68
  ## Configuration Options
52
69
  None required other than initialization hash
53
70
 
54
71
 
72
+ ## Public Methods: SknUtils::Lists::LinkedList, SknUtils::Lists::DoublyLinkedList, and SknUtils::Lists::CircularLinkedList
73
+ Each concrete Class supports the following methods:
74
+
75
+ Navigation: return related value from relative positon in list, stops on first/last node for Single/Double, wraps for Circular.
76
+ #first -- returns first value in list
77
+ #next -- returns next value from current position
78
+ #current -- returns current value
79
+ #prev -- returns previous value from current position (*not supported in Single)
80
+ #last -- returns last value from list
81
+ #nth(i) -- returns value of node at +|- positon relative to current position, (*negative not supported in Singular)
82
+ #at_index(i) -- returns value of i node relative to list's head
83
+
84
+ Enumeration
85
+ #each -- yields each value in list when block given, on Enumerator object
86
+ #to_a -- returns Array of each value in the list
87
+
88
+ State
89
+ #clear -- removes all elements and return number of elements removed
90
+ #empty? -- returns true if list has no elements, otherwise false
91
+ #size -- returns total count of elements in the list
92
+
93
+ Modification: returns number of elements in the list after the operation
94
+ #insert(value) -- inserts value after node at current positon, or appends
95
+ #append(value) -- inserts value after node at current positon
96
+ #prepend(value) -- inserts value before node at current positon
97
+ #insert_before(position_value, value) -- finds node matching position_value, then prepends new node
98
+ #insert_after(position_value, value) -- finds node matching position_value, then appends new node
99
+ #remove(value) -- finds first node matching value, then destroys it
100
+
101
+ Initialization
102
+ #new(*values=nil) -- Instansiates new list and optionally creates nodes for each comma-seperated value.
103
+
104
+
55
105
  ## Public Methods: SknSettings ONLY
56
106
  SknSettings is global constant containing an initialized Object of SknUtils::SknConfiguration using defaults
57
107
  To change the 'development'.yml default please use the following method early or in the case of Rails in 'application.rb
@@ -86,16 +136,7 @@ Ruby Gem containing a Ruby PORO (Plain Old Ruby Object) that can be instantiated
86
136
  #eql?(other) -- returns true/false from camparison of the two objects
87
137
 
88
138
 
89
- ## Public Components
90
- SknUtils::NestedResult # >= V 3.0.0 Primary Key/Value Container with Dot/Hash notiation support.
91
- SknSettings # Application Configuration class, Key/Value Container with Dot/Hash notiation support.
92
-
93
- SknHash # Wrapper for name only, WITHOUT SknUtils namespace, inherits from SknUtils::NestedResult
94
- SknUtils::ResultBean # Wrapper for name only, inherits from SknUtils::NestedResult
95
- SknUtils::PageControls # Wrapper for name only, inherits from SknUtils::NestedResult
96
-
97
-
98
- ## Basic features include:
139
+ ## NestedResult Basic features include:
99
140
  ```ruby
100
141
  - provides the hash or dot notation methods of accessing values:
101
142
 
@@ -133,7 +174,7 @@ Ruby Gem containing a Ruby PORO (Plain Old Ruby Object) that can be instantiated
133
174
  ```
134
175
 
135
176
 
136
- ## Usage:
177
+ ## NestedResult Usage:
137
178
 
138
179
  * The NestedResult produces these effects when given a params hash;
139
180
  * Follow VALUES that are Hashes, Arrays of Hashes, and Arrays of Arrays of Hashes
@@ -0,0 +1,217 @@
1
+
2
+ module SknUtils
3
+ module Lists
4
+ # Circularly Linked List
5
+ # Forward (#next) and Backwards (#prev) navigation
6
+ # No Head or Tail
7
+ class CircularLinkedList
8
+ attr_accessor :size
9
+
10
+ def initialize(*values)
11
+ @current = nil
12
+ @head = nil
13
+ @tail = nil
14
+ @size = 0
15
+ values.each {|value| insert(value) }
16
+ end
17
+
18
+ #
19
+ # Navigation
20
+ #
21
+
22
+ # return values and position current to last node accessed
23
+ # prevent @current from nil assignment
24
+ def first
25
+ @current = head if head
26
+ @current.value rescue nil
27
+ end
28
+
29
+ def next
30
+ @current = @current.next if @current and @current.next
31
+ @current.value rescue nil
32
+ end
33
+
34
+ def current
35
+ @current.value rescue nil
36
+ end
37
+
38
+ def prev
39
+ @current = @current.prev if @current and @current.prev
40
+ @current.value rescue nil
41
+ end
42
+
43
+ def last
44
+ @current = tail if tail
45
+ @current.value rescue nil
46
+ end
47
+
48
+ # -+ int position from current node
49
+ def nth(index)
50
+ node = @current
51
+ position = node
52
+ if index > 0
53
+ while index > 1 and node and node.next
54
+ node = node.next
55
+ index -= 1
56
+ @current = node
57
+ break if position === node
58
+ end
59
+ elsif index < 0
60
+ while index < 0 and node and node.prev
61
+ node = node.prev
62
+ index += 1
63
+ @current = node
64
+ break if position === node
65
+ end
66
+ end
67
+ current
68
+ end
69
+
70
+ # return node at positive index from head
71
+ def at_index(index)
72
+ find_by_index(index)
73
+ current
74
+ end
75
+
76
+ def empty?
77
+ size == 0
78
+ end
79
+
80
+ #
81
+ # Modifications
82
+ #
83
+
84
+ # return new size
85
+ def insert(value)
86
+ temp = @current.value rescue nil
87
+ insert_after(temp, value)
88
+ end
89
+
90
+ # return new size
91
+ def prepend(value)
92
+ temp = head.value rescue nil
93
+ insert_before(temp, value)
94
+ end
95
+ # return new size
96
+ def append(value)
97
+ temp = tail.value rescue nil
98
+ insert_after(temp, value)
99
+ end
100
+
101
+ # return new size
102
+ def insert_before(position_value, value)
103
+ target = find_by_value(position_value)
104
+ node = LinkNode.new(value, target, :circle_before)
105
+ @current = node if target
106
+ self.head = node if head === target
107
+ self.tail = node if tail.nil?
108
+ self.size += 1
109
+ end
110
+
111
+ # return new size
112
+ def insert_after(position_value, value)
113
+ target = find_by_value(position_value)
114
+ node = LinkNode.new(value, target, :circle_after)
115
+ @current = node
116
+ self.head = node if head.nil?
117
+ self.tail = node if tail === target
118
+ self.size += 1
119
+ end
120
+
121
+ # return remaining size
122
+ def remove(value)
123
+ target_node = find_by_value(value)
124
+ if target_node
125
+ @current = target_node.prev
126
+ @current.next = target_node.next
127
+ @current.next.prev = @current if @current and @current.next and @current.next.prev
128
+ target_node.remove!
129
+ end
130
+ self.tail = @current if tail === target_node
131
+ self.head = @current if head === target_node
132
+ self.size -= 1
133
+ end
134
+
135
+ # return number cleared
136
+ def clear
137
+ rc = 0
138
+ node = head
139
+ position = head
140
+ while node do
141
+ node = node.remove!
142
+ rc += 1
143
+ break if position === node
144
+ end
145
+
146
+ @current = nil
147
+ self.head = nil
148
+ self.tail = nil
149
+ self.size = 0
150
+ rc
151
+ end
152
+
153
+ #
154
+ # Enumerate
155
+ #
156
+
157
+ # perform each() or return enumerator
158
+ def each(&block)
159
+ @current = head
160
+ position = head
161
+ if block_given?
162
+ while position do
163
+ yield position.value.dup
164
+ position = position.next
165
+ break if position === @current
166
+ end
167
+ else
168
+ Enumerator.new do |yielder, val|
169
+ while position do
170
+ yielder << position.value.dup
171
+ position = position.next
172
+ break if position === @current
173
+ end
174
+ end
175
+ end
176
+ end
177
+
178
+ # convert self to a value array
179
+ def to_a
180
+ @current = head
181
+ position = head
182
+ result = []
183
+ while position do
184
+ result << position.value.dup
185
+ position = position.next
186
+ break if position === @current
187
+ end
188
+ result
189
+ end
190
+
191
+ private
192
+
193
+ attr_accessor :head, :tail
194
+
195
+ def find_by_value(value)
196
+ return nil if head.nil?
197
+ prior = head
198
+ target = prior
199
+ while not target.match_by_value(value)
200
+ prior = target
201
+ target = prior.next
202
+ @current = target if target
203
+ end
204
+ target
205
+ end
206
+
207
+ def find_by_index(index)
208
+ return nil if head.nil? or index < 1 or index > size
209
+ node = head
210
+ node = node.next while ((index -= 1) > 0 and node.next)
211
+ @current = node if node
212
+ node
213
+ end
214
+
215
+ end # end class
216
+ end # module
217
+ end # end module
@@ -0,0 +1,215 @@
1
+
2
+ module SknUtils
3
+ module Lists
4
+ # Doubly Linked List
5
+ # Forward (#next) and Backwards (#prev) navigation
6
+ # Head when (prev == nil)
7
+ # Tail when (next == nil)
8
+ class DoublyLinkedList
9
+ attr_accessor :size
10
+
11
+ def initialize(*values)
12
+ @current = nil
13
+ @head = nil
14
+ @tail = nil
15
+ @size = 0
16
+ values.each {|value| insert(value) }
17
+ end
18
+
19
+ #
20
+ # Navigation
21
+ #
22
+
23
+ # return values and position current to last node accessed
24
+ # prevent @current from nil assignment
25
+ def first
26
+ @current = head if head
27
+ @current.value rescue nil
28
+ end
29
+
30
+ def next
31
+ @current = @current.next if @current and @current.next
32
+ @current.value rescue nil
33
+ end
34
+
35
+ def current
36
+ @current.value rescue nil
37
+ end
38
+
39
+ def prev
40
+ @current = @current.prev if @current and @current.prev
41
+ @current.value rescue nil
42
+ end
43
+
44
+ def last
45
+ @current = tail if tail
46
+ @current.value rescue nil
47
+ end
48
+
49
+ # -+ int position from current node
50
+ def nth(index)
51
+ node = @current
52
+ if index > 0
53
+ while index > 1 and node and node.next
54
+ node = node.next
55
+ index -= 1
56
+ end
57
+ @current = node
58
+ elsif index < 0
59
+ while index < 0 and node and node.prev
60
+ node = node.prev
61
+ index += 1
62
+ end
63
+ @current = node
64
+ end
65
+ current
66
+ end
67
+
68
+ # return node at positive index from head
69
+ def at_index(index)
70
+ find_by_index(index)
71
+ current
72
+ end
73
+
74
+ def empty?
75
+ size == 0
76
+ end
77
+
78
+ #
79
+ # Modifications
80
+ #
81
+
82
+ # return new size
83
+ def insert(value)
84
+ temp = @current.value rescue nil
85
+ insert_after(temp, value)
86
+ end
87
+
88
+ # return new size
89
+ def prepend(value)
90
+ temp = head.value rescue nil
91
+ insert_before(temp, value)
92
+ end
93
+ # return new size
94
+ def append(value)
95
+ temp = tail.value rescue nil
96
+ insert_after(temp, value)
97
+ end
98
+
99
+ # return new size
100
+ def insert_before(position_value, value)
101
+ target = find_by_value(position_value)
102
+ node = LinkNode.new(value, target, :before)
103
+ @current = node if target
104
+ self.head = node if head === target
105
+ self.tail = node if tail.nil?
106
+ self.size += 1
107
+ end
108
+
109
+ # return new size
110
+ def insert_after(position_value, value)
111
+ target = find_by_value(position_value)
112
+ node = LinkNode.new(value, target, :after)
113
+ @current = node
114
+ self.head = node if head.nil?
115
+ self.tail = node if tail === target
116
+ self.size += 1
117
+ end
118
+
119
+ # return remaining size
120
+ def remove(value)
121
+ target_node = find_by_value(value)
122
+ if target_node
123
+ @current = target_node.prev if target_node.prev
124
+ @current.next = target_node.next if target_node.next
125
+ @current.next.prev = @current if @current and @current.next and @current.next.prev
126
+ target_node.remove!
127
+ end
128
+ self.tail = @current if tail === target_node
129
+ self.head = @current if head === target_node
130
+ self.size -= 1
131
+ end
132
+
133
+ # return number cleared
134
+ def clear
135
+ rc = 0
136
+ node = head
137
+ position = head
138
+ while node do
139
+ node = node.remove!
140
+ rc += 1
141
+ break if position === node
142
+ end
143
+
144
+ @current = nil
145
+ self.head = nil
146
+ self.tail = nil
147
+ self.size = 0
148
+ rc
149
+ end
150
+
151
+ #
152
+ # Enumerate
153
+ #
154
+
155
+ # perform each() or return enumerator
156
+ def each(&block)
157
+ @current = head
158
+ position = head
159
+ if block_given?
160
+ while position do
161
+ yield position.value.dup
162
+ position = position.next
163
+ break if position === @current
164
+ end
165
+ else
166
+ Enumerator.new do |yielder, val|
167
+ while position do
168
+ yielder << position.value.dup
169
+ position = position.next
170
+ break if position === @current
171
+ end
172
+ end
173
+ end
174
+ end
175
+
176
+ # convert self to a value array
177
+ def to_a
178
+ @current = head
179
+ position = head
180
+ result = []
181
+ while position do
182
+ result << position.value.dup
183
+ position = position.next
184
+ break if position === @current
185
+ end
186
+ result
187
+ end
188
+
189
+ private
190
+
191
+ attr_accessor :head, :tail
192
+
193
+ def find_by_value(value)
194
+ return nil if head.nil?
195
+ prior = head
196
+ target = prior
197
+ while not target.match_by_value(value)
198
+ prior = target
199
+ target = prior.next
200
+ @current = target if target
201
+ end
202
+ target
203
+ end
204
+
205
+ def find_by_index(index)
206
+ return nil if head.nil? or index < 1 or index > size
207
+ node = head
208
+ node = node.next while ((index -= 1) > 0 and node.next)
209
+ @current = node if node
210
+ node
211
+ end
212
+
213
+ end # end class
214
+ end # module
215
+ end # end module
@@ -0,0 +1,59 @@
1
+ ##
2
+ #
3
+ ##
4
+
5
+ module SknUtils
6
+ module Lists
7
+
8
+ class LinkNode
9
+ attr_accessor :prev, :next, :value
10
+
11
+ def initialize(val, anchor_node=nil, strategy=:after)
12
+ @value = val
13
+ @prev = nil
14
+ @next = nil
15
+
16
+ case strategy
17
+ when :single # after logic
18
+ anchor_node.next = self if anchor_node
19
+ when :before
20
+ @prev = anchor_node.prev if anchor_node
21
+ @next = anchor_node
22
+ anchor_node.prev = self if anchor_node
23
+ when :after
24
+ @prev = anchor_node
25
+ @next = anchor_node.next if anchor_node
26
+ anchor_node.next = self if anchor_node
27
+ @next.prev = self if @next
28
+ when :circle_before
29
+ @prev = anchor_node ? anchor_node.prev : self
30
+ @next = anchor_node ? anchor_node : self
31
+ anchor_node.prev = self if anchor_node
32
+ @prev.next = self if anchor_node
33
+ when :circle_after
34
+ @prev = anchor_node ? anchor_node : self
35
+ @next = anchor_node ? anchor_node.next : self
36
+ anchor_node.next = self if anchor_node
37
+ @next.prev = self if anchor_node
38
+ end
39
+ end
40
+
41
+ def match_by_value(other_value)
42
+ self.value === other_value
43
+ end
44
+
45
+ # returns next node
46
+ def remove!
47
+ next_node = @next
48
+ @value = nil
49
+ @prev = nil
50
+ @next = nil
51
+ next_node
52
+ end
53
+
54
+ def to_s
55
+ "Node with value: #{@value}"
56
+ end
57
+ end
58
+ end # module
59
+ end