Задача 2: Въпроси
-
Последно за Proxy-то, няма нужда да трием всички му вградени методи, понеже ми се вижда доста варварско :D ?
Публикувано преди повече от 4 години -
аз пък да питам по 3-та задача (Object#&)
в теста се проверява:
assert_equal nil, list.&.reverse.&.i.&.tend.&.to.&.get.&.carried.&.awayкоето разбира се не сработва защото i не е дефиниран метод за класа Array
Ако правилно съм разбрала, в условието на задачата се иска метода & да работи по същия начин като && , т.е.
list.&.reverse.&.i
да върне същото като
list && list.reverse && list.reverse.iи съответно:
irb(main):055:0* list = [-1, -2, -3, nil, -4]
=> [-1, -2, -3, nil, -4]
irb(main):056:0> list && list.reverse && list.reverse.i
NoMethodError: undefined method `i’ for [-4, nil, -3, -2, -1]:Array
from (irb):56
from :0
irb(main):057:0>.. аз ли не го разбирам както трябва или има грешка в теста ?
Публикувано преди повече от 4 години -
“Мислете за foo.&.bar като “върни nil ако foo е nil или foo няма метод bar; иначе върни foo.bar””.gsub(“foo”, “list”).gsub(“bar”, “i”)
По-ясно от условието едва ли може да се каже.Публикувано преди повече от 4 години -
За 5. Object#swap_methods: Трябва ли да работи ако някой метод, или и двата метода ги няма? Тоест
str = “Stringophilia”
str.swap_methods :upcase, :shazam
puts str.shazam
Извежда ли “STRINGOPHILIA” или хвърля NoMethodError?Редакция: И относно 10. Object#expose_all:
Ако вече има дефиниран accessor, да се предефинира ли?Публикувано преди повече от 4 години -
@Матей:
Триенето на всички методи без
object_id
,__id__
и__send__
е практиката за такива неща. Не е варварско, налага се, освен ако не ползваш и Ruby 1.9 и имаш BasicObject.@Евгения: Прочети коментара на Ясен.
@Димитър:
Направи
Object#swap_methods
да работи при дефинирани методи. В другите случаи не ни интересува как се държи. Заexpose_all
не ни интересува също (аз бих го предефинирал).Публикувано преди повече от 4 години -
По хак 3:
Не разбирам. Каквото и да напиша тук:class Object
def &(*args)- …
end
end
на питанката
list = [1, 2, 3]
list.&.reverseRuby отговаря:
ArgumentError: wrong number of arguments (0 for 1)
Мисля, че това е защото в класа Array операторът & е предефиниран и си иска единия аргумент. Т.е. до извикване на моя метод от Object така и не се стига. Някой може ли да ми каже какво пропускам?
Публикувано преди повече от 4 години - …
-
ами става следното (псевдокод)
class Array < Object def &(other) return [] end end
никъде не се вика super (надявам се да имаш представа какво се опитвам да кажа, т.е. дано си програмирал на Java или C++ с класове)
не се вика super 100%, т.к. Object няма &
P.S. леле как го бях набрал текста преди…
Публикувано преди повече от 4 години -
Това ми е ясно :) Въпроса ми е дали няма малко по-умно решение от това да пренаписвам оператора & за всички класове, които го дефинират.
Най-елементарното, което ми идва на ум е просто да сменя името на въпросния метод, но в този случай, определено няма да мина тестовете :)Публикувано преди повече от 4 години -
Миналия път беше казано нещо за извикване на блок от метод, предефиниран чрез around_method. Примерно, да можем да around-нем метод each. Проблемът е, че не мога да измисля смислен начин да накарам това да работи правилно :) Тъй като не пишеше нищо за това в условието, трябва ли around_method да има тази функционалност?
Публикувано преди повече от 4 години -
Ами да задавам и аз:
3.(&)
p nil.&.class # nil
- не ни интересува x.& обекта4.(around) & 7.(proxy)
трябва ли да имат достъп ограждащите функции до евентуалния блок подаден от външния свят на оградения обект
e.g.
Array.around_method do |obj, orig, *args| # access { |x| x>1 } end [1,2].select { |x| x>1 }
8. (Array#==)
работи стандартно, e.g.
[1,2] < [1,2] # false [1,2] > [1,2] # false
Публикувано преди повече от 4 години -
Mен също ме интересува отговорът на въпроса на Радан.
Публикувано преди повече от 4 години -
@Радан: В условието си пише че трябва да накараш & да работи едновременно за [1, 2, 3].&.size и [1, 2, 3] & [2, 3, 4], така че явно ще се наложи да предефинираш метода за всички класове които го дефинират. Хубавото е че това може да стане по по-готин начин от очевидното ръчно предефиниране за всеки такъв клас.
@Ивайло: И аз попаднах на бездънна рекурсия в хак#4, може би и при теб проблема е бил същия. При мен се получаваше от stack`нати around методи, може би тестовия ми код ще хвърли повече светлина на въпроса:
def change_addition_6
new_addition = lambda do |other| self == 6 ? 6 : self.old_plus(other) end self.send(:define_method, :+, new_addition)
self.send(:alias_method, :old_plus, :+)end
def change_addition_5
new_addition = lambda do |other| self == 5 ? 5 : self.old_plus(other) end self.send(:define_method, :+, new_addition)
self.send(:alias_method, :old_plus, :+)end
class Fixnum
change_addition_6
change_addition_5
end6 + 2 и 5 + 2 минават, но 7 + 2 предизвиква безкрайна рекурсия от извиквания на old_plus. Единственото обяснение което ми хрумва е че old_plus в change_addition_5 се дефинира чрез old_plus в change_selection_6 който започва да вика себе си. Явно при “създаването” на метод методите които той вика се “пазят” като имена а не като обекти, което е доста lame обяснение но не съм достатъчно навътре с езика:) Иначе като преименуваш old_plus на old_plus5 и old_plus6 съответно в change_addition_5 и change_addition_6 всичко тръгва без проблеми. Някой да има идея какво точно се случва под капака?
Редакция: интересно, “:+” в поста излиза само като “:” :) Какъв таг използвате за ограждането на код в отговорите си?
Публикувано преди повече от 4 години -
Сравнението на масиви трябва ли да работи за масиви от символи? Или за нещо различно от числа и низове?
Публикувано преди повече от 4 години -
Въпроса на Точо, е изключително животрептющ. Т.е.
nil.&()
Интересува ли ни какво връща ?
Публикувано преди повече от 4 години -
Може ли да одължите времето за задачата до към края на тази семица примерно ?
Публикувано преди повече от 4 години -
На мен и до края на седмицата не би ми стигнало. Отказах се.
Публикувано преди повече от 4 години -
Здрасти. Когато ни показахте 1вия хак, аз ви казах, че няма да работи. Не го казах просто ей така, ами щото аз го бях направил точно по същия начин и (не) знам защо, но юнит теста за Proxy-то не минаваше. След като ви минаха всички тестове, аз останах още по оциклен. Той даже Емил Станчев ви пита точно за същото нещо, а именно:
Ако го напишем така:
class Symbol def to_proc() Proc.new {|var, *vars| var.send(self, *vars)} end end
Това при мен връща:
[[]].reject(&:nil?) # =>[]
Което е турбо нелогично, но такъв е живота. Въпроса ми това с какво е по-различно от :
class Symbol def to_proc() Proc.new {|*vars| vars.first.send(self, *vars[1..-1])} end end
Което връща това което очакваме:
[[]].reject(&:nil?) # =>[[]]
Публикувано преди повече от 4 години -
Мда, определено поведението е доста особено:
def f yiled [1] end f { |var| p var } # резултат: [1] -- ОК f { |*vars| p vars } # резултат: [[1]] -- ОК f { |var, *vars| p var; p vars } # резултат: 1 и [] -- ?!
Нямам идея защо се получава така :)Публикувано преди повече от 4 години -
не виждам нищо нередно в {|var, *vars|}
просто не го викате правилно – по-точно че го викате така че той да не се държи както искате…
yield има синтаксис в който му се подава списък и то го подава нататък като *args към функцията в зависимост от това какво тя очаква, като се старае да напасне максимално аргументите. Също така например ако функцията очаква 1 параметър x, а има yield a,b,c,d подава x=[a,b,c,d].
The code speaks for itself:
def a() yield *[[1]] end # the right way to call yield a { |var| p var } # [1] a { |*vars| p vars } # [[1]] a { |var, *vars| p var; p vars } # [1] , [] a { |v1, v2| p v1, v2 } # [1] , nil p '-----' def b() yield [1] end b { |var| p var } # [1] b { |*vars| p vars } # [[1]] b { |var, *vars| p var; p vars } # 1 , [] b { |v1, v2| p v1, v2 } # 1 , nil p '-----' def c() yield [1,2] end c { |var| p var } # [1,2] c { |*vars| p vars } # [[1,2]] c { |var, *vars| p var; p vars } # 1 , [2] c { |v1, v2| p v1, v2 } # 1 , 2 p '-----' def d() yield Array[1,2] end d { |v1, v2| p v1, v2 } # 1 , 2 def e() yield 1,2 end e { |var| p var } # [1,2] e { |*vars| p vars } # [1,2] e { |var, *vars| p var; p vars } # 1 , [2] e { |v1, v2| p v1, v2 } # 1 , 2
т.е., за да работи както искате – yield *[], block[] или block.call(Ако някой се чуди това държанието на yield е подвърдено под 1.8.6 и 1.9.0 :) )
Публикувано преди повече от 4 години -
Намерих и къде съм го чел това…
Programming Ruby
The Pragmatic Programmer’s Guide
(1st Edition, поради някаква причина не мога до го намеря в pdf-а на 2nd еdition…)"""
What happens if a block has a different number of parameters than are given to the yield? By a staggering coincidence, the rules we discuss under parallel assignment come into play (with a slight twist: multiple parameters passed to a yield are converted to an array if the block has just one argument).
"""ако някой има желание да чете – http://www.rubycentral.com/book/
Публикувано преди повече от 4 години
Нов отговор
Трябва да сте вътре за да отговаряте.