sumhash 0.0.2
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/lib/sumhash/hash.rb +62 -0
- data/lib/sumhash/ostruct.rb +69 -0
- data/lib/sumhash/version.rb +4 -0
- data/lib/sumhash.rb +6 -0
- data/sumhash.gemspec +36 -0
- data/test/suite.rb +5 -0
- data/test/test_division.rb +14 -0
- data/test/test_multiplication.rb +14 -0
- data/test/test_plus.rb +61 -0
- data/test/test_unary_minus.rb +11 -0
- metadata +61 -0
data/lib/sumhash/hash.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
class Hash
|
2
|
+
NUMBER_CLASSES = [Integer, Fixnum, Bignum, Float, Rational]
|
3
|
+
SUPPORTED_CLASSES = NUMBER_CLASSES + [Hash, OpenStruct]
|
4
|
+
|
5
|
+
# Plus
|
6
|
+
def +(hash)
|
7
|
+
(self.keys + hash.keys).inject({}) do |sum, k|
|
8
|
+
sum[k] = sum(self[k], hash[k])
|
9
|
+
sum
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Minus
|
14
|
+
def -(hash)
|
15
|
+
(self.keys + hash.keys).inject({}) do |sum, k|
|
16
|
+
sum[k] = sum(self[k], hash[k], :-)
|
17
|
+
sum
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Unary minus
|
22
|
+
def -@
|
23
|
+
self.inject({}) do |res, (k, v)|
|
24
|
+
res[k] = SUPPORTED_CLASSES.include?(v.class) ? -v : v
|
25
|
+
res
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Unary plus
|
30
|
+
def +@
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
# Division
|
35
|
+
def /(num)
|
36
|
+
raise TypeError, "#{num.class} can't be coerced into Float" unless NUMBER_CLASSES.include? num.class
|
37
|
+
self.inject({}) do |res, (k, v)|
|
38
|
+
res[k] = SUPPORTED_CLASSES.include?(v.class) ? v/num : v
|
39
|
+
res
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Multiplication
|
44
|
+
def *(num)
|
45
|
+
raise TypeError, "#{num.class} can't be coerced into Float" unless NUMBER_CLASSES.include? num.class
|
46
|
+
self.inject({}) do |res, (k, v)|
|
47
|
+
res[k] = SUPPORTED_CLASSES.include?(v.class) ? v*num : v
|
48
|
+
res
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
# Can sum Objects if: 1) both numbers; 2) both Hashes; 3) both OpenStructs.
|
54
|
+
def sum(n, m, sign=:+)
|
55
|
+
if (NUMBER_CLASSES.include?(n.class) && NUMBER_CLASSES.include?(m.class)) || (n.class == Hash && m.class == Hash) || (n.class == OpenStruct && m.class == OpenStruct)
|
56
|
+
n.send(sign, m)
|
57
|
+
else
|
58
|
+
n || m
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class OpenStruct
|
2
|
+
NUMBER_CLASSES = [Integer, Fixnum, Bignum, Float, Rational]
|
3
|
+
SUPPORTED_CLASSES = NUMBER_CLASSES + [Hash, OpenStruct]
|
4
|
+
|
5
|
+
def _fields
|
6
|
+
@table.keys.map{|k| k.to_sym }
|
7
|
+
end
|
8
|
+
|
9
|
+
# Plus
|
10
|
+
def +(os)
|
11
|
+
(self._fields + os._fields).inject(OpenStruct.new()) do |sum, f|
|
12
|
+
sum.send(:"#{f}=", sum(self.send(f), os.send(f)))
|
13
|
+
sum
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Minus
|
18
|
+
def -(os)
|
19
|
+
(self._fields + os._fields).inject(OpenStruct.new()) do |sum, f|
|
20
|
+
sum.send(:"#{f}=", sum(self.send(f), os.send(f), :-))
|
21
|
+
sum
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Unary minus
|
26
|
+
def -@
|
27
|
+
self._fields.inject(OpenStruct.new()) do |res, f|
|
28
|
+
v = self.send(f)
|
29
|
+
res.send(:"#{f}=", SUPPORTED_CLASSES.include?(v.class) ? -v : v)
|
30
|
+
res
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Unary plus
|
35
|
+
def +@
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
# Division
|
40
|
+
def /(num)
|
41
|
+
raise TypeError, "#{num.class} can't be coerced into Float" unless NUMBER_CLASSES.include? num.class
|
42
|
+
self._fields.inject(OpenStruct.new()) do |res, f|
|
43
|
+
v = self.send(f)
|
44
|
+
res.send(:"#{f}=", SUPPORTED_CLASSES.include?(v.class) ? v/num.to_f : v)
|
45
|
+
res
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Multiplication
|
50
|
+
def *(num)
|
51
|
+
raise TypeError, "#{num.class} can't be coerced into Float" unless NUMBER_CLASSES.include? num.class
|
52
|
+
self._fields.inject(OpenStruct.new()) do |res, f|
|
53
|
+
v = self.send(f)
|
54
|
+
res.send(:"#{f}=", SUPPORTED_CLASSES.include?(v.class) && !v.kind_of?(String) ? v*num.to_f : v)
|
55
|
+
res
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
# Can sum Objects if: 1) both numbers; 2) both Hashes; 3) both OpenStructs.
|
61
|
+
def sum(n, m, sign=:+)
|
62
|
+
if (NUMBER_CLASSES.include?(n.class) && NUMBER_CLASSES.include?(m.class)) || (n.class == Hash && m.class == Hash) || (n.class == OpenStruct && m.class == OpenStruct)
|
63
|
+
n.send(sign, m)
|
64
|
+
else
|
65
|
+
n || m
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
data/lib/sumhash.rb
ADDED
data/sumhash.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "sumhash/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "sumhash"
|
7
|
+
s.version = Sumhash::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Alex Avoyants"]
|
10
|
+
s.email = ["shhavel@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/shhavel/sumhash"
|
12
|
+
s.summary = %q{Sum operations for Hash & OpenStruct classes}
|
13
|
+
s.description = %q{This gem provides summing operations to Hashes and OpenStructs. Works with nested structures. If you need a feature added, send me a message on Github!}
|
14
|
+
s.rubyforge_project = "sumhash"
|
15
|
+
s.files = [
|
16
|
+
"sumhash.gemspec",
|
17
|
+
"lib/sumhash.rb",
|
18
|
+
"lib/sumhash/hash.rb",
|
19
|
+
"lib/sumhash/ostruct.rb",
|
20
|
+
"lib/sumhash/version.rb",
|
21
|
+
"test/suite.rb",
|
22
|
+
"test/test_division.rb",
|
23
|
+
"test/test_multiplication.rb",
|
24
|
+
"test/test_plus.rb",
|
25
|
+
"test/test_unary_minus.rb",
|
26
|
+
]
|
27
|
+
s.test_files = [
|
28
|
+
"test/suite.rb",
|
29
|
+
"test/test_division.rb",
|
30
|
+
"test/test_multiplication.rb",
|
31
|
+
"test/test_plus.rb",
|
32
|
+
"test/test_unary_minus.rb",
|
33
|
+
]
|
34
|
+
s.require_paths = ["lib"]
|
35
|
+
end
|
36
|
+
|
data/test/suite.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "ostruct"
|
2
|
+
require "#{File.expand_path('../')}/lib/sumhash.rb"
|
3
|
+
require "test/unit"
|
4
|
+
|
5
|
+
class TestDivision < Test::Unit::TestCase
|
6
|
+
def test_division
|
7
|
+
assert_equal( { n: 2.1, m: 3.2, os: OpenStruct.new(x: 1.1, y: 2.1), s: 'str' },
|
8
|
+
{ n: 4.2, m: 6.4, os: OpenStruct.new(x: 2.2, y: 4.2), s: 'str' } / 2)
|
9
|
+
|
10
|
+
assert_raise(TypeError) { { n: 10, m: 14 }/"2" }
|
11
|
+
assert_raise(TypeError) { OpenStruct.new({ n: 10, m: 14 })/"2" }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "ostruct"
|
2
|
+
require "#{File.expand_path('../')}/lib/sumhash.rb"
|
3
|
+
require "test/unit"
|
4
|
+
|
5
|
+
class TestMultiplication < Test::Unit::TestCase
|
6
|
+
def test_multiplication
|
7
|
+
assert_equal( { n: 4.2, m: 6.4, os: OpenStruct.new(x: 2.2, y: 4.2), s: 'str' },
|
8
|
+
{ n: 2.1, m: 3.2, os: OpenStruct.new(x: 1.1, y: 2.1), s: 'str' } * 2)
|
9
|
+
|
10
|
+
assert_raise(TypeError) { { n: 5, m: 7 } * "2" }
|
11
|
+
assert_raise(TypeError) { OpenStruct.new({ n: 5, m: 7 }) * "2" }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
data/test/test_plus.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require "ostruct"
|
2
|
+
require "#{File.expand_path('../')}/lib/sumhash.rb"
|
3
|
+
require "test/unit"
|
4
|
+
|
5
|
+
class TestPlus < Test::Unit::TestCase
|
6
|
+
def test_hashes
|
7
|
+
h1 = { n: 1.0, m: 2.3, s: 'beg' }
|
8
|
+
h2 = { n: 3.2 }
|
9
|
+
h3 = { m: 1.0, s: 'end' }
|
10
|
+
|
11
|
+
sum = h1 + h2 + h3
|
12
|
+
|
13
|
+
assert_equal({ n: 4.2, m: 3.3, s: "beg" }, sum)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_openstructs
|
17
|
+
os1 = OpenStruct.new(n: 1.0, m: 2.3, s: 'beg')
|
18
|
+
os2 = OpenStruct.new(n: 3.2)
|
19
|
+
os3 = OpenStruct.new(m: 1.0, s: 'end')
|
20
|
+
|
21
|
+
sum = os1 + os2 + os3
|
22
|
+
|
23
|
+
assert_equal OpenStruct.new(n: 4.2, m: 3.3, s: "beg"), sum
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_nested_hashes
|
27
|
+
h1 = { n: 1.0, m: 2.3, h: { x: 1.0, y: 4.2 } }
|
28
|
+
h2 = { n: 3.2 }
|
29
|
+
h3 = { m: 1.0, h: { x: 1.2 } }
|
30
|
+
|
31
|
+
sum = h1 + h2 + h3
|
32
|
+
|
33
|
+
assert_equal({ n: 4.2, m: 3.3, h: { x: 2.2, y: 4.2 } }, sum)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_nested_openstructs
|
37
|
+
h1 = { n: 1.0, m: 2.3, os: OpenStruct.new(x: 1.0, y: 4.2) }
|
38
|
+
h2 = { n: 3.2 }
|
39
|
+
h3 = { m: 1.0, os: OpenStruct.new(x: 1.2) }
|
40
|
+
|
41
|
+
sum = h1 + h2 + h3
|
42
|
+
|
43
|
+
assert_equal({ n: 4.2, m: 3.3, os: OpenStruct.new(x: 2.2, y: 4.2) }, sum)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_unary_minus
|
47
|
+
assert_equal( { n: -4.2, m: -3.3, os: OpenStruct.new(x: -2.2, y: 4.2), s: 'str' },
|
48
|
+
-{ n: 4.2, m: 3.3, os: OpenStruct.new(x: 2.2, y: -4.2), s: 'str' })
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_division
|
52
|
+
assert_equal( { n: 2.1, m: 3.2, os: OpenStruct.new(x: 1.1, y: 2.1), s: 'str' },
|
53
|
+
{ n: 4.2, m: 6.4, os: OpenStruct.new(x: 2.2, y: 4.2), s: 'str' } / 2)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_multiplication
|
57
|
+
assert_equal( { n: 4.2, m: 6.4, os: OpenStruct.new(x: 2.2, y: 4.2), s: 'str' },
|
58
|
+
{ n: 2.1, m: 3.2, os: OpenStruct.new(x: 1.1, y: 2.1), s: 'str' } * 2)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "ostruct"
|
2
|
+
require "#{File.expand_path('../')}/lib/sumhash.rb"
|
3
|
+
require "test/unit"
|
4
|
+
|
5
|
+
class TestUnaryMinus < Test::Unit::TestCase
|
6
|
+
def test_unary_minus
|
7
|
+
assert_equal( { n: -4.2, m: -3.3, os: OpenStruct.new(x: -2.2, y: 4.2), s: 'str' },
|
8
|
+
-{ n: 4.2, m: 3.3, os: OpenStruct.new(x: 2.2, y: -4.2), s: 'str' })
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sumhash
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Alex Avoyants
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-23 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: This gem provides summing operations to Hashes and OpenStructs. Works
|
15
|
+
with nested structures. If you need a feature added, send me a message on Github!
|
16
|
+
email:
|
17
|
+
- shhavel@gmail.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- sumhash.gemspec
|
23
|
+
- lib/sumhash.rb
|
24
|
+
- lib/sumhash/hash.rb
|
25
|
+
- lib/sumhash/ostruct.rb
|
26
|
+
- lib/sumhash/version.rb
|
27
|
+
- test/suite.rb
|
28
|
+
- test/test_division.rb
|
29
|
+
- test/test_multiplication.rb
|
30
|
+
- test/test_plus.rb
|
31
|
+
- test/test_unary_minus.rb
|
32
|
+
homepage: https://github.com/shhavel/sumhash
|
33
|
+
licenses: []
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
requirements: []
|
51
|
+
rubyforge_project: sumhash
|
52
|
+
rubygems_version: 1.8.24
|
53
|
+
signing_key:
|
54
|
+
specification_version: 3
|
55
|
+
summary: Sum operations for Hash & OpenStruct classes
|
56
|
+
test_files:
|
57
|
+
- test/suite.rb
|
58
|
+
- test/test_division.rb
|
59
|
+
- test/test_multiplication.rb
|
60
|
+
- test/test_plus.rb
|
61
|
+
- test/test_unary_minus.rb
|