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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
* [#2733](https://github.com/ruby-grape/grape/pull/2733): Drop the dead `active_support/core_ext/hash/reverse_merge` require; call `ActiveSupport::HashWithIndifferentAccess.new(...)` directly at call sites - [@ericproulx](https://github.com/ericproulx).
* [#2734](https://github.com/ruby-grape/grape/pull/2734): Extract `options_route_enabled` from the Endpoint options Hash into a dedicated `attr_accessor` - [@ericproulx](https://github.com/ericproulx).
* [#2736](https://github.com/ruby-grape/grape/pull/2736): Collapse `Endpoint#run_validators` rescue branches via `ValidationErrors` flatten; `ValidationErrors#initialize` keyword renamed `errors:` → `exceptions:` - [@ericproulx](https://github.com/ericproulx).
* [#2739](https://github.com/ruby-grape/grape/pull/2739): Lazy-allocate `@new_values` in `Grape::Util::BaseInheritable` so settings layers that only inherit never carry an empty Hash; readers in `InheritableValues`/`StackableValues` handle nil - [@ericproulx](https://github.com/ericproulx).
* [#2737](https://github.com/ruby-grape/grape/pull/2737): `rescue_from` raises `ArgumentError` when a meta selector (`:all`, `:grape_exceptions`, `:internal_grape_exceptions`) is mixed with exception classes instead of silently dropping the classes - [@ericproulx](https://github.com/ericproulx).
* [#2735](https://github.com/ruby-grape/grape/pull/2735): Normalize `Grape::Endpoint#options` into an immutable `Grape::Endpoint::Options` `Data` value object; Hash-style `[]` reads kept for back-compat - [@ericproulx](https://github.com/ericproulx).
* Your contribution here.
Expand Down
22 changes: 12 additions & 10 deletions lib/grape/util/base_inheritable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,39 @@ module Grape
module Util
# Base for classes which need to operate with own values kept
# in the hash and inherited values kept in a Hash-like object.
#
# +@new_values+ is lazily allocated on first write so settings layers
# that only inherit (never override) don't carry an empty Hash each.
class BaseInheritable
attr_accessor :inherited_values, :new_values

# @param inherited_values [Object] An object implementing an interface
# of the Hash class.
def initialize(inherited_values = nil)
@inherited_values = inherited_values || {}
@new_values = {}
# @new_values stays nil until the first write.
end

def delete(*keys)
keys.map do |key|
# since delete returns the deleted value, seems natural to `map` the result
new_values.delete key
end
return [] unless @new_values

keys.map { |key| @new_values.delete(key) }
end

def initialize_copy(other)
super
self.inherited_values = other.inherited_values
self.new_values = other.new_values.dup
@inherited_values = other.inherited_values
@new_values = other.new_values&.dup
end

def keys
return inherited_values.keys if new_values.empty?
return @inherited_values.keys if @new_values.nil? || @new_values.empty?

(inherited_values.keys + new_values.keys).uniq
(@inherited_values.keys + @new_values.keys).uniq
end

def key?(name)
inherited_values.key?(name) || new_values.key?(name)
@inherited_values.key?(name) || @new_values&.key?(name) || false
end
end
end
Expand Down
8 changes: 6 additions & 2 deletions lib/grape/util/inheritable_values.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ module Grape
module Util
class InheritableValues < BaseInheritable
def [](name)
return @inherited_values[name] unless @new_values

@new_values.fetch(name) { @inherited_values[name] }
end

def []=(name, value)
new_values[name] = value
(@new_values ||= {})[name] = value
end

def merge(new_hash)
Expand All @@ -22,7 +24,9 @@ def to_hash
protected

def values
@inherited_values.merge(@new_values)
return @inherited_values.merge(@new_values) if @new_values && !@new_values.empty?

@inherited_values.is_a?(Hash) ? @inherited_values.dup : @inherited_values.to_hash
end
end
end
Expand Down
9 changes: 5 additions & 4 deletions lib/grape/util/stackable_values.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@ class StackableValues < BaseInheritable

# Even if there is no value, an empty (frozen) array will be returned.
def [](name)
inherited_value = inherited_values[name]
new_value = new_values[name]
inherited_value = @inherited_values[name]
new_value = @new_values && @new_values[name]

return new_value || EMPTY unless inherited_value

concat_values(inherited_value, new_value)
end

def []=(name, value)
new_values[name] ||= []
new_values[name].push value
@new_values ||= {}
@new_values[name] ||= []
@new_values[name].push value
end

def to_hash
Expand Down
Loading