Занятие 6 22. Language Reflection Language Reflection

Download Report

Transcript Занятие 6 22. Language Reflection Language Reflection

Занятие 6
22. Language Reflection
Language Reflection – способность
объектов
к рефлексии
, то есть
умение давать информацию об исключительно языковых свойствах
объекта – набор методов объекта, класс объекта, суперкласс
класса и т.д.
С одним такими методами мы уже знакомы:
irb>
irb>
irb>
34.6.class
“hello”.class
“hello”.id
Метод #methods класса Object возвращает массив имен всех
методов (в виде текстовых объектов), на которые может отвечать
данный объект, т.е. это все методы, определенные во всех
суперклассах и включенных модулях:
irb>
irb>
“hello”.methods
Fixnum.methods
Метод Object#respond_to? проверяет , может ли объект
ответить на метод:
irb>
irb>
34.respond_to?(“+”)
“hello”.respond_to?(“length”)
Вместо текстовых аргументов этот метода также может
принимать аргумент в виде объекта класса Symbol:
irb>
irb>
34.respond_to?(:+)
“hello”.respond_to?(:length)
Если можно получить список всех методов объекта, а
также определить, отвечает ли объект на определенный
метод, было бы грустно, если бы было невозможно
послать метод объекту динамически. Все последующие
выражения – это один и тот же метод:
irb>
irb>
irb>
“hello”.send(:length)
“hello”.send(“length”)
“hello”.length
Если метод имеет аргументы, в методе #send они
следуют после имени метода:
irb>
“hello”.send(“index”, “l”)
Метод Object#instance_of? возвращает true, если
объект является экземпляром класса, указанного в
аргументе:
irb>
irb>
irb>
56.instance_of?(Fixnum)
56.instance_of?(Integer)
“hello”.instance_of?(Integer)
Метод Object#kind_of? возвращает true, если объект
является экземпляром класса, указанного в аргументе,
или если класс объекта наследуется от указанного класса
(то есть класс – один из суперклассов класса объекта ):
irb>
irb>
irb>
56.kind_of?(Fixnum)
56.kind_of?(Integer)
“hello”.kind_of?(Integer)
В классах Module и Class определены
рефлексивные методы:
irb>
irb>
irb>
String.superclass
45.class.superclass
Object.superclass
Метод #ancestors возвращает
и включенных модулей:
irb>
свои интересные
список всех суперклассов
Fixnum.ancestors
Класс ObjectSpace в Ruby дает доступ к Garbage
Collector. Метод ObjectSpace#each_object – это метод
класса ObjectSpace, итератор , перебирающий по
очереди все существующие объекты.
ObjectSpace.each_object do |object|
puts object
end
В качестве аргумента ObjectSpace#each_object
может принимать класс или модуль, в этом случае будут
перебираться только классы или модули (которые в Ruby,
как известно, являются объектами), являющиеся
наследниками указанного класса или модуля.
Задания
39) Напишите метод #explore, получающий объект , и
возвращающий иерархию классов данного объекта в текстовом
виде следующим образом:
puts explore(5.7)
#=>
“Float <- Numeric <- Object”
def explore(obj)
klass = obj.class
classes = Array.new
until klass == nil # Object.class – nil
classes.push klass.to_s
klass = klass.superclass
end
end
return classes.join(" <- ")
puts explore(45.7)
Задания
40) Напишите скрипт , получающий
отсортированные
имена
всех методов всех стандартных классов и модулей. Для
получения списка методов класса воспользуйтесь методом
Module#public_instance_methods, и помните , что класс
Class – это наследник класса Module
require "set.rb"
all_methods = Set.new
ObjectSpace.each_object(Module) do |class_module|
next if class_module == Set
class_module.public_instance_methods.each do |meth|
all_methods.add meth
end
end
puts all_methods.to_a.sort
23. Marshal
Модуль Marshal позволяет сохранить объект в виде строки (потока
байтов) и затем восстанавливать его из этой строки. Создайте файл –
dump.rb:
obj = [{"Peter" => 23, "John" => 25},
45,["yellow", "red"]]
File.open("data", "w+"){|file|
Marshal.dump(obj, file)
}
Запустите скрипт и посмотрите содержимое файла data.
На месте второго аргумента Marshal.dump может быть любой IO
объект, например, Socket.
Создайте файл load.rb, и запустите :
File.open("data", "r"){|file|
obj = Marshal.load(file)
puts obj.inspect
}
Marshal не работает с объектами , содержащими
объекты:
* IO объекты
* Proc объекты
* синглтон объекты
следующие
24. Работаем
с сетью
Как работает HTTP протокол на примере telnet:
$ telnet localhost 80
Trying 127.0.0.1...
Connected to leikind.
Escape character is '^]'.
GET /index.html
html code here
Connection closed by foreign host.
$
Объект класса TCPServer ждет соединений и возвращает объект
TCPSocket. Простой пример простого веб-сервера:
# Должен быть запущен из-под root'а
require 'socket'
server=TCPServer.new('localhost', 80)
while (session = server.accept)
# puts session.class #=> TCPSocket
puts "Request: #{session.gets}"
session.print "HTTP/1.1 200/OK\r\nContent-type:” +
“ text/html\r\n\r\n"
session.print "<html><body><h1>#{Time.now}</h1>” +
</body></html>"
session.close
end
Пишем http клиент:
require "socket"
socket = TCPSocket.new('localhost', 80)
socket.puts "GET /index.html"
while line = socket.gets
print line
end
socket.close
Однако есть и более высокоуровневые классы, например, класс
Net::HTTP реализует HTTP протокол:
require 'net/http'
http_connection = Net::HTTP.new('localhost', 80)
response, data = http_connection.get('/index.html')
puts response.message
#response.each {|key, val|
# это headers
#
print key, " => ", val, "\n"
#}
puts data
Примитивный чат:
require 'socket'
server=TCPServer.new('leikind', 81)
session = server.accept
while true
puts "< " + session.gets
print "> "
answer = gets
session.puts answer
end
require "socket"
session = TCPSocket.new('leikind', 81)
while true
print "> "
answer = gets
session.puts answer
puts "< " + session.gets
end
25. Пример распределенного вычисления на Ruby
Пересылка объекта по сети:
Require "socket"
some_object = [ 34, "hello",
[23,56,12,["Peter","Jack",0],nil],
{"Peter"=>45, "Jack"=>23}
]
puts some_object.inspect
session = TCPSocket.new('localhost', 81)
Marshal.dump(some_object, session)
session.close
Require 'socket'
server=TCPServer.new('localhost', 81)
while session = server.accept
some_object=Marshal.load(session)
puts some_object.inspect
session.close
end
Таким же образом мы можем переслать несколько объектов,
предварительно переслав количество объектов, и получить какой-то
объект в качестве результата:
Скрипт, отправляющий объект:
Require "socket"
session = TCPSocket.new('leikind', 81)
Marshal.dump(3, session) # будет 3 агрумента
Marshal.dump(10, session) # арг 1
Marshal.dump(20, session) # арг 2
Marshal.dump(5, session) # арг 3
session.flush
result = Marshal.load(session)
puts result
session.close
Скрипт, принимающий объект (TCPServer):
require 'socket'
server=TCPServer.new('leikind', 81)
while session = server.accept
# количество аргументов
n = Marshal.load(session)
arguments = Array.new
1.upto(n){ # получаем все аргументы
arguments.push Marshal.load(session)
}
sum=0
arguments.each{|arg| sum += arg} # суммируем
end
Marshal.dump(sum, session)
session.close
# шлем ответ