hamster 0.1.8 → 0.1.11

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 (69) hide show
  1. data/README.rdoc +34 -10
  2. data/lib/hamster.rb +0 -1
  3. data/lib/hamster/hash.rb +77 -20
  4. data/lib/hamster/list.rb +189 -52
  5. data/lib/hamster/set.rb +78 -23
  6. data/lib/hamster/stack.rb +13 -14
  7. data/lib/hamster/trie.rb +13 -4
  8. data/lib/hamster/version.rb +1 -1
  9. data/spec/hamster/hash/all_spec.rb +53 -0
  10. data/spec/hamster/hash/any_spec.rb +62 -0
  11. data/spec/hamster/hash/construction_spec.rb +21 -5
  12. data/spec/hamster/hash/copying_spec.rb +6 -10
  13. data/spec/hamster/hash/each_spec.rb +6 -18
  14. data/spec/hamster/hash/empty_spec.rb +9 -5
  15. data/spec/hamster/hash/eql_spec.rb +17 -22
  16. data/spec/hamster/hash/filter_spec.rb +61 -0
  17. data/spec/hamster/hash/get_spec.rb +24 -12
  18. data/spec/hamster/hash/has_key_spec.rb +17 -13
  19. data/spec/hamster/hash/map_spec.rb +66 -0
  20. data/spec/hamster/hash/none_spec.rb +62 -0
  21. data/spec/hamster/hash/put_spec.rb +17 -73
  22. data/spec/hamster/hash/reduce_spec.rb +58 -0
  23. data/spec/hamster/hash/reject_spec.rb +57 -0
  24. data/spec/hamster/hash/remove_spec.rb +13 -85
  25. data/spec/hamster/hash/size_spec.rb +25 -0
  26. data/spec/hamster/list/cadr_spec.rb +37 -0
  27. data/spec/hamster/list/construction_spec.rb +46 -6
  28. data/spec/hamster/list/copying_spec.rb +13 -11
  29. data/spec/hamster/list/drop_spec.rb +29 -0
  30. data/spec/hamster/list/drop_while_spec.rb +39 -0
  31. data/spec/hamster/list/each_spec.rb +24 -24
  32. data/spec/hamster/list/empty_spec.rb +15 -6
  33. data/spec/hamster/list/eql_spec.rb +27 -7
  34. data/spec/hamster/list/filter_spec.rb +51 -0
  35. data/spec/hamster/list/head_spec.rb +27 -0
  36. data/spec/hamster/list/include_spec.rb +37 -0
  37. data/spec/hamster/list/lazy_spec.rb +21 -0
  38. data/spec/hamster/list/map_spec.rb +21 -19
  39. data/spec/hamster/list/reduce_spec.rb +27 -15
  40. data/spec/hamster/list/reject_spec.rb +47 -0
  41. data/spec/hamster/list/size_spec.rb +31 -0
  42. data/spec/hamster/list/tail_spec.rb +27 -0
  43. data/spec/hamster/list/take_spec.rb +29 -0
  44. data/spec/hamster/list/take_while_spec.rb +45 -0
  45. data/spec/hamster/set/add_spec.rb +49 -0
  46. data/spec/hamster/set/all_spec.rb +61 -0
  47. data/spec/hamster/set/any_spec.rb +61 -0
  48. data/spec/hamster/set/construction_spec.rb +3 -3
  49. data/spec/hamster/set/copying_spec.rb +21 -0
  50. data/spec/hamster/set/each_spec.rb +36 -0
  51. data/spec/hamster/set/empty_spec.rb +21 -0
  52. data/spec/hamster/set/eql_spec.rb +31 -0
  53. data/spec/hamster/set/filter_spec.rb +61 -0
  54. data/spec/hamster/set/include_spec.rb +29 -0
  55. data/spec/hamster/set/map_spec.rb +66 -0
  56. data/spec/hamster/set/none_spec.rb +61 -0
  57. data/spec/hamster/set/reduce_spec.rb +58 -0
  58. data/spec/hamster/set/reject_spec.rb +57 -0
  59. data/spec/hamster/set/remove_spec.rb +45 -0
  60. data/spec/hamster/set/size_spec.rb +25 -0
  61. data/spec/hamster/stack/copying_spec.rb +1 -1
  62. data/spec/hamster/stack/empty_spec.rb +2 -2
  63. data/spec/hamster/stack/eql_spec.rb +15 -4
  64. data/spec/hamster/stack/push_spec.rb +6 -26
  65. data/spec/hamster/trie/remove_spec.rb +117 -0
  66. metadata +39 -7
  67. data/TODO +0 -1
  68. data/spec/hamster/list/accessor_spec.rb +0 -26
  69. data/spec/hamster/list/car_spec.rb +0 -17
@@ -1,31 +1,31 @@
1
+ require 'hamster/trie'
2
+
1
3
  module Hamster
2
4
 
3
- class Set
5
+ def self.set(*items)
6
+ items.reduce(Set.new) { |set, item| set.add(item) }
7
+ end
4
8
 
5
- def self.[](*items)
6
- items.reduce(self.new) { |set, item| set.add(item) }
7
- end
9
+ class Set
8
10
 
9
11
  def initialize(trie = Trie.new)
10
12
  @trie = trie
11
13
  end
12
14
 
13
- # Returns the number of items in the set.
14
- def size
15
- @trie.size
16
- end
17
-
18
- # Returns <tt>true</tt> if the set contains no items.
19
15
  def empty?
20
16
  @trie.empty?
21
17
  end
22
18
 
23
- # Returns <tt>true</tt> if the given item is present in the set.
19
+ def size
20
+ @trie.size
21
+ end
22
+ alias_method :length, :size
23
+
24
24
  def include?(item)
25
25
  @trie.has_key?(item)
26
26
  end
27
+ alias_method :member?, :include?
27
28
 
28
- # Returns a copy of <tt>self</tt> with the given item added. If already exists, returns <tt>self</tt>.
29
29
  def add(item)
30
30
  if include?(item)
31
31
  self
@@ -33,36 +33,91 @@ module Hamster
33
33
  self.class.new(@trie.put(item, nil))
34
34
  end
35
35
  end
36
+ alias_method :<<, :add
36
37
 
37
- # Returns a copy of <tt>self</tt> with the given item removed. If not found, returns <tt>self</tt>.
38
38
  def remove(key)
39
- copy = @trie.remove(item)
40
- if !copy.equal?(@trie)
41
- self.class.new(copy)
39
+ trie = @trie.remove(key)
40
+ if !trie.equal?(@trie)
41
+ self.class.new(trie)
42
42
  else
43
43
  self
44
44
  end
45
45
  end
46
46
 
47
- # Calls <tt>block</tt> once for each item in the set, passing the item as the only parameter.
48
- # Returns <tt>self</tt>
49
47
  def each
50
48
  block_given? or return enum_for(__method__)
51
- @trie.each { |entry| yield entry.key }
49
+ @trie.each { |entry| yield(entry.key) }
52
50
  self
53
51
  end
54
52
 
55
- # Returns <tt>true</tt> if . <tt>eql?</tt> is synonymous with <tt>==</tt>
53
+ def map
54
+ block_given? or return enum_for(:each)
55
+ if empty?
56
+ self
57
+ else
58
+ self.class.new(@trie.reduce(Trie.new) { |trie, entry| trie.put(yield(entry.key), nil) })
59
+ end
60
+ end
61
+ alias_method :collect, :map
62
+
63
+ def reduce(memo)
64
+ block_given? or return memo
65
+ @trie.reduce(memo) { |memo, entry| yield(memo, entry.key) }
66
+ end
67
+ alias_method :inject, :reduce
68
+
69
+ def filter
70
+ block_given? or return enum_for(__method__)
71
+ trie = @trie.filter { |entry| yield(entry.key) }
72
+ if !trie.equal?(@trie)
73
+ self.class.new(trie)
74
+ else
75
+ self
76
+ end
77
+ end
78
+ alias_method :select, :filter
79
+
80
+ def reject
81
+ block_given? or return enum_for(__method__)
82
+ select { |item| !yield(item) }
83
+ end
84
+
85
+ def any?
86
+ if block_given?
87
+ each { |item| return true if yield(item) }
88
+ else
89
+ each { |item| return true if item }
90
+ end
91
+ false
92
+ end
93
+
94
+ def all?
95
+ if block_given?
96
+ each { |item| return false unless yield(item) }
97
+ else
98
+ each { |item| return false unless item }
99
+ end
100
+ true
101
+ end
102
+
103
+ def none?
104
+ if block_given?
105
+ each { |item| return false if yield(item) }
106
+ else
107
+ each { |item| return false if item }
108
+ end
109
+ true
110
+ end
111
+
56
112
  def eql?(other)
57
113
  other.is_a?(self.class) && @trie.eql?(other.instance_eval{@trie})
58
114
  end
59
- alias :== :eql?
115
+ alias_method :==, :eql?
60
116
 
61
- # Returns <tt>self</tt>
62
117
  def dup
63
118
  self
64
119
  end
65
- alias :clone :dup
120
+ alias_method :clone, :dup
66
121
 
67
122
  end
68
123
 
@@ -1,52 +1,51 @@
1
+ require 'hamster/list'
2
+
1
3
  module Hamster
2
4
 
5
+ def self.stack
6
+ Stack.new
7
+ end
8
+
3
9
  class Stack
4
10
 
5
- def initialize(list = List.new)
11
+ def initialize(list = Hamster.list)
6
12
  @list = list
7
13
  end
8
14
 
9
- # Returns <tt>true</tt> if the stack contains no items.
10
15
  def empty?
11
16
  @list.empty?
12
17
  end
13
18
 
14
- # Returns the number of items on the stack.
15
19
  def size
16
20
  @list.size
17
21
  end
18
22
 
19
- # Returns the item at the top of the stack.
20
23
  def top
21
- @list.car
24
+ @list.head
22
25
  end
23
26
 
24
- # Returns a copy of <tt>self</tt> with the given item as the new top
25
27
  def push(item)
26
28
  self.class.new(@list.cons(item))
27
29
  end
28
30
 
29
- # Returns a copy of <tt>self</tt> without the top item.
30
31
  def pop
31
- copy = @list.cdr
32
- if !copy.equal?(@list)
33
- self.class.new(copy)
32
+ list = @list.tail
33
+ if !list.equal?(@list)
34
+ self.class.new(list)
34
35
  else
35
36
  self
36
37
  end
37
38
  end
38
39
 
39
- # Returns <tt>true</tt> if . <tt>eql?</tt> is synonymous with <tt>==</tt>
40
40
  def eql?(other)
41
41
  other.is_a?(self.class) && @list.eql?(other.instance_eval{@list})
42
42
  end
43
- alias :== :eql?
43
+ alias_method :==, :eql?
44
44
 
45
- # Returns <tt>self</tt>
46
45
  def dup
47
46
  self
48
47
  end
49
- alias :clone :dup
48
+ alias_method :clone, :dup
50
49
 
51
50
  end
52
51
 
@@ -27,12 +27,21 @@ module Hamster
27
27
 
28
28
  # Calls <tt>block</tt> once for each entry in the trie, passing the key-value pair as parameters.
29
29
  def each
30
- @entries.each { |entry| yield entry if entry }
30
+ @entries.each { |entry| yield(entry) if entry }
31
31
  @children.each do |child|
32
- child.each { |entry| yield entry } if child
32
+ child.each { |entry| yield(entry) } if child
33
33
  end
34
34
  end
35
35
 
36
+ def reduce(memo)
37
+ each { |entry| memo = yield(memo, entry) }
38
+ memo
39
+ end
40
+
41
+ def filter
42
+ reduce(self) { |trie, entry| yield(entry) ? trie : trie.remove(entry.key) }
43
+ end
44
+
36
45
  # Returns a copy of <tt>self</tt> with the given value associated with the key.
37
46
  def put(key, value)
38
47
  index = index_for(key)
@@ -86,7 +95,7 @@ module Hamster
86
95
  end
87
96
  true
88
97
  end
89
- alias :== :eql?
98
+ alias_method :==, :eql?
90
99
 
91
100
  protected
92
101
 
@@ -120,7 +129,7 @@ module Hamster
120
129
 
121
130
  # Returns a replacement instance after removing the specified entry. If empty, returns <tt>nil</tt>
122
131
  def remove_at(index = @entries.index { |e| e })
123
- yield @entries[index] if block_given?
132
+ yield(@entries[index]) if block_given?
124
133
  if size > 1
125
134
  entries = @entries.dup
126
135
  child = @children[index]
@@ -1,5 +1,5 @@
1
1
  module Hamster
2
2
 
3
- VERSION = "0.1.8".freeze
3
+ VERSION = "0.1.11".freeze
4
4
 
5
5
  end
@@ -0,0 +1,53 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe Hamster::Hash do
4
+
5
+ describe "#all?" do
6
+
7
+ describe "when empty" do
8
+
9
+ before do
10
+ @hash = Hamster.hash
11
+ end
12
+
13
+ it "with a block returns true" do
14
+ @hash.all? {}.should be_true
15
+ end
16
+
17
+ it "with no block returns true" do
18
+ @hash.all?.should be_true
19
+ end
20
+
21
+ end
22
+
23
+ describe "when not empty" do
24
+
25
+ before do
26
+ @hash = Hamster.hash("A" => "aye", "B" => "bee", "C" => "see")
27
+ end
28
+
29
+ describe "with a block" do
30
+
31
+ it "returns true if the block always returns true" do
32
+ @hash.all? { |item| true }.should be_true
33
+ end
34
+
35
+ it "returns false if the block ever returns false" do
36
+ @hash.all? { |key, value| key == "D" || value == "dee" }.should be_false
37
+ end
38
+
39
+ end
40
+
41
+ describe "with no block" do
42
+
43
+ it "returns true" do
44
+ @hash.all?.should be_true
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,62 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe Hamster::Hash do
4
+
5
+ describe "#any?" do
6
+
7
+ describe "when empty" do
8
+
9
+ before do
10
+ @hash = Hamster.hash
11
+ end
12
+
13
+ it "with a block returns false" do
14
+ @hash.any? {}.should be_false
15
+ end
16
+
17
+ it "with no block returns false" do
18
+ @hash.any?.should be_false
19
+ end
20
+
21
+ end
22
+
23
+ describe "when not empty" do
24
+
25
+ before do
26
+ @hash = Hamster.hash("A" => "aye", "B" => "bee", "C" => "see", nil => "NIL")
27
+ end
28
+
29
+ describe "with a block" do
30
+
31
+ [
32
+ ["A", "aye"],
33
+ ["B", "bee"],
34
+ ["C", "see"],
35
+ [nil, "NIL"],
36
+ ].each do |pair|
37
+
38
+ it "returns true if the block ever returns true (#{pair.inspect})" do
39
+ @hash.any? { |key, value| key == pair.first && value == pair.last }.should be_true
40
+ end
41
+
42
+ it "returns false if the block always returns false" do
43
+ @hash.any? { |key, value| key == "D" && value == "dee" }.should be_false
44
+ end
45
+
46
+ end
47
+
48
+ end
49
+
50
+ describe "with no block" do
51
+
52
+ it "returns true" do
53
+ @hash.any?.should be_true
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -2,14 +2,30 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
2
 
3
3
  describe Hamster::Hash do
4
4
 
5
- describe ".[]" do
5
+ describe ".hash" do
6
+
7
+ describe "with nothing" do
8
+
9
+ before do
10
+ @hash = Hamster.hash
11
+ end
12
+
13
+ it "returns an empty hash" do
14
+ @hash.should be_empty
15
+ end
6
16
 
7
- before do
8
- @hash = Hamster::Hash["A" => "aye", "B" => "bee", "C" => "see"]
9
17
  end
10
18
 
11
- it "is equivalent to repeatedly using #put" do
12
- @hash.should eql(Hamster::Hash.new.put("A", "aye").put("B", "bee").put("C", "see"))
19
+ describe "with an implicit hash" do
20
+
21
+ before do
22
+ @hash = Hamster.hash("A" => "aye", "B" => "bee", "C" => "see")
23
+ end
24
+
25
+ it "is equivalent to repeatedly using #put" do
26
+ @hash.should == Hamster.hash.put("A", "aye").put("B", "bee").put("C", "see")
27
+ end
28
+
13
29
  end
14
30
 
15
31
  end
@@ -3,21 +3,17 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
3
3
  describe Hamster::Hash do
4
4
 
5
5
  before do
6
- @hash = Hamster::Hash.new
6
+ @hash = Hamster.hash("A" => "aye", "B" => "bee", "C" => "see")
7
7
  end
8
8
 
9
- describe "#dup" do
9
+ [:dup, :clone].each do |method|
10
10
 
11
- it "returns self" do
12
- @hash.dup.should equal(@hash)
13
- end
14
-
15
- end
11
+ describe "##{method}" do
16
12
 
17
- describe "#clone" do
13
+ it "returns self" do
14
+ @hash.send(method).should equal(@hash)
15
+ end
18
16
 
19
- it "returns self" do
20
- @hash.clone.should equal(@hash)
21
17
  end
22
18
 
23
19
  end
@@ -5,11 +5,7 @@ describe Hamster::Hash do
5
5
  describe "#each" do
6
6
 
7
7
  before do
8
- @hash = Hamster::Hash.new
9
- @expected_pairs = { "A" => "aye", "B" => "bee", "C" => "sea" }
10
- @expected_pairs.each do |key, value|
11
- @hash = @hash.put(key, value)
12
- end
8
+ @hash = Hamster.hash("A" => "aye", "B" => "bee", "C" => "see")
13
9
  end
14
10
 
15
11
  describe "with a block (internal iteration)" do
@@ -18,26 +14,18 @@ describe Hamster::Hash do
18
14
  @hash.each {}.should equal(@hash)
19
15
  end
20
16
 
21
- it "yields all key value pairs" do
17
+ it "yields all key/value pairs" do
22
18
  actual_pairs = {}
23
- @hash.each do |key, value|
24
- actual_pairs[key] = value
25
- end
26
- actual_pairs.should == @expected_pairs
19
+ @hash.each { |key, value| actual_pairs[key] = value }
20
+ actual_pairs.should == {"A" => "aye", "B" => "bee", "C" => "see"}
27
21
  end
28
22
 
29
23
  end
30
24
 
31
25
  describe "with no block (external iteration)" do
32
26
 
33
- it "returns an enumerator over all key value pairs" do
34
- actual_pairs = {}
35
- enum = @hash.each
36
- loop do
37
- key, value = enum.next
38
- actual_pairs[key] = value
39
- end
40
- actual_pairs.should == @expected_pairs
27
+ it "returns an enumerator over all key/value pairs" do
28
+ Hash[*@hash.each.to_a.flatten].should == {"A" => "aye", "B" => "bee", "C" => "see"}
41
29
  end
42
30
 
43
31
  end