immutable-ruby 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f0b9336a378ad7d4e2cf98b8977c0dbac13ed74b
4
- data.tar.gz: 2ec6d56a86049914a7c3e9807277a6134f5f4842
2
+ SHA256:
3
+ metadata.gz: d4dfc5d75d70e963c56837a552ac1902889f05f2fd73a3995c69959815780594
4
+ data.tar.gz: b9daefb94ad6bd5e3bf3a0bc7b74265a9d97188856ab78508f2cdf813b342636
5
5
  SHA512:
6
- metadata.gz: 02a4a9fa583aa94d5a609b8654247d486e41c51efcf0e3f3447ec47f6fd31e2f204e65dc906b6c6b82341dfdcc826b1a9ed55d9a4c8022e88508068999859d2f
7
- data.tar.gz: 4246f4d3457284cd82c13ed20b92f1b8d00e9cad02d30a0909f8f9d4194e331deac73fbaf5ebbaa1a4f395199c68f90cfdfef68403ac1c6a81edaf5b5e5878dc
6
+ metadata.gz: 306f0ef37c0ba06cf729b230f8eb6ec850cf6ff6130fea45eaf125d307078617f8688bc02b2dd6a75aae11134a45172f7ca11a12e6693409c36d5f00b7f18fc0
7
+ data.tar.gz: '0039ef718ca215f12d6826ea6803c7e404fd211536095c5a4995ca04e30b0effefa11951a640bca03b37ee9834ff94bac7acd9d1ccaf2d08ba449204850e42cb'
@@ -110,10 +110,38 @@ module Immutable
110
110
  @front.last # memoize?
111
111
  end
112
112
 
113
+ # Return a new `Deque` with elements rotated by `n` positions.
114
+ # A positive rotation moves elements to the right, negative to the left, and 0 is a no-op.
115
+ #
116
+ # @example
117
+ # Immutable::Deque["A", "B", "C"].rotate(1)
118
+ # # => Immutable::Deque["C", "A", "B"]
119
+ # Immutable::Deque["A", "B", "C"].rotate(-1)
120
+ # # => Immutable::Deque["B", "C", "A"]
121
+ #
122
+ # @param n [Integer] number of positions to move elements by
123
+ # @return [Deque]
124
+ def rotate(n)
125
+ return self.class.empty if self.empty?
126
+
127
+ n %= self.size
128
+ return self if n == 0
129
+
130
+ a, b = @front, @rear
131
+
132
+ if b.size >= n
133
+ n.times { a = a.cons(b.head); b = b.tail }
134
+ else
135
+ (self.size - n).times { b = b.cons(a.head); a = a.tail }
136
+ end
137
+
138
+ self.class.alloc(a, b)
139
+ end
140
+
113
141
  # Return a new `Deque` with `item` added at the end.
114
142
  #
115
143
  # @example
116
- # Immutable::Deque["A", "B", "C"].add("Z")
144
+ # Immutable::Deque["A", "B", "C"].push("Z")
117
145
  # # => Immutable::Deque["A", "B", "C", "Z"]
118
146
  #
119
147
  # @param item [Object] The item to add
@@ -180,6 +208,13 @@ module Immutable
180
208
  self.class.empty
181
209
  end
182
210
 
211
+ # Return a new `Deque` with the same items, but in reverse order.
212
+ #
213
+ # @return [Deque]
214
+ def reverse
215
+ self.class.alloc(@rear, @front)
216
+ end
217
+
183
218
  # Return true if `other` has the same type and contents as this `Deque`.
184
219
  #
185
220
  # @param other [Object] The collection to compare with
@@ -107,7 +107,7 @@ module Immutable
107
107
  # Return true if `other` contains the same elements, in the same order.
108
108
  # @return [Boolean]
109
109
  def ==(other)
110
- self.eql?(other) || other.respond_to?(:to_ary) && to_ary.eql?(other.to_ary)
110
+ self.eql?(other) || (other.respond_to?(:to_ary) && to_ary == other.to_ary)
111
111
  end
112
112
 
113
113
  # Convert all the elements into strings and join them together, separated by
@@ -771,7 +771,7 @@ module Immutable
771
771
  # @param other [Object] The object to compare with
772
772
  # @return [Boolean]
773
773
  def ==(other)
774
- self.eql?(other) || (other.respond_to?(:to_hash) && to_hash.eql?(other.to_hash))
774
+ self.eql?(other) || (other.respond_to?(:to_hash) && to_hash == other.to_hash)
775
775
  end
776
776
 
777
777
  # Return true if this `Hash` is a proper superset of `other`, which means
@@ -10,8 +10,8 @@ module Immutable
10
10
  # Returns the number of key-value pairs in the trie.
11
11
  attr_reader :size
12
12
 
13
- def initialize(significant_bits, size = 0, entries = [], children = [])
14
- @significant_bits = significant_bits
13
+ def initialize(bitshift, size = 0, entries = [], children = [])
14
+ @bitshift = bitshift
15
15
  @entries = entries
16
16
  @children = children
17
17
  @size = size
@@ -19,7 +19,7 @@ module Immutable
19
19
 
20
20
  # Returns <tt>true</tt> if the trie contains no key-value pairs.
21
21
  def empty?
22
- size == 0
22
+ @size == 0
23
23
  end
24
24
 
25
25
  # Returns <tt>true</tt> if the given key is present in the trie.
@@ -29,15 +29,7 @@ module Immutable
29
29
 
30
30
  # Calls <tt>block</tt> once for each entry in the trie, passing the key-value pair as parameters.
31
31
  def each(&block)
32
- # TODO: Using block.call here is slower than using yield by 5-10%, but
33
- # the latter segfaults on ruby 2.2 and above. Once that is fixed and
34
- # broken versions are sufficiently old, we should revert back to yield
35
- # with a warning that the broken versions are unsupported.
36
- #
37
- # For more context:
38
- # * https://bugs.ruby-lang.org/issues/11451
39
- # * https://github.com/hamstergem/hamster/issues/189
40
- @entries.each { |entry| block.call(entry) if entry }
32
+ @entries.each { |entry| yield entry if entry }
41
33
  @children.each do |child|
42
34
  child.each(&block) if child
43
35
  end
@@ -65,7 +57,7 @@ module Immutable
65
57
 
66
58
  # @return [Trie] A copy of `self` with the given value associated with the
67
59
  # key (or `self` if no modification was needed because an identical
68
- # key-value pair wes already stored
60
+ # key-value pair was already stored
69
61
  def put(key, value)
70
62
  index = index_for(key)
71
63
  entry = @entries[index]
@@ -74,7 +66,7 @@ module Immutable
74
66
  entries = @entries.dup
75
67
  key = key.dup.freeze if key.is_a?(String) && !key.frozen?
76
68
  entries[index] = [key, value].freeze
77
- Trie.new(@significant_bits, @size + 1, entries, @children)
69
+ Trie.new(@bitshift, @size + 1, entries, @children)
78
70
  elsif entry[0].eql?(key)
79
71
  if entry[1].equal?(value)
80
72
  self
@@ -82,7 +74,7 @@ module Immutable
82
74
  entries = @entries.dup
83
75
  key = key.dup.freeze if key.is_a?(String) && !key.frozen?
84
76
  entries[index] = [key, value].freeze
85
- Trie.new(@significant_bits, @size, entries, @children)
77
+ Trie.new(@bitshift, @size, entries, @children)
86
78
  end
87
79
  else
88
80
  child = @children[index]
@@ -94,12 +86,12 @@ module Immutable
94
86
  children = @children.dup
95
87
  children[index] = new_child
96
88
  new_self_size = @size + (new_child.size - child.size)
97
- Trie.new(@significant_bits, new_self_size, @entries, children)
89
+ Trie.new(@bitshift, new_self_size, @entries, children)
98
90
  end
99
91
  else
100
92
  children = @children.dup
101
- children[index] = Trie.new(@significant_bits + 5).put!(key, value)
102
- Trie.new(@significant_bits, @size + 1, @entries, children)
93
+ children[index] = Trie.new(@bitshift + 5).put!(key, value)
94
+ Trie.new(@bitshift, @size + 1, @entries, children)
103
95
  end
104
96
  end
105
97
  end
@@ -141,14 +133,14 @@ module Immutable
141
133
  end
142
134
  else
143
135
  new_children ||= @children.dup
144
- new_children[index] = Trie.new(@significant_bits + 5).put!(key, value)
136
+ new_children[index] = Trie.new(@bitshift + 5).put!(key, value)
145
137
  new_size += 1
146
138
  end
147
139
  end
148
140
  end
149
141
 
150
142
  if new_entries || new_children
151
- Trie.new(@significant_bits, new_size, new_entries || @entries, new_children || @children)
143
+ Trie.new(@bitshift, new_size, new_entries || @entries, new_children || @children)
152
144
  else
153
145
  self
154
146
  end
@@ -172,7 +164,7 @@ module Immutable
172
164
  @children[index] = child.put!(key, value)
173
165
  @size += child.size - old_child_size
174
166
  else
175
- @children[index] = Trie.new(@significant_bits + 5).put!(key, value)
167
+ @children[index] = Trie.new(@bitshift + 5).put!(key, value)
176
168
  @size += 1
177
169
  end
178
170
  end
@@ -193,7 +185,7 @@ module Immutable
193
185
 
194
186
  # Returns a copy of <tt>self</tt> with the given key (and associated value) deleted. If not found, returns <tt>self</tt>.
195
187
  def delete(key)
196
- find_and_delete(key) || Trie.new(@significant_bits)
188
+ find_and_delete(key) || Trie.new(@bitshift)
197
189
  end
198
190
 
199
191
  # Delete multiple elements from a Trie. This is more efficient than
@@ -238,7 +230,7 @@ module Immutable
238
230
  end
239
231
 
240
232
  if new_entries || new_children
241
- Trie.new(@significant_bits, new_size, new_entries || @entries, new_children || @children)
233
+ Trie.new(@bitshift, new_size, new_entries || @entries, new_children || @children)
242
234
  else
243
235
  self
244
236
  end
@@ -297,7 +289,7 @@ module Immutable
297
289
  children = @children.dup
298
290
  children[index] = copy
299
291
  new_size = @size - (child.size - copy_size(copy))
300
- return Trie.new(@significant_bits, new_size, @entries, children)
292
+ return Trie.new(@bitshift, new_size, @entries, children)
301
293
  end
302
294
  end
303
295
  end
@@ -318,14 +310,14 @@ module Immutable
318
310
  else
319
311
  entries[index] = nil
320
312
  end
321
- Trie.new(@significant_bits, @size - 1, entries, children || @children)
313
+ Trie.new(@bitshift, @size - 1, entries, children || @children)
322
314
  end
323
315
  end
324
316
 
325
317
  private
326
318
 
327
319
  def index_for(key)
328
- (key.hash.abs >> @significant_bits) & 31
320
+ (key.hash.abs >> @bitshift) & 31
329
321
  end
330
322
 
331
323
  def copy_size(copy)
@@ -334,5 +326,5 @@ module Immutable
334
326
  end
335
327
 
336
328
  # @private
337
- EmptyTrie = Trie.new(0)
329
+ EmptyTrie = Trie.new(0).freeze
338
330
  end
@@ -1,5 +1,5 @@
1
1
  module Immutable
2
2
  # Current released gem version. Note that master will often have the same
3
3
  # value as a release gem but with different code.
4
- VERSION = "0.0.3"
4
+ VERSION = "0.0.4"
5
5
  end
@@ -26,7 +26,7 @@ describe Immutable::Deque do
26
26
  context "on empty subclass" do
27
27
  let(:subclass) { Class.new(Immutable::Deque) }
28
28
  let(:empty_instance) { subclass.new }
29
- it "returns emtpy object of same class" do
29
+ it "returns empty object of same class" do
30
30
  empty_instance.send(method).class.should be subclass
31
31
  end
32
32
  end
@@ -0,0 +1,68 @@
1
+ require "spec_helper"
2
+
3
+ describe Immutable::Deque do
4
+
5
+ # Deques can have items distributed differently between the 'front' and 'rear' lists
6
+ # and still be equivalent
7
+ # Since the implementation of #rotate depends on how items are distributed between the
8
+ # two lists, we need to test both the case where most items are on the 'front' and
9
+ # where most are on the 'rear'
10
+ big_front = D.alloc(L.from_enum([1, 2, 3]), L.from_enum([5, 4]))
11
+ big_rear = D.alloc(L.from_enum([1, 2]), L.from_enum([5, 4, 3]))
12
+
13
+ describe "#rotate" do
14
+ [
15
+ [[], 9999, []],
16
+ [['A'], -1, ['A']],
17
+ [['A', 'B', 'C'], -1, ['B', 'C', 'A']],
18
+ [['A', 'B', 'C', 'D'], 0, ['A', 'B', 'C', 'D']],
19
+ [%w[A B C D], 2, %w[C D A B]],
20
+ ].each do |values, rotation, expected|
21
+ context "on #{values.inspect}" do
22
+ let(:deque) { D[*values] }
23
+
24
+ it "preserves the original" do
25
+ deque.rotate(rotation)
26
+ deque.should eql(D[*values])
27
+ end
28
+
29
+ it "returns #{expected.inspect}" do
30
+ deque.rotate(rotation).should eql(D[*expected])
31
+ end
32
+
33
+ it "returns a frozen instance" do
34
+ deque.rotate(rotation).should be_frozen
35
+ end
36
+ end
37
+ end
38
+
39
+ context "on a Deque with most items on 'front' list" do
40
+ it "works with a small rotation" do
41
+ big_front.rotate(2).should eql(D[4, 5, 1, 2, 3])
42
+ end
43
+
44
+ it "works with a larger rotation" do
45
+ big_front.rotate(4).should eql(D[2, 3, 4, 5, 1])
46
+ end
47
+ end
48
+
49
+ context "on a Deque with most items on 'rear' list" do
50
+ it "works with a small rotation" do
51
+ big_rear.rotate(2).should eql(D[4, 5, 1, 2, 3])
52
+ end
53
+
54
+ it "works with a larger rotation" do
55
+ big_rear.rotate(4).should eql(D[2, 3, 4, 5, 1])
56
+ end
57
+ end
58
+
59
+ context "on empty subclass" do
60
+ let(:subclass) { Class.new(Immutable::Deque) }
61
+ let(:empty_instance) { subclass.new }
62
+ it "returns an empty object of the same class" do
63
+ empty_instance.rotate(1).class.should be subclass
64
+ empty_instance.rotate(-1).class.should be subclass
65
+ end
66
+ end
67
+ end
68
+ end
@@ -1,4 +1,5 @@
1
1
  require "spec_helper"
2
+ require "bigdecimal"
2
3
 
3
4
  describe Immutable::Hash do
4
5
  let(:hash) { H["A" => "aye", "B" => "bee", "C" => "see"] }
@@ -33,6 +34,11 @@ describe Immutable::Hash do
33
34
  instance = subclass.new("A" => "aye", "B" => "bee", "C" => "see")
34
35
  (hash == instance).should == true
35
36
  end
37
+
38
+ it "performs numeric conversions between floats and BigDecimals" do
39
+ expect(H[a: 0.0] == H[a: BigDecimal('0.0')]).to be true
40
+ expect(H[a: BigDecimal('0.0')] == H[a: 0.0]).to be true
41
+ end
36
42
  end
37
43
 
38
44
  [:eql?, :==].each do |method|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: immutable-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Dowad
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2018-05-12 00:00:00.000000000 Z
14
+ date: 2019-05-16 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: concurrent-ruby
@@ -167,6 +167,7 @@ files:
167
167
  - spec/lib/immutable/deque/pretty_print_spec.rb
168
168
  - spec/lib/immutable/deque/push_spec.rb
169
169
  - spec/lib/immutable/deque/random_modification_spec.rb
170
+ - spec/lib/immutable/deque/rotate_spec.rb
170
171
  - spec/lib/immutable/deque/shift_spec.rb
171
172
  - spec/lib/immutable/deque/size_spec.rb
172
173
  - spec/lib/immutable/deque/to_a_spec.rb
@@ -504,8 +505,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
504
505
  - !ruby/object:Gem::Version
505
506
  version: '0'
506
507
  requirements: []
507
- rubyforge_project:
508
- rubygems_version: 2.6.13
508
+ rubygems_version: 3.0.1
509
509
  signing_key:
510
510
  specification_version: 4
511
511
  summary: Efficient, immutable, thread-safe collection classes for Ruby
@@ -606,6 +606,7 @@ test_files:
606
606
  - spec/lib/immutable/deque/copying_spec.rb
607
607
  - spec/lib/immutable/deque/pop_spec.rb
608
608
  - spec/lib/immutable/deque/to_a_spec.rb
609
+ - spec/lib/immutable/deque/rotate_spec.rb
609
610
  - spec/lib/immutable/deque/marshal_spec.rb
610
611
  - spec/lib/immutable/set/difference_spec.rb
611
612
  - spec/lib/immutable/set/disjoint_spec.rb