eymiha_util 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/gem_package.rb ADDED
@@ -0,0 +1,31 @@
1
+ class GemPackage
2
+
3
+ attr_reader :name, :version, :files
4
+
5
+ def initialize
6
+ @name = 'eymiha_util'
7
+ @version = '0.1.0'
8
+ @files = FileList[
9
+ '*.rb',
10
+ 'lib/*',
11
+ 'test/*',
12
+ 'html/**/*'
13
+ ]
14
+ end
15
+
16
+ def fill_spec(s)
17
+ s.name = name
18
+ s.version = version
19
+ s.summary = "Eymiha general utility classes and methods"
20
+ s.files = files.to_a
21
+ s.require_path = 'lib'
22
+ s.autorequire = name
23
+ s.has_rdoc = true
24
+ s.rdoc_options << "--all"
25
+ s.author = "Dave Anderson"
26
+ s.email = "dave@eymiha.com"
27
+ s.homepage = "http://www.eymiha.com"
28
+ s.rubyforge_project = "cori"
29
+ end
30
+
31
+ end
data/lib/envelope.rb ADDED
@@ -0,0 +1,126 @@
1
+ # Envelopes are useful when finding the boundaries of a set of instances.
2
+ # They expand as new values are added, and keep track of how many items
3
+ # have been added to construct them.
4
+
5
+ # An EnvelopeException is generally raised when adding an object to an
6
+ # instance that it does not know how to interpret, or when requesting
7
+ # bounderies before any values have been added.
8
+ class EnvelopeException < Exception
9
+ end
10
+
11
+
12
+ # A BaseEnvelope provides a means to keep and provide a count of objects that
13
+ # have been added to an envelope.
14
+ class BaseEnvelope
15
+
16
+ # Called when requesting envelope bounderies before any values have been
17
+ # added.
18
+ def raise_no_envelope
19
+ raise EnvelopeException, "No values are enveloped"
20
+ end
21
+
22
+ # Called when the value cannot be compared with the the boundaries of the
23
+ # instance.
24
+ def raise_no_compare(value=nil)
25
+ value = "'#{value}' " unless value == nil
26
+ raise EnvelopeException,
27
+ "The value #{value}cannot be compared with the envelope"
28
+ end
29
+
30
+ # count of added values reader.
31
+ attr_reader :count
32
+
33
+ # Returns a new instance with no values added.
34
+ def initialize
35
+ @count = 0
36
+ end
37
+
38
+ end
39
+
40
+
41
+ # An Envelope is the minimum envelope that will completely contain a set of
42
+ # values. Values may be added to an instance, and it can return the number
43
+ # of values considered so far and its high and low boundaries.
44
+ #
45
+ # Envelopes can be used to generate ranges, however the result may be of
46
+ # limited utility if the types of values being enveloped don't play nicely
47
+ # with ranges.
48
+ class Envelope < BaseEnvelope
49
+
50
+ # Creates and returns an instance. If an argument is given, it is passed to
51
+ # the set method to initialize the new instance.
52
+ def initialize(value=nil)
53
+ super()
54
+ add(value) unless value == nil
55
+ end
56
+
57
+ # Returns a string representation of the instance.
58
+ def to_s
59
+ values = (count > 0)? "\n high #{high}\n low #{low}" : ""
60
+ "Envelope: count #{count}#{values}"
61
+ end
62
+
63
+ # Adds a value to the instance. When
64
+ # * x is an Envelope, it is coalesced into the instance.
65
+ # * otherwise, the envelope is extened to contain the value.
66
+ # * if the value cannot be compared to the boundaries, an EnvelopeException is raised.
67
+ # The modified instance is returned.
68
+ def add(value)
69
+ if value.kind_of? Envelope
70
+ count = value.count
71
+ if (count > 0)
72
+ add value.high
73
+ add value.low
74
+ @count += (count-2)
75
+ end
76
+ self
77
+ else
78
+ begin
79
+ @high = value if (@count == 0 || value > @high)
80
+ @low = value if (@count == 0 || value < @low)
81
+ @count += 1
82
+ self
83
+ rescue
84
+ raise_no_compare value
85
+ end
86
+ end
87
+ end
88
+
89
+ # Returns the high boundary of the instance.
90
+ # * if there are no boundaries, an EnvelopeException is raised.
91
+ def high
92
+ raise_no_envelope if @count == 0
93
+ @high
94
+ end
95
+
96
+ # Returns the low boundary of the instance.
97
+ # * if there are no boundaries, an EnvelopeException is raised.
98
+ def low
99
+ raise_no_envelope if @count == 0
100
+ @low
101
+ end
102
+
103
+ # Returns true if the instance completely contains the argument:
104
+ # * value is an Envelope, its high and low are contained.
105
+ # * otherwise, the value is contained.
106
+ # * if the value cannot be compared to the boundaries, an EnvelopeException is raised.
107
+ def contains?(value)
108
+ if value.kind_of? Envelope
109
+ (contains? value.high) && (contains? value.low)
110
+ else
111
+ begin
112
+ (value >= low) && (value <= high)
113
+ rescue
114
+ raise_no_compare value
115
+ end
116
+ end
117
+ end
118
+
119
+ alias === contains?
120
+
121
+ # Returns an inclusive range from the low to high boundaries
122
+ def to_range
123
+ low..high
124
+ end
125
+
126
+ end
data/lib/histogram.rb ADDED
@@ -0,0 +1,109 @@
1
+ # Histograms have lots of uses - whenever you need to keep track of the
2
+ # occurences of items and how many times they've occured, a histogram is
3
+ # just what's needed.
4
+
5
+
6
+ # An exception thrown when adding Arrays to Histograms that cannot be
7
+ # meaningfully interpretted.
8
+ class HistogramException < Exception
9
+ end
10
+
11
+
12
+ # A Histogram is a hash whose values are counts of the occurences of the keys.
13
+ class Histogram < Hash
14
+
15
+ # Creates and returns an instance. If arguments are given, they are passed to
16
+ # the add method to initialize the new instance.
17
+ def initialize(key=nil,number=1)
18
+ super()
19
+ add(key,number) unless key == nil
20
+ end
21
+
22
+ # Returns the number of occurences of the given key. If an array of keys
23
+ # is given, the sum of the number of occurences of those keys is returned.
24
+ def count(check_keys = keys)
25
+ check_keys = [check_keys] if ! check_keys.kind_of? Array
26
+ count = 0
27
+ check_keys.each { |key| count += self[key] if has_key? key }
28
+ count
29
+ end
30
+
31
+ # Adds the key to the instance if it doesn't already exist, and adds the
32
+ # specified count to it value. If the key is
33
+ # * an Array, each member of the array is added. if the member itself is an Array, then if that array has one member, the member is added as a key; if two members, the member is added as a key and a count; otherwise, a HistogramException is thrown.
34
+ # * another histogram, the keys and counts in the key are added to the instance.
35
+ def add(key,count=1)
36
+ if key.kind_of? Array
37
+ key.each { |member|
38
+ if member.kind_of? Array
39
+ if member.size == 1
40
+ add(member[0])
41
+ elsif (member.size == 2) && (member[1].kind_of? Fixnum)
42
+ add(member[0],member[1])
43
+ else
44
+ raise HistogramException, "add cannot interpret Array to add"
45
+ end
46
+ else
47
+ add member
48
+ end
49
+ }
50
+ elsif key.kind_of? Histogram
51
+ key.each_pair { |k,v| add(k,v) }
52
+ else
53
+ self[key] = ((value = self[key]) == nil) ? count : value+count
54
+ end
55
+ self
56
+ end
57
+
58
+ # Returns the number of keys in the instance.
59
+ def key_count
60
+ keys.size
61
+ end
62
+
63
+ # Returns a new Histogram containing the elements with occurences greater
64
+ # than or equal to the given count.
65
+ def >=(count)
66
+ result = Histogram.new
67
+ each_pair { |k,v| result.add(k,v) if v >= count }
68
+ result
69
+ end
70
+
71
+ # Returns a new Histogram containing the elements with occurences greater
72
+ # than the given count.
73
+ def >(count)
74
+ result = Histogram.new
75
+ each_pair { |k,v| result.add(k,v) if v > count }
76
+ result
77
+ end
78
+
79
+ # Returns a new Histogram containing the elements with occurences less than
80
+ # or equal to the given count.
81
+ def <=(count)
82
+ result = Histogram.new
83
+ each_pair { |k,v| result.add(k,v) if v <= count }
84
+ result
85
+ end
86
+
87
+ # Returns a new Histogram containing the elements with occurences less than
88
+ # the given count.
89
+ def <(count)
90
+ result = Histogram.new
91
+ each_pair { |k,v| result.add(k,v) if v < count }
92
+ result
93
+ end
94
+
95
+ # If count is a number, a new Histogram containing the elements with
96
+ # occurences equal to the given countis returned. If the count is a
97
+ # histogram, true is returned if the instance contains the same keys and
98
+ # values; false otherwise.
99
+ def ==(count)
100
+ if count.kind_of? Numeric
101
+ result = Histogram.new
102
+ each_pair { |k,v| result.add(k,v) if v >= count }
103
+ result
104
+ else
105
+ super
106
+ end
107
+ end
108
+
109
+ end
data/rakefile.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'gem_package'
2
+ require 'gem_raker'
@@ -0,0 +1,99 @@
1
+ require 'test/unit'
2
+
3
+ require 'envelope'
4
+
5
+ class TC_Envelope < Test::Unit::TestCase
6
+
7
+ def test_count
8
+ base = BaseEnvelope.new
9
+ assert(base.count == 0)
10
+ end
11
+
12
+ def test_empty
13
+ envelope = Envelope.new
14
+ assert(envelope.count == 0)
15
+ assert_raise(EnvelopeException) { envelope.high }
16
+ assert_raise(EnvelopeException) { envelope.low }
17
+ end
18
+
19
+ def test_add_numbers
20
+ envelope = Envelope.new
21
+ envelope.add 1
22
+ assert(envelope.high == 1)
23
+ assert(envelope.low == 1)
24
+ assert(envelope.count == 1)
25
+ envelope.add 2
26
+ envelope.add(-3)
27
+ envelope.add 4.5
28
+ assert(envelope.high == 4.5)
29
+ assert(envelope.low == -3)
30
+ assert(envelope.count == 4)
31
+ envelope.add envelope
32
+ assert(envelope.high == 4.5)
33
+ assert(envelope.low == -3)
34
+ assert(envelope.count == 8)
35
+ assert_raise(EnvelopeException) { envelope.add "bad" }
36
+ assert(envelope.count == 8)
37
+ envelope = Envelope.new
38
+ end
39
+
40
+ def test_add_letters
41
+ envelope = Envelope.new('c').add('m').add('e')
42
+ assert(envelope.low == 'c')
43
+ assert(envelope.high == 'm')
44
+ assert(envelope.contains?('d'))
45
+ assert(!(envelope.contains?('a')))
46
+ assert(!(envelope.contains?('r')))
47
+ assert(envelope.contains?(envelope))
48
+ assert(envelope.contains?(Envelope.new('e').add('h')))
49
+ assert(!(envelope.contains?(Envelope.new('a').add('h'))))
50
+ assert(!(envelope.contains?(Envelope.new('e').add('s'))))
51
+ assert(envelope === 'd')
52
+ assert(!(envelope === 'a'))
53
+ assert(!(envelope === 'r'))
54
+ assert(envelope === envelope)
55
+ assert(envelope === Envelope.new('e').add('h'))
56
+ assert(!(envelope === Envelope.new('a').add('h')))
57
+ assert(!(envelope === Envelope.new('e').add('s')))
58
+ range = envelope.to_range
59
+ assert(range === 'd')
60
+ assert(!(range === 'a'))
61
+ assert(!(range === 'r'))
62
+ end
63
+
64
+ def test_add_strings
65
+ envelope = Envelope.new("carl").add("marie").add("edward")
66
+ assert(envelope.low == "carl")
67
+ assert(envelope.high == "marie")
68
+ assert(envelope.contains?("dennis"))
69
+ assert(!(envelope.contains?("aaron")))
70
+ assert(!(envelope.contains?("ralph")))
71
+ assert(envelope.contains?(envelope))
72
+ assert(envelope.contains?(Envelope.new("edward").add("harry")))
73
+ assert(!(envelope.contains?(Envelope.new("aaron").add("harry"))))
74
+ assert(!(envelope.contains?(Envelope.new("edward").add("sally"))))
75
+ range = envelope.to_range
76
+ assert(range === "dennis")
77
+ assert(!(range === "aaron"))
78
+ assert(!(range === "ralph"))
79
+ end
80
+
81
+ def test_contains
82
+ envelope = Envelope.new(0.75).add(3)
83
+ assert(envelope.contains?(1))
84
+ assert(envelope.contains?(3))
85
+ assert(envelope.contains?(2))
86
+ assert(!(envelope.contains?(0)))
87
+ assert(!(envelope.contains?(4)))
88
+ assert(envelope.contains?(envelope))
89
+ assert(envelope.contains?(Envelope.new(1.5).add(2.5)))
90
+ assert(!(envelope.contains?(Envelope.new(0.5).add(2.5))))
91
+ assert(!(envelope.contains?(Envelope.new(1.5).add(3.5))))
92
+ assert_raise(EnvelopeException) { envelope.add "bad" }
93
+ range = envelope.to_range
94
+ assert(range === 2.5)
95
+ assert(!(range === 0))
96
+ assert(!(range === 4))
97
+ end
98
+
99
+ end
@@ -0,0 +1,52 @@
1
+ require 'test/unit'
2
+
3
+ require 'histogram'
4
+
5
+ class TC_Histogram < Test::Unit::TestCase
6
+
7
+ def test_empty
8
+ histogram = Histogram.new
9
+ assert(histogram.count == 0)
10
+ assert(histogram.keys == [])
11
+ end
12
+
13
+ def test_loading
14
+ h1 = Histogram.new "hello"
15
+ h1.add "goodbye",2
16
+ assert(h1.count == 3)
17
+ assert(h1.count("hello") == 1)
18
+ assert(h1.count("goodbye") == 2)
19
+ assert(h1.count("everyone") == 0)
20
+ assert(h1.key_count == 2)
21
+ h2 = Histogram.new [["hello", 4], "goodbye", "everyone"]
22
+ assert(h2.count == 6)
23
+ assert(h2.count("hello") == 4)
24
+ assert(h2.count("goodbye") == 1)
25
+ assert(h2.count("everyone") == 1)
26
+ assert(h2.key_count == 3)
27
+ h1.add h2
28
+ assert(h1.count == 9)
29
+ assert(h1.count("hello") == 5)
30
+ assert(h1.count("goodbye") == 3)
31
+ assert(h1.count("everyone") == 1)
32
+ assert(h1.key_count == 3)
33
+ assert(h1.has_key?("hello"))
34
+ assert(h1.has_key?("goodbye"))
35
+ assert(h1.has_key?("everyone"))
36
+ assert(!(h1.has_key? "help"))
37
+ end
38
+
39
+ def test_subset
40
+ h = Histogram.new [["hello", 4], ["goodbye", 3], "everyone"]
41
+ h1 = Histogram.new [["hello", 4], ["goodbye", 3]]
42
+ assert((h >= 3) == h1)
43
+ h2 = Histogram.new [["hello", 4]]
44
+ assert((h > 3) == h2)
45
+ assert((h == 4) == h2)
46
+ h3 = Histogram.new [["goodbye", 3], "everyone"]
47
+ assert((h <= 3) == h3)
48
+ h4 = Histogram.new "everyone"
49
+ assert((h < 3) == h4)
50
+ end
51
+
52
+ end
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.0
3
+ specification_version: 1
4
+ name: eymiha_util
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.0
7
+ date: 2007-05-10 00:00:00 -04:00
8
+ summary: Eymiha general utility classes and methods
9
+ require_paths:
10
+ - lib
11
+ email: dave@eymiha.com
12
+ homepage: http://www.eymiha.com
13
+ rubyforge_project: cori
14
+ description:
15
+ autorequire: eymiha_util
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Dave Anderson
31
+ files:
32
+ - gem_package.rb
33
+ - rakefile.rb
34
+ - lib/envelope.rb
35
+ - lib/histogram.rb
36
+ - test/tc_envelope.rb
37
+ - test/tc_histogram.rb
38
+ test_files: []
39
+
40
+ rdoc_options:
41
+ - --all
42
+ extra_rdoc_files: []
43
+
44
+ executables: []
45
+
46
+ extensions: []
47
+
48
+ requirements: []
49
+
50
+ dependencies: []
51
+