Войти на сайт

Авторизация, ждите ...
×

ТЕМА: Подключение сторонних гемов

Подключение сторонних гемов 7 года 10 мес. назад #72629

  • Iren_Rin
  • Iren_Rin аватар
  • Вне сайта
  • Мастер
  • Сообщений: 247
  • Спасибо получено: 536
  • Проект года 1 местоКоммерсантПрограммист RubyПроект месяца 1 местоУчитель
Всем привет, я сразу напишу вывод, может кто нибудь не захочет читать дальше :)
Вывод: К игре можно подключить гемы, но я пока что не знаю как подключить любой гем. Во первых есть проблема с тем, что руби в игре немного старое, и немного урезанное, некоторые классы стандартной библиотеки отсутствуют (Etc к примеру), а многие гемы их используют. Во вторых я не знаю пока как работать с гемами с extension (но я точно знаю что можно).

И так, сразу напишу что такое гемы - это крассивое название для сторонних библиотек, оформленных стандартным образом. Это ненмого похоже на сторонние скрипты, которые вы копируете в игру, но чаще всего файлов там гораздо больше чем один. Давайте рассмотрим гем cancan, который мы будем сегодня вставлять в проект. Пока что все что нас интересует - это папка lib, в ней лежит весь код, который нам нужен. Обычно используют Rubygems (часть руби, которая работает с гемами, и которая кстати вырезана из руби игры) для установки гема. Все что rubygems сделают для cancan - это скачают гем, сохранят его, и что самое важное - добавят путь к папке lib гема в $LOAD_PATH. В нормальном проекте вы теперь можете просто написать
require 'cancan'
и использовать библиотеку.
Так же расскожу о extensions. Стандартная реализация руби написана на Си (да да, один язык написан на другом языке, можете на досуге подумать о проблеме яйца и курицы). Руби - скриптовый язык, что означает что его код не нужно компилировать (переводить в бинарный машинный код) перед исполнением. Так же плюс скриптовых языков - на них обычно писать гораздо легче, чем на компилируемых, они крассивее (руби вообще самый крассивый язык :)), программы на них гораздо легче поддерживать и дебажить (искать ошибки). А минус фактически один - они гораздо медленнее, чем компилируемые языки. Но в руби есть одна лазейка - вы можете узкую часть программы написать на Си, а поверх этой части написать обертку на руби, чтобы остальной код мог с ним работать. Это называется расширение (extension), и да, расширение нужно компилировать. Многие гемы реализуют extension. Rubygems берет на себя задачу компиляции, и конечный юзер обычно ничего не замечает. Я пока что не знаю как работать из игры с такими гемами, но точно знаю что возможно. А это такие вкусные гемы как RMagic (удобное рисование граффики на лету) pry (офигенный дебагер) и многие другие.

Довольно лирики, приступим к методике.
Для начала создадим новый проект, открываем редактор скриптов и вставляем в новый скрипт следуещее:
puts Dir.pwd #puts печатает строку, Dir.pwd возращает путь к текущей папке.
Сохраняем, запускаем игру (не забываем кликнуть по пункту меню "Показывать консоль") - в консоли вы увидите путь к папке текущего исполняемого файла. Так вот файла этого самого там нет, игра генерирует его динамически, но путь - есть, это корневая папка проекта. Запоминаем эту полезную информацию.
Продолжаем эксперимент - берем редактор кода (не из игры, сторонний, рекомендую subline), создаем файл hello.rb со следующим кодом:
puts "Hello World" #этот код просто напечатает строку в ковычках
и сохраняем его в папке проекта. Теперь открываем редактор скриптов игры и заменяем код, который мы написали на следующее:
require File.expand_path('hello.rb', Dir.pwd) 
#requrie подключает файл
#File.expand_path возвращает абсолютный путь к  файлу (первый аргумент), 
#используя абсолютный путь из второго аргумента 
Запускаем игру и видим в консоли заветное 'Hello World'. Это означает что мы можем подгружать сторонние скрипты в игру. Теперь ясно, что мы должны сделать - cохранить гем где нибудь в проекте, добавить в $LOAD_PATH путь к папке lib этого гема и сделать require.
Однако беда в том, что многие гемы имеют зависимости от других гемов, т.е. чтобы такой зависимый гем работал, мы должны еще и подгрузить в проект код другого гема. Добавте к этому версионность гемов, и можно сойти сума :). Будем все таки делать так, чтобы остаться в здравом рассудке. Используем bundler. Для начала установим руби, которые нужны для бандлера. Идем сюда и качаем инсталятор. Советую 1.9.3 - будете ближе к версии руби из игры, если захотите потом поиграться с руби, но это не принципиально, главное чтобы не 1.8.7. Устанавливаем руби, нажимаем на клавиатуре windows + r (вы же на винде все это делаете, да?), в появившемся окошке вводим cmd. Знакомьтесь - консоль. Набираем
ruby -v
Если все прошло удачно - вы увидите версию только что установленного руби. Руби от версии 1.9 идут вместе с rubgems в комплекте. Набираем
gem install bundler
Привет старый друг!
Теперь самое сложное в нашей затее - перейти в этой гребанной недоконсоли в папку с проектом. Для начала набираем (заменяем Е на диск где у вас лежит проект)
E:
дальше переходим к самому проекту (тут мой путь, замените на свой)
CD rpg_maker/projects/gems_testing
Не закрываем консоль, она нам еще пригодится.
Теперь открываем subline и создаем файл Gemfile (именно так, без расширения вообще)
source 'https://rubygems.org'
gem 'cancan', '1.5.1'
Тут вроде все прозрачно - первая строка - где брать гемы. Дальше функция gem с двумя параметрами - имя гема и версия. Немного о версии гема - у нас руби в игре версии 1.9.2 (RUBY_VERSION подсказал), они вышли в конце 2010 года, гемы стоит искать начала 2011 года. Более ранние или более поздние могут просто не заработать. Идем на rubygems, вверху справа есть поле поиска, вбиваем туда cancan. Переходим по exact match. Кликаем по show all versions, и ищем версию гему близкую нам по дате. Переходим на его страницу - cancan 1.5.1. Нас интересует 'runtime dependencies' которых тут о чудо - нет! Это значит что мы будем устанавливать только один гем. На development dependencies можно забить.
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]


Ок, мы разобрались с нашим Gemfile для канкан. Теперь разворачиваем консоль (вы же ее не закрыли, да?) и запускаем
bundle install
Наш старый друг Бандлер установит все гемы и их зависимости из Gemfile куда то в систему. Мы бы могли попросить его установить все сразу в проект, но лучше пускай будут и в системе тоже, может потом поиграетесь с cancan. В консоли вводим
bundler show cancan
И бандлер покажет нам куда же он скачал гем. Переходим туда, копируем папку с гемом (она будет называться как гем + версия), переходим в папку проекта, создаем папку gems, скидываем туда папку с гемом.
На данном этапе у нас есть проект, файл Gemfile, папочка gems, папочка cancan-1.5.1 в ней. Теперь нам нужно подгрузить cancan в проект.
Открываем редактор скриптов в игре, создаем скрипт в самом верху (гемы нужно загружать до их использования) называем его как нибудь Gems_Loader и вводим туда
Dir.entries(File.expand_path 'gems', Dir.pwd).each do |entry| #Берем все что есть в папке gems и перебираем
  unless %w(. ..).include? entry # пока наш entry не бдует равен . или .. (это ссылки на текущий каталог и на родительский)
    lib_dir = File.expand_path File.join('gems', entry, 'lib'), Dir.pwd #генерим путь к папке lib каждого гема
    $LOAD_PATH.push lib_dir if Dir.exist? lib_dir # и включаем этот путь в $LOAD_PATH, если такая папка есть
  end
end
 
require 'cancan' #привет cancan!
Запускаем игру и... может вы не заметили, но мы подключили сторонний гем! Если бы что-то пошло не так, мы бы уже увидели бы ошибку!
Ну а для тех кто мне не верит, напишу немножко кода, который докажет что мы можем использовать cancan в игре. Для начала три слова о том что такое cancan - это гем для RoR, который позволяет гибко управлять правами юзера (так нам автор говорит). Но на самом деле он позволяет гибко описывать условия, для if, while и т.п. Короткий пример от балды:
if enemy.alive? && actor.alive? && !enemy.fire_creature? && !enemy.imune_to_spells?  #иногда так лучше не писать
 actor.cast Spells.firbolt, on: enemy
end
 
#VS

if actor.can? :hit, enemy, with: Spells.firebolt
 actor.cast Spells.firbolt, on: enemy
end

Теперь к делу - создаем скрипт в редакторе скриптов в игре, называем его Ability
class Ability
  include CanCan::Ability # Я уже не буду описывать что такое include, и так затянул статью

  def initialize(object)
    can :manage, :all # в общем это не очень полезное правило, оно разрешает всем делать все
  end
end
Создаем еще один скрипт, называем его Dog
class Dog  
  def ability #Создаем объект абилити, сохраняем его в @ability, если интересно что такое ||= - спрашивайте
    @ability ||= Ability.new self
  end
 
  %w(can? cannot?).each do |method_name| #Тут метопрограммирование для ускорения процесса, тоже спрашивайте если не ясно
    define_method method_name do |*args|
      ability.public_send method_name, *args
    end
  end
 
  def bar(target) #каждая сабака должна уметь лаять, да?
    target.puts "BAR!"
  end
end
 
dog = Dog.new #объект сабаки

if dog.can? :bar, $stdout #проверяем может ли сабака гакать на STDOUT
  dog.bar $stdout #гав!
end

Запускаем игру - видим "BAR!" в консоли игры.

Вот собственно и все что я сегодня хотел сказать, потратил пол выходного, надеюсь вам будет полезно, спасибо за внимание!
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: AnnTenna, Agckuu_Coceg, Lekste, DeadElf79, strelokhalfer, caveman, Lipton, Amphilohiy, yuryol, KageDesu

Подключение сторонних гемов 7 года 10 мес. назад #72636

  • DeadElf79
  • DeadElf79 аватар
  • Вне сайта
  • Звездный Страж
  • Сообщений: 3147
  • Спасибо получено: 2650
  • ВетеранПроект месяца 1 местоПроект месяца 2 местоОрганизатор конкурсовУчитель3 место1 место в ГотвПисатель 3 местоПрограммист Ruby
Давно хотел взять и найти, как подключать скрипт из внешнего файла (встроенный редактор не очень радует), большее спасибо за помощь))

Также, спасибо за статью, она получилась очень подробной и простой для понимания, это приятно)
Администратор запретил публиковать записи гостям.

Подключение сторонних гемов 7 года 10 мес. назад #72704

  • Iren_Rin
  • Iren_Rin аватар
  • Вне сайта
  • Мастер
  • Сообщений: 247
  • Спасибо получено: 536
  • Проект года 1 местоКоммерсантПрограммист RubyПроект месяца 1 местоУчитель
Подключение скриптов из вне пока что работает только для проекта, путь к которому задан полностью в ANSII-8BIT символах. Я работаю над этим, надеюсь удастся починить.
Администратор запретил публиковать записи гостям.

Подключение сторонних гемов 7 года 9 мес. назад #73634

  • DeadElf79
  • DeadElf79 аватар
  • Вне сайта
  • Звездный Страж
  • Сообщений: 3147
  • Спасибо получено: 2650
  • ВетеранПроект месяца 1 местоПроект месяца 2 местоОрганизатор конкурсовУчитель3 место1 место в ГотвПисатель 3 местоПрограммист Ruby
Если указанный ранее способ сможет работать с гемами, требую демку с примером дога и канкана ^_^
Администратор запретил публиковать записи гостям.

Подключение сторонних гемов 7 года 9 мес. назад #73635

  • Iren_Rin
  • Iren_Rin аватар
  • Вне сайта
  • Мастер
  • Сообщений: 247
  • Спасибо получено: 536
  • Проект года 1 местоКоммерсантПрограммист RubyПроект месяца 1 местоУчитель
Работает твой метод, я же писал в чате :), перепишу loader на досуге.
Последнее редактирование: 7 года 9 мес. назад от Iren_Rin.
Администратор запретил публиковать записи гостям.

Подключение сторонних гемов 7 года 9 мес. назад #73647

  • Iren_Rin
  • Iren_Rin аватар
  • Вне сайта
  • Мастер
  • Сообщений: 247
  • Спасибо получено: 536
  • Проект года 1 местоКоммерсантПрограммист RubyПроект месяца 1 местоУчитель
Огромное спасибо DeadElf79 за то что подсказал этот способ!

Если вы хотите, чтобы ваши гемы работали в проекте, в пути к которому есть не ANSII символы, то рекомендую использовать этот загрузчик
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]


Что важно - предполагается, что гемы вы сохраняете в папке gems.
Скрипт заюзает стандартный механизм, когда проект сохранен в папке с нормальным путем, и загрузит файлы через File.load, когда стандартный механизм дал сбой.
Последнее редактирование: 7 года 6 мес. назад от Iren_Rin. Причина: Перенс код загрузчика на гитхаб
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: DeadElf79

Подключение сторонних гемов 6 года 6 мес. назад #88021

  • DeadElf79
  • DeadElf79 аватар
  • Вне сайта
  • Звездный Страж
  • Сообщений: 3147
  • Спасибо получено: 2650
  • ВетеранПроект месяца 1 местоПроект месяца 2 местоОрганизатор конкурсовУчитель3 место1 место в ГотвПисатель 3 местоПрограммист Ruby
Ирен, у меня проблема. Не могу подключить гем i18n (отсюда)

Все зависимости внёс в папку, но выдает LoadError.
Текст ошибки [ Нажмите, чтобы развернуть ]


Код загрузки гемов:
gems_list = [
	'json',
	'tzinfo',
	'minitest',
	'concurrent-ruby',
	'activesupport',
	'actionpack',
	'thor',
	'method_source',
	'railties',
	'i18n'
]
 
success = true
gems_list.each do |gem|
	wr "Inlcude gem: #{gem}...",0
	begin
		SideScriptsLoader.add_gems_to_path
		require gem
	rescue Exception => msg
		wr msg.message
		wr msg.backtrace.join("\n")
		success = false
		break
	else
		wr 'successful'
	end
end
 
wr success ? "Current locale is #{I18n.locale}" : "Cannot load system locale"

* wr - аналог puts, взял отсюда
Возможно, немного ошибся темой.
Последнее редактирование: 6 года 6 мес. назад от DeadElf79.
Администратор запретил публиковать записи гостям.

Подключение сторонних гемов 6 года 6 мес. назад #88028

  • Iren_Rin
  • Iren_Rin аватар
  • Вне сайта
  • Мастер
  • Сообщений: 247
  • Спасибо получено: 536
  • Проект года 1 местоКоммерсантПрограммист RubyПроект месяца 1 местоУчитель
1. json тоже гем? Если нет то на нем все и валится - в мейкере нет стандартного json.
2. Зачем тебе i18n от рельсов? Подключай github.com/svenfuchs/i18n/blob/master/i18n.gemspec , гем от рельсов это обертка над этим гемом. Тогда уйдет зависимость от ralities, и видимо, от activesupport, actionpack и т.п. Sourcecode точно имеет extension а их, как минимум, скомпилировать нужно будет. Только скорее всего внутри i18n все равно загружается yaml, а его тоже в мейкере нет.
3. SideScriptsLoader.add_gems_to_path нужно делать только один раз.
Администратор запретил публиковать записи гостям.

Подключение сторонних гемов 6 года 6 мес. назад #88032

  • DeadElf79
  • DeadElf79 аватар
  • Вне сайта
  • Звездный Страж
  • Сообщений: 3147
  • Спасибо получено: 2650
  • ВетеранПроект месяца 1 местоПроект месяца 2 местоОрганизатор конкурсовУчитель3 место1 место в ГотвПисатель 3 местоПрограммист Ruby
1. Да, тоже гем, в зависимостях нашел.
2. Спасибо, посмотрю. Видимо, не в ту сторону рыть начал.
3. О, вот этого не было в примерах или я не так прочитал их.

А ведь всего лишь нужно получать текущую локаль системы, хех.
Администратор запретил публиковать записи гостям.

Подключение сторонних гемов 6 года 6 мес. назад #88033

  • Iren_Rin
  • Iren_Rin аватар
  • Вне сайта
  • Мастер
  • Сообщений: 247
  • Спасибо получено: 536
  • Проект года 1 местоКоммерсантПрограммист RubyПроект месяца 1 местоУчитель
I18n не поможет тебе получить текущую локаль. Это система для хранения переводов. В ней можно установить текущую локаль для самой этой системы, но получить ее из ОСи из вне - нет.
Администратор запретил публиковать записи гостям.
Время создания страницы: 1.007 секунд