enzymator 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -6
  3. data/LICENSE +21 -0
  4. data/README.md +4 -4
  5. data/Rakefile +1 -1
  6. data/enzymator.gemspec +8 -2
  7. data/lib/enzymator.rb +28 -2
  8. data/lib/enzymator/aggregations/average.rb +30 -0
  9. data/lib/enzymator/aggregations/base.rb +15 -0
  10. data/lib/enzymator/aggregations/count.rb +18 -0
  11. data/lib/enzymator/aggregations/mapreduce.rb +31 -0
  12. data/lib/enzymator/aggregations/merge_hashes.rb +14 -0
  13. data/lib/enzymator/aggregations/sum.rb +14 -0
  14. data/lib/enzymator/core_ext/categorizer.rb +23 -0
  15. data/lib/enzymator/core_ext/monoids.rb +76 -0
  16. data/lib/enzymator/transformations/base.rb +39 -0
  17. data/lib/enzymator/transformations/config.rb +22 -0
  18. data/lib/enzymator/transformations/foldable/reduction.rb +22 -0
  19. data/lib/enzymator/transformations/functor/mapping.rb +19 -0
  20. data/lib/enzymator/transformations/monad/join.rb +15 -0
  21. data/lib/enzymator/transformations/object/application.rb +15 -0
  22. data/lib/enzymator/transformations/object/pipelining.rb +19 -0
  23. data/lib/enzymator/transformers/base.rb +11 -0
  24. data/lib/enzymator/transformers/foldable/simple_reducer.rb +13 -0
  25. data/lib/enzymator/transformers/functor/simple_mapper.rb +13 -0
  26. data/lib/enzymator/transformers/monad/simple_joiner.rb +13 -0
  27. data/lib/enzymator/transformers/object/simple_applicator.rb +13 -0
  28. data/lib/enzymator/transformers/object/simple_pipeliner.rb +13 -0
  29. data/lib/enzymator/types/list/foldable/enumerable.rb +33 -0
  30. data/lib/enzymator/types/list/functor/enumerable.rb +13 -0
  31. data/lib/enzymator/types/list/monad/array.rb +17 -0
  32. data/lib/enzymator/version.rb +2 -3
  33. data/test/aggregations/test_average.rb +15 -0
  34. data/test/aggregations/test_count.rb +15 -0
  35. data/test/aggregations/test_merge_hashes.rb +15 -0
  36. data/test/aggregations/test_sum.rb +15 -0
  37. data/test/{test_aggregation.rb → test_introduction.rb} +12 -17
  38. data/test/transformations/test_application.rb +17 -0
  39. data/test/transformations/test_join.rb +14 -0
  40. data/test/transformations/test_mapping.rb +16 -0
  41. data/test/transformations/test_reduction.rb +69 -0
  42. metadata +92 -11
  43. data/Gemfile.lock +0 -33
  44. data/lib/enzymator/aggregation.rb +0 -63
  45. data/lib/enzymator/core_ext/enumerator.rb +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a2ec2a4060b6cda9e9556c05b4feb7f8188b91ed
4
- data.tar.gz: 5c01a79eed612fc1c63a7a496695ef5898e7f38f
3
+ metadata.gz: db6b848beb8684576018917cc3294e62ee74c9b9
4
+ data.tar.gz: 13464a8ce27e97366cdd446ade0f40ef1d9c96fe
5
5
  SHA512:
6
- metadata.gz: 0d7e5533db3223a545e7c175f3ffe65fa33e3d3e18c7469b1d2dd129a604fd386db91666120d8ea19d14149b7636dcfbe76c57478513bcad707a0d8ad8dc4592
7
- data.tar.gz: f7200cc635e0c058d54fa50d8d28593b366f7ea5e61439d4b9c8d81e264b04ffe3a2574c12f79b369af35725707c13643806e85ac9c2c82b47b42ca4a2e25967
6
+ metadata.gz: 06c96d05b1719d9b82edfd21dcfef75f96a77123f7d2b20fb934f7659a012f1a60ed975d0f891042a2fec58d322ce831b4fa40b2a00cc5cf21aa42612237c5bf
7
+ data.tar.gz: 87eb91c6b2c7ec3afb559e8fcd450bb93e3177c78259a120ebcc83f0498a5588fec36048d547779df0953e2f97b3a96bccf68406622afda5ce2c5b693280dfc4
data/Gemfile CHANGED
@@ -2,9 +2,3 @@ source 'http://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in enzymator.gemspec
4
4
  gemspec
5
-
6
- group :development, :test do
7
- gem "rake", "~> 11.2"
8
- gem "minitest", "~> 5.9"
9
- gem 'pry-byebug'
10
- end
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 eugeniobruno
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Enzymator
2
2
 
3
- Enzimator is an extremely simple and powerful aggregation framework. Every ruby app can use it to unleash the infinite power of the MapReduce concept. If it could tame BigData, imagine what it can do with fewer data!
3
+ Enzymator is an extremely simple and powerful aggregation framework. Every ruby app can use it to unleash the infinite power of the MapReduce concept. If it could tame BigData, imagine what it can do with fewer data!
4
4
 
5
5
  You should take two minutes to check out the test examples.
6
6
 
@@ -8,7 +8,7 @@ You should take two minutes to check out the test examples.
8
8
 
9
9
  Add this line to your application's Gemfile:
10
10
 
11
- gem 'enzimator'
11
+ gem 'enzymator'
12
12
 
13
13
  And then execute:
14
14
 
@@ -16,11 +16,11 @@ And then execute:
16
16
 
17
17
  Or install it yourself as:
18
18
 
19
- $ gem install enzimator
19
+ $ gem install enzymator
20
20
 
21
21
  ## Usage
22
22
 
23
- You set up a new Aggregation instance, tell it to run with your Enumerator, and get the result. The tests are self-explanatory.
23
+ You set up a new transformation instance, tell it to run with your Object, and get the result. The tests are self-explanatory.
24
24
 
25
25
  ## Contributing
26
26
 
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'rake/testtask'
2
2
 
3
3
  Rake::TestTask.new do |t|
4
- t.libs << 'test'
4
+ t.pattern = "test/**/test_*.rb"
5
5
  end
6
6
 
7
7
  desc "Run tests"
@@ -6,9 +6,9 @@ require 'enzymator/version'
6
6
  Gem::Specification.new do |s|
7
7
  s.name = 'enzymator'
8
8
  s.version = Enzymator::Version
9
- s.date = '2016-07-17'
9
+ s.date = '2016-07-24'
10
10
  s.summary = "An extremely simple and powerful aggregation framework"
11
- s.description = "A gem to perform any kind of calculation on any kind of data. The essence of MapReduce distilled in a few lines of code for the ruby community to enjoy."
11
+ s.description = "A gem to perform any kind of transformation on any kind of data. The essence of MapReduce distilled in a few lines of code for the ruby community to enjoy."
12
12
  s.authors = ["Eugenio Bruno"]
13
13
  s.email = 'eugeniobruno@gmail.com'
14
14
  s.homepage = 'http://rubygems.org/gems/enzymator'
@@ -19,4 +19,10 @@ Gem::Specification.new do |s|
19
19
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
20
20
  s.require_paths = ['lib']
21
21
 
22
+ s.required_ruby_version = '>= 2.0.0'
23
+
24
+ s.add_development_dependency 'rake', ['~> 11.2']
25
+ s.add_development_dependency 'minitest', ['~> 5.9']
26
+ s.add_development_dependency 'pry-byebug', ['~> 3.4']
27
+
22
28
  end
@@ -1,2 +1,28 @@
1
- require 'enzymator/core_ext/enumerator'
2
- require 'enzymator/aggregation'
1
+ require 'enzymator/core_ext/categorizer'
2
+ require 'enzymator/core_ext/monoids'
3
+
4
+ require 'enzymator/types/list/functor/enumerable'
5
+ require 'enzymator/types/list/foldable/enumerable'
6
+ require 'enzymator/types/list/monad/array'
7
+
8
+ require 'enzymator/transformations/config'
9
+ require 'enzymator/transformations/base'
10
+ require 'enzymator/transformations/object/application'
11
+ require 'enzymator/transformations/object/pipelining'
12
+ require 'enzymator/transformations/functor/mapping'
13
+ require 'enzymator/transformations/foldable/reduction'
14
+ require 'enzymator/transformations/monad/join'
15
+
16
+ require 'enzymator/transformers/base'
17
+ require 'enzymator/transformers/object/simple_applicator'
18
+ require 'enzymator/transformers/object/simple_pipeliner'
19
+ require 'enzymator/transformers/functor/simple_mapper'
20
+ require 'enzymator/transformers/foldable/simple_reducer'
21
+ require 'enzymator/transformers/monad/simple_joiner'
22
+
23
+ require 'enzymator/aggregations/base'
24
+ require 'enzymator/aggregations/count'
25
+ require 'enzymator/aggregations/sum'
26
+ require 'enzymator/aggregations/average'
27
+ require 'enzymator/aggregations/merge_hashes'
28
+ require 'enzymator/aggregations/mapreduce'
@@ -0,0 +1,30 @@
1
+ module Enzymator
2
+ module Aggregations
3
+ class Average < Base
4
+
5
+ def initialize(config = {})
6
+ super
7
+
8
+ @transformation = begin
9
+ stages = []
10
+
11
+ stages << Enzymator::Transformations::Foldable::Reduction.new({
12
+ append: ->(acum, n) { acum[:sum] += n; acum[:count] += 1; acum },
13
+ empty: Hash.new(0)
14
+ })
15
+
16
+ stages << Enzymator::Transformations::Object::Application.new({
17
+ function: ->(sum_and_count) { sum_and_count[:sum] / sum_and_count[:count] }
18
+ })
19
+
20
+ Enzymator::Transformations::Object::Pipelining.new({
21
+ stages: stages
22
+ })
23
+
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ module Enzymator
2
+ module Aggregations
3
+ class Base
4
+
5
+ def initialize(config = {})
6
+ @config = Transformations::Config.new(config)
7
+ end
8
+
9
+ def run_on(object)
10
+ @transformation.run_on(object)
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ module Enzymator
2
+ module Aggregations
3
+ class Count < Base
4
+
5
+ def initialize(config = {})
6
+ super
7
+
8
+ @transformation = begin
9
+ Enzymator::Transformations::Object::Application.new({
10
+ function: ->(objects) { objects.size }
11
+ })
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ module Enzymator
2
+ module Aggregations
3
+ class MapReduce < Base
4
+
5
+ def initialize(config = {})
6
+ super
7
+
8
+ @transformation = begin
9
+ stages = []
10
+
11
+ if @config.map || @config.mapping
12
+ stages << Enzymator::Transformations::Functor::Mapping.new({
13
+ map: @config.map || @config.mapping
14
+ })
15
+ end
16
+
17
+ stages << Enzymator::Transformations::Foldable::Reduction.new({
18
+ append: @config.append || @config.reduction,
19
+ empty: @config.empty
20
+ })
21
+
22
+ Enzymator::Transformations::Object::Pipelining.new({
23
+ stages: stages
24
+ })
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,14 @@
1
+ module Enzymator
2
+ module Aggregations
3
+ class MergeHashes < Base
4
+
5
+ def initialize(config = {})
6
+ super
7
+
8
+ @transformation = Enzymator::Transformations::Foldable::Reduction.new
9
+ # Merge is the default reduction operation for hashes
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Enzymator
2
+ module Aggregations
3
+ class Sum < Base
4
+
5
+ def initialize(config = {})
6
+ super
7
+
8
+ @transformation = Enzymator::Transformations::Foldable::Reduction.new
9
+ # Summation is the default reduction operation for all numeric types
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,23 @@
1
+ module Enzymator
2
+ class Categorizer
3
+
4
+ @@known_classes = Hash.new(0)
5
+
6
+ def self.categorize(klass)
7
+ unless @@known_classes.has_key? klass
8
+
9
+ if klass.included_modules.include? Enumerable
10
+ klass.send :include, Enzymator::Types::List::Functor::Enumerable
11
+ klass.send :include, Enzymator::Types::List::Foldable::Enumerable
12
+ end
13
+
14
+ if klass <= Array
15
+ klass.send :include, Enzymator::Types::List::Monad::Array
16
+ end
17
+
18
+ @@known_classes[klass] += 1
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,76 @@
1
+ class Fixnum
2
+ @enzy_mappend = ->(m, n) { m + n }.freeze
3
+ @enzy_mempty = 0.freeze
4
+ class << self
5
+ attr_reader :enzy_mappend
6
+ attr_reader :enzy_mempty
7
+ end
8
+ end
9
+
10
+ class Float
11
+ @enzy_mappend = ->(m, n) { m + n }.freeze
12
+ @enzy_mempty = 0.to_f.freeze
13
+ class << self
14
+ attr_reader :enzy_mappend
15
+ attr_reader :enzy_mempty
16
+ end
17
+ end
18
+
19
+ class Rational
20
+ @enzy_mappend = ->(m, n) { m + n }.freeze
21
+ @enzy_mempty = 0.to_r.freeze
22
+ class << self
23
+ attr_reader :enzy_mappend
24
+ attr_reader :enzy_mempty
25
+ end
26
+ end
27
+
28
+ class Complex
29
+ @enzy_mappend = ->(m, n) { m + n }.freeze
30
+ @enzy_mempty = 0.to_c.freeze
31
+ class << self
32
+ attr_reader :enzy_mappend
33
+ attr_reader :enzy_mempty
34
+ end
35
+ end
36
+
37
+ class Array
38
+ @enzy_mappend = ->(xs, ys) { xs + ys }.freeze
39
+ @enzy_mempty = [].freeze
40
+ class << self
41
+ attr_reader :enzy_mappend
42
+ #attr_reader :enzy_mempty
43
+ def enzy_mempty
44
+ @enzy_mempty.dup
45
+ end
46
+ end
47
+ end
48
+
49
+ class String
50
+ @enzy_mappend = ->(s, t) { s + t }.freeze
51
+ @enzy_mempty = ''.freeze
52
+ class << self
53
+ attr_reader :enzy_mappend
54
+ attr_reader :enzy_mempty
55
+ end
56
+ end
57
+
58
+ class Hash
59
+ @enzy_mappend = ->(ps, qs) { ps.merge qs }.freeze
60
+ @enzy_mempty = {}.freeze
61
+ class << self
62
+ attr_reader :enzy_mappend
63
+ attr_reader :enzy_mempty
64
+ end
65
+ end
66
+
67
+ if defined? HashWithIndifferentAccess
68
+ class HashHashWithIndifferentAccess
69
+ @enzy_mappend = ->(ps, qs) { ps.merge qs }.freeze
70
+ @enzy_mempty = {}.freeze
71
+ class << self
72
+ attr_reader :enzy_mappend
73
+ attr_reader :enzy_mempty
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,39 @@
1
+ module Enzymator
2
+ module Transformations
3
+ class Base
4
+
5
+ @@default_config = {
6
+ max_threads: 1 # TODO: use this value
7
+ }
8
+
9
+ def initialize(config = {})
10
+ @config = Config.new(interpreted(@@default_config.merge(config)))
11
+ end
12
+
13
+ def run_on_all(*objects)
14
+ # when threads are implemented, the original order must be preserved
15
+ objects.map { |object| run_on(object) }
16
+ end
17
+
18
+ def run_on(object)
19
+ Categorizer.categorize(object.class)
20
+ do_run_on(object)
21
+ end
22
+
23
+ private
24
+
25
+ def interpreted(config)
26
+ config
27
+ end
28
+
29
+ def do_run_on(object)
30
+ transformer.transform(object)
31
+ end
32
+
33
+ def transformer
34
+ transformer_class.new(@config)
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,22 @@
1
+ module Enzymator
2
+ module Transformations
3
+ class Config
4
+
5
+ def initialize(config)
6
+ @config = config.each_with_object({}) do |(k, v), hash|
7
+ hash[k.to_sym] = v
8
+ end
9
+ .freeze
10
+ end
11
+
12
+ def method_missing(name, *args, &block)
13
+ @config[name]
14
+ end
15
+
16
+ def respond_to_missing?(name, include_private = false)
17
+ @config.has_key?(name) || super
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ module Enzymator
2
+ module Transformations
3
+ module Foldable
4
+ class Reduction < Base
5
+
6
+ protected
7
+
8
+ def transformer_class
9
+ Enzymator::Transformers::Foldable::SimpleReducer
10
+ end
11
+
12
+ def interpreted(config)
13
+ config.merge({
14
+ append: config[:append] || config[:reduction] || :mappend,
15
+ empty: config[:empty] || config[:initial] || :mempty
16
+ })
17
+ end
18
+
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ module Enzymator
2
+ module Transformations
3
+ module Functor
4
+ class Mapping < Base
5
+
6
+ protected
7
+
8
+ def transformer_class
9
+ Enzymator::Transformers::Functor::SimpleMapper
10
+ end
11
+
12
+ def interpreted(config)
13
+ config.merge({ map: config[:map] || config[:mapping] })
14
+ end
15
+
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ module Enzymator
2
+ module Transformations
3
+ module Monad
4
+ class Join < Base
5
+
6
+ protected
7
+
8
+ def transformer_class
9
+ Enzymator::Transformers::Monad::SimpleJoiner
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Enzymator
2
+ module Transformations
3
+ module Object
4
+ class Application < Base
5
+
6
+ protected
7
+
8
+ def transformer_class
9
+ Enzymator::Transformers::Object::SimpleApplicator
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ module Enzymator
2
+ module Transformations
3
+ module Object
4
+ class Pipelining < Base
5
+
6
+ protected
7
+
8
+ def transformer_class
9
+ Enzymator::Transformers::Object::SimplePipeliner
10
+ end
11
+
12
+ def interpreted(config)
13
+ config.merge({ stages: config[:stages] || config[:transformations] || [] })
14
+ end
15
+
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ module Enzymator
2
+ module Transformers
3
+ class Base
4
+
5
+ def initialize(config)
6
+ @config = config
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module Enzymator
2
+ module Transformers
3
+ module Foldable
4
+ class SimpleReducer < Base
5
+
6
+ def transform(input)
7
+ input.enzy_fold(@config.empty, @config.append)
8
+ end
9
+
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Enzymator
2
+ module Transformers
3
+ module Functor
4
+ class SimpleMapper < Base
5
+
6
+ def transform(input)
7
+ input.enzy_fmap(@config.map)
8
+ end
9
+
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Enzymator
2
+ module Transformers
3
+ module Monad
4
+ class SimpleJoiner < Base
5
+
6
+ def transform(input)
7
+ input.enzy_join
8
+ end
9
+
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Enzymator
2
+ module Transformers
3
+ module Object
4
+ class SimpleApplicator < Base
5
+
6
+ def transform(input)
7
+ @config.function.call(input)
8
+ end
9
+
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Enzymator
2
+ module Transformers
3
+ module Object
4
+ class SimplePipeliner < Base
5
+
6
+ def transform(input)
7
+ @config.stages.reduce(input) { |acum, stage| stage.run_on(acum) }
8
+ end
9
+
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,33 @@
1
+ module Enzymator
2
+ module Types
3
+ module List
4
+ module Foldable
5
+ module Enumerable
6
+
7
+ def enzy_fold(empty, append)
8
+ append = enzy_mappend if append == :mappend
9
+ empty = enzy_mempty if empty == :mempty
10
+
11
+ reduce(empty, &append)
12
+ end
13
+
14
+ private
15
+
16
+ def enzy_mappend
17
+ enzy_inner_type.enzy_mappend
18
+ end
19
+
20
+ def enzy_mempty
21
+ enzy_inner_type.enzy_mempty
22
+ end
23
+
24
+ def enzy_inner_type
25
+ first_elem = first
26
+ first_elem.nil? ? :missing_inner_type : first_elem.class
27
+ end
28
+
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ module Enzymator
2
+ module Types
3
+ module List
4
+ module Functor
5
+ module Enumerable
6
+ def enzy_fmap(f)
7
+ map(&f)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module Enzymator
2
+ module Types
3
+ module List
4
+ module Monad
5
+ module Array
6
+ include List::Functor::Enumerable
7
+ def self.enzy_unit(object)
8
+ [object]
9
+ end
10
+ def enzy_join
11
+ flatten(1)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,13 +1,12 @@
1
1
  module Enzymator
2
2
  class Version
3
- MAJOR = 0
3
+ MAJOR = 1
4
4
  MINOR = 0
5
- PATCH = 1
5
+ PATCH = 0
6
6
  PRE = nil
7
7
 
8
8
  class << self
9
9
 
10
- # @return [String]
11
10
  def to_s
12
11
  [MAJOR, MINOR, PATCH, PRE].compact.join('.')
13
12
  end
@@ -0,0 +1,15 @@
1
+ require 'minitest/autorun'
2
+ require 'enzymator'
3
+
4
+ class TestAverage < Minitest::Test
5
+
6
+ def test_average
7
+ numbers = (1..10).to_a
8
+ expected = (1..10).reduce(:+) / 10
9
+
10
+ actual = Enzymator::Aggregations::Average.new.run_on(numbers)
11
+
12
+ assert_equal expected, actual
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'minitest/autorun'
2
+ require 'enzymator'
3
+
4
+ class TestCount < Minitest::Test
5
+
6
+ def test_count
7
+ numbers = (1..10).to_a
8
+ expected = numbers.length
9
+
10
+ actual = Enzymator::Aggregations::Count.new.run_on(numbers)
11
+
12
+ assert_equal expected, actual
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'minitest/autorun'
2
+ require 'enzymator'
3
+
4
+ class TestMergeHashes < Minitest::Test
5
+
6
+ def test_merge_hashes
7
+ hashes = [ { 'a' => 1, 'b' => 2, 'c' => 3 }, { 'd' => 4 }, { 'e' => 5 } ]
8
+ expected = { 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }
9
+
10
+ actual = Enzymator::Aggregations::MergeHashes.new.run_on(hashes)
11
+
12
+ assert_equal expected, actual
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'minitest/autorun'
2
+ require 'enzymator'
3
+
4
+ class TestSum < Minitest::Test
5
+
6
+ def test_sum
7
+ numbers = (1..10).to_a
8
+ expected = (1..10).reduce(:+)
9
+
10
+ actual = Enzymator::Aggregations::Sum.new.run_on(numbers)
11
+
12
+ assert_equal expected, actual
13
+ end
14
+
15
+ end
@@ -1,7 +1,7 @@
1
1
  require 'minitest/autorun'
2
2
  require 'enzymator'
3
3
 
4
- class AggregationTest < Minitest::Test
4
+ class TestIntroduction < Minitest::Test
5
5
 
6
6
  def test_sum_numbers
7
7
  numbers = (1..1000).to_a
@@ -9,10 +9,8 @@ class AggregationTest < Minitest::Test
9
9
  expected_sum = numbers.reduce(:+)
10
10
 
11
11
  # but where's the fun in that...
12
- actual_sum = Enzymator::Aggregation.new({
13
- null_result: lambda { 0 },
14
- map: lambda { |n| n },
15
- reduce: lambda { |acum, n, _| acum + n },
12
+ actual_sum = Enzymator::Aggregations::MapReduce.new({
13
+ reduction: ->(acum, n) { acum + n }
16
14
  }).run_on(numbers)
17
15
 
18
16
  assert_equal expected_sum, actual_sum
@@ -39,14 +37,10 @@ class AggregationTest < Minitest::Test
39
37
  'fat.' => 1,
40
38
  }
41
39
 
42
- aggregation = Enzymator::Aggregation.new({
43
- null_result: lambda { Hash.new(0) },
44
- map: lambda { |w| w },
45
- reduce: lambda { |acum, w, _| acum[w] += 1; acum }
46
- }).run_on!(words)
47
- # notice the bang
48
-
49
- actual_hash = aggregation.result
40
+ actual_hash = Enzymator::Aggregations::MapReduce.new({
41
+ reduction: ->(acum, w) { acum[w] += 1; acum },
42
+ empty: Hash.new(0)
43
+ }).run_on(words)
50
44
 
51
45
  assert_equal expected_hash, actual_hash
52
46
 
@@ -55,10 +49,11 @@ class AggregationTest < Minitest::Test
55
49
  expected_hash.delete('The')
56
50
  expected_hash = expected_hash.map { |k, v| { k.downcase => v } }.reduce(&:merge)
57
51
 
58
- aggregation.patch_config( map: lambda { |w| w.downcase } )
59
- .run_on!(words)
60
-
61
- actual_hash = aggregation.result
52
+ actual_hash = Enzymator::Aggregations::MapReduce.new({
53
+ mapping: ->(w) { w.downcase },
54
+ reduction: ->(acum, w) { acum[w] += 1; acum },
55
+ empty: Hash.new(0)
56
+ }).run_on(words)
62
57
 
63
58
  assert_equal expected_hash, actual_hash
64
59
 
@@ -0,0 +1,17 @@
1
+ require 'minitest/autorun'
2
+ require 'enzymator'
3
+
4
+ class TestApplication < Minitest::Test
5
+
6
+ def test_application
7
+ object = 26
8
+ expected = 27
9
+
10
+ actual = Enzymator::Transformations::Object::Application.new({
11
+ function: ->(x) { x + 1 }
12
+ }).run_on(object)
13
+
14
+ assert_equal expected, actual
15
+ end
16
+
17
+ end
@@ -0,0 +1,14 @@
1
+ require 'minitest/autorun'
2
+ require 'enzymator'
3
+
4
+ class TestJoin < Minitest::Test
5
+
6
+ def test_join
7
+ ary = [1, 2, [3, 4], [5], [6, [7, 8], 9]]
8
+ expected = [1, 2, 3, 4, 5, 6, [7, 8], 9]
9
+ actual = Enzymator::Transformations::Monad::Join.new.run_on(ary)
10
+
11
+ assert_equal expected, actual
12
+ end
13
+
14
+ end
@@ -0,0 +1,16 @@
1
+ require 'minitest/autorun'
2
+ require 'enzymator'
3
+
4
+ class TestMapping < Minitest::Test
5
+
6
+ def test_map
7
+ ary = (1..9).to_a
8
+ expected = ary.map { |n| n + 1 }
9
+ actual = Enzymator::Transformations::Functor::Mapping.new({
10
+ map: ->(n) { n + 1 }
11
+ }).run_on(ary)
12
+
13
+ assert_equal expected, actual
14
+ end
15
+
16
+ end
@@ -0,0 +1,69 @@
1
+ require 'minitest/autorun'
2
+ require 'enzymator'
3
+
4
+ class TestReduction < Minitest::Test
5
+
6
+ def test_reduction_sum
7
+ ary = (1..9).to_a
8
+ expected = (1..9).to_a.reduce(:+)
9
+
10
+ actual_explicit = Enzymator::Transformations::Foldable::Reduction.new({
11
+ append: ->(acum, n) { acum + n }
12
+ }).run_on(ary)
13
+
14
+ actual_implicit = Enzymator::Transformations::Foldable::Reduction.new
15
+ .run_on(ary)
16
+
17
+ assert_equal expected, actual_explicit
18
+ assert_equal expected, actual_implicit
19
+ end
20
+
21
+ def test_reduction_product
22
+ ary = (1..9).to_a
23
+ expected = (1..9).to_a.reduce(:*)
24
+
25
+ absorbed = Enzymator::Transformations::Foldable::Reduction.new({
26
+ append: ->(acum, n) { acum * n }
27
+ }).run_on(ary)
28
+
29
+ actual = Enzymator::Transformations::Foldable::Reduction.new({
30
+ append: ->(acum, n) { acum * n },
31
+ empty: 1
32
+ }).run_on(ary)
33
+
34
+ assert_equal 0, absorbed
35
+ assert_equal expected, actual
36
+ end
37
+
38
+ def test_reduction_concat
39
+ ary = (1..9).to_a.map { |n| [+n, -n] }
40
+ expected = (1..9).to_a.map { |n| [+n, -n] }.reduce(:concat).to_a
41
+
42
+ actual_explicit = Enzymator::Transformations::Foldable::Reduction.new({
43
+ append: ->(acum, pair) { acum + pair },
44
+ }).run_on(ary)
45
+
46
+ actual_implicit = Enzymator::Transformations::Foldable::Reduction.new
47
+ .run_on(ary)
48
+
49
+ assert_equal expected, actual_explicit
50
+ assert_equal expected, actual_implicit
51
+ end
52
+
53
+ def test_reduction_merge
54
+ hashes = [ { 'a' => 1, 'b' => 2, 'c' => 3 }, { 'd' => 4 }, { 'e' => 5 } ]
55
+ expected = { 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5 }
56
+
57
+ actual_explicit = Enzymator::Transformations::Foldable::Reduction.new({
58
+ append: ->(acum, pair) { acum.merge pair },
59
+ empty: { 'f' => 6 }
60
+ }).run_on(hashes)
61
+
62
+ actual_implicit = Enzymator::Transformations::Foldable::Reduction.new
63
+ .run_on(hashes)
64
+
65
+ assert_equal expected.merge({ 'f' => 6 }), actual_explicit
66
+ assert_equal expected, actual_implicit
67
+ end
68
+
69
+ end
metadata CHANGED
@@ -1,32 +1,105 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enzymator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eugenio Bruno
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-17 00:00:00.000000000 Z
12
- dependencies: []
13
- description: A gem to perform any kind of calculation on any kind of data. The essence
14
- of MapReduce distilled in a few lines of code for the ruby community to enjoy.
11
+ date: 2016-07-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '11.2'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '11.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.9'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.9'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry-byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.4'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.4'
55
+ description: A gem to perform any kind of transformation on any kind of data. The
56
+ essence of MapReduce distilled in a few lines of code for the ruby community to
57
+ enjoy.
15
58
  email: eugeniobruno@gmail.com
16
59
  executables: []
17
60
  extensions: []
18
61
  extra_rdoc_files: []
19
62
  files:
20
63
  - Gemfile
21
- - Gemfile.lock
64
+ - LICENSE
22
65
  - README.md
23
66
  - Rakefile
24
67
  - enzymator.gemspec
25
68
  - lib/enzymator.rb
26
- - lib/enzymator/aggregation.rb
27
- - lib/enzymator/core_ext/enumerator.rb
69
+ - lib/enzymator/aggregations/average.rb
70
+ - lib/enzymator/aggregations/base.rb
71
+ - lib/enzymator/aggregations/count.rb
72
+ - lib/enzymator/aggregations/mapreduce.rb
73
+ - lib/enzymator/aggregations/merge_hashes.rb
74
+ - lib/enzymator/aggregations/sum.rb
75
+ - lib/enzymator/core_ext/categorizer.rb
76
+ - lib/enzymator/core_ext/monoids.rb
77
+ - lib/enzymator/transformations/base.rb
78
+ - lib/enzymator/transformations/config.rb
79
+ - lib/enzymator/transformations/foldable/reduction.rb
80
+ - lib/enzymator/transformations/functor/mapping.rb
81
+ - lib/enzymator/transformations/monad/join.rb
82
+ - lib/enzymator/transformations/object/application.rb
83
+ - lib/enzymator/transformations/object/pipelining.rb
84
+ - lib/enzymator/transformers/base.rb
85
+ - lib/enzymator/transformers/foldable/simple_reducer.rb
86
+ - lib/enzymator/transformers/functor/simple_mapper.rb
87
+ - lib/enzymator/transformers/monad/simple_joiner.rb
88
+ - lib/enzymator/transformers/object/simple_applicator.rb
89
+ - lib/enzymator/transformers/object/simple_pipeliner.rb
90
+ - lib/enzymator/types/list/foldable/enumerable.rb
91
+ - lib/enzymator/types/list/functor/enumerable.rb
92
+ - lib/enzymator/types/list/monad/array.rb
28
93
  - lib/enzymator/version.rb
29
- - test/test_aggregation.rb
94
+ - test/aggregations/test_average.rb
95
+ - test/aggregations/test_count.rb
96
+ - test/aggregations/test_merge_hashes.rb
97
+ - test/aggregations/test_sum.rb
98
+ - test/test_introduction.rb
99
+ - test/transformations/test_application.rb
100
+ - test/transformations/test_join.rb
101
+ - test/transformations/test_mapping.rb
102
+ - test/transformations/test_reduction.rb
30
103
  homepage: http://rubygems.org/gems/enzymator
31
104
  licenses:
32
105
  - MIT
@@ -39,7 +112,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
39
112
  requirements:
40
113
  - - ">="
41
114
  - !ruby/object:Gem::Version
42
- version: '0'
115
+ version: 2.0.0
43
116
  required_rubygems_version: !ruby/object:Gem::Requirement
44
117
  requirements:
45
118
  - - ">="
@@ -52,4 +125,12 @@ signing_key:
52
125
  specification_version: 4
53
126
  summary: An extremely simple and powerful aggregation framework
54
127
  test_files:
55
- - test/test_aggregation.rb
128
+ - test/aggregations/test_average.rb
129
+ - test/aggregations/test_count.rb
130
+ - test/aggregations/test_merge_hashes.rb
131
+ - test/aggregations/test_sum.rb
132
+ - test/test_introduction.rb
133
+ - test/transformations/test_application.rb
134
+ - test/transformations/test_join.rb
135
+ - test/transformations/test_mapping.rb
136
+ - test/transformations/test_reduction.rb
@@ -1,33 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- enzymator (0.0.1)
5
-
6
- GEM
7
- remote: http://rubygems.org/
8
- specs:
9
- byebug (9.0.5)
10
- coderay (1.1.1)
11
- method_source (0.8.2)
12
- minitest (5.9.0)
13
- pry (0.10.4)
14
- coderay (~> 1.1.0)
15
- method_source (~> 0.8.1)
16
- slop (~> 3.4)
17
- pry-byebug (3.4.0)
18
- byebug (~> 9.0)
19
- pry (~> 0.10)
20
- rake (11.2.2)
21
- slop (3.6.0)
22
-
23
- PLATFORMS
24
- ruby
25
-
26
- DEPENDENCIES
27
- enzymator!
28
- minitest (~> 5.9)
29
- pry-byebug
30
- rake (~> 11.2)
31
-
32
- BUNDLED WITH
33
- 1.12.5
@@ -1,63 +0,0 @@
1
- module Enzymator
2
- class Aggregation
3
-
4
- @@single_cluster_config = {
5
- initial_clusters: lambda { |n| n },
6
- enumerator: lambda { |n| [n].each },
7
- map_each: lambda { |n| :single_cluster },
8
- reduce_each: lambda { |acum, n| :single_cluster },
9
- }
10
-
11
- attr_accessor :config, :results
12
-
13
- def initialize(config, results = [])
14
- @config = @@single_cluster_config.merge(config)
15
- @results = results
16
- end
17
-
18
- def last_result
19
- results.last
20
- end
21
- alias :result :last_result
22
-
23
- def patch_config(config_patch)
24
- self.config = config.merge(config_patch)
25
- self
26
- end
27
-
28
- def run_on!(enumerable, options = {}, config = @config)
29
- add_result(run_on(enumerable, options, config))
30
- self
31
- end
32
-
33
- def run_on(enumerable, options = {}, config = @config)
34
- config[:initial_clusters].call(enumerable).reduce(config[:null_result].call) do |acum, cluster|
35
- group = config[:map].call(cluster)
36
- config[:reduce].call( acum, group, aggregate(cluster, config, options) )
37
- end
38
- end
39
-
40
- protected
41
-
42
- def add_result(result)
43
- @results.push(result)
44
- self
45
- end
46
-
47
- def aggregate(cluster, config, options)
48
- enum = config[:enumerator].call(cluster)
49
- first_element = enum.peek
50
- first_map_result = config[:map_each].call(first_element)
51
-
52
- enum.skip(1).reduce(first_map_result) do |acum, e|
53
- step(acum, e, config, options)
54
- end
55
- end
56
-
57
- def step(previous_result, elem, config, options)
58
- map_result = config[:map_each].call(elem)
59
- config[:reduce_each].call(previous_result, map_result)
60
- end
61
-
62
- end
63
- end
@@ -1,20 +0,0 @@
1
- class Enumerator
2
- #
3
- # Skip the first n elements and return an Enumerator for the rest, or pass them
4
- # in succession to the block, if given.
5
- # Extracted from epitools: https://github.com/epitron/epitools
6
- #
7
- def skip(n)
8
- if block_given?
9
- each do |x|
10
- if n > 0
11
- n -= 1
12
- else
13
- yield x
14
- end
15
- end
16
- else
17
- to_enum(:skip, n)
18
- end
19
- end
20
- end