-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MONGOID-5653 - Move Hash#__nested__ monkey patch method to new module…
… Mongoid::Attributes::Embedded.traverse (#5692) * Move Hash#__nested__ monkey patch method to new module Mongoid::Attributes::Embedded.traverse * Fix whitespace * Fix rubocop whitespace warning * Update embedded.rb * minor changes to test names --------- Co-authored-by: Jamis Buck <[email protected]>
- Loading branch information
1 parent
1efecc9
commit f674f2e
Showing
8 changed files
with
158 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# frozen_string_literal: true | ||
|
||
module Mongoid | ||
module Attributes | ||
# Utility module for working with embedded attributes. | ||
module Embedded | ||
extend self | ||
|
||
# Fetch an embedded value or subset of attributes via dot notation. | ||
# | ||
# @example Fetch an embedded value via dot notation. | ||
# Embedded.traverse({ 'name' => { 'en' => 'test' } }, 'name.en') | ||
# #=> 'test' | ||
# | ||
# @param [ Hash ] attributes The document attributes. | ||
# @param [ String ] path The dot notation string. | ||
# | ||
# @return [ Object | nil ] The attributes at the given path, | ||
# or nil if the path doesn't exist. | ||
def traverse(attributes, path) | ||
path.split('.').each do |key| | ||
break if attributes.nil? | ||
|
||
attributes = if attributes.try(:key?, key) | ||
attributes[key] | ||
elsif attributes.respond_to?(:each) && key.match?(/\A\d+\z/) | ||
attributes[key.to_i] | ||
end | ||
end | ||
attributes | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'spec_helper' | ||
|
||
describe Mongoid::Attributes::Embedded do | ||
describe '.traverse' do | ||
subject(:embedded) { described_class.traverse(attributes, path) } | ||
|
||
let(:path) { '100.name' } | ||
|
||
context 'when the attribute key is a string' do | ||
let(:attributes) { { '100' => { 'name' => 'hundred' } } } | ||
|
||
it 'retrieves an embedded value under the provided key' do | ||
expect(embedded).to eq 'hundred' | ||
end | ||
|
||
context 'when the value is false' do | ||
let(:attributes) { { '100' => { 'name' => false } } } | ||
|
||
it 'retrieves the embedded value under the provided key' do | ||
expect(embedded).to be false | ||
end | ||
end | ||
|
||
context 'when the value does not exist' do | ||
let(:attributes) { { '100' => { 0 => 'Please do not return this value!' } } } | ||
|
||
it 'returns nil' do | ||
expect(embedded).to be_nil | ||
end | ||
end | ||
end | ||
|
||
context 'when the attribute key is an integer' do | ||
let(:attributes) { { 100 => { 'name' => 'hundred' } } } | ||
|
||
it 'retrieves an embedded value under the provided key' do | ||
expect(embedded).to eq 'hundred' | ||
end | ||
end | ||
|
||
context 'when the attribute value is nil' do | ||
let(:attributes) { { 100 => { 'name' => nil } } } | ||
|
||
it 'returns nil' do | ||
expect(embedded).to be_nil | ||
end | ||
end | ||
|
||
context 'when both string and integer keys are present' do | ||
let(:attributes) { { '100' => { 'name' => 'Fred' }, 100 => { 'name' => 'Daphne' } } } | ||
|
||
it 'returns the string key value' do | ||
expect(embedded).to eq 'Fred' | ||
end | ||
|
||
context 'when the string key value is nil' do | ||
let(:attributes) { { '100' => nil, 100 => { 'name' => 'Daphne' } } } | ||
|
||
it 'returns nil' do | ||
expect(embedded).to be_nil | ||
end | ||
end | ||
end | ||
|
||
context 'when attributes is an array' do | ||
let(:attributes) do | ||
[ { 'name' => 'Fred' }, { 'name' => 'Daphne' }, { 'name' => 'Velma' }, { 'name' => 'Shaggy' } ] | ||
end | ||
let(:path) { '2.name' } | ||
|
||
it 'retrieves the nth value' do | ||
expect(embedded).to eq 'Velma' | ||
end | ||
|
||
context 'when the member does not exist' do | ||
let(:attributes) { [ { 'name' => 'Fred' }, { 'name' => 'Daphne' } ] } | ||
|
||
it 'returns nil' do | ||
expect(embedded).to be_nil | ||
end | ||
end | ||
end | ||
|
||
context 'when the path includes a scalar value' do | ||
let(:attributes) { { '100' => 'name' } } | ||
|
||
it 'returns nil' do | ||
expect(embedded).to be_nil | ||
end | ||
end | ||
|
||
context 'when the parent key is not present' do | ||
let(:attributes) { { '101' => { 'name' => 'hundred and one' } } } | ||
|
||
it 'returns nil' do | ||
expect(embedded).to be_nil | ||
end | ||
end | ||
|
||
context 'when the attributes are deeply nested' do | ||
let(:attributes) { { '100' => { 'name' => { 300 => %w[a b c] } } } } | ||
|
||
it 'retrieves the embedded subset of attributes' do | ||
expect(embedded).to eq(300 => %w[a b c]) | ||
end | ||
|
||
context 'when the path is deeply nested' do | ||
let(:path) { '100.name.300.1' } | ||
|
||
it 'retrieves the embedded value' do | ||
expect(embedded).to eq 'b' | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters