Как реализовать пользовательские методы мутации в Ruby? - PullRequest
0 голосов
/ 03 ноября 2018

Я пишу камень, где я хотел бы реализовать условное присваивание в расширении C.

Идея заключается в предоставлении присваивания для логического определения или . Это присваивается только если переменная nil. Например ...

var = false
var //= 42   # var is false
var = nil
var //= 23   # var is 23

Я нашел в репозитории ruby/ruby определение сокращенного назначения :

There are also ||= and &&=. The former makes an assignment if
the value was nil or false while the latter makes an assignment 
if the value was not nil or false.

Мне не удалось найти ссылку в исходном коде. (Как указано в комментариях ниже ||= не оператор, а только синтаксический сахар)

Я попытался посмотреть на apidock.com определение некоторых методов взрыва: например, Array#map!:

static VALUE
rb_ary_collect_bang(VALUE ary)
{
    long i;

    RETURN_ENUMERATOR(ary, 0, 0);
    rb_ary_modify(ary);
    for (i = 0; i < RARRAY_LEN(ary); i++) {
        rb_ary_store(ary, i, rb_yield(RARRAY_PTR(ary)[i]));
    }
    return ary;
}

Мне удалось перейти по ссылкам на rb_ary_modify и rb_ary_store в array.c.

Не знаете ли вы, как реализовать метод мутации, такой как:

require 'logic_or'

# Current behaviour
nil.lor('a') # => "a"
false.lor('a') # => false

a = nil # => nil
a.lor('a') # => "a"
a # => nil

# Expected behaviour
a = nil # => nil
a.lor!('a') # => "a"
a # => "a"

Обновление

Как отмечалось в комментариях, предыдущий заголовок ( Каким образом Double pipe или равно (|| =) реализован в ruby? ) не соответствовал содержанию вопроса

1 Ответ

0 голосов
/ 05 ноября 2018

Я не думаю, что вы можете реализовать val //= 23, что в Perl называется "dor" (определено-или). Там нет основного вызова метода. Вместо этого val ||= 23 компилируется в ...

if !val
  val = 23
end

val //= 23 будет ...

if val.nil?
  val = 23
end

Вы можете найти код для этого в compile.c . Вам нужно как-то взломать анализатор, чтобы добавить новый код операции idDOROP и изменить грамматику. Это не невозможно, это делается на Perl все время, но это очень грязно.

Я тоже не думаю, что вы можете сделать val.dor(23). Для этого потребуется присвоить self, что недопустимо.

class Object
  def dor(value)
    self = value if self.nil?
  end
end

Can't change the value of self
    self = value if self.nil?

Самое близкое, что я могу придумать, это.

class Object
  def dor(value)
    value if self.nil?
  end
end

obj = obj.dor(42)
puts obj

Что является сомнительным улучшением по сравнению с ...

obj = 42 if obj.nil?
puts obj

Как правило, //= не требуется в Ruby. //= появился в Perl, потому что Perl считает 0 и "" ложными. Во многих случаях это допустимые значения, но они будут стерты $var ||= $default. Люди устали писать $var = $default if !defined $var и //= родился.

В Ruby есть только два ложных значения, nil и false. Все остальное правда. var ||= default будет делать правильные вещи с 0 и "", поэтому нет необходимости в //=.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...