Программирование на языке Ruby
Программирование на языке Ruby читать книгу онлайн
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
break if eof? line = gets range = (line=~/=begin/)..(line=~/=end/) puts line if range endЧтобы понять, в чем дело, нужно осознать, что весь диапазон (включая обе границы) вычисляется на каждой итерации цикла, но с учетом внутреннего состояния. Поэтому оператор переключения — вообще не настоящий диапазон. Тот факт, что он выглядит похожим на диапазон, хотя по сути таковым не является, многие считают «злом».
И наконец, задумаемся о границах в операторе переключения. Они вычисляются каждый раз, но результат вычисления нельзя сохранить в переменной и затем просто подставить ее. В некотором смысле граничные точки оказываются похожи на объекты
procprocИ несмотря на все вышесказанное, функциональность-то полезная!.. Можно ли написать класс, который инкапсулирует ее, но при этом не будет таким «магическим»? Можно и даже не очень трудно. В листинге 6.1 приведен простой класс
Transitionclass Transition А, В = :А, :В T, F = true, false # state,p1,p2 => newstate, result Table = {[A,F,F]=>[A,F], [B,F,F]=>[B,T], [A,T,F]=>[B,T], [B,T,F]=>[B,T], [A,F,T]=>[A,F], [B,F,T]=>[A,T], [A,T,T]=>[A,T], [B,T,T]=>[A,T]} def initialize(proc1, proc2) @state = A @proc1, @proc2 = proc1, proc2 check? end def check? p1 = @proc1.call ? T : F p2 = @proc2.call ? T : F @state, result = *Table[[@state,p1,p2]] return result endendВ классе
TransitionproclineВот слегка измененный вариант того же подхода. Здесь метод
initializeprocdef initialize(var,flag1,flag2) @state = A @proc1 = proc { flag1 === var.call } @proc2 = proc { flag2 === var.call } check?endОператор ветвящегося равенства проверяет соотношение между границами и переменной. Переменная обернута в объект
procprocline = niltrans = Transition.new(proc {line}, /=begin/, /=end/)loop do break if eof? line = gets puts line if trans.check?endЯ рекомендую именно такой подход, поскольку в нем все делается открыто, без привлечения «волшебства». Особую актуальность это приобретет, когда оператор переключения будет исключен из языка.
6.2.8. Нестандартные диапазоны
Рассмотрим пример диапазона, состоящего из произвольных объектов. В листинге 6.2 приведен класс для работы с римскими числами.
class Roman include Comparable I,IV,V,IX,X,XL,L,XC,C,CD,D,CM,M = 1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000 Values = %w[M CM D CD С XC L XL X IX V IV I] def Roman.encode(value) return "" if self == 0 str = "" Values.each do |letters| rnum = const_get(letters) if value >= rnum return(letters + str=encode(value-rnum)) end end str end def Roman.decode(rvalue) sum = 0 letters = rvalue.split('') letters.each_with_index do |letter,i| this = const_get(letter) that = const_get(letters[i+1]) rescue 0 op = that > this ? :- : :+ sum = sum.send(op,this) end sum end def initialize(value) case value when String @roman = value @decimal = Roman.decode(@roman) when Symbol
