hamster 0.1.8 → 0.1.11

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