Skip to content

Commit

Permalink
MONGOID-5123 Fix methods incompatible with Ruby 3 (#5015)
Browse files Browse the repository at this point in the history
  • Loading branch information
comandeo-mongo committed Jul 21, 2021
1 parent dfc2be2 commit 6cc7001
Show file tree
Hide file tree
Showing 13 changed files with 71 additions and 11 deletions.
1 change: 1 addition & 0 deletions lib/mongoid.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require "forwardable"
require "time"
require "set"
require "ruby2_keywords"

require "active_support"
require "active_support/core_ext"
Expand Down
2 changes: 1 addition & 1 deletion lib/mongoid/association/embedded/embeds_many/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ def integrate(document)
# @param [ Proc ] block Optional block to pass.
#
# @return [ Criteria, Object ] A Criteria or return value from the target.
def method_missing(name, *args, &block)
ruby2_keywords def method_missing(name, *args, &block)
return super if _target.respond_to?(name)
klass.send(:with_scope, criteria) do
criteria.public_send(name, *args, &block)
Expand Down
4 changes: 2 additions & 2 deletions lib/mongoid/association/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,12 @@ def characterize_one(document)
# @param [ String, Symbol ] name The name of the method.
# @param [ Array ] args The arguments passed to the method.
#
def method_missing(name, *args, &block)
ruby2_keywords def method_missing(name, *args, &block)
_target.send(name, *args, &block)
end

# @api private
def respond_to_missing?(name, *args)
ruby2_keywords def respond_to_missing?(name, *args)
_target.respond_to?(name, *args)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/mongoid/association/referenced/has_many/enumerable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ def set_base(document)
end
end

def method_missing(name, *args, &block)
ruby2_keywords def method_missing(name, *args, &block)
entries.send(name, *args, &block)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/mongoid/association/referenced/has_many/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ def cascade!(document)
# @return [ Criteria, Object ] A Criteria or return value from the target.
#
# @since 2.0.0.beta.1
def method_missing(name, *args, &block)
ruby2_keywords def method_missing(name, *args, &block)
if _target.respond_to?(name)
_target.send(name, *args, &block)
else
Expand Down
2 changes: 1 addition & 1 deletion lib/mongoid/criteria.rb
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ def initialize_copy(other)
# @return [ Object ] The result of the method call.
#
# @since 1.0.0
def method_missing(name, *args, &block)
ruby2_keywords def method_missing(name, *args, &block)
if klass.respond_to?(name)
klass.send(:with_scope, self) do
klass.send(name, *args, &block)
Expand Down
2 changes: 1 addition & 1 deletion lib/mongoid/interceptable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def run_before_callbacks(*kinds)
# @return [ Document ] The document
#
# @since 2.3.0
def run_callbacks(kind, *args, &block)
ruby2_keywords def run_callbacks(kind, *args, &block)
cascadable_children(kind).each do |child|
if child.run_callbacks(child_callback_type(kind, child), *args) == false
return false
Expand Down
12 changes: 12 additions & 0 deletions mongoid.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ Gem::Specification.new do |s|
s.add_dependency("activemodel", [">=6.0", "<6.2"])
end
s.add_dependency("mongo", ['>=2.10.5', '<3.0.0'])
# Using this gem is recommended for handling argument delegation issues,
# especially if support for 2.6 or prior is required.
# See https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/#delegation
#
# We have a bunch of complex delegation logic, including various method_missngs.
# If we try to fix them "right", it will add too much logic. We will have to
# handle different Ruby versions (including minor ones, Ruby 2.6 and 2.7
# behave differently), hash key types (strings vs symbols), ways of passing
# arguments (with curly braces vs without ones).
#
# Therefore, usage of this gem looks like a reasonable solution at the moment.
s.add_dependency("ruby2_keywords", "~> 0.0.5")

s.add_development_dependency("bson", ['>=4.9.4', '<5.0.0'])

Expand Down
21 changes: 17 additions & 4 deletions spec/mongoid/association/embedded/embeds_many/proxy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2449,13 +2449,26 @@ class TrackingIdValidationHistory
end

context "when providing a criteria class method" do
context "without keyword arguments" do

let(:addresses) do
person.addresses.california
let(:addresses) do
person.addresses.california
end

it "applies the criteria to the documents" do
expect(addresses).to eq([ address_one ])
end
end

it "applies the criteria to the documents" do
expect(addresses).to eq([ address_one ])
context "with keyword arguments" do

let(:addresses) do
person.addresses.city_and_state(city: "Sacramento", state: "CA")
end

it "applies the criteria to the documents" do
expect(addresses).to eq([])
end
end
end

Expand Down
17 changes: 17 additions & 0 deletions spec/mongoid/association/referenced/belongs_to/proxy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1349,4 +1349,21 @@ class C
end
end
end

describe "#method_missing" do
let!(:person) do
Person.create
end

let!(:game) do
Game.create(person: person)
end

it 'handles keyword args' do
expect do
game.person.set_personal_data(ssn: '123', age: 25)
end.not_to raise_error
end

end
end
4 changes: 4 additions & 0 deletions spec/mongoid/criteria_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3532,10 +3532,14 @@ def self.ages; self; end

before do
expect(Person).to receive(:minor).and_call_original
expect(Person).to receive(:older_than).and_call_original
end

it "calls the method on the class" do
expect(criteria.minor).to be_empty
expect do
criteria.older_than(age: 25)
end.not_to raise_error
end
end

Expand Down
4 changes: 4 additions & 0 deletions spec/support/models/address.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,9 @@ def homes
def streets
all.map(&:street)
end

def city_and_state(city:, state:)
where(city: city, state: state)
end
end
end
9 changes: 9 additions & 0 deletions spec/support/models/person.rb
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ def extension
scope :without_ssn, ->{ without(:ssn) }
scope :search, ->(query){ any_of({ title: query }) }

def self.older_than(age:)
where(:age.gt => age)
end

def score_with_rescoring=(score)
@rescored = score.to_i + 20
self.score_without_rescoring = score
Expand Down Expand Up @@ -206,6 +210,11 @@ def set_on_map_with_default=(value)
self.map_with_default["key"] = value
end

def set_personal_data(ssn:, age:)
self.ssn = ssn
self.age = age
end

reset_callbacks(:validate)
reset_callbacks(:create)
reset_callbacks(:save)
Expand Down

0 comments on commit 6cc7001

Please sign in to comment.