Как объединить NamedTuples в макрос в Crystal? - PullRequest
1 голос
/ 25 июня 2019

Я пытаюсь сделать JSON.mapping в классе (OtherThing) на основе объединения двух именованных кортежей.

class Thing
  MAPPING = {
    id:                  {type: String, default: UUID.random.to_s},
    email:               {type: String, nilable: true},
  }

  JSON.mapping({{MAPPING}})
end

class OtherThing
  MAPPING = Thing::MAPPING.merge({
    address:                              String,
    city:                                 String,
    zip:                                  {type: String, nilable: true},
    latitude:                             {type: Float64, nilable: true},
    longitude:                            {type: Float64, nilable: true},
  })

  JSON.mapping({{MAPPING}})
end

Это приводит к ошибке в зависимости от того, как я организовал код.

Одна ошибка:

Error expanding macro

FOR expression must be an array, hash or tuple literal, not Call:

Thing::MAPPING.merge

{% for key, value in _properties_ %}
                     ^~~~~~~~~~~~

Другая возможная ошибка:

undefined macro method 'NamedTupleLiteral#merge' в JSON.mapping из OtherThing

Ответы [ 2 ]

0 голосов
/ 27 июня 2019

Спасибо @ Blacksmoke16 за помощь в указании, что вы можете достичь желаемого результата, задав собственный макрос с помощью восклицательных знаков.

Ниже код должен работать. Кредит идет на @ Blacksmoke16

macro define(*args)
  JSON.mapping(    
    {% for t in args %}
      {{t.double_splat}},
    {% end %}
  )
end

class Thing
  MAPPING = {
    id:                  {type: String, default: UUID.random.to_s},
    email:               {type: String, nilable: true},
  }

  define {{MAPPING}}
end

class OtherThing
  MAPPING = {
    address:                              String,
    city:                                 String,
    zip:                                  {type: String, nilable: true},
    latitude:                             {type: Float64, nilable: true},
    longitude:                            {type: Float64, nilable: true},
  }

  define {{MAPPING}}, {{Thing::MAPPING}}
end
0 голосов
/ 27 июня 2019

Короткий ответ - нет, вы не можете интерполировать константу в макросе прямо сейчас.

@ asterite:

Проблема состоит в том, что макросы сопоставления ожидают HashLiteral какаргумент, но теперь они получают путь

. В вашем случае вместо макроса NamedTuple появился узел Call.В обсуждении Crystal Repo https://github.com/crystal-lang/crystal/issues/2388 было найдено решение, которое теоретически может решить эту проблему, но JSON.mapping - это старый метод, который будет удален из языка в следующих версиях, вместо этого попробуйте JSON :: Serializable

...