Comments (16)
What about implementing a fetch method that raises a key error much like a hash does? This then stays with the spirit of a hash.
class Hashie::Mash
def fetch(key)
raise KeyError, 'key not found' unless self.include?(key)
self[key]
end
end
from hashie.
@scottnicolson -- but that wouldn't apply to the hashie dot syntax, would it? I like the dot syntax a lot (e.g. users.first.address.city
) and I want a way to make my mash (or mash-like object) raise appropriate errors when used in that fashion.
from hashie.
BTW, for anyone who tries my snippet above: it works on 1.9 but I discovered it didn't work on 1.8.7 because there is no Hash#default_proc=
method on 1.8. I found a work around for 1.8 that you can checkout if you're interested in using it.
from hashie.
I'd be happy to help review a pull if you've come up with a solution you like.
from hashie.
@myronmarston any developments?
from hashie.
Bump.
from hashie.
👍 for that feature
from hashie.
I believe the StrictKeyAccess extension in 3.4.3 does this, can someone confirm and close this issue?
from hashie.
@dblock When I was attempting to verify, I discovered that StrictKeyAccess
doesn't work with Mash
. See the following:
class StrictMash < Hashie::Mash
include Hashie::Extensions::StrictKeyAccess
end
h = StrictMash.new('a' => {'b' => 3}) #=> Hashie::Extensions::StrictKeyAccess::DefaultError
The reason is because Mash
implicitly checks whether #default_proc
and #default
exist. Those checks for existence raise a DefaultError
in the current implementation.
I'm not a big fan of that, but I don't really see a clear way forward. We could make it so accessing #default_proc
or #default
doesn't raise an error, but I do feel that the current behavior is "correct" because have a default doesn't make sense in strict key access.
We could make a different extension that is only for Mash that is slightly less constraining, but I don't know if that's a good way forward either. What are your thoughts?
from hashie.
Maybe we should build a StringKeyAccess extension for Mash then that is based on Hashie::Extensions::StrictKeyAccess
from hashie.
Pretty old issue but in case somebody needs that too: I tried a few approaches and for now, I'm on a variation of @scottnicolson suggestion that override Mash#method_missing
instead:
require "hashie/mash"
class StrictMash < Hashie::Mash
# Extends Hashie::Mash but raises a KeyError when trying to access a property
# that doens't exist yet. A naive version of this consists in aliasing `[]` to
# `fetch` but it makes it impossible to use nice Mash aliases such as `<field>!`,
# `<field>?`, etc.
# So instead we override `method_missing` with just a tiny patch inside.
def method_missing(method_name, *args, &blk)
return self.[](method_name, &blk) if key?(method_name)
name, suffix = method_name_and_suffix(method_name)
# PATCH
if !key?(name) and !suffix
raise KeyError, %(key not found: "#{name}")
end
# EOF PATCH
case suffix
when '='.freeze
assign_property(name, args.first)
when '?'.freeze
!!self[name]
when '!'.freeze
initializing_reader(name)
when '_'.freeze
underbang_reader(name)
else
self[method_name]
end
end
end
The nice thing is that it preserves all Mash behaviours, including sub-hashes being StrictMash instances (s.foo!.bar!.meh!.class # => StrictMash
).
StrictKeyAccess is actually too strict and will prevent using Mash's "!", "?", etc suffixes from what I saw. I think StrictKeyAccess not working in Mash is a bug in either Mash or StrictKeyAccess though: Mash first argument is a hash to be converted, not a default value, so it shouldn't trigger the DefaultError it triggers right now if you don't pass a default value / block.
If somebody finds the issue interesting enough, I'm up for discussing it and work on a clean PR that could be merged at some point. Else I'll keep my dirty hack, "it works" ;-)
from hashie.
I find it interesting enough for a PR!
from hashie.
Instead of a module, what would we think of making the handler injectable? Basically, the else
case of the case
statement is the "default handler". If we make that something you can inject upon creation -- or via an accessor -- it gives an extension point to the Mash itself.
Of course, that increases the responsibilities of an already huge class ... 🤔
from hashie.
@jbbarth's patch, simplified by using Module.prepend
:
Module.new do
def method_missing(method_name, *args, &blk)
unless key?(method_name)
name, suffix = method_name_and_suffix(method_name)
raise KeyError, %(key not found: "#{name}") unless key?(name) || suffix
end
super
end
Hashie::Mash.prepend self
end
from hashie.
This is the oldest issue in Hashie. Can someone PR the version above as an extension? @betesh
from hashie.
I'm not involved in any projects using hashie at the moment. If you just want someone to open a PR, feel free to use my code.
from hashie.
Related Issues (20)
- deep_merge does not function as expected on a Ruby Hash including Hashie::Extensions::DeepMerge
- Problem flattening multiple nested properties via Trash HOT 3
- Release v. next HOT 2
- Integer key upsets Hashie::Mash with SymbolizeKeys extension HOT 16
- Slice doesn't work using symbols HOT 5
- I got in dev a failing test from master, how to properly setup? HOT 5
- RFC: Switch to Github Actions for CI HOT 3
- Multiple Trash properties that use the same key from a source hash HOT 3
- Undefined quiet method HOT 4
- New Release? HOT 3
- Behavior change in accessing Mash values in 5.0 release HOT 5
- [Informative] `deep_symbolize_keys` broken in Rails 7 with `Mash` HOT 7
- [Question] Why use :to_sym in Hashie::Mash#convert_key HOT 1
- Release version 5 HOT 1
- Memory leak possible HOT 5
- DeepMerge changes ActiveRecord instance HOT 2
- Trash warning when translating string to symbol
- Mash.load is insecure HOT 5
- Including MethodAccessWithOverride in Hashie::Mash breaks dup method
- PredefinedValues is undefined ... :( HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from hashie.