GithubHelp home page GithubHelp logo

Comments (16)

scottnicolson avatar scottnicolson commented on July 20, 2024

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.

myronmarston avatar myronmarston commented on July 20, 2024

@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.

myronmarston avatar myronmarston commented on July 20, 2024

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.

jch avatar jch commented on July 20, 2024

I'd be happy to help review a pull if you've come up with a solution you like.

from hashie.

lukaszx0 avatar lukaszx0 commented on July 20, 2024

@myronmarston any developments?

from hashie.

dblock avatar dblock commented on July 20, 2024

Bump.

from hashie.

alex-fedorov avatar alex-fedorov commented on July 20, 2024

👍 for that feature

from hashie.

dblock avatar dblock commented on July 20, 2024

I believe the StrictKeyAccess extension in 3.4.3 does this, can someone confirm and close this issue?

from hashie.

michaelherold avatar michaelherold commented on July 20, 2024

@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.

dblock avatar dblock commented on July 20, 2024

Maybe we should build a StringKeyAccess extension for Mash then that is based on Hashie::Extensions::StrictKeyAccess

from hashie.

jbbarth avatar jbbarth commented on July 20, 2024

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.

dblock avatar dblock commented on July 20, 2024

I find it interesting enough for a PR!

from hashie.

michaelherold avatar michaelherold commented on July 20, 2024

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.

betesh avatar betesh commented on July 20, 2024

@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.

dblock avatar dblock commented on July 20, 2024

This is the oldest issue in Hashie. Can someone PR the version above as an extension? @betesh

from hashie.

betesh avatar betesh commented on July 20, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.