Ruby - расширить встроенные переменные в Ruby

Я хотел бы расширить функциональность переменных в Ruby. Причина в том, что я работаю над чем-то похожим на систему типов или проверку значений (это звучит немного странно, но вся идея состоит в том, чтобы долго объяснять, именно поэтому я хотел бы расширить переменные по умолчанию).

Я читал, что в Ruby все является объектом; поэтому переменные являются объектами. И Руби должен быть достаточно либеральным в отношении того, что можно изменить с помощью метапрограммирования.

Есть ли какой-то класс, связанный с локальными переменными, который я мог бы расширить?

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

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

Обходной путь должен был бы создать новый класс для моих Переменных (и не использовать сборку в локальных переменных Ruby). Этот класс может иметь атрибут value, атрибут (сохраняемый как строка) для типа и метод get и set. Таким образом, я могу решить свою проблему, но я бы хотел расширить встроенные переменные в ruby, если это возможно.

текущая работа в процессе

class Fixnum
        attr_accessor :tp
        @tp

        def mytype ( type )
                @tp = type
        end
        def typecheck
                #call typechecker
                puts "checked"
        end
end

Тестовый код:

a = 3
a.mytype("nat")
puts a.tp
a.typecheck

Есть еще две проблемы.Во-первых, я думаю, что невозможно добавить новый конструктор в Fixnum. Во-вторых, я хотел бы перехватить доступ к переменной, т. Е. "B = a" вызывает метод "проверки типов" объекта a. Но для этого потребуется нечто подобное Аспектно-ориентированному программированию, и я не уверен, что это можно решить с помощью метапрограммирования Руби.

3 ответа

Я читал, что в Ruby все является объектом

Это зависит от вашего определения "объекта" и каждой "вещи". "Объект" может означать "сущность, которой может манипулировать программа" (которую я теперь буду называть объектом), или "значение, являющееся членом системы объектов" (которое я назову Object впредь).

В Ruby все, что может манипулировать программой (т. Е. Каждый объект), также является Objectт.е. экземпляр класса. Это, в отличие от Java, например, когда программа может манипулировать примитивами (т.е. являются объектами в этом смысле слова), но не Objects, В Ruby такого различия не существует: каждый объект является Object и каждый Object тоже объект.

Однако в языке есть вещи, которыми программа не может манипулировать и которые не являются экземплярами класса, т.е. они не являются ни объектами, ни Objects. Это, например, методы, переменные, синтаксис, списки параметров, списки аргументов, ключевые слова.

Примечание: вы можете использовать API отражения Ruby, чтобы дать вам объект, который представляет метод или список параметров, но этот объект является только прокси, а не реальным.

Итак, когда мы говорим "все является объектом", мы имеем в виду, что "каждый объект является Object", т. е. то, что все, чем может манипулировать программа, также является членом объектной системы, или, другими словами, не существует значений вне объектной системы (в отличие от примитивов в Java). Мы не подразумеваем, что все, что существует на языке также может манипулировать во время выполнения программой.

поэтому переменные являются объектами

Нет, к сожалению, они не являются ни объектами, ни Objects.

Это также четко указано в спецификации языка Ruby (выделено мной):

6.2 Переменные

6.2.1 Общее описание

Переменная обозначается именем и относится к объекту, который называется значением переменной. Сама переменная не является объектом.

В книге "Язык программирования Ruby " Матца и Дэвида Фланагана говорится на странице 2:

каждое значение является объектом

Обратите внимание, это не говоритвсе, только каждое значение.

Смотрите также вопрос Является ли переменная объект в ruby?

Есть пара вещей, которые вы можете сделать. Для начала, все (или почти все) классы Ruby (включая "примитивы", такие как числа) поддерживают метод to_s, который возвращает строковое представление объекта. Для чисел to_s просто вернет строковое представление этого числа (например, "42" для 42). Значение строки, возвращаемое для других классов, будет различным. Приятно то, что вы можете переопределить методы класса с помощью "мартышки". Вот чрезвычайно надуманный пример:

class Array
  def to_s
    return "An array of size #{self.size}."
  end
end

a = [1, 2, 3, 4]
puts a.to_s
# => "An array of size 4."

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

class MyClass
  # Use the default getter for var.
  attr_reader :var      

  def initialize
    @var = 1
  end

  # Custom setter for var.
  def var= v
    @var = v
    puts "var changed to #{v}"
  end
end

mc = MyClass.new
mc.var = 9
# => "var chaged to 9"

Вы можете сделать что-то вроде этого, но это работает только для глобальных:

$type_checked = {:$a => String, :$b => Array}
$type_checked.keys.each do |var|
  trace_var(var) do |obj|
    puts "hey, don't assign #{var} to a #{obj.class}" unless $type_checked[var] == obj.class
    #or raise an Error
  end
end

$a = 1
$a = "a"
$b = 1

#output:
#hey, don't assign $a to a Fixnum
#hey, don't assign $b to a Fixnum

Но это явно идет вразрез с языком.

Другие вопросы по тегам