Posts Tagged linux

LPT мигает светодиодом

Эту статью я написал года четыре назад. А сейчас внезапно нашёл её, и решил выложить в блог. Довольно забавно :) Предупреждаю, я не несу ответственности за то, что может произойти с вашей техникой в результате применения данной информации.

В последнее время довольно долгое время меня мучила мысль о том, что неплохо бы как-нибудь своими силами связать компьютер с внешним миром. Плюс ко всему впустую простаивающий параллельный порт принтера меня угнетал, ибо у меня принтер подключён через USB. Я просмотрел несколько статей, описаний и прочей литературы, и то что у меня вышло в результате экспериментов назвать оригинальным язык не поворачивается, но, тем не менее, это может показаться кому-то интересным.

Задача стоит весьма тривиальная: научиться управлять мерцанием светодиода, подключённого к ПК через LPT-порт. Почему именно LPT? Потому что он довольно прост и в меру интересен.
Поехали!

Подготовка

Итак, что нам нужно для воплощения этого ужаса в реальное существо:

  • ПК
  • Компилятор какого-нибудь языка программирования (Assembler, С, С++, Pascal, etc…).
  • Некоторый программный инструментарий
  • Светодиод на 5В
  • LPT-шнур

Шнур у меня был только разрезанный, но вы можете использовать любой, главное всё правильно соединять. Вот мой шнур, с уже выведенными контактами для подключения светодиода (об этом речь пойдёт далее):

image

Вот, собственно, светодиод, купленный на ближайшем базаре за несколько денег. Он который будет светиться ярким синим светом:

image

Железо

Прежде чем приступить к практике, немного теории.

Как работаете LPT-порт? Об этом достаточно много написано, однако я всё-таки кратко расскажу как обстаят дела.

Параллельный порт ПК обычно используется для подключения принтеров, но на этом его возможности не ограничиваются. К нему можно подключать любое внешнее, самодельное устройство. LPT-порт имеет 25 пинов, но не все 25 необходимы. В нашем примере, например, нужно только 2. Рассматривать предназначение всех не будем.

image

Подключать светодиод будем плюсом к 2 пину, а минусом – к пину 18. Смотрите, не перепутайте, в противном случае светодиод может сгореть. Лучше предварительно проверить где у него плюс, где минус на маломощной батарейке.

Если у вас шнур папа-мама, то есть при подключении к компьютеру, на вашем конце шнура остаются входы, дело простое – просто воткнуть в нужные пины диод. Следует быть осторожным, неправильно подключив, можно повредить LPT-порт.

image

Лично я, раскурочив шнур, определил, какой относится к D0, какой к земле, и у меня всё выглядит примерно так, как показано на следующем рисунке. Я сидел с пробником, и вычислял, какая линия относится к D0. Очень занимательно! Вы можете найти более удочное решение.

image

В мерах предосторожности можно последовательно к диоду припаять сопротивление. Рекомендуют 470 Ом. На счёт заземления: кто-то заземляет не на пин GRD, а на корпус коннектора, но я предпочитаю пин.

На этом этапе вы должны представлять себе, как можно подключить светодиод к LPT-порту.

Программная часть

Подключить светодиод к компьютеру мы готовы, но вот, дальше-то что? А дальше самое интересное: управление им с бортового пульта. С одним светодиодом много не сделаешь: только включать/выключать его можно. Но зато можно менять частоту мигания, можно подключить ещё 7 светодиодов к остальным пинам D1-D8, и сделать светомузыку. Или приобрести яркие белые светодиоды, и сделать настольную лампу, питающуюся от LPT-порта, которая включается, когда вы начинаете печатать, чтобы подсветить вам клавиатуру. Можно вывести зелёненький светодиод куда-нибудь на видное место и написать программу, мигающую им, когда вам на E-mail приходит письмо. Сколько всего можно сделать только лишь с использованием светодиода! А подковав себя в электронике, можно собирать полноценные внешние устройства, но это, к сожалению, выходит за рамки данной скромной статьи.

Управление LPT-портом зависит от ОС. В былые времена, операционные системы DOS и Windows 95/98 разрешали пользовательским программам напрямую иметь доступ к железу. С появлением Windows NT/2000/XP всё изменилось, теперь общение с портами напрямую пользовательским программам запрещено, а разрешено только коду, выполняющемуся в режиме ядра. Всё это сделано в целях защиты и в других нужных и полезных целях, однако всё это одновременно и усложняет нашу задачу по подмигиванию светодиодом. Нам пришлось бы писать специальный драйвер устройства, разбираться в HAL (Hardware Abstraction Layer) и прочих премудростях. Вы можете заняться этим, почитав материалы по Microsoft DDK (Device Driver Kit). Но существует несколько обходных путей, позволяющих напрямую общаться с нашим LPT. Вообще, так делать не рекомендуется, но всё же, мы сделаем именно так, ибо так проще и нагляднее. Другими словами, напрямую получить доступ к регистрам LPT-порта просто так не удастся. Вы можете работать с драйвером устройства LPT как с обычным файлом при помощи функций CreateFile, ReadFile, WriteFile, а так же получать некоторую информацию о состоянии устройства функцией DeviceIoContol. Но работать с регистром, например, D0, который включает наш светодиод, не получится.

В ОС Linux всё обстоит по-иному. Там можно делать всё просто, имея на то специальные права. Необходимо только узнать по какому адресу находится ваш LPT. Обычно он находится по адресу 0378h. Узнать адрес в вашей системе можно, просмотрев файл /proc/ioports. Хотя, проще работать с файлом устройства /dev/lp0.

Разберём, как справиться с ОС Windows, потому что это немного сложнее.

Перед тем, как перейти непосредственно к программированию своими силами, проверим, работает ли всё это дело, собранное в прошлой части статьи. Для этого я использую чудесную программу мониторинга параллельного порта, так и названную: Parallel Port Monitor by Neil Fraser.

Как делаю я: запускаю программу, выключаю в ней все пины с 2 до 9, затем подключаю светодиод к LPT-порту (в нашем случае во второй пин, в D0). После этого в Parallel Port Monitor подаю единицу на D0. Светодиод должен загореться. Если ничего не произошло, возможно, вы неправильно его подключили или же в программе выбрали не тот LPT-порт. Попробуйте LPT1, LPT2, LPT3, если у вас их несколько.

Светодиод мигает? Отлично. Теперь можно побаловаться с ним своим программным кодом. Как было сказано ранее, это делать мы будем обходным путём. Если вы используете Windows 95/98/ME, можете сразу перейти к написанию программы, обходные пути вам не нужны, эти версии ОС Windows позволяют напрямую обращаться к портам.

1) Использование драйвера UserPort

Программа UserPort (автор Tomas Franzon), это системный драйвер режима ядра для Windows NT/2000/XP, который позволяет обращаться к портам ввода-вывода напрямую. Как раз то, что нам необходимо. Найти её в любом поисковике не составит труда. Скачав, настроив, согласно документации и запустив, мы получаем возможность мигать светодиодом из наших программ.

Сперва определим адреса портов в Device Manager. Видим, LPT1 по адресу 0378-037F. Именно туда мы и будем писать биты управления светодиодом. Пишем 1 – на контакты светодиода подаётся напряжение +5В, он загорается, пишем бит 0 – светодиод гаснет.

image

Напишем тестовую программу, мигающую светодиодом раз в секунду. Исходный текст приведён ниже. Здесь я использовал С++ со вставками ассемблерного кода и компилятор Visual C++. Вы можете использовать свой любимый язык программирования и компилятор, суть не меняется.

#include <iostream>
#include <windows.h>

void doLight(bool on)
{
	__asm
	{
		mov DX,0378h
		mov AL,on
		out DX,AL
	}
}

int main()
{
	while(1)
	{
		doLight(true);
		std::cout<<"Light On!"<<std::endl;
		Sleep(1000);
		doLight(false);
		std::cout<<"Light Off!"<<std::endl;
		Sleep(1000);
	}
	return 0;
}

Компилируем, запускаем, проверяем. Если светодиод стал мигать, значит всё ОК, всё работает, и можно издеваться дальше. Если же появилось сообщение об ошибке, например «First-chance exception at 0×00411524 in program.exe: 0xC0000096: Privileged instruction», значит, вы неправильно запустили или настроили UserPort. Обратитесь к документации по нему, там есть пример.

2) Использование библиотеки inpout32.dll.

Домашняя страница разработчиков библиотеки: http://www.logix4u.net. Там же можно найти много полезной информации. Перед тем как писать код, поместим в каталог с нашим проектом файлы inpout32.dll и inpout32.lib. В этих библиотеках имеются функции, позволяющие читать и записывать в порты.

Вот как выглядит исходный текст программы, с использованием этой библиотеки:

#include <iostream>
#include <windows.h>

#pragma comment(lib, "inpout32.lib")

// прототип функции
void _stdcall Out32(short PortAddress, short data);

void doLight(bool on)
{  Out32(0x378, on);
}

int main()
{   while(1)   {   doLight(true);   std::cout<<"Light On!"<<std::endl;   Sleep(1000);   doLight(false);   std::cout<<"Light Off!"<<std::endl;   Sleep(1000);   }  return 0;
}

Вот так вот:

image

Вроде, всё. Идею можно развить, и сделать какие-нибудь более полезные или интересные программные решения.

Заключение

Как видно, LPT-порт один из наиболее простых в работе портов, и с ним можно довольно-таки интересно работать. Умельцы собирают и подключают роботов через LPT-порт, делают в некотором роде систему управления квартирой, включают/выключают свет в комнате с компьютера и ещё много интересных вещей.

P.S.: Я где-то слышал, что люди собирают LPT- и USB-фонарики, и решил себе сделать нечто подобное из старого микрофона от наушников. Вот что вышло:

image

.NET, cc, e-mail, Hardware

Введение в расширения Ruby на C

Ruby – это замечательный язык программирования, приобретающий всю большую популярность в последнее время. Наверное, вы знакомы с Ruby, раз принялись читать эту статью. В противном случае вам сначала лучше познакомиться с информацией, представленной на официальном сайте www.ruby-lang.org, прежде чем приступать к чтению.

Одна из привлекательных черт Ruby – это возможность создавать свои расширения как на самом Ruby, так и на других языках. Например, у вас есть участок кода, критичный к производительности, то вам лучше реализовать его на C, и потом работать с ним из Ruby. Или же если Ruby не поддерживает вашу любимую библиотеку, а вы хотите «научить» Ruby с ней работать (сперва загляните на www.rubyforge.org, наверняка расширение Ruby для этой библиотеки уже реализовано). А может, вы хотите использовать какие-то специфические возможности операционной системы? Так или иначе, вы всегда можете взять в руки клавиатуру, опуститься на нижний уровень, и запрограммировать всё необходимое на C. Демонстрацией того, как это можно сделать, мы и займёмся в данной статье.

Инструментарий

Инструментарий зависит от ОС в которой мы будем работать. В любом случае, нам понадобится дистрибутив Ruby, последнюю версию которого вы можете загрузить с www.ruby-lang.org. В данной статье мы строим расширения Ruby для Windows. Сборка в среде Linux выполняется аналогично с использованием gcc и make.

Нам понадобится Microsoft Visual Studio. Загрузить Visual Studio Express Visual C++ вы можете совершенно бесплатно отсюда: http://microsoft.com/express/.

Простое расширение

Сейчас мы напишем самое простое расширение. Оно будет содержать две полезные функции: одна выводит на консоль ”Hello World!”, а вторая вычисляет квадрат переданного числа.

Запустим командную строку, в которой будем работать, и создадим для нашего расширения отдельную директорию:

>mkdir MyTest
>cd MyTest
Пишем исходный текст

Теперь создадим файл mytest.c, в котором будет располагаться код нашего расширения:

#include "ruby.h"
void Init_mytest();
VALUE method_sqr(VALUE, VALUE);
VALUE method_sayhello(VALUE);

VALUE mytest = Qnil;

void Init_mytest() {
  mytest = rb_define_module("MyTest");
  rb_define_method(mytest, "sqr", method_sqr, 1);
  rb_define_method(mytest, "sayhello", method_sayhello, 0);
}

VALUE method_sayhello(VALUE self) {
  puts("Hello World!");
  return Qnil;
}

VALUE method_sqr(VALUE self, VALUE x) {
  int y = NUM2INT(x);
  y *= y;
  return INT2NUM(y);
}
Генерируем Makefile

В той же директории создайте файл extconf.rb, со следующим содержимым:

# mkmf используется для создания мейкфайла расширения
require 'mkmf'
extension_name = 'mytest'
dir_config(extension_name)
create_makefile(extension_name)

Запускаем этот скрипт, и он создаст нам Makefile для нашего расширения. Благо нам не нужно составлять его вручную, Ruby побеспокоился об этом за нас:

>ruby extconf.rb
creating Makefile

Теперь один важный момент: если путь до каталога с Ruby содержит пробелы, вам наверняка нужно будет внести изменения в Makefile, иначе расширение скомпилируется неправильно. Откройте Makefile и убедитесь, что значения переменных topdir и ruby не содержат пробелов, либо заключены в кавычки.

Устанавливаем переменные окружения

Если всё верно, самое время скомпилировать расширение.

Сначала необходимо загрузить переменные окружения Visual С++, чтобы компилятор и линковщик могли найти то, что им нужно. Для этого из командной строки, в которой вы работаете, перейдите в каталог \Каталог_Вижуал_Студии\VC\bin\ и запустите vcvars32.bat.

Правим config.h

Ещё одна вещь, которую нужно сделать перед сборкой проекта, это отредактировать файл /Каталог_Ruby/lib/ruby/1.8/i386-mswin32/config.h

Необходимо закомментировать, или удалить следующие строчки в начале файла, чтобы Ruby не ругался, когда мы начнём компилировать расширение:

#if _MSC_VER != 1200
#error MSC version unmatch
#endif
Собираем проект

Теперь вернитесь в каталог с нашим расширением и запустите nmake:

>nmake
Microsoft (R) Program Maintenance Utility Version 9.00.20209
Copyright (C) Microsoft Corporation.  All rights reserved.
  cl -nologo -I. -I"E:/Program Files/ruby/lib/ruby/1.8/i386-mswin32"
  -I"E:/Program Files/ruby/lib/ruby/1.8/i386-mswin32" -I. -MD
  -Zi -O2b2xg- -G6  -c -Tcmytest.c
mytest.c
  cl -nologo -LD -Femytest.so mytest.obj msvcrt-ruby18.lib
  oldnames.lib  user32.lib advapi32.lib ws2_32.lib  -link
  -incremental:no -debug -opt:ref -opt:icf -dll
  -libpath:"E:/Program Files/ruby/lib" -def:mytest-i386-mswin32.def
  -implib:mytest-i386-mswin32.lib -pdb:mytest-i386-mswin32.pdb   Creating library mytest-i386-mswin32.lib and object mytest-i386-mswin32.exp
Добавляем манифест в библиотеку

Расширение скомпилировано. Теперь нужно добавить в него манифест, чтобы библиотека правильно загружалась. Манифест – это некое представление всего, что находится в библиотеке.

Так, выполним команду:

>mt.exe -manifest mytest.so.manifest -outputresource:mytest.so;2
Microsoft (R) Manifest Tool version 5.2.3790.2014
Copyright (c) Microsoft Corporation 2005.
All rights reserved.

Подробнее про манифесты вы можете прочесть в MSDN по следующему адресу: http://msdn2.microsoft.com/en-us/library/Aa375365.aspx

Проверяем расширение

Расширение готово. Теперь протестируем его с помощью irb, запустив его из той же директории:

>irb
irb(main):001:0> require "mytest"
=> true
irb(main):002:0> include MyTest
=> Object
irb(main):003:0> sayhello()
Hello World!
=> false
irb(main):004:0> sqr(5)
=> 25
irb(main):005:0> quit

Поздравляю! Первое расширение работает. Это файл mytest.so. Для того, чтобы его можно было использовать в ваших программах на Ruby, его нужно скопировать в \Каталог_Ruby\lib\ruby\site_ruby\1.8\i386-msvcrt\. Либо выполнить nmake install.

Стоит заметить, что для того, чтобы это расширение работало на других компьютерах, необходимо, чтобы на них был установлен Visual C++ Redistributable Package, который можно загрузить с сайта Microsoft.

На данном этапе предполагается, что процесс сборки расширения Ruby был описан, и больше возвращаться к этой теме мы не будем, а заострим внимание непосредственно на программировании.

Так что же мы запрограммировали?

Разберемся с тем, что представляет собой исходный код нашего модуля. Мы подключаем файл ruby.h, в котором содержатся все объявления, которые нам необходимы.

Основная функция нашего расширения – это Init_mytest(), её вызывает интерпретатор Ruby, когда вы пытаетесь загрузить расширения из своего скрипта. В ней обычно при помощи функций rb_define_module, rb_define_method, rb_define_class и других, регистрируется содержимое расширения. Любое расширение Ruby должно определить глобальную функцию Init_name, где name – имя расширения.

В ruby.h объявлен основной тип объектов Ruby – VALUE. VALUE представляет собой указатель на область памяти, в которой располагается какой-то объект Ruby (на самом деле, VALUE не всегда указатель, но он этом чуть позже). Параметры функций, вызываемых из Ruby имеют тип VALUE, ровно как и каждая функция, которая может быть вызвана из Ruby должна возвращать VALUE. Даже если функции не нужно ничего возвращать, она обязана вернуть Qnil. Qnil представляет собой NULL-значение указателя любого объекта Ruby.

Так, в нашем расширении определяется модуль, содержащий две функции. Указатель на модуль представляет следующая переменная:

VALUE mytest = Qnil;

Самое интересное начинается, когда интерпретатор Ruby вызывает Init_mytest() тогда, когда встречает команду require “mytest” в Ruby-программе:

void Init_mytest() {
  mytest = rb_define_module("MyTest");
  rb_define_method(mytest, "sqr", method_sqr, 1);
  rb_define_method(mytest, "sayhello", method_sayhello, 0);
}

В первой строке функции мы объявляем модуль Ruby с именем MyTest. Это то имя, которое мы использовали в проверочном скрипте когда писали include MyTest. В следующих двух строках мы объявляем метод уровня модуля, соответственно, функция rb_define_method принимает четыре параметра: указатель на сущность, в которой определяется модуль (может быть модуль, может быть класс), имя метода, ссылка на функцию и количество параметров. Функции библиотеки Ruby обычно имеют префикс rb_.

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

Документацию по Ruby API можно найти по следующему адресу: http://www.ruby-doc.org/doxygen/current/

Тип VALUE

Переменные типа VALUE как непосредственные значения

Наш первый метод method_sayhello довольно примитивен – он лишь печатает строку. А вот о втором, method_sqr, нужно сказать несколько слов. Не так давно мы отметили, что VALUE это указатель на какой то объект. Однако, из соображений производительности, для некоторых простых типов Ruby, значения располагаются прямо в переменной. Получается, переменные типа VALUE могут быть и указателями, и непосредственными значениями. Ruby использует магические манипуляции с битами, чтобы определить, является ли значение переменной указателем на объект, либо непосредственным значением. Следующие типы Ruby хранятся непосредственно в переменной типа VALUE: Fixnum, Symbol, true, false, nil.

В нашей функции method_sqr в переменной x передаётся число, а не указатель. В нашем случае, мы приводим VALUE к int с помощью макроса NUM2INT, далее выполняем возведение в квадрат, и затем результат преобразуем обратно с помощью INT2NUM.

Переменные типа VALUE как строки

В C строка представляется последовательностью байтов, завершаемой нулевым символом ». Строки Ruby представляются типом RString и содержат в себе длину строки, и ссылку на саму строку. Для создания Ruby-строки из C-строки используется следующая функция:

rb_str_new2(char*)

Если мы имеем строку Ruby, мы можем получить доступ к её «внутренностям» с помощью макроса:

RSTRING(str)->len // длина строки
RSTRING(str)->ptr // указатель на C-строку
Переменные типа VALUE как другие объекты

Переменные типа VALUE, как было сказано, могут быть указателями на объекты Ruby. Среди таких объектов: массивы, хеш-таблицы, строки, и многие другие типы. Все они определены в ruby.h и имеют имена, начинающиеся с R: RArray, RHash и т.д. Для проверки соответствия типа нашим ожиданиям, мы можем использовать следующий макрос:

Check_Type(VALUE value, int type)
Пример работы с VALUE: массивы

Мы немного изменим наше расширение, добавив в него ещё одну функцию, чтобы увидеть объектное «лицо» типа VALUE на примере массива. Мы реализуем функцию, которая вычисляет сумму всех элементов числового массива.

Определим прототип:

VALUE method_sum(VALUE, VALUE);

Объявим метод в функции Init_mytest:

rb_define_method(mytest, "sum", method_sum, 1);

Поставленную задачу можно решить двумя способами. В стиле Ruby, и в стиле C. Сначала посмотрим на способ в стиле Ruby.

// Функция, представляющая «итерационный блок»
VALUE iter_sum (VALUE c, int *psum) {
  *psum += NUM2INT(c);
  return Qnil;
}

// Возвращает сумму элементов массива а
VALUE method_sum(VALUE self, VALUE a) {
  int sum = 0;
  Check_Type(a, T_ARRAY);
  rb_iterate(rb_each, a, iter_sum, (VALUE)&sum);
  return INT2NUM(sum);
}

iter_sum – вспомогательная функция. Она представляет собой содержимое «блока» each. В method_sum мы сначала с помощью Check_Type требуем, чтобы наша функция вызывалась только с аргументом-массивом. Далее с помощью rb_iterate запускаем итерацию по массиву.

Наш «блок» iter_sum вызывается для каждого элемента массива. Результаты суммирования сохраняются в переменной sum, указатель на которую мы тоже передаём в iter_sum. В результате работы rb_iterate у нас в переменной sum находится сумма всех элементов массива, мы преобразуем это число в Fixnum и возвращаем из метода.

Теперь мы можем из Ruby вызывать этот метод:

> require “mytest”
=> true
> include MyTest
=> Object
> sum([1,2,3])
=> 6
> sum(”hello”)
TypeError: wrong argument type String (expected Array)

Рассмотрим второй способ.

VALUE method_sum(VALUE self, VALUE a) {
  int i = 0;
  int sum = 0;
  Check_Type(a, T_ARRAY);
  for(i = 0; i < RARRAY(a)->len; i++)
    sum += NUM2INT(RARRAY(a)->ptr[i]);
  return INT2NUM(sum);
}

Вы видите, здесь мы общаемся с «внутренностями» массива Ruby. Мы пользуемся знанием того, как устроен массив и пробегаем по всем его элементам при помощи указателей. Результат работы аналогичен предыдущему.

Классы

До сих пор мы рассматривали расширения, в которых был объявлен модуль, а в нём обычные методы. В этом разделе мы рассмотрим классы: как объявлять классы Ruby в C-коде, и как работать с ними.

Сначала мы рассмотрим простой класс в Ruby, а затем создадим эквивалентный на C.

class Person < Object
  def initialize(name)
    @name = name
  end

  def say
    print "My name is #{@name}"
  end
end

Результаты работы:

>person = Person.new("Vasya");
>person.say
My name is Vasya

Теперь посмотрим, как создать аналогичный класс в C. Наш класс наследует от Object, имеет конструктор с параметром, который сохраняется в переменной уровня экземпляра. Затем метод say выводит дружественную строку.

#include "ruby.h"
void Init_mytest();
VALUE initialize(VALUE, VALUE);
VALUE say(VALUE);

VALUE personclass = Qnil; // Наш класс

// Инициализация расширения
void Init_mytest() {
  personclass = rb_define_class("Person", rb_cObject);
  rb_define_method(personclass, "initialize", initialize, 1);
  rb_define_method(personclass, "say", say, 0);
}

// Конструктор
VALUE initialize(VALUE self, VALUE name) {
  Check_Type(name, T_STRING);
  rb_iv_set(self, "@name", name);
  return self;
}

// Метод say
VALUE say(VALUE self) {
  VALUE name = rb_iv_get(self, "@name");
  printf("My name is %s", RSTRING(name)->ptr);
  return Qnil;
}

Результаты работы:

>require “mytest”
>person = Person.new("Vasya");
>person.say
My name is Vasya

Рассмотрим подробнее, что теперь представляет собой наше расширение.

В функции инициализации расширения мы делаем следующее:

personclass = rb_define_class("Person", rb_cObject);

Объявляем класс с именем Person. Второй параметр функции – это класс, от которого мы наследуем. В Ruby API такие классы представлены переменными с именами rb_cName, где Name – имя класса. Далее объявляются конструктор и ещё один метод класса Person.

В конструкторе мы проверяем, является ли параметр строкой, и при помощи функции rb_iv_set устанавливаем переменную уровня экземпляра с именем ”@name”. В методе say при помощи «обратной» функции rb_iv_get мы получаем значение переменной @name и выводим текст на консоль.

В этом примере мы не определяли модуль. Если мы хотим определить модуль, а в него поместить класс, то следует использовать функцию rb_define_class_under, например:

mytest = rb_define_module("MyTest");
personclass = rb_define_class_under(mytest, "Person", rb_cObject);

В таком случае, из Ruby к нашему классу нужно будет обращаться так (либо использовать include):

person = MyTest::Person.new("Vasya")

Заключение

В данной статье была описана общая идея, введение в создание расширений для Ruby на языке C. Вы могли видеть, это не так уж и сложно. Возможность написания расширений для скриптового языков – несомненное преимущество для него. Желаю успешного программирования!

cc, linux, microsoft, opera