threach-0.2.0/0000755000175000017500000000000012577435633013062 5ustar mcrusoemcrusoethreach-0.2.0/metadata.yml0000644000175000017500000000463612577435633015376 0ustar mcrusoemcrusoe--- !ruby/object:Gem::Specification name: threach version: !ruby/object:Gem::Version hash: 23 prerelease: false segments: - 0 - 2 - 0 version: 0.2.0 platform: ruby authors: - Bill Dueber autorequire: bindir: bin cert_chain: [] date: 2010-08-10 00:00:00 -04:00 default_executable: dependencies: - !ruby/object:Gem::Dependency name: thoughtbot-shoulda prerelease: false requirement: &id001 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" type: :development version_requirements: *id001 - !ruby/object:Gem::Dependency name: yard prerelease: false requirement: &id002 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" type: :development version_requirements: *id002 - !ruby/object:Gem::Dependency name: cucumber prerelease: false requirement: &id003 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" type: :development version_requirements: *id003 description: An addition to the Enumerable module that allows easy use of threaded each and each-like iterators email: bill@dueber.com executables: [] extensions: [] extra_rdoc_files: - LICENSE - README.markdown files: - .document - .gitignore - LICENSE - README.markdown - Rakefile - VERSION - features/step_definitions/threach_steps.rb - features/support/env.rb - features/threach.feature - lib/threach.rb - test/helper.rb - test/test_threach.rb has_rdoc: true homepage: http://github.com/billdueber/threach licenses: [] post_install_message: rdoc_options: - --charset=UTF-8 require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" requirements: [] rubyforge_project: rubygems_version: 1.3.7 signing_key: specification_version: 3 summary: Threaded each test_files: - test/helper.rb - test/test_threach.rb threach-0.2.0/test/0000755000175000017500000000000012577435633014041 5ustar mcrusoemcrusoethreach-0.2.0/test/test_threach.rb0000644000175000017500000000033712577435633017046 0ustar mcrusoemcrusoerequire 'helper' class TestThreach < Test::Unit::TestCase should "probably rename this file and start testing for real" do flunk "hey buddy, you should probably rename this file and start testing for real" end end threach-0.2.0/test/helper.rb0000644000175000017500000000033212577435633015643 0ustar mcrusoemcrusoerequire 'rubygems' require 'test/unit' require 'shoulda' $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) $LOAD_PATH.unshift(File.dirname(__FILE__)) require 'threach' class Test::Unit::TestCase end threach-0.2.0/lib/0000755000175000017500000000000012577435633013630 5ustar mcrusoemcrusoethreach-0.2.0/lib/threach.rb0000644000175000017500000000130612577435633015573 0ustar mcrusoemcrusoerequire 'thread' module Enumerable def threach(threads=0, iterator=:each, &blk) if threads == 0 self.send(iterator) do |*args| blk.call *args end else bq = SizedQueue.new(threads * 2) consumers = [] threads.times do |i| consumers << Thread.new(i) do |i| until (a = bq.pop) === :end_of_data blk.call(*a) end end end # The producer count = 0 self.send(iterator) do |*x| bq.push x count += 1 end # Now end it threads.times do bq << :end_of_data end # Do the join consumers.each {|t| t.join} end end end threach-0.2.0/features/0000755000175000017500000000000012577435633014700 5ustar mcrusoemcrusoethreach-0.2.0/features/threach.feature0000644000175000017500000000040312577435633017670 0ustar mcrusoemcrusoeFeature: something something In order to something something A user something something something something something Scenario: something something Given inspiration When I create a sweet new gem Then everyone should see how awesome I am threach-0.2.0/features/support/0000755000175000017500000000000012577435633016414 5ustar mcrusoemcrusoethreach-0.2.0/features/support/env.rb0000644000175000017500000000021312577435633017525 0ustar mcrusoemcrusoe$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib') require 'threach' require 'test/unit/assertions' World(Test::Unit::Assertions) threach-0.2.0/features/step_definitions/0000755000175000017500000000000012577435633020246 5ustar mcrusoemcrusoethreach-0.2.0/features/step_definitions/threach_steps.rb0000644000175000017500000000000012577435633023415 0ustar mcrusoemcrusoethreach-0.2.0/VERSION0000644000175000017500000000000612577435633014126 0ustar mcrusoemcrusoe0.2.0 threach-0.2.0/Rakefile0000644000175000017500000000337312577435633014535 0ustar mcrusoemcrusoerequire 'rubygems' require 'rake' begin require 'jeweler' Jeweler::Tasks.new do |gem| gem.name = "threach" gem.summary = %Q{Threaded each} gem.description = %Q{An addition to the Enumerable module that allows easy use of threaded each and each-like iterators} gem.email = "bill@dueber.com" gem.homepage = "http://github.com/billdueber/threach" gem.authors = ["Bill Dueber"] gem.add_development_dependency "thoughtbot-shoulda", ">= 0" gem.add_development_dependency "yard", ">= 0" gem.add_development_dependency "cucumber", ">= 0" # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings end Jeweler::GemcutterTasks.new rescue LoadError puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler" end require 'rake/testtask' Rake::TestTask.new(:test) do |test| test.libs << 'lib' << 'test' test.pattern = 'test/**/test_*.rb' test.verbose = true end begin require 'rcov/rcovtask' Rcov::RcovTask.new do |test| test.libs << 'test' test.pattern = 'test/**/test_*.rb' test.verbose = true end rescue LoadError task :rcov do abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov" end end task :test => :check_dependencies begin require 'cucumber/rake/task' Cucumber::Rake::Task.new(:features) task :features => :check_dependencies rescue LoadError task :features do abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber" end end task :default => :test begin require 'yard' YARD::Rake::YardocTask.new rescue LoadError task :yardoc do abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard" end end threach-0.2.0/README.markdown0000644000175000017500000000712512577435633015570 0ustar mcrusoemcrusoe# threach `threach` adds to the Enumerable module to provide a threaded version of whatever enumerator you throw at it (`each` by default). ## Warning: Deadlocks under JRuby if an exception is thrown `threach` works fine, so long as nothing goes wrong. In particular, there's no safe way (that I can find; see below) to break out of a `threach` loop without a deadlock under JRuby. This is, shall we say, an Issue. Under vanilla ruby, `threach` will exit as expected, but who the hell wants to use `threach` where there are no real threads??? ## Installation `threach` is on rubygems.org, so you should just be able to do gem install threach # or jruby -S gem install threach ## Use # You like #each? You'll love...err.."probably like" #threach require 'rubygems' require 'threach' # Process with 2 threads. It assumes you want 'each' # as your iterator. (1..10).threach(2) {|i| puts i.to_s} # You can also specify the iterator File.open('mybigfile') do |f| f.threach(2, :each_line) do |line| processLine(line) end end # threach does not care what the arity of your block is # as long as it matches the iterator you ask for ('A'..'Z').threach(3, :each_with_index) do |letter, index| puts "#{index}: #{letter}" end # Or with a hash h = {'a' => 1, 'b'=>2, 'c'=>3} h.threach(2) do |letter, i| puts "#{i}: #{letter}" end ## Major problem I can't figure out how to exit gracefully from a threach loop. begin ('a'..'z').threach(2, :each_with_index) do |letter, i| break if i > 10 # will deadlock under jruby; fine under ruby # raise StandardError if i > 10 # deadlock under jruby; find under ruby puts letter end rescue puts "Rescued; broke out of the loop" end The `break` under jruby prints "Exception in thread "Thread-1" org.jruby.exceptions.JumpException$BreakJump," but if there's a way to catch that in the enclosing code I sure don't know how. Use of `catch` and `throw` seemed like an obvious choice, but they don't work across threads. Then I thought I'd use `catch` within the consumers and throw or raise an error at the producer, but that doesn't work, either. I'm clearly up against (or well beyond) my knowledge limitations, here. If anyone has a solution to what should be a simple problem (and works under both ruby and jruby) boy, would I be grateful. ## Why and when to use it? Well, if you're using stock (MRI) ruby -- you probably shouldn't bother with `threach`. It'll just slow things down. But if you're using a ruby implementation that has real threads, like JRuby, this will give you relatively painless multi-threading. You can always do something like: if defined? JRUBY_VERSION numthreads = 3 else numthreads = 0 end my_enumerable.threach(numthreads) {|i| ...} Note the "relatively" in front of "painless" up there. The block you pass still has to be thread-safe, and there are many data structures you'll encounter that are *not* thread-safe. Scalars, arrays, and hashes are, though, under JRuby, and that'll get you pretty far. ## Note on Patches/Pull Requests * Fork the project. * Make your feature addition or bug fix. * Add tests for it. This is important so I don't break it in a future version unintentionally. * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) * Send me a pull request. Bonus points for topic branches. ## Copyright Copyright (c) 2010 Bill Dueber. See LICENSE for details. threach-0.2.0/LICENSE0000644000175000017500000000203712577435633014071 0ustar mcrusoemcrusoeCopyright (c) 2009 Bill Dueber Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. threach-0.2.0/.gitignore0000644000175000017500000000022212577435633015046 0ustar mcrusoemcrusoe## MAC OS .DS_Store ## TEXTMATE *.tmproj tmtags ## EMACS *~ \#* .\#* ## VIM *.swp ## PROJECT::GENERAL coverage rdoc pkg ## PROJECT::SPECIFIC threach-0.2.0/.document0000644000175000017500000000007412577435633014702 0ustar mcrusoemcrusoeREADME.rdoc lib/**/*.rb bin/* features/**/*.feature LICENSE