eymiha_util 0.1.0
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.
- 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
|
+
|