Занятие 5
17. Регулярные выражения Памятка (основные элементы регулярных выражений): a+ – любая последовательность a a* – любая последовательность a или отсутствие a a? – a один раз или или отсутствие a [abc] – один из указанных символов [A-E] – один из символов от A до E [^A-E] – любой символ, отличный от символов от A до E ^ – начало строки $ – конец строки \w – любая буква или цифра \s – пробел или табуляция
Регулярные выражения в Ruby – это объекты класса Regexp, соответственно, с ними можно делать все, что делается с объектами, например, присваивать: irb> a = Regexp.new(/^[A-Z]\w*\s+$/) irb> a = /^[A-Z]\w*\s+$/ Метод для разбора строки по регулярному выражению - #match : irb> /^[A-Z]\w*\s+$/.match('Yukihiro ')
Так как в случае несоответствия строки регулярному выражению #match возвращает nil, #match можно использовать в условных выражениях: Ruby поддерживает также и Perl стиль: str = SomeName if /^[A-Z][\w_]*$/.match(str) puts #{str} is a valid constant name end str = SomeName if /^[A-Z][\w_]*$/ =~ str puts #{str} is a valid constant name end
Регулярные выражения в Ruby поддерживают запоминание фрагментов строки согласно фрагментам регулярного выражения: Ruby поддерживает также и Perl стиль: regex = /^(\w+) (\w+) (\d\d?) (\d\d):(\d\d):(\d\d) \w+ (\d+)$/ if regex =~ ("Thu Jan 30 15:27:26 EET 2003") puts "day: " + $1 + ", " + $3 puts "month: " + $2 puts "year: " + $7 end
Если используется #match, возвращается объект класса MatchData, содержащий всю информацию о соответствии строки регулярному выражению: regex = /^(\w+) (\w+) (\d\d?) (\d\d):(\d\d):(\d\d) \w+ (\d+)$/ result = regex.match("Thu Jan 30 15:27:26 EET 2003") unless result.nil? puts "day: " + result[1] + ", " + result[3] puts "month: " + result[2] puts "year: " + result[7] end
Многие методы в Ruby используют регулярные выражения, в частности методы класса String : string = "Thu Jan 30 15:55:37 EET 2003" string.scan(/\d+/) {|number| puts number } puts string.split(/[,]/).inspect
Методы #gsub и #sub : #sub заменяет подстроку 1 раз, #gsub заменяет подстроки, пока находятся такие, которые соответствуют регулярному выражению : string = "Thu, Jan, 30, 15:55:37,EET, 2003" # заменить последовательность запятая-пробелы на ";" puts string.sub(/, +/,";") # заменить все последовательности запятая-пробелы на ";" puts string.gsub(/, +/,";") # найти все числа и увеличить их на 1 # $& - найденная регулярным выражением подстрока puts string.gsub(/\d+/){($&.to_i+1).to_s}
18. Еще раз о переменных Переменные, знакомые нам: * Локальные – обычные переменные, невидимые за пределами блока, метода и т.д. * Переменные объекта уникальные для каждого объекта и видимые только изнутри Новые виды переменных: * Глобальные переменные, видные везде: $var * Переменные класса, видимые внутри класса и объектов этого класса: * Константы, видимые в том классе/модуле, в котором они определены: Var
class Foo = 0 def initialize += 1 puts objects of class Foo" end a = Foo.new b = Foo.new Переменные класса – общие для всех объектов класса, видные из всех методов и тела класса. Отредактируйте файл class_vars_methods.rb :
class Foo = 0 def initialize += 1 end def Foo.counter return end a = Foo.new b = Foo.new puts Foo.counter Методы класса – это методы, адресаты (получатели сообщений) которых – это сам класс, а не его объекты:
CONST = 3.14 module Baz CONST = 10 end class Foo CONST = 45 $var = 56 # место определения значения не имеет end puts CONST puts Baz::CONST puts Foo::CONST puts $var Константы и глобальные переменные. Отредактируйте файл vars.rb :
a = 8 b = 7 p = Proc.new { a + b } puts p.call a = 1 puts p.call 19. Класс Proc (lambda-функции) Класс Proc позволяет создавать объекты, идентичные функциям в Lisp и других функциональных языках. Внутри любого метода видны только свои локальные переменные. В отличие от методов, внутри Proc объектов видны все внешие переменные, и они связывают (bind), то есть запоминают их. Значение Proc объекта – это значение последнего выражения ( return отсутствует).
a = 8 b = 7 p = lambda {|c| a + b + c } puts p.call(34) a = 1 puts p.call(2) Синонимы Proc.new{} - proc{} и lambda{}. Аргументы в Proc объект передаются следующим образом:
def generate_accumulator(starting_value) lambda{|a| starting_value += a } end accum = generate_accumulator(10) puts accum.call(3) puts accum.call(6) puts accum.call(-10) Свойства Proc позволяют создавать так называемые closures: 36) Напишите метод, принимающий массив в качестве аргумента, и генерирующий Proc объект, который при первом вызове возвращал бы первый элемент массива, при втором – второй, и т.д.
def generate_clos(ar) i = -1 lambda{ i += 1 ar[i] } end cl = generate_clos([2,3,"hi", 12]) puts cl.call 37) Модифицируйте код так, чтобы метод принимал также стартовый индекс элемента массива, а созданный Proc объект принимал true или false, и в зависимости от этого аргумента возвращал следующий или предыдущий элемент.
def generate_clos(ar, i) lambda{|direction| if direction i += 1 else i -= 1 end ar[i] } end cl = generate_clos([2,3,"hi", 12], 1) puts cl.call(true) puts cl.call(false)
class Foo def say_hi puts hi end a = Foo.new b = Foo.new def a.say_bye puts bye end a.say_hi b.say_hi a.say_bye b.say_bye #=> undefined method `say_bye' #=>for # (NameError) 20. Синглтон-методы Синглтон-методы – методы, определенные только для одного объекта.
class Foo def say_hi puts hi end some_class = Foo a = some_class.new some_class = Hash b = some_class.new 21. Классы как объекты Класс – это всего лишь объект класса Class. Имена классов – это константы. Таким образом, с классами можно делать все, что можно делать с объектами, например присваивание( singleton.rb ):
Связь между классами и метаклассами Object ( Object ) OtherClass (OtherClass) ( Module ) Modul e Class ( Class )
Методы класса – это синглтон методы объектов класса Class. class Foo def Foo.some_method # code end puts Foo.some_method class Foo end # такой же синтаксис: def Foo.some_method # code end puts Foo.some_method
class Foo def object_method # code end a = Foo.new b = Foo.new def a.singleton_method1 end def b.singleton_method2 end a.object_method b.object_method a.singleton_method1 b.singleton_method2 class Class def new # code end def String.class_method1 end def Integer.class_method2 end String.new Integer.new String.class_method1 Integer.class_method2
Если некоторые методы определены в классе Class, на них отзывается любой класс ( Class объект). Синглтоны, они же методы класса, уникальны для своих объектов, в данном случае – классов. class Class def some_method return "метод класса для всех классов" end class Foo def Foo.another_method return "метод класса Baz" end class Baz ; end puts Foo.some_method ; puts Baz.some_method puts Foo.another_method puts Baz.another_method #=> undefined method #=>`another_method' for Baz:Class (NameError)
В коде между class... end, но вне методов объектов класса self – это объект класса Class, таким образом, методы Class или синглтоны объектов Class вызываемы без явного указания объекта, которому посылается метод: class Class def some_method return "метод класса для всех классов" end class Foo def Foo.another_method return "метод класса Baz" end another_method some_method end
Теперь легко догадаться, что загадочные attr_reader и attr_accessor – это просто методы, определенные в классе Class. Задания 38) Напишите метод класса Class, который бы придал всем классам языка возможность самодокументации следующим образом: class Foo doc "Класс для тестирования " end puts Foo.get_doc #=> "Класс для тестирования "
class Class def = str end def end class Foo doc "Класс для тестирования " end puts Foo.get_doc