Новости

Обновление исправляет совместимость с Freenode после обновления этой сетью версии IRCd.

Вышел второй релиз-кандидат KVIrc 4.0

Ричард Столлман дал автограф проекту и пожелал успеха в разработке.

Image:Feed.png RSS

Материал из IRC клиент KVIrc.

Перейти к: навигация, поиск

Содержание

[править] Введение

Язык сценариев KVIrc по сути не является объектно-ориентированным. Тем не менее, объекты являются абстракциями высокого уровня, которые позволяют писать сложный код "чисто". Потому я добавил по крайней мере какую-то поддержку псевдо-объектов.

[править] Общее представление

Объекты упорядочиваются в виде древовидных структур. Каждый созданный вами объект является объектом верхнего уровня или children (наследником, дочерним объектом) другого объекта. Объект верхнего уровня не имеет предков (родительских объектов). Очевидно, что у всех объектов могут быть дочерние объекты.

Когда объект уничтожается, все его наследники также уничтожаются. Объекты верхнего уровня автоматически уничтожаются при выходе из KVirc. Объекты являются глобальными для всего приложения (в этом отличие от предыдущих версий KVirc, где объекты были локальными для текущего окна и упорядочивались в единственное дерево с встроенным root-объектом).

Каждый объект это экземпляр класса, который определяет его возможности. Каждый объект также имеет имя, которое не обязательно должно быть уникальным и присваивается программистом; имя это всего лишь мнемоническая уловка (?) и вам оно возможно не понадобится (the name is just a mnemonic expedient, and you may also not need it).

Каждый объект идентифицируется с помощью OPAQUE UNIQUE ID. ID присваивается KVIrc и может удерживаться в любой переменной. Можно считать, что идентификатор объекта (id) - это "хэндл объекта" ("handle for the object") или указатель на объект. Любое действие, выполняемое над объектом, потребует ID объекта.

[править] Создание и уничтожение

Для создания объектов следует использовать функцию $new(). $new() принимает три параметра:

- Класс объекта (про классы будет сказано дальше в этой документации)

- ID родительского объекта , (может быть 0).

- Имя объекта (может быть пустым)

   %myobject = $new(object,0,theName)

$new() возвращает значение ID, присвоенное только что созданому объекту, или "0" если создание объекта завершилось неудачей (обратите внимание, что "0" это строка потому что идентификаторы объектов по большей части строки и 0 это неправильный идентификатор объекта). В правильно написаных скриптах, неудачное создание объектов это скорее исключения из правил. Но вы все равно можете проверить, что объект был создан без ошибок.

   if(%myobject)echo "Object created!"
   else echo "Object creation failed!"

Вы можете сравнивать объекты по их ID:

   if(%myobject == %anotherobject)echo "Это одинаковые объекты!";

Идентификатор родительского объекта опционален, и если он не указан то устанавливается в 0. Имя объекта также опционально, но оно может пригодиться, например для поиска, так что не пренебрегайте им.

Для удаления объекта используейте команду delete. (В прошлых версиях эта команда называлась "destroy").

   delete %myobject

Если удаляемый объект имеет дочерние объекты, то они также будут удалены.

Каждый объект может иметь свои переменные (поля). Вы можете обращаться к ним через оператор "->":

   %myobject->%fieldVariable = dataString

Для освобождения поля присвойте ему пустую строку (как и в случае с обычными переменными). Чтобы получить значение любого поля используйте :"->":

   echo %myobject->%fieldVariable

Оператор '->' заимствован из языка C. В скриптовом языке KVIrc он является переключателем с глобального пространства имен на пространство имен объекта. В примере выше поле %fieldVariable принадлежит объекту %myobject. Первый символ в названии переменной не имеет специального значения в пространстве имен объекта (в глобальном пространстве имен переменные названые с большой буквы являются глобальными для приложения, названые же с маленькой буквы являются локальными). Т.е. в пространстве имен объкта все переменные регистронезависимые.

Любой оператор можно применить к полям объекта:

   %myobject->%fieldVariable = 0
   %myobject->%fieldVarialbe ++
   if(%myobject->%fieldVariable != 1)echo KVIrc is drunk , maybe a reboot will help ?

Вы можете имитировать структуру языка С "на лету":

   # Create an user description on the fly
   %myobj = $new(object,0,userDescription)
   # Set the fields
   %myobj->%nickname = Pragma
   %myobj->%username = daemon
   %myobj->%hostname = pippo.pragma.org
   %myobj->%info = Pragma goes always sleep too late
   %myobj->%info << and wakes up too late too!
   # Call an (user defined) alias that stores the data to a file
   storetofile %myobj
   # Destroy the object
   delete %myobj

Поля могут быть массивами:

   %theobj->%field[key] = something

В отличии от С, в kvs не нужно заранее объявлять поля. Любой из объектов может иметь любое поле; уничтожение поля "unset", эквивалентно присваиванию ему пустого значения.

Примечание: Скриптовый язык KVIrc не типизирован. Любой идентификатор класса объекта (информация о классах будет приведена ниже) может храниться в обычной переменной KVIrc, и узнать о каких-либо присущих ему свойствах по идентификатору невозможно. Это может немного затруднить работу с объектами. Однако, при определенном умении, вполне возможно использовать все преимущества объектов. Идентификацию классов объектов можно, например, "эмулировать" при осторожном использовании имен объектов; так, в приведенном выше примере объект %myobj был создан с именем "userDescription". В таком случае алиас storetofile мог бы проверять присвоенное объекту имя, и в случае его несоответствия с "userDescription" прекращать выполнение.

Note: The KVIrc scripting language is not typed. Any object class (be patient...I'll explain classes in a while) identifier can be stored in any KVIrc variable: it is not possible to find out the object features by "examining" its identifier. This may make the usage of objects a bit "unclear"; Howewer, with some experience you will be able to use the objects in a very powerful way. The type-safety can be also simulated by a careful usage of object names; in the above example, the %myobj object was created with the "userDescription" name. The storetofile alias could check the passed object's name and refuse to work if that does not match "userDescription". A more complex use of fields will be described later in this document.

[править] Методы (функции-члены)

Как и в C++, объекты могут иметь функции-члены. Например, объекты класса "object" предоставляют функции $name() и $classname().

   %tmp = $new(object,0,myobject)
   echo The object's name is %tmp->$name() , the class name is %tmp->$classname()
   # Destroy the object
   delete %tmp

Кроме того, этим классом предоставляется функция $children(). Она возвращает разделенный запятыми список дочерних объектов.

   %tmp = $new(object,0,myobject)
   %tmpchild = $new(object,%tmp,child1)
   %tmpchild = $new(object,%tmp,child2)
   %tmpchild = $new(object,%tmp,child3)
   echo The object's children list is : %tmp->$children()
   # Destroy the object and the children
   delete %tmp

Также для любого объекта имеются две специальные функции: конструктор (constructor) и деструктор (destructor). Более подробную информацию о них Вы сможете найти далее в этом документе, а пока достаточно будет отметить, что они вызываются в KVIrc автоматически: constructor - при создании объекта, destructor - при уничтожении с помощью delete.

Функции объектов могут быть переопределены "на лету" при помощи команды privateimpl. (Это необычная возможность: в отличие от многих других языков, можно переопределять функции во время выполнения, когда объект уже создан.)

   %tmp = $new(object,0,myobject)
   foreach(%i,1,2,3)
   {
       %tmpchild = $new(object,%tmp,child%i)
       privateimpl(%tmpchild,destructor){ echo Object $this ($this->$name()) destroyed; }
   }
   privateimpl(%tmp,destructor)
   {
       %count = 0;
       foreach(%t,$this->$children())
       {
           echo Children : %t->$name() with class %t->$classname()
           %count++
       }
       echo Just before destroying my %count children.
   }
   # Destroy the object and the children
   delete %tmp

В этом примере создаются четыре объекта. "Родительский" объект с именами "myobject", и три дочерних. Для каждого из дочерних объектов переопределяются деструкторы таким образом, чтобы они сообщали свои имена (обратите внимание на использование $this). В деструкторе родительского объекта выполняется перечисление дочерних объектов. Затем родительский объект уничтожается, вызывая следующие действия:

- выполняется деструктор родительского объекта

- уничтожаются дочерние объекты (с последовательными вызовами всех их "индивидуальных" деструкторов)


Не все функции объектов обязаны возвращать какое-либо значение. Если функция не возвращает значение или возвращаемое значение не нужно, то можно вызвать ее следующим способом:

   %anyobject->$functionname()

[править] Классы

Все объекты являются экземплярами определенных классов. Эта концепция присутствует практически во всех объектно-ориентированных языках. Класс является набором методов, определяющих поведение объекта... не самая легкая задача все это объяснить, лучше покажу на примере:

class HostAddress
{
   field hostname
   function ipnumber()
   function isLocalhost()
}

Показанный класс представляет сетевое имя. После создания экземпляра этого класса можно задать его поле hostname, указав, например, "www.kernel.org". Теперь объект способен прозрачным путем выдавать информацию об указанном имени: посредством вызова функции ipnumber() можно получить IP-адрес, соответствующий указанному имени; функция isLocalhost() будет определять, не ссылается ли указанный адрес на текущий компьютер (localhost). Внутренняя работа объекта скрыта от пользователя, но она вполне может быть довольно велика. Чтобы получить IP-адрес компьютера, объекту возможно потребуется выполнить вызов DNS (обычно это непростая задача). Для проверки, ссылается ли указанное имя на текущий компьютер, объекту возможно потребуется получить имя текущего компьютера от операционной системы и затем сравнить его со значением, записанным в поле hostname.

Внутренняя работа объекта определяется реализацией класса. Соответственно, программист, создающий класс, должен написать его реализацию.

class HostAddress
{
   field hostname
   function ipnumber()
   {
       find the nearest DNS server
       make the dns call
       wait for the response
       decode the response
   }
   function isLocalhost()
   {
       query the kernel for the local hostname
       compare the obtained hostname with the hostname field
   }
}

В этом примере я реализовал функции, используя несуществующий "фантастический" язык.

Давайте теперь вернемся к реальному миру.

KVirc содержит множество встроенных и готовых к использованию классов. Основной класс - это "object": все остальные классы порождаются от него (подробнее о наследовании смотрите далее в этом документе).

Другой доступный класс - это "socket", являющийся интерфейсом к реальным сокетам системы. Экземпляр этого класса может соединяться и обмениваться информацией с другими компьютерами в сети.

Определения классов являются ГЛОБАЛЬНЫМИ для всего приложения, т.е. могут использоваться в любом месте.

Теперь можно сказать что в KVIrc класс - это набор возможностей, определяющих поведение объекта. Пользовательский интерфейс класса - это функции-члены и события.

[править] Наследование

Команда class позволяет определять новые классы объектов. В KVI++ новый класс всегда должен быть унаследован от другого класса. Минимальный уровень наследования - это наследование от класса object.

   class(helloworld,object)
   {
       sayhello()
       {
           echo Hello world!
       }
   }

Продемонстрированный класс назван "helloworld" и унаследован от класса "object". А это означает, что "helloworld" имеет также функции: $name() , $classname() , $children() ... , имеющиеся в классе "object". Кроме того, в классе имеется функция $sayhello() , выдающая в консоли фразу "Hello world!" . Теперь можно создавать экземпляры этого класса:

   %instance = $new(helloworld)
   %instance->$sayhello()

Это было очень просто... Давайте немного усложним задачу и сделаем немного больше: унаследуем от "helloworld" другой класс и заставим его выводить фразу "Hello world!" на двух разных языках:

class(localizedhelloworld,helloworld)
{
   # define the setlanguage function
   # note that <$0 = language> is just a programmer reminder
   setlanguage(<$0 = language>)
   {
       if(($0 == english) || ($0 == italian))
       {
           [fnc:$this]$$[/fnc]->%lang = $0
           return 1
       } else {
           echo I don't know that language ($0)
           echo defaulting to english
           [fnc:$this]$$[/fnc]->%lang = english
           return 0
       }
   }
   sayhello()
   {
       if([fnc:$this]$$[/fnc]->%lang == italian)echo Ciao mondo!
       else [fnc:$this]$$[/fnc]->$helloworld:sayhello()
   }
}

Теперь можно выполнить следующее:

 %m = $new(localizedhelloworld)
 %m->$setLanguage(italian)
 %m->$sayhello()
 %m->$setLanguage(english)
 %m->$sayhello()
 %m->$setLanguage(turkish)
 %m->$sayhello()
 delete %myobj

Данный класс унаследован от ранее определенного helloworld, и, соответственно, получает функции и события класса object, а также функцию sayhello класса helloworld. В новом классе определена также функция setlanguage, которая сохраняет в переменную название языка, переданное ей в качестве параметра (после проверки на правильность указания языка). ($0 - это первый переданный параметр) Если язык неизвестен, то функция setlanguage возвращает 0 (false). Теперь, мы хотим возможность выдавать "hello world" на итальянском и английском. Для этого переопределяется унаследованная функция sayhello, т.е. определяется ее новая реализация: если при вызове %object->$sayhello() переменная %object содержит ID объекта класса localizedhelloworld, то будет вызвана новая реализация этой функции. Унаследованная функция sayhello могла выдавать "hello world" только на английском, однако мы можем ее использовать в новой реализации, не выполняя написание ее кода еще раз: если указанный язык не итальянский (а кроме итальянского мы представили в этом классе только английский), то вызываем реализацию из базового класса.

   [fnc]$this/[fnc]->$helloworld:sayhello()
   # equivalent to $$->$helloworld:sayhello(),
   # to $this->$helloworld::sayhello(),
   # and to $$->$helloworld::sayhello()

В этом примере все значения %lang, которые не равны "italian" мы считаем равными "english". Это не всегда правильно. Однако, сразу после создания объекта переменная %lang будет пуста. Показанный класс будет работать нормально в любом случае, но если мы хотим, чтобы переменные всегда находились в корректном состоянии, то нужно использовать конструкторы, которые будут описаны ниже.

Примечание: множественное наследование (наследование от более чем одного базового класса) не реализовано, KVIrc это не компилятор :)

[править] Конструкторы и деструкторы

Конструктор класса - это функция, вызываемая в KVIrc автоматически сразу после создания объекта перед возвратом из функции $new(). Конструктор может быть использован для инициализации внутреннего состояния объекта. В отличие от C++, в KVIrc конструктор может возвращать значение: если конструктор возвращает 0, то это говорит о неудаче создания объекта - он незамедлительно уничтожается и функция $new() возвращает 0. Любое другое значение воспринимается как успешность создания объекта, и функция $new() возвращает ID созданного объекта. Во всех встроенныех в KVIrc классах конструкторы определены таким образом, что неудачи создания объекта никогда не бывает (за исключением случая нехватки памяти - "out of memory"), поэтому проверять возвращаемый $new() результат необязательно при создании объектов таких классов.

В унаследованных классах конструктор может быть переопределен для инициализации состояния объекта. Однако, следует не забывать вызывать из него конструктор базового класса, чтобы состояние базового класса было корректно установлено, и проверять возвращаемое им значение (вполне возможно, например, что инициализация в базовом классе будет успешна, а в унаследованном - неуспешна). Конструкторы встроенных классов ничего не делают кроме возврата значения 1, и поэтому их вызывать необязательно, но в некоторых случаях это может понадобиться. Такое поведение несколько отличается от таких языков как C++, где конструкторы вызываются автоматически.

[править] Сигналы и слоты

The signals and slots are a powerful mean of inter-object communication. A signal is emitted by an object to notify a change in its state. For example , the button class emits the clicked signal when the user clicks the button.

A signal is emitted by an object and can be received and handled by any other existing object (including the object that emits the signal). The handler function for a signal is called "slot". It is just a convention : in fact , a slot is a normal object function (and any object function can be a slot). More than one slot can be connected to a single signal , and more signals can be connected to a single slot. In this way , many objects can be notified of a change in a single object , as well as a single object can easily handle state-changes for many objects. The signal / slot behaviour could be easily implemented by a careful usage of object functions. So why signals and slots ? Because signals are much more powerful in many situations. The signals have no equivalent in C/C++...but they have been implemented in many highlevel C/C++ libraries and development kits (including the system-wide signal/handler mechanism implemented by all the modern kernels and used in inter-process communication).

Личные инструменты
Инструменты
Наши кнопки
Размести кнопку KVirc у себя на сайте:
www.kvirc.ru - кроссплатформенный IRC клиент с богатым графическим интерфейсом и внутренним языком скриптинга
Друзья и спонсоры
  • Fireforge.net
Linux coutner