RubyHammer: различия между версиями
Содержимое удалено Содержимое добавлено
MaxSem (обсуждение | вклад) м Исправление опечаток и коррекция по мелочи , typos fixed: еще → ещё (19), ее → её (27), в нем → в нём (9), того-же → того же, нашелся → нашёлся (6), объем |
|||
Строка 328:
Диапазон-мотоцикл (<big><code>..</code></big>) проезжает от первого указанного объекта к его <code>.succ</code> (''succedent'' — «последующему»), и до последнего включительно. Три точки — то же, но мотоцикл остановился прямо перед последним элементом. Ещё раз:
<big><code>1..99</code>
{{info|Объекты, имеющие <code>.succ</code> называют [[w:Последовательность|последовательными]]: этим методом можно по текущему элементу достоверно определить следующий.}}
Строка 572:
<source lang=ruby>(1..6).to_a #-> [1,2,3,4,5,6]</source>
Есть
=== Диапазоны ===
Строка 586:
<code>[ 'a'<math>{}^{0}</math>, 'b'<math>{}^{1}</math>, 'c'<math>{}^{2}</math>, 'd'<math>{}^{3}</math>, 'e'<math>{}^{4}</math> ]</code>
Такая нумерация называется в Ruby положительной индексацией. Хм, — скажете вы, — а есть
<code>[ 'a'<math>{}^{+0}_{-5}</math>, 'b'<math>{}^{+1}_{-4}</math>, 'c'<math>{}^{+2}_{-3}</math>, 'd'<math>{}^{+3}_{-2}</math>, 'e'<math>{}^{+4}_{-1}</math> ]</code>
Плюсы расставлены лишь для красоты. Но вернемся к отрицательной индексации. Каков
<code>maccuB = [ 'a', 'b', 'c', <u>'d'</u>, 'e']
Строка 632:
==== Получение размера массива ====
В Ruby массивы динамические: в каждый конкретный момент времени неизвестно сколько в
<code>[1,'считайте',3,'количество',5,6,'зяпятых',2,5]<u>.size</u> #-> 9</code>
Строка 862:
Основную его логику занимает именно чтение нужного формата, кеширование, разбор, десериализация и т.п.
Просто реализуйте <code>.each</code> и включите в ваш класс mixin <code>Enumerable</code>. В
методов, таких как <code>.inject</code>, <code>.each_with_index</code> и т.п.
Строка 914:
noJIHbIu_maccuB<u> == []</u> #-> false</code>
<code>nycTou_maccuB = []
Строка 1091:
Невероятно, но ''от изменения имен переменных, результат остается прежним''. Помните это!
Для полноты картины решим
<code>maccuB = [1,2,3,4,5]
Строка 1432:
#-> {5=>1, 1=>3, 2=>4, 3=>1, 4=>1}</code>
Страшноватая запись. Поэтому будем разбирать
<code>result.update<u>( { i=>1 } )</u>{ |key,old,new| old+new }</code>
Сразу после названия метода (в нашем случае <code>.update</code>) идет передача параметра. Страшная запись <code>{ i => 1 }</code> — это не что иное, как
{{info|Не обязательно писать именно <code><nowiki>{ i=>1 }</nowiki></code>. Можно "сократить" фигурные скобки и записать <code><nowiki>i=>1</nowiki></code>}}
Строка 1505:
Чуть ранее уже говорилось, что в большинстве случаев индексные массивы удобней ассоциативных.
{{Рамка}}Некоторые программисты утверждают, что при больших
Мнение авторов таково, что у программиста на Руби есть более благородные пути времяпровождения, чем заниматься такой вот псевдооптимизационной ерундой.{{Акмар}}
Строка 1601:
noJIHbIu_xew.empty? #-> false</source>
а то
{{info|Обратите внимание, что метод <code>.empty?</code> полностью повторяет такой же метод у индексных массивов}}
Строка 1612:
kapmaH<u>.keys.include?( "гаечный" )</u> #-> true</code>
В данном примере у нас в <code>kapmaH</code>`e
Но лучше задавать вопрос напрямую, это покажет ваше прекрасное знание языка.
Строка 1739:
Строковый тип является самым популярным в любом языке программирования. Ведь без него невозможно написать любую программу (особенно учитывая, что любая программа — это строка). При выводе на экран или записи в файл, любой тип данных преобразовывается к строке (явно или неявно). Это значит, что в конечном итоге все сводится к строковому типу. Кстати, и ввод данных тоже осуществляется в виде строки (и только потом преобразовывается в другие типы).
{{Начало цитаты}}Студенты 4-го курса МЭТТ ГАИ поступили на подготовительные курсы в МГИУ. Там им начали преподавать основы программирования на Ruby. И одна из заданных им задач была: "Дано число, необходимо поменять порядок цифр на обратный". Задача сложная, но наши студенты об этом не знали и решили
Язык Ruby унаследовал работу со строками из языка Perl (признанного лидера по работе со строками). В частности такой мощный инструмент как «правила» (rules).
Строка 1761:
Давайте будем называть строки в минутах «ленивыми», а строки в лапках — «работящими».
{{info|«Вставка» — это хитрая конструкция, которая вставляется между ограничительными символами (внутрь строки). Она состоит из комбинации решетки и двух ушек ( <code><u>#{</u> 'здесь был Вася' <u>}</u></code> ). Внутри
{{Начало цитаты}}
Строка 1838:
{{info|Заниматься оформлением выходных данных стоит только непосредственно перед выводом результата. В остальное время, использование оформительских элементов будет только мешать}}
Всем известно, что числа внутри компьютера хранятся в двоичной системе. Но вот парадокс: получить двоичное представление числа иногда очень сложно. В частности, для того, чтобы получить двоичную запись числа необходимо создать строку и записывать результат в
<code>ucxogHoe_4ucJIo = 123
Строка 1873:
Теперь за свое будущее можно не беспокоиться! Хотя нам может попасться неграмотная кукушка…
С делением совсем другая история. Сейчас его в языке просто нет, но этот недостаток уже ощущают многие. Смысл деления состоит в том, чтобы преобразовать строку в массив, разбив
<code>pe4b_kykywku = "Ky-ky! Ky-ky! Ky-ky! Ky-ky! Ky-ky! Ky-ky! Ky-ky! ... Ky-ky! Ky-ky! "
Строка 2016:
{{Начало цитаты}}
В массив
Учителям он свыше дан!<br />
Зачем его я вспомнил?!
Строка 2080:
=====Квантификатор=====
Квантификатор показывает сколько раз может повторяться предыдущий символ (группа, альтернатива или
<code>/\w<u>{3}</u>/ #-> три латинских буквы или цифры
Строка 2208:
На этот раз мы просто задействовали символьный класс вместо альтернативы, который описывает первую букву слога с оШЫбкой.
Есть
* А как получить весь текст, который совпал с правилом?
* Неужели необходимо делать всеобщую группировку?
Строка 2238:
cTpoka.scan(/(?:[-a-z_\.])*@(?:[-a-z])*(?:\.[a-z]{2,4})+/) #-> ["nata@rambler.ru"]</code>
Выполните
Ну со <code>.scan</code> должно быть все понятно. А вот то, что метод <code>[]</code> начинает тоже правильно искать — пока нет.
Строка 2275:
=== Хитрости ===
====Перенос по словам====
Несколько лет назад (
<source lang=ruby>class String
Строка 2292:
<source lang=ruby>(.{1,80})( +|$\n?)|(.{1,80})</source>
Очевидно, что оно состоит из
* '''(.{1,80})''' — строка длиной от 1 до 80 символов (любых). Результат группировки записывается в <code>$1</code> (один доллар) или <code>"\\1"</code>
* '''( +|$\n?)''' — пробелы или конец строки. Результат группировки записывается в <code>$2</code> (два доллара) или <code>"\\2"</code>. Обратите внимание на запись <code>$\n?</code>, которая означает "конец строки (<code>$</code>), после которого может идти перенос (<code>\n</code>)". Обратите внимание, что <code>$2</code> мы не используем и поэтому можно использовать <code>(?: )</code> (группировку без сохранения результата)
Строка 2430:
Если вы реализуете программу, которой будут пользоваться другие, считается хорошим тоном реализовывать методы-предикаты.
<source lang=ruby>arr = [1,2 ,3]
Строка 2517:
Ruby позволяет создавать анонимные методы и передавать их функциям - такие анонимные методы называются **блоками**. Очень большое количество функций Ruby основано
на использовании блоков - например, итераторы (такие как <code>each</code> и <code>map</code>). Блок - это фактически "функция в функции" - программист определяет
операцию, которую необходимо выполнить, но непосредственно
==== Зачем они нужны ====
Строка 2556:
==== Блоки принимают аргументы ====
Другое замечательное свойство блоков — они, как и функции, могут принимать аргументы. В таком случае метод, которому передан блок, сам "решает", что этот блок получит в качестве аргумента. Например, уже продемонстрированный метод <code>.map</code>
<source lang=ruby>puts (1..3).map do | index |
Строка 2894:
{{Начало цитаты}}При разработке своего Rails-приложения мной применялся класс <code>OrderedHash</code>, который работает как стандартный хеш, но при этом имеет упорядоченные ключи. Это позволяет, к примеру, удобно сгруппировать новости по датам, сохраняя порядок дат.''
''В какой-то момент моя программа перестала работать''. Почему? В Rails был, для внутренних нужд, добавлен другой класс <code>OrderedHash</code>, но при этом он не соответствовал моему (и даже не соответствовал обычному <code>Hash</code> — некоторых методов в
{{Подпись|[[Участник:Julik|Julik]] 01:52, 25 июня 2006}}
Строка 2903:
== Матрицы и вектора ==
Давно хотел написать историю про то, как использовать [[w:Матрица (математика)|матрицы]] и [[w:Вектор (математика)|вектора]] в Ruby, но руки дошли только сейчас. Мое знакомство с реализацией матричного исчисления в Ruby началось
<source lang=ruby>require 'matrix'
p Matrix[[1,-2,3],[3,4,-5],[2,4,1]].det #-> -50</source>
Строка 2911:
И в некоторых случаях это меня действительно выручало. Но не всегда... стоило появиться делению на 3, как появлялись ненужные остатки и погрешности. И чем больше исходная матрица, тем больше вероятность появления таких остатков. В некоторых случаях это было несущественным, а в остальных приходилось прибегать к услугам специальных математических пакетов (например,[[w:Maxima|Maxima]]). Было жутко неудобно (я тогда писал курсовой, который решал все варианты контрольной работы по предмету <Математическое программирование>. Да простит меня преподаватель, который так и не понял секрета тотальной успеваемости группы) и обидно за такую "кривую реализацию".
На этом бы история и закончилась (как позже я узнал, на этом она заканчивалась для многих), но мне в руки попалась книга Programming Ruby 2ed с описанием возможностей стандартной библиотеки версии 1.8.2. Именно там (на стр. 671) я наткнулся на описание библиотеки mathn. Уникальность
{{info|Проще говоря, появляется возможность делить числа без погрешностей (класс <tt>Rational</tt>) и возможность извлекать квадратный корень из отрицательного числа (класс <tt>Complex</tt>)}}
Одновременно с этим она добавляет матричное и векторное исчисления (правда, почему-то в книге дополнительно подключали <tt>complex</tt> и <tt>matrix</tt>). И после этого матричное счисление начинает работать "из коробки" и
Чуть позднее, один из моих студентов написал мне письмо с просьбой объяснить как <работать с матрицами в Руби>? При этом он задал всего три вопроса:
Строка 2929:
=== Как послать в матрицу 2-мерный массив? ===
Немножко перефразируем вопрос: <как преобразовать двумерный массив в матрицу>? Пусть ответ будет неожиданным, но это делается при помощи того
<source lang=ruby>require 'mathn'
maccuB = [[1, -2, 3], [3, 4, -5], [2, 4, 1]]
Matrix[ *maccuB ]</source>
Оператор * преобразует <tt>maccuB</tt> в список параметров, что позволяет существенно упросить процесс создания матрицы. Более того, это единственно удобный метод
=== Как изменить элемент матрицы? ===
Строка 2970:
{{info|Обратите внимание, что <tt>BekTop</tt> создается точно также, как и матрица. По сути, вектор - это матрица, которая состоит лишь из одной строки. А матрица, в свою очередь - это массив векторов}}
Итак, в
=== Хитрости ===
Строка 2977:
==== Решение систем линейных уравнений методом Гаусса ====
Как я уже рассказывал раньше, первая моя программа на Ruby (декабрь 2002 года) -- реализация симплексного алгоритма для решения задач оптимизации. Весь фокус в том, что я эту программу
Но суть не в этом. После того, как я
<source lang=ruby>require 'mathn'
ypaBHeHue = [Vector[1,2,1,1],Vector[1,5,6,2],Vector[1,5,7,10]]</source>
Строка 3052:
p ypaBHeHue #-> [Vector[1,0,0,19], Vector[0,1,0,-13], Vector[0,0,1,8]]</source>
Ну вот и все... вроде как решение получили. Но было бы замечательно, если бы выводилось не все уравнение, а только столбец свободных членов. Задачка простенькая, но важная. Давайте
<source lang=ruby>p ypaBHeHue.map{ |vector| vector.to_a }.transpose[-1] #-> [19,-13,8]</source>
Теперь задачу можно считать решенной! Жаль только, что программа работает только для уравнения 3х4. Надо бы добавить несколько итераторов, чтобы они самостоятельно определяли размерность уравнения. Для этого нужно проследить чередование индексов и записать для них итераторы (хоть я и недолюбливаю <tt>.each</tt>, но для данного случая он
<source lang=ruby>require 'mathn'
Строка 3081:
Обратите внимание, что <tt>ypaBHeHue</tt> задается через матрицу (которая, не без помощи метода <tt>.row_vectors</tt>, преобразуется в массив векторов). Также обратите внимание, что получить последний столбец можно посредством итератора <tt>.map</tt> и метода "батарейка".
Кстати, реализация симплексного алгоритма подразумевает
# Если какой либо элемент главной диагонали нулевой, то необходимо переставить строки и/или столбцы, чтобы это исправить.
# Преобразование целевой функции и системы уравнений из текстового формата (<tt>2*x1-x2-x4 > min</tt> и <tt>x1-2*x2-2*x3-x4 <= 10</tt>) в <tt>YAML</tt>
Строка 3135:
После этого, он сильно бьет себя по лбу и выкрикивает нечто вроде «Я идиот!» И все от осознания того, что процесс откладки давно можно было упростить таким способом.
А вот другая история. Программист пишет и отлаживает программу, которая все необходимые данных выводит на экран. Но в конечном итоге программа должна запускаться без участия человека и
<code>$stdout = File.open('выходные данные.txt',<u>'w'</u>)
$stderr = File.open('сообщения об ошибках.txt',<u>'a'</u>)</code>
Строка 3175:
== Сети ==
===Как написать [[w:Троянская программа|троян]]?===
Однажды, один из студентов (<tt>Geka</tt>) попросил меня рассказать о том, как создать простейшее клиент-серверное приложение на Ruby. Перед тем, как подойти ко мне он уже облазил несколько форумов, но у него все равно осталось много вопросов. Отчаявшись он наконец
{{Начало цитаты}}
Строка 3182:
====Построение серверной части====
На руках у него уже была серверная часть программы, которая позволяла манипулировать удаленной файловой системой (как потом оказалось, ему
<code>require 'socket'
Строка 3264:
Этот программный код создает сервер, который будет прослушивать порт <tt>3000</tt>. В качестве порта может использоваться любой другой (например, <tt>31337</tt>). Менять имя хоста (<tt>localhost</tt>) не нужно, если только у Вас не несколько сетевых интерфейсов. Если у Вас их все таки несколько, то ничего по поводу смены хоста Вам объяснять не надо. Вы и так все, скорее всего, знаете ...
* <code>if (<u>session = server.accept</u>) ... end</code>
При помощи такой нехитрой комбинации ловится соединение с сервером. Обратите внимание, что в примере студента использовалась конструкция <code>while</code>.
* <code>cmd, arg = <u>*</u>session.gets.chomp.split</code>
Данный код интересен тем, что в программе студента для его реализации задействовано аж три строчки. И все лишь потому, что он не знал, что такое оператор <tt>*</tt> (звездочка). Этот оператор преобразует массив в список параметров. Тем самым он освобождает нас от нуждого присваивания. Сам же код получает от клиента строку, которая интерпретируется им как "команда и аргумент, разделенные пробелом". Обратите внимание, что работа идет с переменной <code>session</code>, а не <code>server</code>.
Строка 3273:
{{info|Для того, чтобы прекратить работу сервера необходимо нажать комбинацию клавиш <tt>Ctrl+C</tt> или <tt>Ctrl+Break</tt>. Команду отключения данный сервер не поддерживает. Команда <tt>shutdown</tt> относится к клиенту}}
Несмотря на то, что данный сервер вполне рабочий, у него есть один существенный недостаток - он не работает для нескольких клиентов. Для того, чтобы это реализовать необходимо обрабатывать каждое соединение с клиентом в отдельном потоке. Кто изучал мультипроцессорное программирование, тот понимает о
<code><u>require 'gserver'</u>
Строка 3331:
Как мы уже видели выше, серверная часть полностью определяет функциональность всего клиент-серверного приложения. Клиентская часть же лишь принимает от пользователя запросы, пересылает их серверу и получает ответ, который передает пользователю.
Хотя Geka и имел в своем распоряжении клиентскую программу,
Для соединения с сервером по протоколу [[w:TCP/IP|TCP/IP]] используется класс <tt>TCPSocket</tt> из библиотеки <tt>socket</tt>. Для того, чтобы наша задача была конкретней, мы заставим сервер (при помощи нашего клиента) выполнить следующие команды: <tt>ls</tt>, <tt>cd ..</tt>, <tt>ls</tt> и <tt>shutdown</tt>. Вывод результата выполнения этих команд мы будем осуществлять на экран, но пользователь не получит возможности изменять эту последовательность действий (кроме как исправив программу). Он увидит только результат. Логика здесь следующая: зачем заставлять пользователя вводить команды, если это может делать программа? Если же пользователю нужна другая последовательность команд, то пусть использует telnet или правит клиентскую часть под свои нужды.
Строка 3363:
}</code>
Уже лучше... по крайней мере программа работает. Но давайте поразмышляем над ситуацией, которая произошла с методом <code>.read</code>. Если немного подправить сервер и выдавать после каждой передачи этот символ, то программа с <code>.read</code> могла бы с успехом работать. Какова здесь мораль? А мораль в том, что для успешной работы необходимо с сервера передавать сигнал, который означал бы "последняя строка, которую я передаю клиенту". Чтобы клиент не пытался читать данные с сервера, а начинал их передачу. Вполне естественно, что добавление такого сигнала означает модификацию сервера. В качестве сигнала последней строки мы будем использовать строку <tt>+ОК</tt>. Почему именно такую? Просто видел
<code>require 'gserver'
Строка 3403:
</code>
Была добавлена лишь одна команда (хотя, самые внимательные могут заметить, что
<code>require 'socket'
Строка 3530:
<nowiki>loop{</nowiki> <u>system</u>( gets )<nowiki>{ |str|</nowiki> puts str <nowiki>} }</nowiki></code>
Способ не совсем честный, но нет причин о
После запуска данной программы надо ввести имя хоста и порт. Далее, можно вводить команды, которые поддерживает сервер (в нашем случае <tt>ls</tt>, <tt>cd</tt> и <tt>shutdown</tt>).
Строка 3536:
===Как создать сетевой блокнот?===
Идея написать подобную программу появилась после прочтения статьи [http://doci.nnm.ru/php_forall_/22.11.2006/sozdaem_svoj_onlajn_bloknot/ Создаем свой online-блокнот]. Продемонстрированная там программа предельно проста, но на
====Первое приближение====
В первом приближении мы попытаемся реализовать ту же самую функциональность, что и описана в статье. Вот только [[w:PHP|PHP]] подразумевает наличие веб-сервера, который будет заниматься интерпретацией его команд. В нашем же примере мы самостоятельно поднимем веб-сервер (написанный на Ruby), чтобы не заморачиваться с настройкой стороннего.
Строка 3591:
{{Внимание|Обработка кода внутри тегов ERB идет только во время обработки шаблона (вызова метода <tt>.result</tt>)}}
Не знаю почему, но ERB для меня это "PHP, только на Ruby". Эта фраза обладает столь магическим свойством, что после
{{info|Библиотека WEBrick поддерживает PHP-скрипты благодаря [[w:CGI|CGI]]-сервлету}}
Строка 3617:
: Создаем переменную <tt>wa6JIoH</tt> и присваиваем ей строку, которая по совместительству является ERB-шаблоном. Внутри строки можно заметить тег <tt><nowiki><%= ... %></nowiki></tt> внутри которого осуществляется считывание файла <tt>notepad.txt</tt>. Результат считывания будет вставлен вместо тега <tt><nowiki><%= ... %></nowiki></tt> во время обработки ERB-шаблона.
* <code>resp.body = <u>ERB.new( wa6JIoH ).result</u></code>
Создаем объект ERB и передаем туда подготовленный ERB-шаблон. Обрабатываем его методом <tt>.result</tt> и результирую строку передаем методу <tt>.body=</tt>, который подставляет
И что мы получаем в результате? Подключили "лишнюю" библиотеку и создали "лишнюю" переменную? Не будем спешить с выводами. Использование библиотеки ERB позволяет вынести шаблон во внешний файл. Тем самым мы очищаем Ruby-код от HTML-кода.
Строка 3637:
</html></source>
Переменную шаблон мы убираем, а вместо
<code>require 'webrick'
Строка 3673:
На этом все... из чего состоит наша программа теперь?
* <tt>notepad.rb</tt>. Программа-сервер. Назвать файл можно на свое усмотрение. Главное, чтобы работал. Содержит логику, которая осуществляет конфигурирование и запуск сервера.
* <tt>index.html</tt>. ERB-шаблон. В
* <tt>notepad.txt</tt>. Файл данных. В
В качестве задания для самостоятельной проработки, предлагаю вам реализовать не только ввод и редактирование, но и просмотр без возможности редактирования. Подсказка: подключайте второй сервлет.
Строка 3702:
end
p ping(ARGV[0] || "localhost")</source>
Итак, давайте разберем, что делает наш метод. Он создает соединение посредством класса TCPSocket и тут же закрывает его. Если соединение проходит слишком долго (хост не существует в сети) или произошла какая-то другая ошибка (не поддерживается протокол или
=== Простейший датчик работы службы ===
Строка 3711:
* баннер службы.
<source lang=ruby>require 'socket'
Строка 3738:
f.puts( "#{sprintf( '%02d',Time.now.hour )} | #{end_time-begin_time} | #{request}" )
}</code>
Великолепно! Программа работает... но иногда зависает. И тогда меня посетила
<code><u>require 'timeout'</u>
require 'socket'
Строка 3793:
}
}.real</source>
Или можно просто вместо <tt>Benchmark.measure</tt> использовать <tt>Benchmark.realtime</tt>. Теперь надо бы разделить ошибки по таймауту и ошибки соединения. Для этого надо добавить лишь
<code>require 'socket'
require 'benchmark'
Строка 3873:
====Запрос заголовка====
Во время скачивания передается не только сама страница (<b>тело сообщения</b> или на англ. body), но и техническая информация (<b>заголовок</b> или на англ. head). Мы
<code>require 'net/http'
Строка 3962:
{{info|Очень часто необходимо осуществить передачу данных между компьютерами по сети. Для этого вполне подойдет <tt>WEBrick</tt>. Быстро напишите веб-сервер, который будет просматривать нужную директорию. Теперь, для вас это больше не проблема!}}
Но вернемся к заказанной мне программе. Она будет состоять из двух частей: обычная <tt>html</tt>-страница (<tt>index.html</tt>) и [[w:Сервлет|сервлет]] (<tt>/input</tt>). Страница <tt>public_html/index.html</tt> будет содержать форму в которую будут вводится исходные данные.
<source lang="html4strict"><nowiki><HTML><BODY><form </nowiki><u>action='/input' method='post'</u><nowiki>><div align=center>
Строка 4015:
{{info|Geka, когда увидел этот код, воскликнул: "И не лень было такой код писать?" На что я ему резонно ответил, что этот код является результатом программы-генератора, которую я не привожу здесь, чтобы не отвлекать внимание читателя от более интересной темы}}
Хотя код и довольно
* <code>action='<u>/input</u>'</code>
: Адрес, по которому будут передаваться данные. Это может быть как [[w:CGI|CGI]]-приложение, так и сервлет. В нашем случае это сервлет <tt>/input</tt>.
Строка 4110:
====Сервлетки в рубиновом соусе====
Мы уже неоднократно упоминали понятие [[w:Сервлет|сервлет]], но особенно на
* '''Файловый сервлет'''
: Реализует взаимосвязь запроса с реальным файлом (или директорией). В самом первом примере мы использовали файловый сервлет, когда передавали <code>:DocumentRoot => 'public_html'</code> в качестве параметра методу <code>.new</code>. Это было равнозначно созданию файлового сервлета на корневой директории веб-сервера. Функциональность файлового сервлета описана в классе WEBrick::HTTPServlet::FileHandler.
|