jinx 2.1.3 → 2.1.4

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