trivet 1.1 → 1.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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +32 -7
  3. data/lib/trivet.rb +259 -51
  4. metadata +16 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b09cc26cad8b1fbc420bb6868a184dbd29d51816ad584deb8196c97d8a69b396
4
- data.tar.gz: a70bbc909538386b6dc2e3fb18a7de6cb1d8c2220a40b961c8bba8c5ef7bda4f
3
+ metadata.gz: '08e89a9e0bf927395b3957b685542a8e9ce4971f455b1214f6fd14dc25d0c15e'
4
+ data.tar.gz: 7f50bf59dbaa328abfc4dcdd1f2500a342b44430cfdfe758614917ff7ccf84c7
5
5
  SHA512:
6
- metadata.gz: 91990c0931cf9a24efc58ea659e78a29080b7cf66acd82677f79a6329e0debeb4483d9dcdaf45731e6bcbf3baa624eedecc09d31249d1911abfadb32fe4bdbc9
7
- data.tar.gz: 3a2842b26cee8dfb2f2777220c03224274f37bf21e0412312efdddc2c15ad3aa8f22fc5e351bc10fe974dc756c7fdd6079a389a0a28a5f75dd327365db5289ec
6
+ metadata.gz: 46ecd9c3584757faec3db79f6ceee686299b597fe6666336858d03820166ce5962d36ce4c36e69808147d96f66eda01865489ea8c24336ee1770917f5b3a3ce3
7
+ data.tar.gz: a1060b86507afb34f49f26f96f22e9a884e4cc6c828d92ca06162d4e15dad0c4b7b6a55e27100aaded5d5c0e85225633e508f7731e8f098aed94d56f594b48a2
data/README.md CHANGED
@@ -25,10 +25,10 @@ Trivet is a generic class for organizing a hierarchy.
25
25
  19.
26
26
  20. puts food.to_tree
27
27
 
28
- Line 1 creates a `Trivet::Node` object and assigns it the id "food".
29
- Lines 3 to 18 use the `node()` method to create child nodes.
28
+ Line {#start#} creates a `Trivet::Node` object and assigns it the id "food".
29
+ Lines {#spices#} to {#fruit-end#} use the `node()` method to create child nodes.
30
30
 
31
- Line 20 uses the `to_tree()` method to display the tree as text, which
31
+ Line {#end#} uses the `to_tree()` method to display the tree as text, which
32
32
  looks like this:
33
33
 
34
34
  food
@@ -74,7 +74,32 @@ mike@idocs.com
74
74
 
75
75
  ## History
76
76
 
77
- | version | date | notes |
78
- |---------|---------------|-------------------------------------------------------|
79
- | 1.0 | June 18, 2020 | Initial upload. |
80
- | 1.1 | June 22, 2020 | Consolidated can_have_children? and can_have_child? into allow_child?. |
77
+ <table>
78
+
79
+ <tr>
80
+ <th>version</th>
81
+ <th>date</th>
82
+ <th>notes</th>
83
+ </tr>
84
+
85
+ <tr>
86
+ <td>1.0</td>
87
+ <td>June 18, 2020</td>
88
+ <td>Initial upload.</td>
89
+ </tr>
90
+
91
+ <tr>
92
+ <td>1.1</td>
93
+ <td>June 22, 2020</td>
94
+ <td>Consolidated can_have_children? and can_have_child? into allow_child?.</td>
95
+ </tr>
96
+
97
+ <tr>
98
+ <td>1.2</td>
99
+ <td>January 3, 2021</td>
100
+ <td>
101
+ Added several methods to Trivet::Node: next_sibling, previous_sibling, have_child?, and move_child.
102
+ </td>
103
+ </tr>
104
+
105
+ </table>
@@ -1,4 +1,5 @@
1
1
  require 'forwardable'
2
+ require 'lx'
2
3
 
3
4
 
4
5
  #===============================================================================
@@ -10,7 +11,7 @@ require 'forwardable'
10
11
  # Trivet::Node to learn about this package.
11
12
  module Trivet
12
13
  # Version
13
- VERSION = '1.1'
14
+ VERSION = '1.2'
14
15
 
15
16
  #---------------------------------------------------------------------------
16
17
  # query control constants
@@ -71,7 +72,7 @@ end
71
72
  class Trivet::Node
72
73
  # delegate
73
74
  extend Forwardable
74
- delegate %w(remove_child) => :@children
75
+ delegate %w(remove_child have_child?) => :@children
75
76
 
76
77
 
77
78
  #---------------------------------------------------------------------------
@@ -295,17 +296,22 @@ class Trivet::Node
295
296
  # - replace: The node node replaces the caller object and the caller is removed from the tree.
296
297
  # - [integer]: The new node is placed at the index of the given integer.
297
298
  #
299
+ # option: use
300
+ #
301
+ # If the `use` option is sent, then that object is used as the new node.
298
302
  def node(opts={})
299
303
  # normalize opts
300
304
  if opts.is_a?(String)
301
305
  opts = {'id'=>opts}
306
+ elsif opts.is_a?(Trivet::Node)
307
+ opts = {'use'=>opts}
302
308
  end
303
309
 
304
310
  # $tm.hrm
305
311
  idx = opts['index'] || 'last'
306
312
 
307
313
  # create child object
308
- new_node = child_class(opts).new()
314
+ new_node = opts['use'] || child_class(opts).new()
309
315
 
310
316
  # id if sent
311
317
  if opts['id']
@@ -356,12 +362,29 @@ class Trivet::Node
356
362
  #---------------------------------------------------------------------------
357
363
 
358
364
 
365
+ #---------------------------------------------------------------------------
366
+ # add
367
+ #
368
+
369
+ # A shortcut for adding children of any arbistrary class. Takes zero or more
370
+ # params, each of which is an object.
371
+
372
+ def add(*objs)
373
+ objs.each do |obj|
374
+ @children.push obj
375
+ end
376
+ end
377
+ #
378
+ # add
379
+ #---------------------------------------------------------------------------
380
+
381
+
359
382
  #---------------------------------------------------------------------------
360
383
  # id=
361
384
  #
362
385
 
363
386
  # Sets the id property of the node. If any other node already has that id
364
- # then an exception is raised.
387
+ # then that node loses its id.
365
388
  def id=(new_id)
366
389
  # $tm.hrm
367
390
 
@@ -369,7 +392,8 @@ class Trivet::Node
369
392
  if new_id
370
393
  root.traverse('self'=>true) do |tag|
371
394
  if (tag.id == new_id) and (tag != self)
372
- raise 'redundant-id: ' + new_id.to_s
395
+ # raise 'redundant-id: ' + new_id.to_s
396
+ tag.id = nil
373
397
  end
374
398
  end
375
399
  end
@@ -767,19 +791,23 @@ class Trivet::Node
767
791
 
768
792
 
769
793
  #---------------------------------------------------------------------------
770
- # to_s
794
+ # to_s, to_debug
771
795
  #
772
796
 
773
797
  # Returns the id if there is one. Otherwise returns Object#to_s.
774
798
  def to_s
775
- if @id
776
- return @id
777
- else
778
- return super()
779
- end
799
+ return @id || super()
800
+ end
801
+
802
+ # Useful to outputting a string that represents the node for the purpose of
803
+ # debugging. By default, outputs to_s. This method is used in to_tree, so
804
+ # it's usually a good idea to return a single-line string.
805
+ def to_debug
806
+ return to_s
780
807
  end
808
+
781
809
  #
782
- # to_s
810
+ # to_s, to_debug
783
811
  #---------------------------------------------------------------------------
784
812
 
785
813
 
@@ -787,13 +815,13 @@ class Trivet::Node
787
815
  # to_tree
788
816
  #
789
817
 
790
- # This method is mainly for development and debugging. Returns a string
791
- # consisting of the node and all its descending arranged as an indented
792
- # tree. Each node's Trivet::Node#to_s method is used to display the node.
793
- # Descendents that are not Trivet::Node objects are not displayed.
818
+ # This method is for development and debugging. Returns a string consisting
819
+ # of the node and all its descending arranged as an indented tree. Each
820
+ # node's Trivet::Node#to_s method is used to display the node. Descendents
821
+ # that are not Trivet::Node objects are not displayed.
794
822
  def to_tree(opts={})
795
823
  opts = {'depth'=>0}.merge(opts)
796
- rv = ' ' * opts['depth'] + self.to_s
824
+ rv = tab() * opts['depth'] + self.to_debug
797
825
 
798
826
  # indent
799
827
  if opts['indent']
@@ -806,8 +834,23 @@ class Trivet::Node
806
834
 
807
835
  # recurse
808
836
  @children.each do |child|
837
+ # recurse into child node
809
838
  if child.is_a?(Trivet::Node)
810
839
  rv += "\n" + child.to_tree(send_opts)
840
+
841
+ # elsif if there's a custom child_to_tree method
842
+ elsif respond_to?('child_to_tree')
843
+ send_opts['tab'] = tab()
844
+ add = child_to_tree(child, send_opts)
845
+
846
+ if add and add.match(/./mu)
847
+ rv += "\n" + add
848
+ end
849
+
850
+ # String
851
+ elsif child.is_a?(String)
852
+ rv += "\n" + (tab() * send_opts['depth'] ) + child.lx.collapse
853
+
811
854
  end
812
855
  end
813
856
 
@@ -819,6 +862,17 @@ class Trivet::Node
819
862
  #---------------------------------------------------------------------------
820
863
 
821
864
 
865
+ #---------------------------------------------------------------------------
866
+ # tab
867
+ #
868
+ def tab
869
+ return ' '
870
+ end
871
+ #
872
+ # tab
873
+ #---------------------------------------------------------------------------
874
+
875
+
822
876
  #---------------------------------------------------------------------------
823
877
  # node_by_id
824
878
  #
@@ -846,6 +900,20 @@ class Trivet::Node
846
900
  #---------------------------------------------------------------------------
847
901
 
848
902
 
903
+ #---------------------------------------------------------------------------
904
+ # allow_child?
905
+ #
906
+
907
+ # This method is called when a node or other object is added to a node. By
908
+ # default, always returns true. Override this method to create custom rules.
909
+ def allow_child?(child)
910
+ return true
911
+ end
912
+ #
913
+ # allow_child?
914
+ #---------------------------------------------------------------------------
915
+
916
+
849
917
  #---------------------------------------------------------------------------
850
918
  # shortcut to create allow_child? that returns false
851
919
  #
@@ -856,9 +924,7 @@ class Trivet::Node
856
924
  # self.no_children()
857
925
  #
858
926
  def self.no_children()
859
- self.child_levels = []
860
-
861
- self.define_method('allow_child?') do
927
+ self.define_method('allow_child?') do |child|
862
928
  return false
863
929
  end
864
930
  end
@@ -867,20 +933,6 @@ class Trivet::Node
867
933
  #---------------------------------------------------------------------------
868
934
 
869
935
 
870
- #---------------------------------------------------------------------------
871
- # allow_child?
872
- #
873
-
874
- # This method is called when a node or other object is added to a node. By
875
- # default, always returns true. Override this method to create custom rules.
876
- def allow_child?(child)
877
- return true
878
- end
879
- #
880
- # allow_child?
881
- #---------------------------------------------------------------------------
882
-
883
-
884
936
  #---------------------------------------------------------------------------
885
937
  # document
886
938
  #
@@ -930,6 +982,82 @@ class Trivet::Node
930
982
  #
931
983
  # depth
932
984
  #---------------------------------------------------------------------------
985
+
986
+
987
+ #---------------------------------------------------------------------------
988
+ # previous_sibling
989
+ #
990
+
991
+ # Returns the node's previous sibling
992
+ def previous_sibling
993
+ # $tm.hrm
994
+ latest = nil
995
+
996
+ # if parent, search through sibling
997
+ if parent
998
+ parent.children.each do |sib|
999
+ if sib == self
1000
+ return latest
1001
+ else
1002
+ latest = sib
1003
+ end
1004
+ end
1005
+ end
1006
+
1007
+ # no parent
1008
+ return nil
1009
+ end
1010
+
1011
+ #
1012
+ # previous_sibling
1013
+ #---------------------------------------------------------------------------
1014
+
1015
+
1016
+ #---------------------------------------------------------------------------
1017
+ # next_sibling
1018
+ #
1019
+
1020
+ # Returns the node's next sibling.
1021
+ def next_sibling
1022
+ # $tm.hrm
1023
+ found_self = false
1024
+
1025
+ # if parent, search through siblings
1026
+ if parent
1027
+ parent.children.each do |sib|
1028
+ if sib == self
1029
+ found_self = true
1030
+ elsif found_self
1031
+ return sib
1032
+ end
1033
+ end
1034
+ end
1035
+
1036
+ # no next sibling
1037
+ return nil
1038
+ end
1039
+
1040
+ #
1041
+ # next_sibling
1042
+ #---------------------------------------------------------------------------
1043
+
1044
+
1045
+ #---------------------------------------------------------------------------
1046
+ # move_child
1047
+ #
1048
+
1049
+ # Moves the given object from this node to the given node. Note that the
1050
+ # object being moved doesn't actually have to be a child of this node, but
1051
+ # it will be removed if it is.
1052
+
1053
+ def move_child(child, tgt)
1054
+ # $tm.hrm
1055
+ @children.remove_child child
1056
+ tgt.add child
1057
+ end
1058
+ #
1059
+ # move_child
1060
+ #---------------------------------------------------------------------------
933
1061
  end
934
1062
  #
935
1063
  # Trivet::Node
@@ -950,7 +1078,7 @@ class Trivet::Childset
950
1078
  extend Forwardable
951
1079
 
952
1080
  delegate %w(
953
- [] each each_with_index length include? find_index reverse
1081
+ [] each each_with_index length find_index reverse include?
954
1082
  all? at any? empty? reject + - collect cycle) => :@children;
955
1083
  #
956
1084
  # delegate
@@ -1003,6 +1131,23 @@ class Trivet::Childset
1003
1131
  #---------------------------------------------------------------------------
1004
1132
 
1005
1133
 
1134
+ #---------------------------------------------------------------------------
1135
+ # include?
1136
+ #
1137
+ # def include?(obj)
1138
+ # @children.each do |child|
1139
+ # if child.equal?(obj)
1140
+ # return true
1141
+ # end
1142
+ # end
1143
+ #
1144
+ # return false
1145
+ # end
1146
+ #
1147
+ # include?
1148
+ #---------------------------------------------------------------------------
1149
+
1150
+
1006
1151
  #---------------------------------------------------------------------------
1007
1152
  # methods for adding a child to the array
1008
1153
  #
@@ -1011,14 +1156,14 @@ class Trivet::Childset
1011
1156
  # check if the child can be added. Does nothing if the node is already a
1012
1157
  # child.
1013
1158
  def push(new_child, opts={})
1014
- return add_child new_child, 'last', opts
1159
+ return add_child(new_child, 'last', opts)
1015
1160
  end
1016
1161
 
1017
1162
  # Adds a child to the end of the array. Calls Trivet::Node#allow_child? to
1018
1163
  # check if the child can be added. Does nothing if the node is already a
1019
1164
  # child.
1020
1165
  def append(new_child, opts={})
1021
- return add_child new_child, 'last', opts
1166
+ return add_child(new_child, 'last', opts)
1022
1167
  end
1023
1168
 
1024
1169
  # Shortcut for append without any options.
@@ -1030,14 +1175,14 @@ class Trivet::Childset
1030
1175
  # check if the child can be added. Does nothing if the node is already a
1031
1176
  # child.
1032
1177
  def unshift(new_child, opts={})
1033
- return add_child new_child, 'first', opts
1178
+ return add_child(new_child, 'first', opts)
1034
1179
  end
1035
1180
 
1036
1181
  # Inserts the child at the position indicated by index. Calls Trivet::Node#allow_child? to
1037
1182
  # check if the child can be added. Does nothing if the node is already a
1038
1183
  # child.
1039
1184
  def insert(index, new_child, opts={})
1040
- return add_child new_child, index, opts
1185
+ return add_child(new_child, index, opts)
1041
1186
  end
1042
1187
  #
1043
1188
  # methods for adding a child to the array
@@ -1051,18 +1196,24 @@ class Trivet::Childset
1051
1196
  # Removes the given child from the array of children. Does nothing if the
1052
1197
  # child isn't present.
1053
1198
  def remove_child(child, opts={})
1054
- opts = {'recurse'=>true}.merge(opts)
1199
+ # opts = {'recurse'=>true}.merge(opts)
1055
1200
 
1056
1201
  @children.reject!() do |el|
1057
- el == child
1202
+ el.equal? child
1058
1203
  end
1059
1204
  end
1060
1205
 
1061
1206
  # Removes all children.
1062
1207
  def clear()
1208
+ # explicitly unlink childen
1063
1209
  @children.clone.each do |child|
1064
- child.unlink
1210
+ if child.is_a?(Trivet::Node)
1211
+ child.unlink
1212
+ end
1065
1213
  end
1214
+
1215
+ # remove all other child objects
1216
+ @children.clear
1066
1217
  end
1067
1218
  #
1068
1219
  # remove_child
@@ -1155,6 +1306,23 @@ class Trivet::Childset
1155
1306
  #---------------------------------------------------------------------------
1156
1307
 
1157
1308
 
1309
+ #---------------------------------------------------------------------------
1310
+ # have_child?
1311
+ #
1312
+ def have_child?(potential)
1313
+ @children.each_with_index do |child, idx|
1314
+ if child.equal?(potential)
1315
+ return idx
1316
+ end
1317
+ end
1318
+
1319
+ return false
1320
+ end
1321
+ #
1322
+ # have_child?
1323
+ #---------------------------------------------------------------------------
1324
+
1325
+
1158
1326
  # private
1159
1327
  private
1160
1328
 
@@ -1167,18 +1335,20 @@ class Trivet::Childset
1167
1335
 
1168
1336
  # check if this parent is allowed to have this child
1169
1337
  if not @node.allow_child?(new_child)
1170
- raise 'parent-cannot-have-this-child: ' + @node.to_s + ' / ' + new_child.to_s
1171
- end
1172
-
1173
- # dup_ok
1174
- if new_child.is_a?(Trivet::Node)
1175
- dup_ok = false
1176
- else
1177
- dup_ok = true
1338
+ if new_child.respond_to?('to_debug')
1339
+ child_debug = new_child.to_debug
1340
+ elsif new_child.is_a?(String)
1341
+ child_debug = new_child
1342
+ else
1343
+ child_debug = '[unrecognized object]'
1344
+ end
1345
+
1346
+ raise 'parent-cannot-have-this-child: ' + @node.to_debug + ' / ' + child_debug
1178
1347
  end
1179
1348
 
1180
1349
  # add to children if not already there
1181
- if dup_ok or (not @children.include?(new_child))
1350
+ # if dup_ok or (not @children.include?(new_child))
1351
+ if (not have_child?(new_child))
1182
1352
  # add to start of array
1183
1353
  if index == 'first'
1184
1354
  @children.unshift new_child
@@ -1241,6 +1411,7 @@ class Trivet::Document
1241
1411
  def initialize(new_root=nil)
1242
1412
  # init
1243
1413
  @root = nil
1414
+ @misc = {}
1244
1415
 
1245
1416
  # set new root
1246
1417
  if new_root
@@ -1263,6 +1434,9 @@ class Trivet::Document
1263
1434
  # Returns the root node. Returns nil if the document does not have a root.
1264
1435
  attr_reader :root
1265
1436
 
1437
+ # A hash of any miscellaneous information you want to attach to the node.
1438
+ attr_reader :misc
1439
+
1266
1440
  #
1267
1441
  # reader
1268
1442
  #---------------------------------------------------------------------------
@@ -1276,6 +1450,7 @@ class Trivet::Document
1276
1450
  def root=(new_root)
1277
1451
  set_root new_root
1278
1452
  end
1453
+
1279
1454
  #
1280
1455
  # root=
1281
1456
  #---------------------------------------------------------------------------
@@ -1313,6 +1488,26 @@ class Trivet::Document
1313
1488
  #---------------------------------------------------------------------------
1314
1489
 
1315
1490
 
1491
+ #---------------------------------------------------------------------------
1492
+ # children
1493
+ #
1494
+
1495
+ # If there is a root node, returns an array consisting of just the root
1496
+ # node. Else returns an empty array. This method if is a convenience to that
1497
+ # a node can always call its parent's children.
1498
+ def children
1499
+ if @root
1500
+ return [@root]
1501
+ else
1502
+ return []
1503
+ end
1504
+ end
1505
+
1506
+ #
1507
+ # children
1508
+ #---------------------------------------------------------------------------
1509
+
1510
+
1316
1511
  #---------------------------------------------------------------------------
1317
1512
  # traverse
1318
1513
  #
@@ -1348,6 +1543,19 @@ class Trivet::Document
1348
1543
  #---------------------------------------------------------------------------
1349
1544
 
1350
1545
 
1546
+ #---------------------------------------------------------------------------
1547
+ # []
1548
+ #
1549
+
1550
+ # Shortcut for #node_by_id().
1551
+
1552
+ def [](id)
1553
+ return node_by_id(id)
1554
+ end
1555
+ #
1556
+ # []
1557
+ #---------------------------------------------------------------------------
1558
+
1351
1559
  # include method from querier
1352
1560
  include Trivet::Querier
1353
1561
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trivet
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.1'
4
+ version: '1.2'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike O'Sullivan
@@ -9,7 +9,21 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2020-06-18 00:00:00.000000000 Z
12
- dependencies: []
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: lx
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
13
27
  description: Generic class for organizing objects in a hierarchy.
14
28
  email: mike@idocs.com
15
29
  executables: []