skn_utils 3.2.1 → 3.3.0

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