Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: ef6d89a3491e
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 1dc7967b4f74
Choose a head ref
  • 2 commits
  • 2 files changed
  • 2 contributors

Commits on Dec 12, 2015

  1. [ruby-2.3] Feature #10984 - Hash comparison operators

    Implements Hash#<=, #<, #>=, #>
    
    I'd like review on RubyHash.hash_le to make sure it's implemented as efficiently as possible.
    cheald committed Dec 12, 2015
    Copy the full SHA
    f12fb11 View commit details
  2. Merge pull request #3533 from cheald/hash_cmp

    [ruby-2.3] Feature #10984 - Hash comparison operators
    enebo committed Dec 12, 2015
    Copy the full SHA
    1dc7967 View commit details
Showing with 70 additions and 0 deletions.
  1. +45 −0 core/src/main/java/org/jruby/RubyHash.java
  2. +25 −0 test/mri/ruby/test_hash.rb
45 changes: 45 additions & 0 deletions core/src/main/java/org/jruby/RubyHash.java
Original file line number Diff line number Diff line change
@@ -1212,6 +1212,51 @@ public IRubyObject op_aref(ThreadContext context, IRubyObject key) {
return ((value = internalGet(key)) == null) ? invokedynamic(context, this, DEFAULT, key) : value;
}

/** hash_le_i
*
*/
private boolean hash_le(RubyHash other) {
RubyArray keys = keys();
for (Object key : keys) {
if (!other.get(key).equals( get(key) )) {
return false;
}
}
return true;
}

@JRubyMethod(name = "<", required = 1)
public IRubyObject op_lt(ThreadContext context, IRubyObject other) {
final RubyHash otherHash = other.convertToHash();
if (size() >= otherHash.size()) {
return RubyBoolean.newBoolean(context.runtime, false);
}

return RubyBoolean.newBoolean(context.runtime, hash_le(otherHash));
}

@JRubyMethod(name = "<=", required = 1)
public IRubyObject op_le(ThreadContext context, IRubyObject other) {
final RubyHash otherHash = other.convertToHash();
if (size() > otherHash.size()) {
return RubyBoolean.newBoolean(context.runtime, false);
}

return RubyBoolean.newBoolean(context.runtime, hash_le(otherHash));
}

@JRubyMethod(name = ">", required = 1)
public IRubyObject op_gt(ThreadContext context, IRubyObject other) {
final RubyHash otherHash = other.convertToHash();
return otherHash.op_lt(context, this);
}

@JRubyMethod(name = ">=", required = 1)
public IRubyObject op_ge(ThreadContext context, IRubyObject other) {
final RubyHash otherHash = other.convertToHash();
return otherHash.op_le(context, this);
}

/** rb_hash_hash
*
*/
25 changes: 25 additions & 0 deletions test/mri/ruby/test_hash.rb
Original file line number Diff line number Diff line change
@@ -1286,6 +1286,31 @@ def test_label_syntax
assert_equal({:foo => 1, :'foo-bar' => 2, :'hello-world' => 3, :'hello-#{x}' => 4, :bar => {}}, hash)
end

def test_cmp
h1 = {a:1, b:2}
h2 = {a:1, b:2, c:3}

assert_operator(h1, :<=, h1)
assert_operator(h1, :<=, h2)
assert_not_operator(h2, :<=, h1)
assert_operator(h2, :<=, h2)

assert_operator(h1, :>=, h1)
assert_not_operator(h1, :>=, h2)
assert_operator(h2, :>=, h1)
assert_operator(h2, :>=, h2)

assert_not_operator(h1, :<, h1)
assert_operator(h1, :<, h2)
assert_not_operator(h2, :<, h1)
assert_not_operator(h2, :<, h2)

assert_not_operator(h1, :>, h1)
assert_not_operator(h1, :>, h2)
assert_operator(h2, :>, h1)
assert_not_operator(h2, :>, h2)
end

class TestSubHash < TestHash
class SubHash < Hash
def reject(*)