# Customizing Hash

**URL:** <https://discourse.dry-rb.org/t/customizing-hash/1200>\
**Category:** dry-types\
**Created:** [February 9, 2021, 7:37pm UTC](https://discourse.dry-rb.org/t/customizing-hash/1200 "2021-02-09T19:37:09Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![glasserc](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/glasserc/32/596_2.png) [@glasserc](https://discourse.dry-rb.org/u/glasserc)\
**Post date:** [February 9, 2021, 7:37pm UTC](https://discourse.dry-rb.org/t/customizing-hash/1200/1 "2021-02-09T19:37:09Z")

</div>

Hi! I’m trying to write a `dry-types` type useable for parsing a localization API that has data of a strange shape. It’s mostly a hash of `String` to `Hash.map(Types::String, Types::String)`, but there’s one key which has a completely different value. Something like this:

```auto
{
    "blog": {
        "next": "Next page",
        "previous": "Previous page"
    },
    "wizard": {
        "continue": "Click here to continue"
    },
    "garbage": 123
}

```

I’d prefer to model this as a Hash rather than a Struct because I don’t care what pages are present or what strings they support. However, the presence of this `garbage` key makes things challenging. I don’t care about this one `garbage` so I’d like to drop it.

I see [dry-rb - dry-types v1.2 - Custom Types](https://dry-rb.org/gems/dry-types/1.2/custom-types/) shows a bunch of information about defining specific kinds of custom types, but nothing about my use case. Is it enough to e.g. subclass `Nominal` and override `call`? I did that and it worked, but from looking at the code, I get the impression that the actual calling contract is that I should support calling `call_unsafe`, `call_safe`,

For the record, this worked:

```auto
    without_garbage = Class.new(Dry::Types::Nominal) do
      def initialize(wrapped)
        @wrapped = wrapped
        super(::Hash)
      end

      def call(input = Undefined, &block)
        if input.is_a?(Hash)
          input.delete("garbage")
        end
        @wrapped.call(input, &block)
      end
    end
    attribute :localized_strings, without_garbage.new(Types::Hash.map(Types::String, Types::Hash.map(Types::String, Types::String)))

```

---

<div class="post-metadata">

**Author:** ![glasserc](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/glasserc/32/596_2.png) [@glasserc](https://discourse.dry-rb.org/u/glasserc)\
**Post date:** [February 10, 2021, 1:02am UTC](https://discourse.dry-rb.org/t/customizing-hash/1200/2 "2021-02-10T01:02:31Z")

</div>

I actually found an example on [dry-rb - dry-types v1.2 - Hash Schemas](https://dry-rb.org/gems/dry-types/1.2/hash-schemas/) which uses `.constructor`, and I was able to adapt it:

```auto
attribute(:localized_strings, Types::Hash.map(Types::String, Types::Hash.map(Types::String, Types::String)).constructor do |value| 
  if value.is_a?(Hash)
    value.delete("garbage")
  end
  value
end)

```

Is this correct? I saw some mention of `.constructor` here and there on the forum, but I couldn’t find anything in the docs about it.

---

<div class="post-metadata">

**Author:** ![solnic](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/solnic/32/779_2.png) [@solnic](https://discourse.dry-rb.org/u/solnic)\
**Post date:** [February 12, 2021, 6:03am UTC](https://discourse.dry-rb.org/t/customizing-hash/1200/3 "2021-02-12T06:03:32Z")

</div>

I don’t recommend using dry-types for parsing/preprocessing/mapping data. I know it’s tempting to do due to flexibility of the types, and it even may work well in various cases, but it’s not a dedicated solution so you may hit a wall or end up with too complicated code. You _especially_ should not use dry-struct with complex dry-types for complex mappings. Again, you can get away this if things are simple but it’s not the right abstraction.

We just had a short convo about this in [this thread](https://discourse.dry-rb.org/t/dry-struct-dependent-attributes/1191).

I feel like we should finally come up with a nice solution. There’s dry-transformer that you could evaluate too. It’ll become a generic data mapping solution eventually that works well with dry-types. I’ll be working on this _for sure_ later this year because rom 6.0 will use it under the hood.

---

<div class="post-metadata">

**Author:** ![glasserc](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/glasserc/32/596_2.png) [@glasserc](https://discourse.dry-rb.org/u/glasserc)\
**Post date:** [February 12, 2021, 4:24pm UTC](https://discourse.dry-rb.org/t/customizing-hash/1200/4 "2021-02-12T16:24:17Z")

</div>

Thanks for your response. I agree, `dry-struct` is clearly meant for defining data objects. Even the fact that `attribute :some_attribute, MyClass` constructs a `MyClass` feels kind of weird.

My next question was going to be how I could rename fields, using `dry-struct`, `dry-schema`, or anything else. I will hold off for now 🙂

Looking forward to hearing about the nice solution!
