Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions compar.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,13 @@ cmpint(VALUE x, VALUE y)

/*
* call-seq:
* obj > other -> true or false
* self > other -> true or false
*
* Compares two objects based on the receiver's <code><=></code>
* method, returning true if it returns a value greater than 0.
* Returns whether +self+ is "greater than" +other+;
* equivalent to <tt>(self <=> other) > 0</tt>:
*
* 'foo' > 'foo' # => false
* 'food' > 'foo' # => true
*/

static VALUE
Expand Down
167 changes: 92 additions & 75 deletions enumerator.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,79 +34,93 @@
/*
* Document-class: Enumerator
*
* A class which allows both internal and external iteration.
* \Class \Enumerator supports:
*
* An Enumerator can be created by the following methods.
* - Object#to_enum
* - Object#enum_for
* - Enumerator.new
* - {External iteration}[rdoc-ref:Enumerator@External+Iteration].
* - {Internal iteration}[rdoc-ref:Enumerator@Internal+Iteration].
*
* Most methods have two forms: a block form where the contents
* are evaluated for each item in the enumeration, and a non-block form
* which returns a new Enumerator wrapping the iteration.
* An \Enumerator may be created by the following methods:
*
* enumerator = %w(one two three).each
* puts enumerator.class # => Enumerator
* - Object#to_enum.
* - Object#enum_for.
* - Enumerator.new.
*
* enumerator.each_with_object("foo") do |item, obj|
* puts "#{obj}: #{item}"
* end
* In addition, certain Ruby methods return \Enumerator objects:
* a Ruby iterator method that accepts a block
* may return an \Enumerator if no block is given.
* There are many such methods, for example, in classes Array and Hash.
* (In the documentation for those classes, search for `new_enumerator`.)
*
* # foo: one
* # foo: two
* # foo: three
* == Internal Iteration
*
* enum_with_obj = enumerator.each_with_object("foo")
* puts enum_with_obj.class # => Enumerator
* In _internal iteration_, an iterator method drives the iteration
* and the caller's block handles the processing;
* this example uses method #each_with_index:
*
* enum_with_obj.each do |item, obj|
* puts "#{obj}: #{item}"
* end
* words = %w[foo bar baz] # => ["foo", "bar", "baz"]
* enumerator = words.each # => #<Enumerator: ...>
* enumerator.each_with_index {|word, i| puts "#{i}: #{word}" }
* 0: foo
* 1: bar
* 2: baz
*
* # foo: one
* # foo: two
* # foo: three
* Iterator methods in class \Enumerator include:
*
* This allows you to chain Enumerators together. For example, you
* can map a list's elements to strings containing the index
* and the element as a string via:
* - #each:
* passes each item to the block.
* - #each_with_index:
* passes each item and its index to the block.
* - #each_with_object (aliased as #with_object):
* passes each item and a given object to the block.
* - #with_index:
* like #each_with_index, but starting at a given offset (instead of zero).
*
* puts %w[foo bar baz].map.with_index { |w, i| "#{i}:#{w}" }
* # => ["0:foo", "1:bar", "2:baz"]
* \Class \Enumerator includes module Enumerable,
* which provides many more iterator methods.
*
* == External Iteration
*
* An Enumerator can also be used as an external iterator.
* For example, Enumerator#next returns the next value of the iterator
* or raises StopIteration if the Enumerator is at the end.
*
* e = [1,2,3].each # returns an enumerator object.
* puts e.next # => 1
* puts e.next # => 2
* puts e.next # => 3
* puts e.next # raises StopIteration
*
* +next+, +next_values+, +peek+, and +peek_values+ are the only methods
* which use external iteration (and Array#zip(Enumerable-not-Array) which uses +next+ internally).
*
* These methods do not affect other internal enumeration methods,
* unless the underlying iteration method itself has side-effect, e.g. IO#each_line.
*
* FrozenError will be raised if these methods are called against a frozen enumerator.
* Since +rewind+ and +feed+ also change state for external iteration,
* these methods may raise FrozenError too.
*
* External iteration differs *significantly* from internal iteration
* due to using a Fiber:
* - The Fiber adds some overhead compared to internal enumeration.
* - The stacktrace will only include the stack from the Enumerator, not above.
* - Fiber-local variables are *not* inherited inside the Enumerator Fiber,
* which instead starts with no Fiber-local variables.
* - Fiber storage variables *are* inherited and are designed
* to handle Enumerator Fibers. Assigning to a Fiber storage variable
* only affects the current Fiber, so if you want to change state
* in the caller Fiber of the Enumerator Fiber, you need to use an
* extra indirection (e.g., use some object in the Fiber storage
* In _external iteration_, the user's program both drives the iteration
* and handles the processing in stream-like fashion;
* this example uses method #next:
*
* words = %w[foo bar baz]
* enumerator = words.each
* enumerator.next # => "foo"
* enumerator.next # => "bar"
* enumerator.next # => "baz"
* enumerator.next # Raises StopIteration: iteration reached an end
*
* External iteration methods in class \Enumerator include:
*
* - #feed:
* sets the value that is next to be returned.
* - #next:
* returns the next value and increments the position.
* - #next_values:
* returns the next value in a 1-element array and increments the position.
* - #peek:
* returns the next value but does not increment the position.
* - #peek_values:
* returns the next value in a 1-element array but does not increment the position.
* - #rewind:
* sets the position to zero.
*
* Each of these methods raises FrozenError if called from a frozen \Enumerator.
*
* == External Iteration and \Fiber
*
* External iteration that uses Fiber differs *significantly* from internal iteration:
*
* - Using \Fiber adds some overhead compared to internal enumeration.
* - The stacktrace will only include the stack from the \Enumerator, not above.
* - \Fiber-local variables are *not* inherited inside the \Enumerator \Fiber,
* which instead starts with no \Fiber-local variables.
* - \Fiber storage variables *are* inherited and are designed
* to handle \Enumerator Fibers. Assigning to a \Fiber storage variable
* only affects the current \Fiber, so if you want to change state
* in the caller \Fiber of the \Enumerator \Fiber, you need to use an
* extra indirection (e.g., use some object in the \Fiber storage
* variable and mutate some ivar of it).
*
* Concretely:
Expand All @@ -126,7 +140,7 @@
* e.each { p _1 }
* p Fiber[:storage_var] # => 2 (it ran in the same Fiber/"stack" as the current Fiber)
*
* == Convert External Iteration to Internal Iteration
* == Converting External Iteration to Internal Iteration
*
* You can use an external iterator to implement an internal iterator as follows:
*
Expand Down Expand Up @@ -445,28 +459,31 @@ convert_to_feasible_size_value(VALUE obj)

/*
* call-seq:
* Enumerator.new(size = nil) { |yielder| ... }
* Enumerator.new(size = nil) {|yielder| ... }
*
* Creates a new Enumerator object, which can be used as an
* Enumerable.
* Returns a new \Enumerator object that can be used for iteration.
*
* Iteration is defined by the given block, in
* which a "yielder" object, given as block parameter, can be used to
* yield a value by calling the +yield+ method (aliased as <code><<</code>):
* The given block defines the iteration;
* it is called with a "yielder" object that can yield an object
* via a call to method <tt>yielder.yield</tt>:
*
* fib = Enumerator.new do |y|
* a = b = 1
* loop do
* y << a
* a, b = b, a + b
* fib = Enumerator.new do |yielder|
* n = next_n = 1
* while true do
* yielder.yield(n)
* n, next_n = next_n, n + next_n
* end
* end
*
* fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
*
* The optional parameter can be used to specify how to calculate the size
* in a lazy fashion (see Enumerator#size). It can either be a value or
* a callable object.
* Parameter +size+ specifies how the size is to be calculated (see #size);
* it can either be a value or a callable object:
*
* Enumerator.new{}.size # => nil
* Enumerator.new(42){}.size # => 42
* Enumerator.new(-> {42}){}.size # => 42
*
*/
static VALUE
enumerator_initialize(int argc, VALUE *argv, VALUE obj)
Expand Down
30 changes: 0 additions & 30 deletions ext/objspace/objspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,35 +336,6 @@ count_symbols(int argc, VALUE *argv, VALUE os)
return hash;
}

/*
* call-seq:
* ObjectSpace.count_nodes([result_hash]) -> hash
*
* Counts nodes for each node type.
*
* This method is only for MRI developers interested in performance and memory
* usage of Ruby programs.
*
* It returns a hash as:
*
* {:NODE_METHOD=>2027, :NODE_FBODY=>1927, :NODE_CFUNC=>1798, ...}
*
* If the optional argument, result_hash, is given, it is overwritten and
* returned. This is intended to avoid probe effect.
*
* Note:
* The contents of the returned hash is implementation defined.
* It may be changed in future.
*
* This method is only expected to work with C Ruby.
*/

static VALUE
count_nodes(int argc, VALUE *argv, VALUE os)
{
return setup_hash(argc, argv);
}

static void
cto_i(VALUE v, void *data)
{
Expand Down Expand Up @@ -834,7 +805,6 @@ Init_objspace(void)

rb_define_module_function(rb_mObjSpace, "count_objects_size", count_objects_size, -1);
rb_define_module_function(rb_mObjSpace, "count_symbols", count_symbols, -1);
rb_define_module_function(rb_mObjSpace, "count_nodes", count_nodes, -1);
rb_define_module_function(rb_mObjSpace, "count_tdata_objects", count_tdata_objects, -1);
rb_define_module_function(rb_mObjSpace, "count_imemo_objects", count_imemo_objects, -1);

Expand Down
5 changes: 2 additions & 3 deletions hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -4971,10 +4971,9 @@ rb_hash_ge(VALUE hash, VALUE other)

/*
* call-seq:
* self > other_hash -> true or false
* self > other -> true or false
*
* Returns +true+ if the entries of +self+ are a proper superset of the entries of +other_hash+,
* +false+ otherwise:
* Returns whether the entries of +self+ are a proper superset of the entries of +other+:
*
* h = {foo: 0, bar: 1, baz: 2}
* h > {foo: 0, bar: 1} # => true # Proper superset.
Expand Down
6 changes: 4 additions & 2 deletions numeric.c
Original file line number Diff line number Diff line change
Expand Up @@ -1638,7 +1638,8 @@ rb_float_cmp(VALUE x, VALUE y)
* call-seq:
* self > other -> true or false
*
* Returns +true+ if +self+ is numerically greater than +other+:
* Returns whether the value of +self+ is greater than the value of +other+;
* +other+ must be numeric, but may not be Complex:
*
* 2.0 > 1 # => true
* 2.0 > 1.0 # => true
Expand Down Expand Up @@ -4958,7 +4959,8 @@ fix_gt(VALUE x, VALUE y)
* call-seq:
* self > other -> true or false
*
* Returns +true+ if the value of +self+ is greater than that of +other+:
* Returns whether the value of +self+ is greater than the value of +other+;
* +other+ must be numeric, but may not be Complex:
*
* 1 > 0 # => true
* 1 > 1 # => false
Expand Down
23 changes: 16 additions & 7 deletions object.c
Original file line number Diff line number Diff line change
Expand Up @@ -2009,14 +2009,23 @@ rb_mod_ge(VALUE mod, VALUE arg)

/*
* call-seq:
* mod > other -> true, false, or nil
* self > other -> true, false, or nil
*
* Returns true if <i>mod</i> is an ancestor of <i>other</i>. Returns
* <code>false</code> if <i>mod</i> is the same as <i>other</i>
* or <i>mod</i> is a descendant of <i>other</i>.
* Returns <code>nil</code> if there's no relationship between the two.
* (Think of the relationship in terms of the class definition:
* "class A < B" implies "B > A".)
* If +self+ is a class, returns +true+ if +self+ is a superclass of +other+,
* returns +false+ if +self+ is the same as +other+ or if +self+ is a subclass
* of +other+, and returns +nil+ if there are no relationship between the two:
*
* Numeric > Float # => true
* Float > Numeric # => false
* Float > Float # => false
* Float > Hash # => nil
*
* If +self+ is a module, returns +true+ if +other+ includes +self+,
* returns +false+ if +self+ is the same as +other+ or if +self+ includes
* +other+, and returns +nil+ if there are no relationship between the two:
*
* Enumerable > Array # => true
* Enumerable > String # => nil
*
*/

Expand Down
10 changes: 0 additions & 10 deletions test/objspace/test_objspace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,6 @@ def test_count_objects_size_with_wrong_type
assert_raise(TypeError) { ObjectSpace.count_objects_size(0) }
end

def test_count_nodes
res = ObjectSpace.count_nodes
assert_not_empty(res)
arg = {}
ObjectSpace.count_nodes(arg)
assert_not_empty(arg)
bug8014 = '[ruby-core:53130] [Bug #8014]'
assert_empty(arg.select {|k, v| !(Symbol === k && Integer === v)}, bug8014)
end if false

def test_count_tdata_objects
res = ObjectSpace.count_tdata_objects
assert_not_empty(res)
Expand Down
20 changes: 20 additions & 0 deletions test/ruby/test_yjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,26 @@ def foo(obj)
RUBY
end

def test_struct_aset_guards_recv_is_not_frozen
assert_compiles(<<~RUBY, result: :ok, exits: { opt_send_without_block: 1 })
def foo(obj)
obj.foo = 123
end

Foo = Struct.new(:foo)
obj = Foo.new(123)
100.times do
foo(obj)
end
obj.freeze
begin
foo(obj)
rescue FrozenError
:ok
end
RUBY
end

def test_getblockparam
assert_compiles(<<~'RUBY', insns: [:getblockparam])
def foo &blk
Expand Down
3 changes: 3 additions & 0 deletions tool/rbs_skip_tests
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ TestInstanceNetHTTPResponse depending on external resources

test_TOPDIR(RbConfigSingletonTest) `TOPDIR` is `nil` during CI while RBS type is declared as `String`

# Failing because ObjectSpace.count_nodes has been removed
test_count_nodes(ObjectSpaceTest)

## Unknown failures

# NoMethodError: undefined method 'inspect' for an instance of RBS::UnitTest::Convertibles::ToInt
Expand Down
Loading