jinx 2.1.3 → 2.1.4

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 (40) hide show
  1. data/Gemfile.lock +27 -0
  2. data/History.md +4 -0
  3. data/lib/jinx/helpers/class.rb +16 -12
  4. data/lib/jinx/helpers/collection.rb +277 -29
  5. data/lib/jinx/helpers/collections.rb +35 -2
  6. data/lib/jinx/helpers/conditional_enumerator.rb +2 -2
  7. data/lib/jinx/helpers/filter.rb +8 -2
  8. data/lib/jinx/helpers/flattener.rb +2 -2
  9. data/lib/jinx/helpers/hash.rb +3 -2
  10. data/lib/jinx/helpers/{hashable.rb → hasher.rb} +125 -77
  11. data/lib/jinx/helpers/module.rb +1 -1
  12. data/lib/jinx/helpers/multi_enumerator.rb +25 -9
  13. data/lib/jinx/helpers/options.rb +4 -3
  14. data/lib/jinx/helpers/partial_order.rb +16 -8
  15. data/lib/jinx/helpers/pretty_print.rb +14 -4
  16. data/lib/jinx/helpers/transformer.rb +3 -1
  17. data/lib/jinx/helpers/transitive_closure.rb +3 -3
  18. data/lib/jinx/helpers/visitor.rb +33 -42
  19. data/lib/jinx/import/java.rb +40 -27
  20. data/lib/jinx/importer.rb +86 -33
  21. data/lib/jinx/metadata/attribute_enumerator.rb +5 -11
  22. data/lib/jinx/metadata/dependency.rb +65 -30
  23. data/lib/jinx/metadata/id_alias.rb +1 -0
  24. data/lib/jinx/metadata/introspector.rb +21 -9
  25. data/lib/jinx/metadata/inverse.rb +14 -11
  26. data/lib/jinx/metadata/java_property.rb +15 -26
  27. data/lib/jinx/metadata/propertied.rb +80 -19
  28. data/lib/jinx/metadata/property.rb +13 -8
  29. data/lib/jinx/metadata/property_characteristics.rb +2 -2
  30. data/lib/jinx/resource.rb +62 -32
  31. data/lib/jinx/resource/inversible.rb +4 -0
  32. data/lib/jinx/resource/match_visitor.rb +0 -1
  33. data/lib/jinx/resource/mergeable.rb +16 -6
  34. data/lib/jinx/resource/reference_enumerator.rb +1 -2
  35. data/lib/jinx/version.rb +1 -1
  36. data/test/lib/jinx/helpers/collections_test.rb +29 -14
  37. data/test/lib/jinx/helpers/visitor_test.rb +7 -20
  38. data/test/lib/jinx/import/mixed_case_test.rb +17 -3
  39. metadata +4 -4
  40. data/lib/jinx/helpers/enumerable.rb +0 -245
@@ -272,8 +272,8 @@ module Jinx
272
272
  end
273
273
  @flags << flag
274
274
  case flag
275
- when :owner then owner_flag_set
276
- when :dependent then dependent_flag_set
275
+ when :owner then owner_flag_set
276
+ when :dependent then dependent_flag_set
277
277
  end
278
278
  end
279
279
 
@@ -286,12 +286,17 @@ module Jinx
286
286
  if dependent? then
287
287
  raise MetadataError.new("#{declarer.qp}.#{self} cannot be set as a #{type.qp} owner since it is already defined as a #{type.qp} dependent")
288
288
  end
289
- inv_attr = type.dependent_attribute(@declarer)
290
- if inv_attr.nil? then
291
- raise MetadataError.new("#{@declarer.qp} owner attribute #{self} does not have a #{type.qp} dependent inverse")
289
+ inv_prop = inverse_property
290
+ if inv_prop then
291
+ inv_prop.qualify(:dependent) unless inv_prop.dependent?
292
+ else
293
+ inv_attr = type.dependent_attribute(@declarer)
294
+ if inv_attr.nil? then
295
+ raise MetadataError.new("The #{@declarer.qp} owner attribute #{self} of type #{type.qp} does not have an inverse")
296
+ end
297
+ logger.debug { "#{declarer.qp}.#{self} inverse is the #{type.qp} dependent attribute #{inv_attr}." }
298
+ self.inverse = inv_attr
292
299
  end
293
- logger.debug { "#{declarer.qp}.#{self} inverse is the #{type.qp} dependent attribute #{inv_attr}." }
294
- self.inverse = inv_attr
295
300
  end
296
301
 
297
302
  # Validates that this is not an owner attribute.
@@ -299,7 +304,7 @@ module Jinx
299
304
  # @raise [MetadataError] if this is an owner attribute
300
305
  def dependent_flag_set
301
306
  if owner? then
302
- raise MetadataError.new("#{declarer.qp}.#{self} cannot be set as a #{type.qp} dependent since it is already defined as a #{type.qp} owner")
307
+ raise MetadataError.new("#{declarer.qp}.#{self} cannot be set as a #{type.qp} dependent since it is already defined as a #{type.qp} owner")
303
308
  end
304
309
  end
305
310
  end
@@ -30,8 +30,8 @@ module Jinx
30
30
  # @return [Boolean] whether the subject attribute returns a domain object or a collection
31
31
  # of domain objects
32
32
  def domain?
33
- # the type must be a Ruby class rather than a Java Class, and include the Domain mix-in
34
- Class === type and type < Resource
33
+ # the type must be a Ruby class that extends the {Metadata} mix-in
34
+ Class === type and type < Resource and type.introspected?
35
35
  end
36
36
 
37
37
  # @return [Boolean] whether the subject attribute is not a domain object attribute
@@ -29,13 +29,16 @@ module Jinx
29
29
  # module Domain
30
30
  # include Jinx::Resource
31
31
  # # The caTissue Java package name.
32
- # packages 'app.domain'
32
+ # package 'app.domain'
33
33
  # # The JRuby mix-ins directory.
34
34
  # definitions File.expand_path('domain', dirname(__FILE__))
35
35
  # end
36
36
  module Resource
37
37
  include Mergeable, Inversible
38
38
 
39
+ # A proxied subclass can override the +domain_class+.
40
+ alias :domain_class :class
41
+
39
42
  # @quirk JRuby Bug #5090 - JRuby 1.5 object_id is no longer a reserved method, and results
40
43
  # in a String value rather than an Integer (cf. http://jira.codehaus.org/browse/JRUBY-5090).
41
44
  # Work-around is to make a proxy object id.
@@ -45,6 +48,13 @@ module Jinx
45
48
  # make a hash code on demand
46
49
  @_hc ||= (Object.new.object_id * 31) + 17
47
50
  end
51
+
52
+ # Initialization hook. This default implementation is a no-op.
53
+ #
54
+ # @quirk JRuby calling super in a module initialize method results in an infinite loop.
55
+ # The work-around is to add a post_initialize method that mix-in modules can override.
56
+ def post_initialize
57
+ end
48
58
 
49
59
  # Prints this object's class demodulized name and object id.
50
60
  def print_class_and_id
@@ -134,12 +144,13 @@ module Jinx
134
144
  # is preserved, e.g. an Array value is assigned to a set domain type by first clearing the set
135
145
  # and then merging the array content into the set.
136
146
  #
137
- # @see Mergeable#merge_attribute
138
- def set_property_value(attribute, value)
139
- prop = self.class.property(attribute)
147
+ # @param [Property, Symbol] prop the property or attribute to set
148
+ # @param value the new value
149
+ def set_property_value(prop, value)
150
+ prop = self.class.property(prop) if Symbol === prop
140
151
  if prop.domain? and prop.collection? then
141
- clear_attribute(attribute)
142
- merge_attribute(attribute, value)
152
+ clear_attribute(prop.attribute)
153
+ merge_attribute(prop.attribute, value)
143
154
  else
144
155
  set_typed_property_value(prop, value)
145
156
  end
@@ -196,8 +207,10 @@ module Jinx
196
207
  self.class.owner_attributes.detect_value { |pa| send(pa) }
197
208
  end
198
209
 
199
- # @return [(Property, Resource), nil] the (property, value) pair for which there is an
200
- # owner reference, or nil if this domain object does not reference an owner
210
+ # Returns the (property, value) pair for which there is an owner reference, or nil if
211
+ # this domain object does not reference an owner.
212
+ #
213
+ # @return [(Property, Resource), nil] the owner (property, value) pair
201
214
  def effective_owner_property_value
202
215
  self.class.owner_properties.detect_value do |op|
203
216
  ref = send(op.attribute)
@@ -207,12 +220,17 @@ module Jinx
207
220
 
208
221
  # Sets this dependent's owner attribute to the given domain object.
209
222
  #
210
- # @param [Resource] owner the owner domain object
211
- # @raise [NoMethodError] if this Resource's class does not have exactly one owner attribute
212
- def owner=(owner)
213
- pa = self.class.owner_attribute
214
- if pa.nil? then raise NoMethodError.new("#{self.class.qp} does not have a unique owner attribute") end
215
- set_property_value(pa, owner)
223
+ # @param [Resource] obj the owner domain object
224
+ # @raise [NoMethodError] if this Resource's class does not have an owner property
225
+ # which accepts the given domain object
226
+ def owner=(obj)
227
+ if obj.nil? then
228
+ op, ov = effective_owner_property_value || return
229
+ else
230
+ op = self.class.owner_properties.detect { |prop| prop.type === obj }
231
+ end
232
+ if op.nil? then raise NoMethodError.new("#{self.class.qp} does not have an owner attribute for #{obj}") end
233
+ set_property_value(op.attribute, obj)
216
234
  end
217
235
 
218
236
  # @param [Resource] other the domain object to check
@@ -220,26 +238,36 @@ module Jinx
220
238
  # {#owner_ancestor?} of this object's {#owner}
221
239
  def owner_ancestor?(other)
222
240
  ownr = self.owner
223
- ownr and (ownr == other or ownr.owner_ancestor?(other))
241
+ if ownr then
242
+ ownr == other or ownr.owner_ancestor?(other)
243
+ elsif self.class.owner_types.size == self.class.owner_properties.size then
244
+ false
245
+ else
246
+ path = other.class.dependency_path_to(self.class)
247
+ !!path and other.reachable?(self, path)
248
+ end
224
249
  end
225
250
 
251
+ # @param [Resource] other the domain object to check
252
+ # @param [<Property>] the property path to follow
253
+ # @return [Boolean] whether following there is a path from this object through the given
254
+ # properties to the other object
255
+ def reachable?(other, path)
256
+ return false if path.empty?
257
+ prop = path.shift
258
+ send(prop.attribute).to_enum.any? do |ref|
259
+ ref == other or ref.reachable?(other, path)
260
+ end
261
+ end
262
+
226
263
  # @param [Resource] other the domain object to check
227
264
  # @return [Boolean] whether the other domain object is a dependent of this object
228
265
  # and has an update-only non-domain attribute.
229
266
  def dependent_update_only?(other)
230
267
  other.owner == self and
231
- other.class.nondomain_attributes.detect_with_property { |prop| prop.updatable? and not prop.creatable? }
232
- end
233
-
234
- # Returns an attribute => value hash for the specified attributes with a non-nil, non-empty value.
235
- # The default attributes are this domain object's class {Propertied#attributes}.
236
- # Only non-nil attributes defined by this Resource are included in the result hash.
237
- #
238
- # @param [<Symbol>, nil] attributes the attributes to merge
239
- # @return [{Symbol => Object}] the attribute => value hash
240
- def value_hash(attributes=nil)
241
- attributes ||= self.class.attributes
242
- attributes.to_compact_hash { |pa| send(pa) if self.class.method_defined?(pa) }
268
+ other.class.nondomain_attributes.detect_attribute_with_property do |prop|
269
+ prop.updatable? and not prop.creatable?
270
+ end
243
271
  end
244
272
 
245
273
  # Returns the domain object references for the given attributes.
@@ -398,13 +426,15 @@ module Jinx
398
426
  #
399
427
  # @param [Resource] other the domain object to compare
400
428
  # @param [<Symbol>, nil] attributes the attributes to compare
401
- # @return (see Hashable#diff)
402
- def diff(other, attributes=nil)
429
+ # @return (see Hasher#diff)
430
+ def difference(other, attributes=nil)
403
431
  attributes ||= self.class.nondomain_attributes
404
432
  vh = value_hash(attributes)
405
433
  ovh = other.value_hash(attributes)
406
434
  vh.diff(ovh) { |key, v1, v2| Resource.value_equal?(v1, v2) }
407
435
  end
436
+
437
+ alias :diff :difference
408
438
 
409
439
  # Returns the domain object in others which matches this dependent domain object
410
440
  # within the scope of a parent on a minimally acceptable constraint. This method
@@ -696,7 +726,7 @@ module Jinx
696
726
  end
697
727
  end
698
728
  # If there is an owner reference attribute, then there must be an owner.
699
- if self.class.bidirectional_dependent? then
729
+ if self.class.bidirectional_java_dependent? then
700
730
  raise ValidationError.new("Dependent #{self} does not reference an owner")
701
731
  end
702
732
  end
@@ -708,8 +738,8 @@ module Jinx
708
738
  begin
709
739
  send(property.writer, value)
710
740
  rescue TypeError
711
- # Add the attribute to the error message.
712
- raise TypeError.new("Cannot set #{self.class.qp} #{property} to #{value.qp} - " + $!)
741
+ logger.error("Cannot set #{self.class.qp} #{property} to #{value.qp} - " + $!)
742
+ raise
713
743
  end
714
744
  end
715
745
 
@@ -34,8 +34,10 @@ module Jinx
34
34
  clr_wtr = self.class === oldval && oldval.send(rdr).equal?(self) ? wtr : inverse_writer
35
35
  oldval.send(clr_wtr, nil)
36
36
  end
37
+
37
38
  # call the writer
38
39
  send(wtr, newval)
40
+
39
41
  # call the inverse writer on self
40
42
  if newval then
41
43
  newval.send(inverse_writer, self)
@@ -67,8 +69,10 @@ module Jinx
67
69
  coll = oldval.send(inverse)
68
70
  coll.delete(self) if coll
69
71
  end
72
+
70
73
  # call the writer on this object
71
74
  send(wtr, newval)
75
+
72
76
  # add self to the inverse collection
73
77
  if newval then
74
78
  coll = newval.send(inverse)
@@ -149,7 +149,6 @@ module Jinx
149
149
  # add residual matches
150
150
  rsd_mtchs.each { |src, tgt| add_match(src, tgt) }
151
151
  logger.debug { "#{qp} matched #{rsd_mtchs.qp}..." } if @verbose and not rsd_mtchs.empty?
152
-
153
152
  # The source => target match hash.
154
153
  # If there is a copier, then copy each unmatched source.
155
154
  matches = srcs.to_compact_hash { |src| match_for(src) or copy_unmatched(src) }
@@ -39,10 +39,9 @@ module Jinx
39
39
  return self if other.nil? or other.equal?(self)
40
40
  attributes = [attributes] if Symbol === attributes
41
41
  attributes ||= self.class.mergeable_attributes
42
-
43
- # if the source object is not a hash, then convert it to an attribute => value hash
44
- vh = Hashable === other ? other : other.value_hash(attributes)
45
- # merge the value hash
42
+ # If the source object is not a hash, then convert it to an attribute => value hash.
43
+ vh = Hasher === other ? other : other.value_hash(attributes)
44
+ # Merge the Java values hash.
46
45
  vh.each { |pa, value| merge_attribute(pa, value, matches, &filter) }
47
46
  self
48
47
  end
@@ -100,6 +99,17 @@ module Jinx
100
99
  end
101
100
  end
102
101
 
102
+ # Returns an attribute => value hash for the specified attributes with a non-nil, non-empty value.
103
+ # The default attributes are this domain object's class {Propertied#attributes}.
104
+ # Only non-nil values of attributes defined by this domain object are included in the result hash.
105
+ #
106
+ # @param [<Symbol>, nil] attributes the attributes to merge
107
+ # @return [{Symbol => Object}] the attribute => value hash
108
+ def value_hash(attributes=nil)
109
+ attributes ||= self.class.attributes
110
+ attributes.to_compact_hash { |pa| send(pa) rescue nil }
111
+ end
112
+
103
113
  private
104
114
 
105
115
  # @see #merge_attribute
@@ -118,7 +128,7 @@ module Jinx
118
128
  # the dependent owner writer method, if any
119
129
  if property.dependent? then
120
130
  val = property.collection? ? newval.first : newval
121
- klass = val.class if val
131
+ klass = val.domain_class if val
122
132
  inv_prop = self.class.inverse_property(property, klass)
123
133
  if inv_prop and not inv_prop.collection? then
124
134
  owtr = inv_prop.writer
@@ -178,8 +188,8 @@ module Jinx
178
188
  # If the target is a dependent, then set the dependent owner, which will in turn
179
189
  # set the attribute to the dependent. Otherwise, set the attribute to the target.
180
190
  owtr ? delegate_to_inverse_setter(property, ref, owtr) : set_typed_property_value(property, ref)
191
+ ref
181
192
  end
182
- newval
183
193
  end
184
194
 
185
195
  # @quirk Java Java TreeSet comparison uses the TreeSet comparator rather than an
@@ -2,14 +2,13 @@ require 'enumerator'
2
2
  require 'generator'
3
3
  require 'jinx/helpers/options'
4
4
  require 'jinx/helpers/collections'
5
-
6
5
  require 'jinx/helpers/validation'
7
6
  require 'jinx/helpers/visitor'
8
7
 
9
8
  module Jinx
10
9
  # A ReferenceEnumerator iterates over domain property references.
11
10
  class ReferenceEnumerator
12
- include Enumerable
11
+ include Enumerable, Collection
13
12
 
14
13
  # @return [Resource] the domain object containing the references
15
14
  attr_reader :subject
@@ -1,3 +1,3 @@
1
1
  module Jinx
2
- VERSION = '2.1.3'
2
+ VERSION = '2.1.4'
3
3
  end
@@ -66,6 +66,10 @@ class CollectionsTest < Test::Unit::TestCase
66
66
  assert_nil([1, 2, 3].detect_value { |item| item * 2 if item > 3 }, "Value incorrectly detected")
67
67
  end
68
68
 
69
+ def test_hash_detect_value
70
+ assert_equal(4, {1 => 2, 3 => 4}.detect_value { |k, v| v if k > 1 }, "Detect hash value incorrect")
71
+ end
72
+
69
73
  def test_detect_with_value
70
74
  assert_equal([2, 1], [1, 2].detect_with_value { |item| item / 2 if item % 2 == 0 }, "Detect with value incorrect")
71
75
  end
@@ -96,12 +100,15 @@ class CollectionsTest < Test::Unit::TestCase
96
100
 
97
101
  def test_union
98
102
  base = [1, 2]
99
- sum = base.union([4])
100
- assert_equal([1, 2, 4], sum.to_a, 'Enumerator union incorrect')
101
- assert(sum.include?(2), "Enumerator union missing first array element")
102
- assert(sum.include?(4), "Enumerator union missing second array element")
103
+ u = base.union([4])
104
+ assert_equal([1, 2, 4], u.to_a, 'Enumerator on union incorrect')
105
+ assert(u.include?(2), "Enumerator on union missing first array element")
106
+ assert(u.include?(4), "Enumerator on union missing second array element")
103
107
  base << 3
104
- assert_equal([1, 2, 3, 4], sum.to_a, 'Enumerator union does not reflect operand modification')
108
+ assert_equal([1, 2, 3, 4], u.to_a, 'Enumerator on union does not reflect operand modification')
109
+ # A union of a unions yields the flattened result.
110
+ uu = u.union([5])
111
+ assert_equal([1, 2, 3, 4, 5], uu.to_a, 'Enumerator on union of unions incorrect')
105
112
  end
106
113
 
107
114
  def test_intersection
@@ -137,9 +144,16 @@ class CollectionsTest < Test::Unit::TestCase
137
144
  end
138
145
 
139
146
  def test_partial_sort
140
- sorted = [Array, Object, Numeric, Enumerable, Set].partial_sort
147
+ sorted = [Enumerable, Array, Object, String].partial_sort
141
148
  assert(sorted.index(Array) < sorted.index(Enumerable), "Partial sort order incorrect")
142
- assert(sorted.index(Set) < sorted.index(Enumerable), "Partial sort order incorrect")
149
+ assert(sorted.index(Array) < sorted.index(Object), "Partial sort order incorrect")
150
+ assert(sorted.index(String) < sorted.index(Enumerable), "Partial sort order incorrect")
151
+ assert(sorted.index(String) < sorted.index(Object), "Partial sort order incorrect")
152
+ end
153
+
154
+ def test_partial_sort_with_block
155
+ sorted = [Array, Module, Enumerable].partial_sort { |a, b| b <=> a }
156
+ assert(sorted.index(Array) > sorted.index(Enumerable), "Partial sort order incorrect")
143
157
  end
144
158
 
145
159
  def test_hash_union
@@ -182,7 +196,7 @@ class CollectionsTest < Test::Unit::TestCase
182
196
  assert_equal(expected, actual, 'Association hash incorrect')
183
197
  end
184
198
 
185
- def test_hashable_equal
199
+ def test_hasher_equal
186
200
  assert_equal({:a => 1}, {:a => 1}.filter, "Hash equal incorrect")
187
201
  end
188
202
 
@@ -305,11 +319,12 @@ class CollectionsTest < Test::Unit::TestCase
305
319
  end
306
320
 
307
321
  def test_key_transformer_hash
308
- hash = Jinx::KeyTransformerHash.new { |k| k % 2 }
309
- hash[1] = :a
310
- assert_equal(:a, hash[1], 'Key transformer hash entered value not found')
311
- assert_nil(hash[2], 'Transformed hash unentered value found')
312
- assert_equal(:a, hash[3], 'Key transformer hash equivalent value not found')
322
+ h = {1 => :a, 2 => :b}
323
+ xfm = h.transform_key { |n| n * 2 }
324
+ assert_equal([2, 4], xfm.keys, 'Key transformer hash keys incorrect')
325
+ assert_equal(:a, xfm[2], 'Key transformer hash access incorrect')
326
+ h[3] = :c
327
+ assert_equal(:c, xfm[6], 'Key transformer hash does not reflect change to underlying hash')
313
328
  end
314
329
 
315
330
  def test_transform_value
@@ -347,7 +362,7 @@ class CollectionsTest < Test::Unit::TestCase
347
362
  assert_nil(hash[:c], "Hashinator has association not in the base")
348
363
  base.first[1] = 3
349
364
  assert_equal(3, hash[:a], "Hashinator does not reflect change to underlying Enumerator")
350
- assert_equal(base, hash.to_hash.to_a, "Hashable to_hash incorrect")
365
+ assert_equal(base, hash.to_hash.to_a, "Hasher to_hash incorrect")
351
366
  end
352
367
 
353
368
  def test_collector
@@ -83,21 +83,6 @@ class VistorTest < Test::Unit::TestCase
83
83
  assert_equal(3, child.value, "Child visited twice")
84
84
  end
85
85
 
86
- def test_root_cycle
87
- parent = Node.new(1)
88
- c1 = Node.new(2, parent)
89
- c2 = Node.new(3, parent)
90
- c2.children << parent
91
- gc11 = Node.new(4, c1)
92
- gc12 = Node.new(5, c1)
93
- gc12.children << c1
94
- gc121 = Node.new(6, gc12)
95
- gc121.children << parent
96
- visitor = Jinx::Visitor.new { |node| node.children }
97
- result = visitor.visit(parent)
98
- assert_equal([[2, 5, 2], [1, 2, 5, 6, 1], [1, 3, 1]], visitor.cycles.map { |cycle| cycle.map { |node| node.value } }, "Root cycles incorrect")
99
- end
100
-
101
86
  def increment(parent, limit)
102
87
  visitor = Jinx::Visitor.new { |node| node.children }
103
88
  visitor.visit(parent) { |node| node.value < limit ? node.value += 1 : return }
@@ -122,11 +107,13 @@ class VistorTest < Test::Unit::TestCase
122
107
  c1 = Node.new(2, parent)
123
108
  c2 = Node.new(3, parent)
124
109
  visitor = Jinx::Visitor.new { |node| node.children }
125
- result = visitor.to_enum(parent).map { |node| node.value }
126
- assert_equal([1, 2, 3], result, "Enumeration result incorrect")
110
+ result = visitor.to_enum(parent).to_a
111
+ assert_equal([parent, c1, c2], result, "Enumeration result incorrect")
127
112
  end
128
113
 
129
- def test_exclude_cycles
114
+ def test_prune_cycle
115
+ # Make a graph with paths parent -> c1 -> gc11 -> c1 and
116
+ # parent -> c2 -> gc21 -> parent.
130
117
  parent = Node.new(1)
131
118
  c1 = Node.new(2, parent)
132
119
  gc11 = Node.new(3, c1)
@@ -135,8 +122,8 @@ class VistorTest < Test::Unit::TestCase
135
122
  gc21 = Node.new(5, c2)
136
123
  gc21.children << parent
137
124
  visitor = Jinx::Visitor.new(:prune_cycle) { |node| node.children }
138
- result = visitor.to_enum(parent).map { |node| node.value }
139
- assert_equal([1, 2, 3], result, "Exclude result incorrect")
125
+ result = visitor.to_enum(parent).to_a
126
+ assert_equal([parent, c1], result, "Exclude result incorrect")
140
127
  end
141
128
 
142
129
  def test_missing_block