Создание DSL в JavaScript аналогично Ruby DSL - PullRequest
1 голос
/ 30 мая 2020

Я хочу углубиться в JavaScript хотел посмотреть, смогу ли я создать язык c Domain Specifi, который был бы похож на то, что я мог бы сделать в Ruby, используя instance_eval и block_given?. Я в основном не знаю, по каким терминам искать, и когда я ищу DSL, я обычно получаю очень много мета-вещей, с которыми я не знаком. Изначально мне очень повезло с поиском Ruby, и я нашел хороший блог, который мне помог. Мои примеры в Ruby:

# frozen_string_literal: true

require 'phil_dsl/version'

module PhilDsl
  class Error < StandardError; end

  # The DSL Class.
  class Pipeline
    def initialize(&block)
      if block_given? # rubocop:disable Style/GuardClause
        if block.arity == 1
          yield self
        else
          instance_eval(&block)
        end
      end
    end

    def pipeline(&block)
      if block_given? # rubocop:disable Style/GuardClause
        if block.arity == 1
          yield self
        else
          instance_eval(&block)
        end
      end
    end

    def print_stuff(name = 'bob', &block)
      puts name.to_s

      if block_given? # rubocop:disable Style/GuardClause
        if block.arity == 1
          yield self
        else
          instance_eval(&block)
        end
      end
    end
  end
end

, а затем фактическое использование DSL после установки

#!/usr/bin/env ruby
# frozen_string_literal: true

require 'phil_dsl'

PhilDsl::Pipeline.new.pipeline do
  print_stuff('hello') do
    print_stuff
  end
end

Глядя на Mocha JS, я хочу подражать, но я не уверен, с чего начать или go, чтобы выяснить, как создать DSL, аналогично тому, что я могу сделать в Ruby.

My Ruby Полный пример DSL: https://github.com/FilBot3/phil_dsl

1 Ответ

1 голос
/ 30 мая 2020

Это не так красиво в JS, потому что вам всегда нужно ключевое слово this, но основная часть DSL - это функциональность instance_exec, которую очень легко сделать в JS, используя bind, apply или стрелочные функции.

Вместо того, чтобы использовать класс (который не поддерживает стрелочные функции), я построю новую область видимости, используя IIFE:

MyDsl = (function(){
  return this;
}).apply({});

Затем я Добавим однофункциональный DSL:

MyDsl = (function(){
  this.print_stuff = (arg, callback) => {
    console.log(arg);
    callback && callback.apply(this);
  };
  return this;
}).apply({});

Поскольку я определяю print_stuff как стрелочную функцию, я гарантирую , что внутри него this всегда будет ссылаться на MyDsl.

Затем я могу использовать DSL следующим образом:

MyDsl.print_stuff("foo", function() {
  this.print_stuff("bar");
});

Обратите внимание, что мы не можем использовать здесь функцию ошибки, потому что тогда .apply(this) будет проигнорирован.

...