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
@@ -1,8 +1,14 @@
1
1
  module Jinx
2
2
  # This Filter helper class applies a selection block to a base enumeration.
3
3
  class Filter
4
- include Collection
4
+ include Enumerable, Collection
5
5
 
6
+ # Initializes this Filter's from the given base enumeration and optional filter test.
7
+ # The default filter test is whether the item is non-nil and not +false+.
8
+ #
9
+ # @param [Enumerable] enum the base enumeration to filter
10
+ # @yield [item] the block called on each item
11
+ # @yieldparam item the enumerated item
6
12
  def initialize(enum=[], &filter)
7
13
  @base = enum
8
14
  @filter = filter
@@ -10,7 +16,7 @@ module Jinx
10
16
 
11
17
  # Calls the given block on each item which passes this Filter's filter test.
12
18
  #
13
- # @yield [item] the block called on each item
19
+ # @yield [item] the block called on each filtered item
14
20
  # @yieldparam item the enumerated item
15
21
  def each
16
22
  @base.each { |item| yield(item) if @filter ? @filter.call(item) : item }
@@ -1,10 +1,10 @@
1
1
  module Jinx
2
2
  # A Flattener applies a given block to flattened collection content.
3
3
  class Flattener
4
- include Collection
4
+ include Enumerable, Collection
5
5
 
6
6
  # Visits the enumerated items in the given object's flattened content.
7
- # block is called on the base itself if the base is neither nil nor a Enumerable.
7
+ # The given block is called on the base itself if the base is neither nil nor a Enumerable.
8
8
  # If the base object is nil or empty, then this method is a no-op and returns nil.
9
9
  def self.on(obj, &block)
10
10
  obj.collection? ? obj.each { |item| on(item, &block) } : yield(obj) unless obj.nil?
@@ -1,7 +1,7 @@
1
- require 'jinx/helpers/hashable'
1
+ require 'jinx/helpers/hasher'
2
2
 
3
3
  class Hash
4
- include Jinx::Hashable
4
+ include Jinx::Hasher
5
5
 
6
6
  # The EMPTY_HASH constant is an immutable empty hash, used primarily as a default argument.
7
7
  class << EMPTY_HASH ||= Hash.new
@@ -10,3 +10,4 @@ class Hash
10
10
  end
11
11
  end
12
12
  end
13
+
@@ -1,49 +1,62 @@
1
1
  require 'jinx/helpers/collection'
2
- require 'jinx/helpers/hashable'
3
2
 
4
3
  module Jinx
5
- # Hashable is a Hash mixin that adds utility methods to a Hash.
6
- # Hashable can be included by any class or module which implements an _each_ method
7
- # with arguments _key_ and _value_.
8
- module Hashable
9
- include Collection
4
+ # Hasher is a mix-in that adds utility methods to a Hash.
5
+ # This Hasher module can be included by any class or module which implements an _each_
6
+ # method with arguments _key_ and _value_.
7
+ module Hasher
8
+ include Enumerable, Collection
10
9
 
11
10
  # @see Hash#each_pair
12
11
  def each_pair(&block)
13
12
  each(&block)
14
13
  end
15
14
 
16
- # @see Hash#[]
17
- def [](key)
18
- detect_value { |k, v| v if k == key }
19
- end
20
-
21
15
  # @see Hash#each_key
22
16
  def each_key
23
17
  each { |k, v| yield k }
24
18
  end
25
19
 
20
+ # @example
21
+ # {1 => :a, 2 => :b, 3 => :c}.detect_key { |k| k > 1 } #=> 2
22
+ #
26
23
  # @yield [key] the detector block
27
24
  # @yieldparam key the hash key
28
- # @return the key for which the detector block returns a non-nil, non-false value,
25
+ # @return the hash key for which the detector block returns a non-nil, non-false result,
29
26
  # or nil if none
30
- # @example
31
- # {1 => :a, 2 => :b, 3 => :c}.detect_key { |k| k > 1 } #=> 2
32
27
  def detect_key
33
28
  each_key { |k| return k if yield k }
34
29
  nil
35
30
  end
36
-
31
+
32
+ # @param key the search target
33
+ # @return [Boolean] whether this Hasher has the given key
37
34
  def has_key?(key)
38
- !!detect_key { |k| k == key }
35
+ each_key { |k| return true if k.eql?(key) }
36
+ false
39
37
  end
40
38
 
39
+ alias :include? :has_key?
40
+
41
+ # @see {Enumerable#hash_value}
42
+ # @example
43
+ # {1 => 2, 3 => 4}.detect_value { |k, v| v if k > 1 } #=> 4
44
+ # @return (see Enumerable#hash_value)
45
+ def detect_value
46
+ each do |k, v|
47
+ value = yield(k, v)
48
+ return value if value
49
+ end
50
+ nil
51
+ end
52
+
53
+ # @example
54
+ # {:a => 1, :b => 2, :c => 3}.detect_key_with_value { |v| v > 1 } #=> :b
55
+ #
41
56
  # @yield [value] the detector block
42
57
  # @yieldparam value the hash value
43
58
  # @return the key for which the detector block returns a non-nil, non-false value,
44
59
  # or nil if none
45
- # @example
46
- # {:a => 1, :b => 2, :c => 3}.detect_key_with_value { |v| v > 1 } #=> :b
47
60
  def detect_key_with_value
48
61
  each { |k, v| return k if yield v }
49
62
  nil
@@ -53,9 +66,26 @@ module Jinx
53
66
  def each_value
54
67
  each { |k, v| yield v }
55
68
  end
69
+
70
+ # @example
71
+ # {:a => 1, :b => 2}.detect_hash_value { |v| v > 1 } #=> 2
72
+ #
73
+ # @yield [value] the detector block
74
+ # @yieldparam value the hash value
75
+ # @return a hash value for which the detector block returns a non-nil, non-false result,
76
+ # or nil if none
77
+ def detect_hash_value
78
+ each_value { |v| return v if yield v }
79
+ nil
80
+ end
81
+
82
+ # @see Hash#[]
83
+ def [](key)
84
+ detect_value { |k, v| v if k.eql?(key) }
85
+ end
56
86
 
57
- # Returns a Hashable which composes each value in this Hashable with the key of
58
- # the other Hashable, e.g.:
87
+ # Returns a Hasher which composes each value in this Hasher with the key of the
88
+ # other Hasher, e.g.:
59
89
  # x = {:a => :c, :b => :d}
60
90
  # y = {:c => 1}
61
91
  # z = x.compose(y)
@@ -68,14 +98,14 @@ module Jinx
68
98
  #
69
99
  # Update operations on the result are not supported.
70
100
  #
71
- # @param [Hashable] other the Hashable to compose with this Hashable
72
- # @return [Hashable] the composed result
101
+ # @param [Hasher] other the Hasher to compose with this Hasher
102
+ # @return [Hasher] the composed result
73
103
  def compose(other)
74
104
  transform_value { |v| {v => other[v]} if other.has_key?(v) }
75
105
  end
76
106
 
77
- # Returns a Hashable which joins each value in this Hashable with the key of
78
- # the other Hashable, e.g.:
107
+ # Returns a Hasher which joins each value in this Hasher with the key of the
108
+ # other Hasher, e.g.:
79
109
  # x = {:a => :c, :b => :d}
80
110
  # y = {:c => 1}
81
111
  # z = x.join(y)
@@ -88,14 +118,14 @@ module Jinx
88
118
  #
89
119
  # Update operations on the result are not supported.
90
120
  #
91
- # @param [Hashable] other the Hashable to join with this Hashable
92
- # @return [Hashable] the joined result
121
+ # @param [Hasher] other the Hasher to join with this Hasher
122
+ # @return [Hasher] the joined result
93
123
  def join(other)
94
124
  transform_value { |v| other[v] }
95
125
  end
96
126
 
97
- # Returns a Hashable which associates each key of both this Hashable and the other Hashable
98
- # with the corresponding value in the first Hashable which has that key, e.g.:
127
+ # Returns a Hasher which associates each key of both this Hasher and the other
128
+ # Hasher with the corresponding value in the first Hasher which has that key, e.g.:
99
129
  # x = {:a => 1, :b => 2}
100
130
  # y = {:b => 3, :c => 4}
101
131
  # z = x + y
@@ -107,23 +137,23 @@ module Jinx
107
137
  #
108
138
  # Update operations on the result are not supported.
109
139
  #
110
- # @param [Hashable] other the Hashable to form a union with this Hashable
111
- # @return [Hashable] the union result
140
+ # @param [Hasher] other the Hasher to form a union with this Hasher
141
+ # @return [Hasher] the union result
112
142
  def union(other)
113
143
  MultiHash.new(self, other)
114
144
  end
115
145
 
116
146
  alias :+ :union
117
147
 
118
- # Returns a new Hashable that iterates over the base Hashable <key, value> pairs for which the block
119
- # given to this method evaluates to a non-nil, non-false value, e.g.:
148
+ # Returns a new Hasher that iterates over the base Hasher <key, value> pairs for which
149
+ # the block given to this method evaluates to a non-nil, non-false value, e.g.:
120
150
  # {:a => 1, :b => 2, :c => 3}.filter { |k, v| k != :b }.to_hash #=> {:a => 1, :c => 3}
121
151
  #
122
152
  # The default filter block tests the value, e.g.:
123
153
  # {:a => 1, :b => nil}.filter.to_hash #=> {:a => 1}
124
154
  #
125
155
  # @yield [key, value] the filter block
126
- # @return [Hashable] the filtered result
156
+ # @return [Hasher] the filtered result
127
157
  def filter(&block)
128
158
  Filter.new(self, &block)
129
159
  end
@@ -135,25 +165,25 @@ module Jinx
135
165
  #
136
166
  # @yield [key] the filter block
137
167
  # @yieldparam key the hash key to filter
138
- # @return [Hashable] the filtered result
168
+ # @return [Hasher] the filtered result
139
169
  def filter_on_key(&block)
140
170
  KeyFilter.new(self, &block)
141
171
  end
142
172
 
143
- # @return [Hashable] a {#filter} that only uses the value.
173
+ # @return [Hasher] a {#filter} that only uses the value.
144
174
  # @yield [value] the filter block
145
175
  # @yieldparam value the hash value to filter
146
- # @return [Hashable] the filtered result
176
+ # @return [Hasher] the filtered result
147
177
  def filter_on_value
148
178
  filter { |k, v| yield v }
149
179
  end
150
180
 
151
- # @return [Hash] a {#filter} of this Hashable which excludes the entries with a null value
181
+ # @return [Hash] a {#filter} of this Hasher which excludes the entries with a null value
152
182
  def compact
153
183
  filter_on_value { |v| not v.nil? }
154
184
  end
155
185
 
156
- # Returns the difference between this Hashable and the other Hashable in a Hash of the form:
186
+ # Returns the difference between this Hasher and the other Hasher in a Hash of the form:
157
187
  #
158
188
  # _key_ => [_mine_, _theirs_]
159
189
  #
@@ -162,22 +192,24 @@ module Jinx
162
192
  # * _mine_ is the value for _key_ in this hash
163
193
  # * _theirs_ is the value for _key_ in the other hash
164
194
  #
165
- # @param [Hashable] other the Hashable to subtract
195
+ # @param [Hasher] other the Hasher to subtract
166
196
  # @yield [key, v1, v2] the optional block which determines whether values differ (default is equality)
167
197
  # @yieldparam key the key for which values are compared
168
- # @yieldparam v1 the value for key from this Hashable
169
- # @yieldparam v2 the value for key from the other Hashable
198
+ # @yieldparam v1 the value for key from this Hasher
199
+ # @yieldparam v2 the value for key from the other Hasher
170
200
  # @return [{Object => (Object,Object)}] a hash of the differences
171
- def diff(other)
201
+ def difference(other)
172
202
  (keys.to_set + other.keys).to_compact_hash do |k|
173
203
  mine = self[k]
174
204
  yours = other[k]
175
205
  [mine, yours] unless block_given? ? yield(k, mine, yours) : mine == yours
176
206
  end
177
207
  end
208
+
209
+ alias :diff :difference
178
210
 
179
211
  # @yield [key1, key2] the key sort block
180
- # @return [Hashable] a hash whose #each and {#each_pair} enumerations are sorted by key
212
+ # @return [Hasher] a hash whose #each and {#each_pair} enumerations are sorted by key
181
213
  def sort(&sorter)
182
214
  SortedHash.new(self, &sorter)
183
215
  end
@@ -188,7 +220,7 @@ module Jinx
188
220
  # {:a => 1, :b => 2}.assoc_values({:a => 3, :c => 4}) #=> {:a => [1, 3], :b => [2, nil], :c => [nil, 4]}
189
221
  # {:a => 1, :b => 2}.assoc_values({:a => 3}, {:a => 4, :b => 5}) #=> {:a => [1, 3, 4], :b => [2, nil, 5]}
190
222
  #
191
- # @param [<Hashable>] others the other Hashables to associate with this Hashable
223
+ # @param [<Hasher>] others the other Hashers to associate with this Hasher
192
224
  # @return [Hash] the association hash
193
225
  def assoc_values(*others)
194
226
  all_keys = keys
@@ -209,25 +241,17 @@ module Jinx
209
241
  filter_on_value(&filter).keys
210
242
  end
211
243
 
212
- # @return [Enumerable] Enumerable over this Hashable's keys
244
+ # @return [Enumerable] Enumerable over this Hasher's keys
213
245
  def enum_keys
214
246
  Enumerable::Enumerator.new(self, :each_key)
215
247
  end
216
248
 
217
- # @return [Array] this Hashable's keys
249
+ # @return [Array] this Hasher's keys
218
250
  def keys
219
251
  enum_keys.to_a
220
252
  end
221
253
 
222
- # @param key search target
223
- # @return [Boolean] whether this Hashable has the given key
224
- def has_key?(key)
225
- enum_keys.include?(key)
226
- end
227
-
228
- alias :include? :has_key?
229
-
230
- # @return [Enumerable] an Enumerable over this Hashable's values
254
+ # @return [Enumerable] an Enumerable over this Hasher's values
231
255
  def enum_values
232
256
  Enumerable::Enumerator.new(self, :each_value)
233
257
  end
@@ -262,7 +286,7 @@ module Jinx
262
286
  end
263
287
 
264
288
  # @param value search target
265
- # @return [Boolean] whether this Hashable has the given value
289
+ # @return [Boolean] whether this Hasher has the given value
266
290
  def has_value?(value)
267
291
  enum_values.include?(value)
268
292
  end
@@ -288,7 +312,7 @@ module Jinx
288
312
  #
289
313
  # This method is useful for preserving and restoring hash associations.
290
314
  #
291
- # @return [Hash] a deep copy of this Hashable
315
+ # @return [Hash] a deep copy of this Hasher
292
316
  def copy_recursive
293
317
  copy = Hash.new
294
318
  keys.each do |k|
@@ -298,27 +322,46 @@ module Jinx
298
322
  copy
299
323
  end
300
324
 
325
+ # Returns a new Hasher which applies a transformer block to each value in this
326
+ # base Hasher. The result reflects changes to this underlying base Hasher.
327
+ #
301
328
  # @example
302
- # {:a => 1, :b => 2}.transform_value { |n| n * 2 }.values #=> [2, 4]
329
+ # h = {:a => 1, :b => 2}
330
+ # xfm = h.transform_value { |n| n * 2 }
331
+ # xfm.values #=> [2, 4]
332
+ # xfm[:a] #=> 2
333
+ # xfm[:b] #=> 4
334
+ # h[:c] = 3
335
+ # xfm[:c] #=> 6
303
336
  #
304
337
  # @yield [value] transforms the given value
305
- # @yieldparam [value] the value to transform
306
- # @return [Hash] a new Hash that transforms each value
338
+ # @yieldparam value the value to transform
339
+ # @return [Hasher] a new Hasher that transforms each value
307
340
  def transform_value(&transformer)
308
341
  ValueTransformerHash.new(self, &transformer)
309
342
  end
310
343
 
344
+ # Returns a new Hasher which applies a transformer block to each key in this
345
+ # base Hasher. The result reflects changes to this underlying base Hasher.
346
+ #
311
347
  # @example
312
- # {1 => :a, 2 => :b}.transform_key { |n| n * 2 }.keys #=> [2, 4]
348
+ # h = {1 => :a, 2 => :b}
349
+ # xfm = h.transform_key { |n| n * 2 }
350
+ # xfm.keys #=> [2, 4]
351
+ # xfm[2] #=> :a
352
+ # xfm[3] #=> nil
353
+ # xfm[4] #=> :b
354
+ # h[3] = :c
355
+ # xfm[6] #=> :c
313
356
  #
314
357
  # @yield [key] transforms the given key
315
- # @yieldparam [value] the key to transform
316
- # @return [Hash] a new Hash that transforms each key
358
+ # @yieldparam key the key to transform
359
+ # @return [Hasher] a new Hasher that transforms each key
317
360
  def transform_key(&transformer)
318
361
  KeyTransformerHash.new(self, &transformer)
319
362
  end
320
363
 
321
- # @return [Hash] a new Hash created from this Hashable's content
364
+ # @return [Hash] a new Hash created from this Hasher's content
322
365
  def to_hash
323
366
  hash = {}
324
367
  each { |k, v| hash[k] = v }
@@ -345,7 +388,7 @@ module Jinx
345
388
 
346
389
  # @see #filter
347
390
  class Filter
348
- include Hashable
391
+ include Hasher
349
392
 
350
393
  def initialize(base, &filter)
351
394
  @base = base
@@ -359,7 +402,7 @@ module Jinx
359
402
 
360
403
  # @see #filter_on_key
361
404
  class KeyFilter < Filter
362
- include Hashable
405
+ include Hasher
363
406
 
364
407
  def initialize(base)
365
408
  super(base) { |k, v| yield(k) }
@@ -372,7 +415,7 @@ module Jinx
372
415
 
373
416
  # @see #sort
374
417
  class SortedHash
375
- include Hashable
418
+ include Hasher
376
419
 
377
420
  def initialize(base, &comparator)
378
421
  @base = base
@@ -384,11 +427,11 @@ module Jinx
384
427
  end
385
428
  end
386
429
 
387
- # Combines hashes. See Hash#+ for details.
430
+ # Combines hashes. See {Hasher#union} for details.
388
431
  class MultiHash
389
- include Hashable
432
+ include Hasher
390
433
 
391
- # @return [<Hashable>] the enumerated hashes
434
+ # @return [<Hasher>] the enumerated hashes
392
435
  attr_reader :components
393
436
 
394
437
  def initialize(*hashes)
@@ -417,13 +460,18 @@ module Jinx
417
460
  end
418
461
  self
419
462
  end
463
+
464
+ # Returns the union of the results of calling the given method symbol on each component.
465
+ def method_missing(symbol, *args)
466
+ @components.map { |hash| hash.send(symbol, *args) }.inject { |value, result| result.union(value) }
467
+ end
420
468
  end
421
469
  end
422
470
 
423
- # The ValueTransformerHash class pipes the value from a base Hashable into a transformer block.
471
+ # The ValueTransformerHash class pipes the value from a base Hasher into a transformer block.
424
472
  # @private
425
473
  class ValueTransformerHash
426
- include Hashable
474
+ include Hasher
427
475
 
428
476
  # Creates a ValueTransformerHash on the base hash and value transformer block.
429
477
  #
@@ -450,14 +498,14 @@ module Jinx
450
498
  end
451
499
  end
452
500
 
453
- # The KeyTransformerHash class pipes the key from a base Hashable into a transformer block.
501
+ # The KeyTransformerHash class applies a transformer block to each key in a base Hasher.
454
502
  # @private
455
503
  class KeyTransformerHash
456
- include Hashable
504
+ include Hasher
457
505
 
458
506
  # Creates a KeyTransformerHash on the base hash and key transformer block.
459
507
  #
460
- # @param [Hash, nil] base the hash to transform
508
+ # @param [Hash] base the hash to transform
461
509
  # @yield [key] transforms the base key
462
510
  # @yieldparam key the base key to transform
463
511
  def initialize(base, &transformer)
@@ -473,7 +521,7 @@ module Jinx
473
521
  end
474
522
  end
475
523
 
476
- # Hashinator creates a Hashable from an Enumerable on [_key_, _value_] pairs.
524
+ # Hashinator creates a Hasher from an Enumerable on [_key_, _value_] pairs.
477
525
  # The Hashinator reflects changes to the underlying Enumerable.
478
526
  #
479
527
  # @example
@@ -483,7 +531,7 @@ module Jinx
483
531
  # base.first[1] = 3
484
532
  # hash[:a] #=> 3
485
533
  class Hashinator
486
- include Hashable
534
+ include Hasher
487
535
 
488
536
  def initialize(enum)
489
537
  @base = enum