enumerator_concurrent 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OGE1OGJhNzFmZDI1NDJjMjE0NTQ5ZGM5N2I2MTQzMjVhMzIzY2I3Mw==
5
+ data.tar.gz: !binary |-
6
+ ZTBjY2IwNWY0ZDJjNjc2MGExMDY1YTM3ODQzNmY1Mjg2MGRiMjc2OQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MGRjYzc1NGNiNDU1ZmJkMDM2YmZhNmNkY2M5ZmMwNzU4YmY0NjYyZmU3YTZh
10
+ MTdjNjM5ZWRlYWE0M2MzNDkzODZlZGI2ZDU3YjY3Y2E3OTRjOTE3NjIxMjRl
11
+ OWVjOGE3NzAyMTZiOTViMmQwNThkMTQ1OTY2NTQ5ZmJkOThmYmM=
12
+ data.tar.gz: !binary |-
13
+ ODQ1ZGNiYTY5ZTMwYTk2ZTdjNDViZmJhMDY0ZGQwODVhNzgyNTRhZTFhNTYy
14
+ NjRjNDk2NjI2Yjk3MjM1OWMwN2ZiMWFlMjYxMTJhMzE3NDQ4NGVhOTIzNDdh
15
+ NTQ3MjI2NDQyNTQ1Njk1ZTAyYzk3NTRmOTJhZTEyOGE5ZjRlMzA=
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ .DS_store
16
+ *.swp
17
+ *.gem
data/.hound.yml ADDED
@@ -0,0 +1,3 @@
1
+ ruby:
2
+ enabled: true
3
+ config_file: .rubocop.yml
data/.rubocop.yml ADDED
File without changes
data/.travis.yml ADDED
@@ -0,0 +1,17 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.0
4
+ - 2.0.0
5
+ - jruby-19mode
6
+ - rbx-2
7
+ - ruby-head
8
+ - jruby-head
9
+ deploy:
10
+ provider: rubygems
11
+ api_key:
12
+ secure: kaHhG0D7M5ImRK0AoO5UsdcAKRtms57Mix6lzJIK+tYADnDQFRGDTZ/odUYkwup5dwW1zX/GkehEee6zEvmxnwgQz3+qAf4NSR7lqSzvD5Q4ZssLt6tw2jEmKijG/0MUTGojtPidPcR/wDpsxDdasBvxuFTObaLTTdATCiy2wRM=
13
+ gem: enumerator_concurrent
14
+ on:
15
+ all_branches: true
16
+ tags: true
17
+ repo: doodzik/enumerator_concurrent
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in Enumerator-Concurrent.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 doodzik
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # enumerator_concurrent
2
+ [![Build Status](https://travis-ci.org/doodzik/enumerator_concurrent.svg?branch=master)](https://travis-ci.org/doodzik/enumerator_concurrent)
3
+ [![Stories in Ready](https://badge.waffle.io/doodzik/enumerator_concurrent.svg?label=ready&title=Ready)](http://waffle.io/doodzik/enumerator_concurrent)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'enumerator_concurrent'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install enumerator-concurrent
20
+
21
+ ## Usage
22
+
23
+ ```ruby
24
+ # Enumerator::Concurrent inherits from Array
25
+ require 'enumerator_concurrent'
26
+
27
+ # every iteration is run in an own thread
28
+ [1,2,3,4].concurrent.each { |x| x*2 }
29
+ # => [2,4,6,8]
30
+
31
+ # specify how many threads should deal with the Enumerable.
32
+ queued = [1,2,3,4].concurrent.threads(2)
33
+
34
+ # doesn't preserve the structure
35
+ queued.each { |x| x*2 }
36
+ # => [1,2,3,4]
37
+
38
+ # preserves the structure
39
+ queued.map { |x| x*2 }
40
+ # => [2,4,6,8]
41
+
42
+ ```
43
+
44
+ ## Contributing
45
+
46
+ 1. Fork it ( https://github.com/doodzik/enumerator-concurrent/fork )
47
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
48
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
49
+ 4. Push to the branch (`git push origin my-new-feature`)
50
+ 5. Create a new Pull Request
51
+
52
+
53
+ ## License (MIT)
54
+
55
+ Copyright (c) 2014 Frederik Dudzik
56
+
57
+ Permission is hereby granted, free of charge, to any person obtaining a copy
58
+ of this software and associated documentation files (the "Software"), to deal
59
+ in the Software without restriction, including without limitation the rights
60
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
61
+ copies of the Software, and to permit persons to whom the Software is
62
+ furnished to do so, subject to the following conditions:
63
+
64
+ The above copyright notice and this permission notice shall be included in
65
+ all copies or substantial portions of the Software.
66
+
67
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
68
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
69
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
70
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
71
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
72
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
73
+ THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+ require 'rubocop/rake_task'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'test'
7
+ end
8
+
9
+ RuboCop::RakeTask.new
10
+
11
+ desc 'Run tests and rubocop'
12
+ task default: [:rubocop, :test]
@@ -0,0 +1,2 @@
1
+ require 'benchmark'
2
+ require 'enumerator_concurrent'
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'enumerator_concurrent/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'enumerator_concurrent'
8
+ spec.version = EnumeratorConcurrent::VERSION
9
+ spec.authors = ['doodzik']
10
+ spec.email = ['frederik.dudzik@gmail.com']
11
+ spec.summary = 'Implements a concurrent each'
12
+ spec.description = 'for each iteration a new thread is started.'\
13
+ 'Then the started threads are joind'
14
+ spec.homepage = 'https://github.com/doodzik/enumerator_concurrent.git'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\u0000")
18
+ spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(/^(test|spec|features)\//)
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_development_dependency 'bundler', '~> 1.6'
23
+ spec.add_development_dependency 'rake', '~> 10.0'
24
+ spec.add_development_dependency 'minitest', '~> 5.4'
25
+ spec.add_development_dependency 'rubocop', '~> 0.27'
26
+ end
@@ -0,0 +1,59 @@
1
+ # Namespace
2
+ module EnumeratorConcurrent
3
+ # Enumerator with thread count speciyfied to handle loop
4
+ class Queued < Array
5
+ # @param arr [Array]
6
+ # @param thread_count [Int] how many thread should be handle the Enumarator
7
+ def initialize(arr, thread_count)
8
+ @thread_count = 0...thread_count
9
+ @queue = Queue.new
10
+ @arr = arr
11
+ super(arr)
12
+ end
13
+
14
+ # @yield [x] element in array
15
+ # @return [self]
16
+ def each
17
+ @arr.each { |x| @queue.push x }
18
+ init_workers do
19
+ pop_queue do |x|
20
+ yield(x)
21
+ end
22
+ end
23
+ self
24
+ end
25
+
26
+ # @yield [x] element in self
27
+ # @return [Array] with modified values
28
+ def map
29
+ return_value = []
30
+ @arr.map.with_index { |x, i| @queue.push(i => x) }
31
+ init_workers do
32
+ pop_queue do |x|
33
+ key, value = x.first
34
+ return_value[key] = yield(value)
35
+ end
36
+ end
37
+ return_value
38
+ end
39
+
40
+ private
41
+
42
+ # @yield run block in specified Thread count
43
+ def init_workers
44
+ to_join = @thread_count.map do
45
+ Thread.new do
46
+ yield
47
+ end
48
+ end
49
+ to_join.map(&:join)
50
+ end
51
+
52
+ # @yield [x] poped element from the queue
53
+ def pop_queue
54
+ loop { yield(@queue.pop(true)) }
55
+ rescue ThreadError => e
56
+ p e unless e.message == 'queue empty'
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,29 @@
1
+ # Implements a Concurrent Each
2
+ module EnumeratorConcurrent
3
+ # Each Iteration in an own Thread. Less overhead then Queued
4
+ class Threaded < Array
5
+ # @param &block [Block] takes a block an passes it to each_to_thread
6
+ # @return [Array] as the standard each does
7
+ def each(&block)
8
+ each_to_thread(&block).join_threads
9
+ end
10
+
11
+ # joins a list of threads and returns the threads value
12
+ # @return [Array<thread.join.value>]
13
+ def join_threads
14
+ Threaded.new map { |x| x.join.value }
15
+ end
16
+
17
+ # initializes for every iteration a new Thread
18
+ # @return [Array<thread>] Array of Thread instances
19
+ def each_to_thread
20
+ Threaded.new map { |x| Thread.new { yield(x) } }
21
+ end
22
+
23
+ # @param thread_workers [Int] number of threads running. defaults to four
24
+ # @return [Enumerator::ConcurrentQueue]
25
+ def threads(thread_workers)
26
+ Queued.new self, thread_workers
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,6 @@
1
+ # Change the version and
2
+ # add an tagged commit with -a flag
3
+ # to auto deploy to rubygems
4
+ module EnumeratorConcurrent
5
+ VERSION = '0.0.1'
6
+ end
@@ -0,0 +1,12 @@
1
+ require 'enumerator_concurrent/version'
2
+ require 'enumerator_concurrent/threaded'
3
+ require 'enumerator_concurrent/queued'
4
+
5
+ # opens Array class and adds concurrent method
6
+ class Array
7
+ # @return [Enumerator::Concurrent] instance of Enumerator::Concurrent
8
+ # initialized with self
9
+ def concurrent
10
+ EnumeratorConcurrent::Threaded.new(self)
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ require 'minitest/autorun'
2
+ require 'enumerator_concurrent'
3
+
4
+ # test implementation of the lib
5
+ class EnumeratorConcurrentTest < Minitest::Test
6
+ def test_extended_array
7
+ assert_equal(EnumeratorConcurrent::Threaded, [].concurrent.class)
8
+ assert_equal([1, 2, 3], [1, 2, 3].concurrent)
9
+ end
10
+
11
+ def test_extended_concrrent_with_threads
12
+ cq = EnumeratorConcurrent::Queued.new [1, 2, 3, 4], 2
13
+ assert_equal([1, 2, 3, 4].concurrent.threads(2), cq)
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ require 'minitest/autorun'
2
+ require 'enumerator_concurrent/queued'
3
+
4
+ # Test for EnumeratorQueued
5
+ class EnumeratorConcurrentQueuedTest < Minitest::Test
6
+ def test_map_workers
7
+ cq = EnumeratorConcurrent::Queued.new [1, 2, 3, 4], 2
8
+ assert_equal([2, 4, 6, 8], cq.map { |x| x * 2 })
9
+ end
10
+
11
+ def test_each_workers
12
+ cq = EnumeratorConcurrent::Queued.new [1, 2, 3, 4], 2
13
+ result = 0
14
+ result1 = cq.each { |x| result += x }
15
+ assert_equal([1, 2, 3, 4], result1)
16
+ assert_equal(10, result)
17
+ end
18
+
19
+ def test_init_workers
20
+ cq = EnumeratorConcurrent::Queued.new [], 2
21
+ result1, result2 = cq.send(:init_workers) {}
22
+ assert result1.is_a? Thread
23
+ assert result2.is_a? Thread
24
+ end
25
+ end
@@ -0,0 +1,51 @@
1
+ require 'minitest/autorun'
2
+ require 'enumerator_concurrent/threaded'
3
+
4
+ # Mock for thread to see if thread was invoked
5
+ class ThreadMock
6
+ attr_reader :joined, :valued
7
+ @joined = false
8
+ @value = false
9
+
10
+ def join
11
+ @joined = true
12
+ self
13
+ end
14
+
15
+ def value
16
+ @valued = true
17
+ self
18
+ end
19
+ end
20
+
21
+ # test Threaded
22
+ class EnumeratorConcurrentTest < Minitest::Test
23
+ def test_creates_list_of_threads
24
+ threaded = EnumeratorConcurrent::Threaded.new([2, 3])
25
+ thread1, thread2 = threaded.each_to_thread do |x|
26
+ x + 10
27
+ end
28
+
29
+ assert(thread1.is_a? Thread)
30
+ assert(thread2.is_a? Thread)
31
+ assert_equal(thread1.value, 12)
32
+ assert_equal(thread2.value, 13)
33
+ end
34
+
35
+ def test_joining_threads
36
+ threads = [ThreadMock.new, ThreadMock.new]
37
+ t1, t2 = EnumeratorConcurrent::Threaded.new(threads).join_threads
38
+ assert(t1.joined)
39
+ assert(t1.valued)
40
+ assert(t2.joined)
41
+ assert(t2.valued)
42
+ end
43
+
44
+ def test_each
45
+ values = [3, 2]
46
+ ec = EnumeratorConcurrent::Threaded.new(values)
47
+ t1, t2 = ec.each { |x| x + 2 }
48
+ assert_equal(t1, 5)
49
+ assert_equal(t2, 4)
50
+ end
51
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: enumerator_concurrent
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - doodzik
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '5.4'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '5.4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '0.27'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '0.27'
69
+ description: for each iteration a new thread is started.Then the started threads are
70
+ joind
71
+ email:
72
+ - frederik.dudzik@gmail.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - .gitignore
78
+ - .hound.yml
79
+ - .rubocop.yml
80
+ - .travis.yml
81
+ - Gemfile
82
+ - LICENSE.txt
83
+ - README.md
84
+ - Rakefile
85
+ - benchmark/benchmark.rb
86
+ - enumerator_concurrent.gemspec
87
+ - lib/enumerator_concurrent.rb
88
+ - lib/enumerator_concurrent/queued.rb
89
+ - lib/enumerator_concurrent/threaded.rb
90
+ - lib/enumerator_concurrent/version.rb
91
+ - test/test_enumerator_concurrent.rb
92
+ - test/test_enumerator_concurrent_queued.rb
93
+ - test/test_enumerator_oncurrent_threaded.rb
94
+ homepage: https://github.com/doodzik/enumerator_concurrent.git
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ! '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ! '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.4.5
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: Implements a concurrent each
118
+ test_files:
119
+ - test/test_enumerator_concurrent.rb
120
+ - test/test_enumerator_concurrent_queued.rb
121
+ - test/test_enumerator_oncurrent_threaded.rb