diff --git a/README.md b/README.md index 74df22078..1ad625c84 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,6 @@ This library contains a variety of concurrency abstractions at high and low leve ### High-level, general-purpose asynchronous concurrency abstractions -* [Actor](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Actor.html): Implements the Actor Model, where concurrent actors exchange messages. * [Agent](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Agent.html): A single atomic value that represents an identity. * [Async](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Async.html): A mixin module that provides simple asynchronous behavior to any standard class/object or object. * [Future](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Future.html): An asynchronous operation that produces a value. @@ -60,7 +59,6 @@ This library contains a variety of concurrency abstractions at high and low leve * [Promise](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Promise.html): Similar to Futures, with more features. * [ScheduledTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ScheduledTask.html): Like a Future scheduled for a specific future time. * [TimerTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TimerTask.html): A Thread that periodically wakes up to perform work at regular intervals. -* [Channel](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Channel.html): Communicating Sequential Processes (CSP). ### Java-inspired ThreadPools and other executors @@ -90,6 +88,19 @@ This library contains a variety of concurrency abstractions at high and low leve * [Software transactional memory](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TVar.html) (TVar) * [ReadWriteLock](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ReadWriteLock.html) +### Edge features + +They are available in the `concurrent-ruby-edge` companion gem, install with `gem install concurrent-ruby-edge`. + +These features are under active development and may change frequently. They are expected not to +keep backward compatibility (there may also lack tests and documentation). Semantic versions will +be obeyed though. Features developed in `concurrent-ruby-edge` are expected to move to `concurrent-ruby` when final. + +* [Actor](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Actor.html): + Implements the Actor Model, where concurrent actors exchange messages. +* [Channel](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Channel.html): + Communicating Sequential Processes (CSP). + ## Usage All abstractions within this gem can be loaded simply by requiring it: @@ -105,9 +116,7 @@ require 'concurrent' # everything # groups -require 'concurrent/actor' # Concurrent::Actor and supporting code require 'concurrent/atomics' # atomic and thread synchronization classes -require 'concurrent/channels' # Concurrent::Channel and supporting code require 'concurrent/executors' # Thread pools and other executors require 'concurrent/utilities' # utility methods such as processor count and timers @@ -127,6 +136,11 @@ require 'concurrent/promise' # Concurrent::Promise require 'concurrent/scheduled_task' # Concurrent::ScheduledTask require 'concurrent/timer_task' # Concurrent::TimerTask require 'concurrent/tvar' # Concurrent::TVar + +# experimental - available in `concurrent-ruby-edge` companion gem + +require 'concurrent/actor' # Concurrent::Actor and supporting code +require 'concurrent/channel ' # Concurrent::Channel and supporting code ``` ## Installation @@ -147,8 +161,8 @@ and run `bundle install` from your shell. Potential performance improvements may be achieved under MRI by installing optional C extensions. To minimize installation errors the C extensions are available in the `concurrent-ruby-ext` extension -gem. The extension gem lists `concurrent-ruby` as a dependency so it is not necessary to install both. -Simply install the extension gen: +gem. `concurrent-ruby` and `concurrent-ruby-ext` are always released together with same version. +Simply install the extension gen too: ```ruby gem install concurrent-ruby-ext diff --git a/Rakefile b/Rakefile index 735254f29..7429f4a8b 100644 --- a/Rakefile +++ b/Rakefile @@ -1,23 +1,27 @@ #!/usr/bin/env rake +require_relative './lib/concurrent/version' require_relative './lib/extension_helper' ## load the two gemspec files CORE_GEMSPEC = Gem::Specification.load('concurrent-ruby.gemspec') EXT_GEMSPEC = Gem::Specification.load('concurrent-ruby-ext.gemspec') +EDGE_GEMSPEC = Gem::Specification.load('concurrent-ruby-edge.gemspec') ## constants used for compile/build tasks GEM_NAME = 'concurrent-ruby' -EXTENSION_NAME = 'extension' +EXT_NAME = 'extension' +EDGE_NAME = 'edge' JAVA_EXT_NAME = 'concurrent_ruby_ext' if Concurrent.jruby? CORE_GEM = "#{GEM_NAME}-#{Concurrent::VERSION}-java.gem" else CORE_GEM = "#{GEM_NAME}-#{Concurrent::VERSION}.gem" - EXTENSION_GEM = "#{GEM_NAME}-ext-#{Concurrent::VERSION}.gem" + EXT_GEM = "#{GEM_NAME}-ext-#{Concurrent::VERSION}.gem" NATIVE_GEM = "#{GEM_NAME}-ext-#{Concurrent::VERSION}-#{Gem::Platform.new(RUBY_PLATFORM)}.gem" + EDGE_GEM = "#{GEM_NAME}-edge-#{Concurrent::EDGE_VERSION}.gem" end ## safely load all the rake tasks in the `tasks` directory @@ -49,7 +53,7 @@ elsif Concurrent.allow_c_extensions? ## create the compile tasks for the extension gem require 'rake/extensiontask' - Rake::ExtensionTask.new(EXTENSION_NAME, EXT_GEMSPEC) do |ext| + Rake::ExtensionTask.new(EXT_NAME, EXT_GEMSPEC) do |ext| ext.ext_dir = 'ext/concurrent' ext.lib_dir = 'lib/concurrent' ext.source_pattern = '*.{c,h}' @@ -63,9 +67,9 @@ elsif Concurrent.allow_c_extensions? 'x64-mingw32' => 'x86_64-w64-mingw32' } platforms.each do |platform, prefix| - task "copy:#{EXTENSION_NAME}:#{platform}:#{ruby_version}" do |t| + task "copy:#{EXT_NAME}:#{platform}:#{ruby_version}" do |t| %w[lib tmp/#{platform}/stage/lib].each do |dir| - so_file = "#{dir}/#{ruby_version[/^\d+\.\d+/]}/#{EXTENSION_NAME}.so" + so_file = "#{dir}/#{ruby_version[/^\d+\.\d+/]}/#{EXT_NAME}.so" if File.exists?(so_file) sh "#{prefix}-strip -S #{so_file}" end @@ -94,7 +98,11 @@ end namespace :build do - build_deps = [:clean] + task :mkdir_pkg do + mkdir_p 'pkg' + end + + build_deps = [:clean, 'build:mkdir_pkg'] build_deps << :compile if Concurrent.jruby? desc "Build #{CORE_GEM} into the pkg directory" @@ -104,8 +112,15 @@ namespace :build do end unless Concurrent.jruby? - desc "Build #{EXTENSION_GEM} into the pkg directory" - task :ext => [:clean] do + + desc "Build #{EDGE_GEM} into the pkg directory" + task :edge => 'build:mkdir_pkg' do + sh "gem build #{EDGE_GEMSPEC.name}.gemspec" + sh 'mv *.gem pkg/' + end + + desc "Build #{EXT_GEM} into the pkg directory" + task :ext => build_deps do sh "gem build #{EXT_GEMSPEC.name}.gemspec" sh 'mv *.gem pkg/' end @@ -113,8 +128,8 @@ namespace :build do if Concurrent.allow_c_extensions? desc "Build #{NATIVE_GEM} into the pkg directory" - task :native do - sh "gem compile pkg/#{EXTENSION_GEM}" + task :native => 'build:mkdir_pkg' do + sh "gem compile pkg/#{EXT_GEM}" sh 'mv *.gem pkg/' end end @@ -124,8 +139,8 @@ if Concurrent.jruby? desc 'Build JRuby-specific core gem (alias for `build:core`)' task :build => ['build:core'] else - desc 'Build core and extension gems' - task :build => ['build:core', 'build:ext'] + desc 'Build core, extension, and edge gems' + task :build => ['build:core', 'build:ext', 'build:edge'] end ## the RSpec task that compiles extensions when available diff --git a/concurrent-ruby-edge.gemspec b/concurrent-ruby-edge.gemspec new file mode 100644 index 000000000..a43fe8385 --- /dev/null +++ b/concurrent-ruby-edge.gemspec @@ -0,0 +1,31 @@ +$:.push File.join(File.dirname(__FILE__), 'lib') + +require 'concurrent/version' +require 'concurrent/file_map' + +Gem::Specification.new do |s| + git_files = `git ls-files`.split("\n") + + s.name = 'concurrent-ruby-edge' + s.version = Concurrent::EDGE_VERSION + s.platform = Gem::Platform::RUBY + s.authors = ["Jerry D'Antonio", 'The Ruby Concurrency Team'] + s.email = ['jerry.dantonio@gmail.com', 'concurrent-ruby@googlegroups.com'] + s.homepage = 'http://www.concurrent-ruby.com' + s.summary = 'Edge features and additions to the concurrent-ruby gem.' + s.license = 'MIT' + s.date = Time.now.strftime('%Y-%m-%d') + s.files = Concurrent::FILE_MAP.fetch :edge + s.extra_rdoc_files = Dir['README*', 'LICENSE*'] + s.require_paths = ['lib'] + s.description = <<-TXT +These features are under active development and may change frequently. They are expected not to +keep backward compatibility (there may also lack tests and documentation). Semantic versions will +be obeyed though. Features developed in `concurrent-ruby-edge` are expected to move to `concurrent-ruby` when final. +Please see http://concurrent-ruby.com for more information. + TXT + + s.required_ruby_version = '>= 1.9.3' + + s.add_runtime_dependency 'concurrent-ruby', "~> #{Concurrent::VERSION}" +end diff --git a/concurrent-ruby.gemspec b/concurrent-ruby.gemspec index d4e306560..b7b587359 100644 --- a/concurrent-ruby.gemspec +++ b/concurrent-ruby.gemspec @@ -1,29 +1,30 @@ $:.push File.join(File.dirname(__FILE__), 'lib') require 'concurrent/version' +require 'concurrent/file_map' Gem::Specification.new do |s| - s.name = 'concurrent-ruby' - s.version = Concurrent::VERSION - s.platform = Gem::Platform::RUBY - s.author = "Jerry D'Antonio" - s.email = 'jerry.dantonio@gmail.com' - s.homepage = 'http://www.concurrent-ruby.com' - s.summary = 'Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell, F#, C#, Java, and classic concurrency patterns.' - s.license = 'MIT' - s.date = Time.now.strftime('%Y-%m-%d') + git_files = `git ls-files`.split("\n") - s.description = <<-EOF - Modern concurrency tools including agents, futures, promises, thread pools, actors, supervisors, and more. - Inspired by Erlang, Clojure, Go, JavaScript, actors, and classic concurrency patterns. - EOF - - s.files = Dir['lib/**/*.rb'] + s.name = 'concurrent-ruby' + s.version = Concurrent::VERSION + s.platform = Gem::Platform::RUBY + s.authors = ["Jerry D'Antonio", 'The Ruby Concurrency Team'] + s.email = ['jerry.dantonio@gmail.com', 'concurrent-ruby@googlegroups.com'] + s.homepage = 'http://www.concurrent-ruby.com' + s.summary = 'Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell, F#, C#, Java, and classic concurrency patterns.' + s.license = 'MIT' + s.date = Time.now.strftime('%Y-%m-%d') + s.files = Concurrent::FILE_MAP.fetch :core s.extra_rdoc_files = Dir['README*', 'LICENSE*', 'CHANGELOG*'] s.require_paths = ['lib'] + s.description = <<-EOF +Modern concurrency tools including agents, futures, promises, thread pools, actors, supervisors, and more. +Inspired by Erlang, Clojure, Go, JavaScript, actors, and classic concurrency patterns. + EOF if defined?(JRUBY_VERSION) - s.files += Dir['lib/**/*.jar'] + s.files += Dir['lib/**/*.jar'] s.platform = 'java' else s.add_runtime_dependency 'ref', '~> 1.0', '>= 1.0.5' diff --git a/lib/concurrent-edge.rb b/lib/concurrent-edge.rb new file mode 100644 index 000000000..15352629b --- /dev/null +++ b/lib/concurrent-edge.rb @@ -0,0 +1,6 @@ +require 'concurrent' + +require 'concurrent/actor' +require 'concurrent/channel' + + diff --git a/lib/concurrent.rb b/lib/concurrent.rb index 48af73a6b..7cef42da8 100644 --- a/lib/concurrent.rb +++ b/lib/concurrent.rb @@ -2,9 +2,7 @@ require 'concurrent/configuration' -require 'concurrent/actor' require 'concurrent/atomics' -require 'concurrent/channels' require 'concurrent/collections' require 'concurrent/errors' require 'concurrent/executors' diff --git a/lib/concurrent/actress.rb b/lib/concurrent/actress.rb deleted file mode 100644 index f2cbcce54..000000000 --- a/lib/concurrent/actress.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'concurrent/actor' - -Concurrent::Actress = Concurrent::Actor diff --git a/lib/concurrent/channel.rb b/lib/concurrent/channel.rb new file mode 100644 index 000000000..7990c6300 --- /dev/null +++ b/lib/concurrent/channel.rb @@ -0,0 +1,6 @@ +require 'concurrent/channel/blocking_ring_buffer' +require 'concurrent/channel/buffered_channel' +require 'concurrent/channel/channel' +require 'concurrent/channel/ring_buffer' +require 'concurrent/channel/unbuffered_channel' +require 'concurrent/channel/waitable_list' diff --git a/lib/concurrent/collection/blocking_ring_buffer.rb b/lib/concurrent/channel/blocking_ring_buffer.rb similarity index 100% rename from lib/concurrent/collection/blocking_ring_buffer.rb rename to lib/concurrent/channel/blocking_ring_buffer.rb diff --git a/lib/concurrent/collection/ring_buffer.rb b/lib/concurrent/channel/ring_buffer.rb similarity index 100% rename from lib/concurrent/collection/ring_buffer.rb rename to lib/concurrent/channel/ring_buffer.rb diff --git a/lib/concurrent/channels.rb b/lib/concurrent/channels.rb deleted file mode 100644 index 36a49ec81..000000000 --- a/lib/concurrent/channels.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'concurrent/collections' - -require 'concurrent/channel/channel' -require 'concurrent/channel/unbuffered_channel' -require 'concurrent/channel/buffered_channel' diff --git a/lib/concurrent/collections.rb b/lib/concurrent/collections.rb index 3fbb09321..8f1e2bb04 100644 --- a/lib/concurrent/collections.rb +++ b/lib/concurrent/collections.rb @@ -1,3 +1 @@ require 'concurrent/collection/priority_queue' -require 'concurrent/collection/ring_buffer' -require 'concurrent/collection/blocking_ring_buffer' diff --git a/lib/concurrent/edge.rb b/lib/concurrent/edge.rb new file mode 100644 index 000000000..0b2fc182d --- /dev/null +++ b/lib/concurrent/edge.rb @@ -0,0 +1,24 @@ +module Concurrent + + # A submodule for unstable, highly experimental features that are likely to + # change often and which may never become part of the core gem. Also for + # new, experimental version of abstractions already in the core gem. + # + # Most new features should start in this module, clearly indicating the + # experimental and unstable nature of the feature. Once a feature becomes + # more stable and is a candidate for inclusion in the core gem it should + # be moved up to the `Concurrent` module, where it would reside once merged + # into the core gem. + # + # The only exception to this is for features which *replace* features from + # the core gem in ways that are breaking and not backward compatible. These + # features should remain in this module until merged into the core gem. This + # will prevent namespace collisions. + # + # This file should *never* be used as a global `require` for all files within + # the edge gem. Because these features are experimental users should always + # explicitly require only what they need. + module Edge + + end +end diff --git a/lib/concurrent/file_map.rb b/lib/concurrent/file_map.rb new file mode 100644 index 000000000..d2bff69f2 --- /dev/null +++ b/lib/concurrent/file_map.rb @@ -0,0 +1,16 @@ +module Concurrent + + git_files = `git ls-files`.split("\n") + all_lib_files = Dir['lib/concurrent/**/*.rb'] & git_files + edge_lib_files = Dir['lib/concurrent/actor.rb', + 'lib/concurrent/actor/**/*.rb', + 'lib/concurrent/channel.rb', + 'lib/concurrent/channel/**/*.rb'] & git_files + core_lib_files = all_lib_files - edge_lib_files + + FILE_MAP = { + core: core_lib_files + %w(lib/concurrent.rb lib/concurrent_ruby.rb), + edge: edge_lib_files + %w(lib/concurrent-edge.rb) + } +end + diff --git a/lib/concurrent/version.rb b/lib/concurrent/version.rb index 6124e5fe0..182ea0f24 100644 --- a/lib/concurrent/version.rb +++ b/lib/concurrent/version.rb @@ -1,3 +1,4 @@ module Concurrent - VERSION = '0.8.0' + VERSION = '0.8.0' + EDGE_VERSION = '0.1.0' end diff --git a/lib/concurrent_ruby.rb b/lib/concurrent_ruby.rb index 2e9e4f3ab..632aa33a3 100644 --- a/lib/concurrent_ruby.rb +++ b/lib/concurrent_ruby.rb @@ -1 +1,2 @@ +warn "'[DEPRECATED] use `require 'concurrent'` instead of `require 'concurrent_ruby'`" require 'concurrent' diff --git a/spec/concurrent/collection/blocking_ring_buffer_spec.rb b/spec/concurrent/channel/blocking_ring_buffer_spec.rb similarity index 100% rename from spec/concurrent/collection/blocking_ring_buffer_spec.rb rename to spec/concurrent/channel/blocking_ring_buffer_spec.rb diff --git a/spec/concurrent/collection/ring_buffer_spec.rb b/spec/concurrent/channel/ring_buffer_spec.rb similarity index 100% rename from spec/concurrent/collection/ring_buffer_spec.rb rename to spec/concurrent/channel/ring_buffer_spec.rb diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 9a893c615..eba05716c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -21,6 +21,8 @@ $VERBOSE = nil # suppress our deprecation warnings require 'concurrent' +require 'concurrent/actor' +require 'concurrent/channel' logger = Logger.new($stderr) logger.level = Logger::WARN