jinx 2.1.3 → 2.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +27 -0
- data/History.md +4 -0
- data/lib/jinx/helpers/class.rb +16 -12
- data/lib/jinx/helpers/collection.rb +277 -29
- data/lib/jinx/helpers/collections.rb +35 -2
- data/lib/jinx/helpers/conditional_enumerator.rb +2 -2
- data/lib/jinx/helpers/filter.rb +8 -2
- data/lib/jinx/helpers/flattener.rb +2 -2
- data/lib/jinx/helpers/hash.rb +3 -2
- data/lib/jinx/helpers/{hashable.rb → hasher.rb} +125 -77
- data/lib/jinx/helpers/module.rb +1 -1
- data/lib/jinx/helpers/multi_enumerator.rb +25 -9
- data/lib/jinx/helpers/options.rb +4 -3
- data/lib/jinx/helpers/partial_order.rb +16 -8
- data/lib/jinx/helpers/pretty_print.rb +14 -4
- data/lib/jinx/helpers/transformer.rb +3 -1
- data/lib/jinx/helpers/transitive_closure.rb +3 -3
- data/lib/jinx/helpers/visitor.rb +33 -42
- data/lib/jinx/import/java.rb +40 -27
- data/lib/jinx/importer.rb +86 -33
- data/lib/jinx/metadata/attribute_enumerator.rb +5 -11
- data/lib/jinx/metadata/dependency.rb +65 -30
- data/lib/jinx/metadata/id_alias.rb +1 -0
- data/lib/jinx/metadata/introspector.rb +21 -9
- data/lib/jinx/metadata/inverse.rb +14 -11
- data/lib/jinx/metadata/java_property.rb +15 -26
- data/lib/jinx/metadata/propertied.rb +80 -19
- data/lib/jinx/metadata/property.rb +13 -8
- data/lib/jinx/metadata/property_characteristics.rb +2 -2
- data/lib/jinx/resource.rb +62 -32
- data/lib/jinx/resource/inversible.rb +4 -0
- data/lib/jinx/resource/match_visitor.rb +0 -1
- data/lib/jinx/resource/mergeable.rb +16 -6
- data/lib/jinx/resource/reference_enumerator.rb +1 -2
- data/lib/jinx/version.rb +1 -1
- data/test/lib/jinx/helpers/collections_test.rb +29 -14
- data/test/lib/jinx/helpers/visitor_test.rb +7 -20
- data/test/lib/jinx/import/mixed_case_test.rb +17 -3
- metadata +4 -4
- 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
|
-
|
276
|
-
|
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
|
-
|
290
|
-
if
|
291
|
-
|
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
|
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
|
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
|
data/lib/jinx/resource.rb
CHANGED
@@ -29,13 +29,16 @@ module Jinx
|
|
29
29
|
# module Domain
|
30
30
|
# include Jinx::Resource
|
31
31
|
# # The caTissue Java package name.
|
32
|
-
#
|
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
|
-
# @
|
138
|
-
|
139
|
-
|
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
|
-
#
|
200
|
-
#
|
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]
|
211
|
-
# @raise [NoMethodError] if this Resource's class does not have
|
212
|
-
|
213
|
-
|
214
|
-
if
|
215
|
-
|
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
|
-
|
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.
|
232
|
-
|
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
|
402
|
-
def
|
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.
|
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
|
-
|
712
|
-
raise
|
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
|
-
|
44
|
-
|
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.
|
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
|
data/lib/jinx/version.rb
CHANGED
@@ -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
|
-
|
100
|
-
assert_equal([1, 2, 4],
|
101
|
-
assert(
|
102
|
-
assert(
|
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],
|
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,
|
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(
|
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
|
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
|
-
|
309
|
-
|
310
|
-
assert_equal(
|
311
|
-
|
312
|
-
|
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, "
|
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).
|
126
|
-
assert_equal([
|
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
|
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).
|
139
|
-
assert_equal([
|
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
|