trivet 1.1 → 1.2

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