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 +31 -0
- data/lib/envelope.rb +126 -0
- data/lib/histogram.rb +109 -0
- data/rakefile.rb +2 -0
- data/test/tc_envelope.rb +99 -0
- data/test/tc_histogram.rb +52 -0
- metadata +51 -0
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
data/test/tc_envelope.rb
ADDED
@@ -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
|
+
|