# How to translate following transformation into the dry-transformer DSL?

**URL:** <https://discourse.dry-rb.org/t/how-to-translate-following-transformation-into-the-dry-transformer-dsl/1624>\
**Category:** Support\
**Created:** [March 14, 2023, 2:11pm UTC](https://discourse.dry-rb.org/t/how-to-translate-following-transformation-into-the-dry-transformer-dsl/1624 "2023-03-14T14:11:22Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![wuarmin](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/wuarmin/32/641_2.png) [@wuarmin](https://discourse.dry-rb.org/u/wuarmin)\
**Post date:** [March 14, 2023, 2:11pm UTC](https://discourse.dry-rb.org/t/how-to-translate-following-transformation-into-the-dry-transformer-dsl/1624/1 "2023-03-14T14:11:22Z")

</div>

Hey,

I can’t figure out how to translate the following transformation into the dry-transformer DSL.

```ruby
Dry::Transformer::Recursion.t(
    :recursion, Dry::Transformer::Conditional.t(
        :is, ::Hash, Dry::Transformer::HashTransformations.t(
            :map_keys, ->(key) { Hanami.app["inflector"].underscore(key) }
         )
     )
 )[
    {
        :ID => "57d79414-ab95-4887-8fd8-6418f6adb113",
        :Read => true,
        :Subject => "Hello World.",
        :Attachments => [
            {
                :PartID => "2",
                :FileName => "test.pdf",
                :ContentType => "application/pdf",
                :ContentID => "",
                :Size => 307686,
            },
        ],
    }
]

```

I tried the following, but without success:

```ruby
class PayloadAdapter < Dry::Transformer::Pipe
    import Dry::Transformer::HashTransformations
    import Dry::Transformer::Recursion
    import Dry::Transformer::Conditional

    define! do
        recursion(is(::Hash, map_keys(->(key) { Hanami.app["inflector"].underscore(key) })))
    end
end

```

Please can you help?

thanks and best regards

---

<div class="post-metadata">

**Author:** ![alassek](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/alassek/32/314_2.png) [@alassek](https://discourse.dry-rb.org/u/alassek)\
**Post date:** [March 14, 2023, 5:57pm UTC](https://discourse.dry-rb.org/t/how-to-translate-following-transformation-into-the-dry-transformer-dsl/1624/2 "2023-03-14T17:57:20Z")

</div>

This is happening because all the examples are built around using `Dry::Transformer` directly, whereas any bare words in the `define!` block are generating ASTs, not objects.

This is easily the most confusing thing about this library.

Here’s how you would write this as-is:

```ruby
class PayloadAdapter < Dry::Transformer::Pipe
    import Dry::Transformer::HashTransformations
    import Dry::Transformer::Recursion
    import Dry::Transformer::Conditional

    define! do
        recursion t(:is, Hash, t(:map_keys, ->(key) { Hanami.app["inflector"].underscore(key) }))
    end
end

```

However, I don’t think the next person who comes along is going to understand what they’re looking at.

Here’s an approach to this that I have taken

```ruby
module Transform
  class Registry
    extend Dry::Transformer::Registry

    import Dry::Transformer::ArrayTransformations
    import Dry::Transformer::HashTransformations
    import Dry::Transformer::Conditional

    class << self
      def deep_transform_keys(hash, fn)
        hash.each_with_object({}) do |(key, value), result|
          result[fn.(key)] = if value.is_a?(Hash)
            deep_transform_keys(value, fn)
          elsif value.is_a?(Array)
            value.map { deep_transform_keys(_1, fn) }
          else
            value
          end
        end
      end
    end
  end

  class Function < Dry::Transformer::Pipe
    extend Dry::Initializer
  end
end

class PayloadAdapter < Transform::Function
  option :inflector, default: -> { Hanami.app.inflector }

  import :deep_transform_keys, from: Transform::Registry

  define! do
    deep_transform_keys(&:underscore)
  end

  def underscore(key) = inflector.underscore(_1.to_s)
end

```

---

<div class="post-metadata">

**Author:** ![wuarmin](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/wuarmin/32/641_2.png) [@wuarmin](https://discourse.dry-rb.org/u/wuarmin)\
**Post date:** [November 25, 2024, 8:51am UTC](https://discourse.dry-rb.org/t/how-to-translate-following-transformation-into-the-dry-transformer-dsl/1624/3 "2024-11-25T08:51:02Z")

</div>

Hey @alassek,

a little bit late, but I found out, that there’s a bug at your `deep_transform_keys`-implementation. It will fail i.e. for a hash like this:

```ruby
{
  "id" => 1,
  "stringArray" => ["hello", "world"]
}

```

Here’s a fix:

```ruby
  def deep_transform_keys(value, fn)
    if value.is_a?(Hash)
      value.each_with_object({}) do |(key, value), result|
        result[fn.call(key)] = deep_transform_keys(value, fn)
      end
    elsif value.is_a?(Array)
      value.map { deep_transform_keys(_1, fn) }
    else
      value
    end
  end

```

If you are using this in any code base, maybe this message will save you from a bugfix in the future.

best regards
