Читаем Crystal Programming. Введение на основе проекта в создание эффективных, безопасных и читаемых веб-приложений и приложений CLI полностью

Основная причина, по которой #each нельзя использовать, заключается в том, что циклу необходим доступ к реальной программе, чтобы иметь возможность вставить сгенерированный код. #each можно использовать внутри макроса, но он должен использоваться в синтаксисе макроса и не может использоваться для генерации кода. Лучше всего это продемонстрировать на примере:

{% begin %}

  {% hash = {"foo" => "bar", "biz" => "baz"} %}

  {% for key, value in hash %}

    puts "#{{{key}}}=#{{{value}}}"

  {% end %}

{% end %}

{% begin %}

  {% arr = [1, 2, 3] %}

  {% hash = {} of Nil => Nil %}

  {% arr.each { |v| hash[v] = v * 2 } %}

  puts({{hash}})

{% end %}

В этом примере мы перебирали ключи и значения хеша, генерируя вызов метода puts, который печатает каждую пару. Мы также использовали ArrayLiteral#each для перебора каждого значения и установки вычисленного значения в хеш-литерал, который затем печатаем. В большинстве случаев синтаксис for in можно использовать вместо #each, но #each нельзя использовать вместо for in. Проще говоря, поскольку метод #each использует блок, у него нет возможности вывод сгенерированного кода. Таким образом, его можно использовать только для итерации, а не генерации кода.

Следующее, что делает наш макрос def_methods, — это использует оператор if, чтобы определить, должен ли он генерировать метод или нет для текущего числа. Операторы if/unless в макросах работают идентично своим аналогам во время выполнения, хотя и в рамках синтаксиса макросов.

Далее обратите внимание, что у этого метода есть комментарий, включающий {{idx}}. Макровыражения оцениваются как в комментариях, так и в обычном коде. Это позволяет генерировать комментарии на основе расширенного значения макровыражений. Однако эта функция также делает невозможным комментирование кода макроса, поскольку он все равно будет оцениваться как обычно.

Наконец, у нас есть логика, создающая метод. В данном случае мы интерполировали индекс из цикла в строку, представляющую имя метода. Обратите внимание, что мы использовали для строки метод #id. Метод #id возвращает значение как MacroId, что по существу нормализует значение как один и тот же идентификатор, независимо от типа входных данных. Например, вызов #id для “foo”, :foo и foo приводит к возврату того же значения foo. Это полезно, поскольку позволяет вызывать макрос с любым идентификатором, который предпочитает пользователь, при этом создавая тот же базовый код.

В самом конце определения макроса вы могли заметить строку {{debug}}. Это специальный метод макроса, который может оказаться неоценимым при отладке кода макроса. При использовании он выводит код макроса, который будет сгенерирован в строке, в которой он был вызван. В нашем примере мы увидим следующий вывод на консоли перед выводом ожидаемых значений:

# Returns the number at index 0.

def number_0

1

end

# Returns the number at index 1.

def number_1

3

end

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

Макрос также может генерировать другие макросы. Однако при этом необходимо соблюдать особую осторожность, чтобы гарантировать правильное экранирование выражений внутреннего макроса. Например, следующий макрос аналогичен предыдущему примеру, но вместо непосредственного определения методов он создает другой макрос и немедленно вызывает его, в результате чего создаются связанные методы:

macro def_macros(*numbers)

  {% for num, idx in numbers %}

    macro def_num_{{idx}}_methods(n)

      def num_\{{n}}

        \{{n}}

      end

      def num_\{{n}}_index

        {{idx}}

      end

    end

    def_num_{{idx}}_methods({{num}})

  {% end %}

end

def_macros 2, 1

pp num_1_index # => 1

pp num_2_index # => 0

В конце макросы расширяются и определяют четыре метода. Ключевым моментом, на который следует обратить внимание в этом примере, является использование \{{. Обратная косая черта экранирует выражение синтаксиса макроса, поэтому оно не оценивается внешним макросом, что означает, что оно расширяется только внутренним макросом. На переменные макроса из внешнего макроса по-прежнему можно ссылаться во внутреннем макросе, используя переменную во внутреннем макросе, не экранируя выражение.

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных