Где же ты? Heredoc из JavaScript

console.log(hered0c);
Меня нет
Совсем нет
Полностью - до конца!
Меня никогда не было и не будет.
И не спрашивайте на форумах где я,
Там меня всегда бьют и обижают потом!
Они не понимают меня и не знают где я... © HEREDOC

Не буду томить в, JavaScript действительно нет heredoc.

Но черт возьми! Это нисколько не помешало «HEREDOC» написать многосторочным текстом, что его нет.

Этот пример протестирован мной на Midori и Chrome. Как-то в Opere и Firefox я не сомневаюсь, а на IE всегда приходиться надеяться)). Так что есть основания для оптимизма!

У этого способа есть единственное ограничение: нельзя употреблять в такой последовательности вот эти 2 символа */ — в принципе у всех скриптовых heredoc есть такие ограничения. Просто обычно они позволяют нам выбрать те символы которые не будут использоваться внутри heredoc.

Приступим:
!function (root) {

  function heredoc(fn) {
    return fn.toString().split('\n').slice(1,-1).join('\n') + '\n'
  }

  var stripPattern = /^\s*(?=[^\s]+)/mg
  heredoc.strip = function(fn) {
    var text = heredoc(fn)
    
    var indentLen = text.match(stripPattern)
                                 .reduce(function (min, line) {
      return Math.min(min, line.length)
    }, Infinity)

    var indent = new RegExp('^\\s{' + indentLen + '}', 'mg')
    return indentLen > 0
      ? text.replace(indent, '')
      : text
  }

  if (typeof exports === 'object') {
    module.exports = heredoc
  }
  else if (typeof define === 'function' && define.amd) {
    define(function() {
      return heredoc
    })
  }
  else {
    root.heredoc = heredoc
  }
}(this)


А теперь тестируем:

var hered0c = heredoc(function () {/*
Меня нет
Совсем нет
Полностью - до конца!
Меня никогда не было и не будет.
И не спрашивайте на форумах где я,
Там меня всегда бьют и обижают потом!
Они не понимают меня и не знают где я... © HEREDOC
*/});
console.log(hered0c);


GitHub
JSFiddle

Протестировать на пригодность для использования в разных браузерах можно прямо тут!
Если кому не сложно, отпишитесь пожалуйста где «heredoc» не работает.
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 26

  • UFO just landed and posted this here
      +10
      JavaScript пишется слитно.
        +4
        var test = function ( data ) {
            /** @params {string} data */
        };
        
        console.log(test.__doc__);  // @params {string} data
        


        github.com/monolithed/__doc__/
          0
          OP говорит о многострочных строковых литералах. Но ваша штука очень прикольная!
          0
          У этого способа есть единственное ограничение: нельзя употреблять в такой последовательности вот эти 2 символа */ — в принципе у всех скриптовых heredoc есть такие ограничения.

          /* *\/ */
          
            0
            собственно да, достаточно ввести две escape-последовательности:
            \/ и \\
            0
            А если при сжатии скриптов оптимизатор выкинет все комментарии? Не годно для production уровня.
              0
              Там уже написали, что можно использовать такие /** */ комменты. Их минимизаторы (оптимизаторы?) не выкидывают.
                0
                Еще как выкидывают, смотрите «таблетку» ниже:
                0
                Если используется Google Closure Compiler, то спасет директива @preserve:
                /**
                @preserve 
                ...... 
                */
                


                В UglifyJS немного иной подход:

                /*! 
                   ....
                */ 
                
                  +2
                  Простите, но /regexp/.exec(fn.toString()) — это вообще в принципе не продакшн.
                    –2
                    Регулярки в JS настолько медленные?
                      –1
                      Дело в другом:

                      var foo = function () {
                          /* foo */
                      };
                      
                      foo.toString(); // "function () { /* foo */ }"
                      


                      var foo = function () {
                          /* foo */
                      };
                      
                      foo.bind(null).toString(); // "function () { [native code] }"
                      


                        –1
                        Зачем кому-то в здравом уме писать
                        var hered0c = heredoc(function () {/*
                        Меня нет
                        Совсем нет
                        Полностью - до конца!
                        Меня никогда не было и не будет.
                        И не спрашивайте на форумах где я,
                        Там меня всегда бьют и обижают потом!
                        Они не понимают меня и не знают где я... © HEREDOC
                        */}.bind(null));
                        
                        ?
                          0
                          Вы не обратили внимание, что я отвечал на другой вопрос?
                            –1
                            В контексте поста ваш пример не имеет смысла, а значит ваша претензия к fn.toString() не валидна.
                              0
                              Еще раз, я отвечал на конкретный вопрос:
                              Регулярки в JS настолько медленные?

                              Зачем вы пытаетесь это связывать с чем-то другим, я честно не понимаю.

                              А если мы уже говорим о Here docs, то в тех же PHP, Perl, Bash, Ruby и т.д. можно использовать еще языковые конструкции, например интерполяцию:

                              my $name = "Vasya";
                               
                              print <<"END";
                              Hello $name,
                              Have a nice day!
                              END
                              


                              И по хорошему, такой функционал можно было бы и поддержать.
                              Правда сейчас это уже не имеет никакого смысла, т.к. в ES6 есть Quasi-Literals с нормальными полифилами.

                      0
                      > /regexp/.exec(fn.toString()) — это вообще в принципе не продакшн.

                      Не могли бы вы пальцем ткнуть к чему это относиться? Я не силен в JS. Сам использую grunt, проверил работоспостобность — все работает. Но суть не в этом. В статичном JS файле в принципе я тоже не вижу необходимости использовать такой подход.

                      У меня ситуация другая. Получаю через AJAX переменные(html) и команды на JS. И мне в итоге либо регулярку ставить на стороне сервера и превращать html в однострочыний или добавлять слеши или использовать xml(и доп запрос на сервер слать). Причем тогда мне нужно будет делать перехват вывода. Мне этот метод показался панацеей в моем случае.

                      Если у него есть проблемы я бы хотел знать о них.
                        0
                        Ну, во-первых, это хак. Изящный и, кстати, давно известный, но всё-таки хак.
                        И, кстати, помнится, то ли в старом файрфоксе, то ли в старом ИЕ комменты вырезались. На современных браузерах всё работает ок, но нет никакой гарантии, что так будет вечно. В спецификации английским по белому написано, что результат Function.prototype.toString — implementation specific.

                        Во-вторых, производительность. В то время, как люди меняю на jsperf микросекунды, тут накладные расходы на вызов функции и регулярку вообще не считаются.

                        Варианты выхода из ситуации:

                        Если вам нужно на стороне сервера сгенерировать что-либо в нотации JavaScript, можно использовать JSON. Даже само его название, «JavaScript Object Notation» как бы намекает. Тем более, поддерка на серверной стороне широчайшая — от PHP до Erlang,

                        Можно использовать экранирование символа переноса строки:
                        var myVar = "foo\
                        bar\
                        baz";

                        (Во, даже хабрапарсер правильно подсветил код!) Но предупреждаю, в спецификации про этот способ ни слова, опять-таки, 100% совместимость никто не гарантирует.

                        Вариант три: в ES6 уже есть поддержка строк с переносами. Вполне возможно, какой-нибудь Traceur это уже умеет.
                          0
                          Ага, в спеке ES3 вот даже как:

                          «A line terminator character cannot appear in a string literal, except as part of a LineContinuation to produce the empty character sequence. The correct way to cause a line terminator character to be part of the String value of a string literal is to use an escape sequence such as \n or \u000A.»

                          И Google Closure Compiler в advanced режиме выдаст ошибку.
                    0
                    Видел подобную штуку в марте этого года очень понравилась идея multiline template через комментарии и анонимную функцию. Их реализация мне нравится больше.

                    Про то термин «heredoc» слышу впервые — спасибо.
                      0
                      Странно, что никто не вспомнил про coffeescript
                      html = """
                             <strong>
                               cup of coffeescript
                             </strong>
                             """
                      
                      будет оттранслировано в
                      var html;
                      
                      html = "<strong>\n  cup of coffeescript\n</strong>";
                      
                      
                        0
                        Его ведь еще надо оттранслировать в браузере.
                          0
                          Это что же, только ради многострочности на кофескрипт переходить?
                          0
                          А чем это отличается от github.com/sindresorhus/multiline?
                            0
                            Мне кажется, что пример в статье быстрее.

                          Only users with full accounts can post comments. Log in, please.