sumhash 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+
@@ -0,0 +1,4 @@
1
+ module Sumhash
2
+ VERSION = "0.0.2"
3
+ end
4
+
data/lib/sumhash.rb ADDED
@@ -0,0 +1,6 @@
1
+ $:.unshift File.dirname(__FILE__) # for use/testing when no gem is installed
2
+
3
+ require 'ostruct'
4
+ require 'sumhash/hash'
5
+ require 'sumhash/ostruct'
6
+
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,5 @@
1
+ tests = Dir["#{File.dirname(__FILE__)}/test_*.rb"]
2
+ tests.each do |file|
3
+ require file
4
+ end
5
+
@@ -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