mbklein / confstruct

Yet another hash/struct-like configuration object for Ruby

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Regression with Hashie 3.4.3 and property/method conflicts

cbeer opened this issue · comments

With Hashie 3.4.2, this code used to work

require 'timeout'
require 'confstruct'
Confstruct::Configuration.new(timeout: 1)

Using 3.4.3, this fails with:

ArgumentError: The property timeout clashes with an existing method.
    from /Users/cabeer/.gem/ruby/2.2.1/gems/hashie-3.4.3/lib/hashie/extensions/mash/safe_assignment.rb:6:in `custom_writer'
    from /Users/cabeer/.gem/ruby/2.2.1/gems/hashie-3.4.3/lib/hashie/mash.rb:177:in `block in deep_update'
    from /Users/cabeer/.gem/ruby/2.2.1/gems/hashie-3.4.3/lib/hashie/mash.rb:170:in `each_pair'
    from /Users/cabeer/.gem/ruby/2.2.1/gems/hashie-3.4.3/lib/hashie/mash.rb:170:in `deep_update'
    from /Users/cabeer/.gem/ruby/2.2.1/gems/hashie-3.4.3/lib/hashie/mash.rb:88:in `initialize'
    from /Users/cabeer/.gem/ruby/2.2.1/gems/confstruct-1.0.2/lib/confstruct/configuration.rb:8:in `initialize'

In 3.4.3, hashie "fixed" their property/method clashing logic, but broke some of our code that had property/method conflicts. On one hand, the new behavior seems more correct. On the other, we're loading this configuration from YAML into Confstruct so we can pass it off to e.g. Faraday (which has configuration with a timeout property) with minimal transformation.

I've left a comment upstream (hashie/hashie#320), but we may want to file a real bug report if we think it's an upstream issue.

Confstruct since 1.0 was intending prevent you from setting a key that conflicted with a method on the object.

The prime example of why we did this was Kernel#format, defined on all objects. In earlier versions of Confstruct, you could set configuration_object.format = "something" no problem (There isn't already an Object#format= method), or of course configuration_object["format"] = "something" no problem. But if you tried to read it back with configuration_object.format, you'd wind up getting Kernel#format instead, complaining about wrong number of arguments, leading to hours of confusing debugging for several people. I did this hours of confusing debugging several different times, forgetting the last time it happened until I had debugged it again! ("format" is a popular configuration key).

So anyway, since confstruct 1.0, I think it was a bug in Hashie that let you do this.

But I see the problem, you've got an existing timeout key, you need it to keep working somehow.

The only thing I can think of is making Confstruct give you an option to disable/turn-off Hashie::Mash::SafeAssignment, returning you to the state of affairs I described above: You still won't be able to read the value with conf.timeout, but you'll be able to read it with conf['timeout']. Would that be useful to you? I can see if I can make it so.

Me, in any future projects I am never again going to try to have a configuration object which can behave as both a Hash and a Struct with multi-levels of nesting. Every time I've tried to do it has led to failure. Confstruct was intended to finally do it right after years of frustration with several other solutions that failed. I think Confstruct has failed too. It's just not worth it. From now on, my projects will involve configuration objects that only have a single-level (no nesting) and require hash access (no method/struct access), heh.

But if ALL you're doing is loading from a YAML to pass to Faraday -- do you need confstruct at all, or can you just use ordinary Yaml.load?