diff --git a/CHANGELOG.md b/CHANGELOG.md index 593a6eb2d465..a031eae5f1f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Compatibility: * Do not autosplat a proc that accepts a single positional argument and keywords (#3039, @andrykonchin). * Support passing anonymous * and ** parameters as method call arguments (#3039, @andrykonchin). * Handle either positional or keywords arguments by default in `Struct.new` (#3039, @rwstauner). +* Promote `Set` class to core library (#3039, @andrykonchin). Performance: diff --git a/spec/ruby/core/enumerable/fixtures/classes.rb b/spec/ruby/core/enumerable/fixtures/classes.rb index fb4951c6e626..2701c6999c43 100644 --- a/spec/ruby/core/enumerable/fixtures/classes.rb +++ b/spec/ruby/core/enumerable/fixtures/classes.rb @@ -342,4 +342,10 @@ def ===(*args) @block.call(*args) end end + + # Set is a core class since Ruby 3.2 + ruby_version_is '3.2' do + class SetSubclass < Set + end + end end # EnumerableSpecs utility classes diff --git a/spec/ruby/core/enumerable/to_set_spec.rb b/spec/ruby/core/enumerable/to_set_spec.rb new file mode 100644 index 000000000000..c21a2772c478 --- /dev/null +++ b/spec/ruby/core/enumerable/to_set_spec.rb @@ -0,0 +1,29 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "3.2" do + describe "Enumerable#to_set" do + it "returns a new Set created from self" do + [1, 2, 3].to_set.should == Set[1, 2, 3] + {a: 1, b: 2}.to_set.should == Set[[:b, 2], [:a, 1]] + end + + it "passes down passed blocks" do + [1, 2, 3].to_set { |x| x * x }.should == Set[1, 4, 9] + end + + it "instantiates an object of provided as the first argument set class" do + set = [1, 2, 3].to_set(EnumerableSpecs::SetSubclass) + set.should be_kind_of(EnumerableSpecs::SetSubclass) + set.to_a.sort.should == [1, 2, 3] + end + + it "does not need explicit `require 'set'`" do + output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1') + puts [1, 2, 3].to_set + RUBY + + output.chomp.should == "#" + end + end +end diff --git a/spec/ruby/library/set/set_spec.rb b/spec/ruby/library/set/set_spec.rb new file mode 100644 index 000000000000..b4d8045d21af --- /dev/null +++ b/spec/ruby/library/set/set_spec.rb @@ -0,0 +1,12 @@ +require_relative '../../spec_helper' + +describe 'Set' do + ruby_version_is '3.2' do + it 'is available without explicit requiring' do + output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1') + puts Set.new([1, 2, 3]) + RUBY + output.chomp.should == "#" + end + end +end \ No newline at end of file diff --git a/spec/tags/core/enumerable/to_set_tags.txt b/spec/tags/core/enumerable/to_set_tags.txt new file mode 100644 index 000000000000..82e107cac6ad --- /dev/null +++ b/spec/tags/core/enumerable/to_set_tags.txt @@ -0,0 +1 @@ +slow:Enumerable#to_set does not need explicit `require 'set'` diff --git a/spec/tags/library/set/set_tags.txt b/spec/tags/library/set/set_tags.txt new file mode 100644 index 000000000000..4e1f64012047 --- /dev/null +++ b/spec/tags/library/set/set_tags.txt @@ -0,0 +1 @@ +slow:Set is available without explicit requiring diff --git a/src/main/ruby/truffleruby/core/enumerable.rb b/src/main/ruby/truffleruby/core/enumerable.rb index a18e90fe8e54..ebd5e2e12cd7 100644 --- a/src/main/ruby/truffleruby/core/enumerable.rb +++ b/src/main/ruby/truffleruby/core/enumerable.rb @@ -332,6 +332,10 @@ def to_h(*arg) h end + def to_set(klass = Set, ...) + klass.new(self, ...) + end + # Synchronize with Enumerator#zip and Array#zip def zip(*enums) enums.map! do |enum| diff --git a/src/main/ruby/truffleruby/core/post.rb b/src/main/ruby/truffleruby/core/post.rb index 2b572f1f5fcf..370bb8ff417d 100644 --- a/src/main/ruby/truffleruby/core/post.rb +++ b/src/main/ruby/truffleruby/core/post.rb @@ -112,3 +112,8 @@ def p(*a) $LOAD_PATH.unshift(*extra_load_paths.map { |path| File.expand_path(path) }) end end + +# Set class is in the core library but it's still possible to require it as a standard +# library with `require`. So it doesn't make sense to have two copies of the same code +# and it's easier just to autoload CRuby's provided source file here. +autoload :Set, 'set' diff --git a/src/main/ruby/truffleruby/core/truffle/versioned_array.rb b/src/main/ruby/truffleruby/core/truffle/versioned_array.rb index 142abc942356..1f981ae88723 100644 --- a/src/main/ruby/truffleruby/core/truffle/versioned_array.rb +++ b/src/main/ruby/truffleruby/core/truffle/versioned_array.rb @@ -655,6 +655,11 @@ def to_s(*args, &block) copy.to_s(*args, &block) end + def to_set(*args, &block) + copy = TruffleRuby.synchronized(@lock) { Array.new self } + copy.to_set(*args, &block) + end + def transpose(*args, &block) copy = TruffleRuby.synchronized(@lock) { Array.new self } copy.transpose(*args, &block)