У некоторых людей Ruby надо отбирать. И не отдавать. Автор официальной обёртки twitter api принял гениальный design decision: класс SearchResult при итерации по нему «прозрачно для пользователя» загружает из Тви следующую страницу результатов (и следующую, пока она есть...). То есть сделав например twitter.search('wtf').each ... — вы получите весьма, весьма неожиданный результат. Но нескоро.
(насколько я — пока — понял, поведение обойти невозможно никак, кроме как переписав соотв. кусок кода. факин осом) ‎- новомодная имитация мышления
мне кажется, что в правильной версии этого тезиса дело на самом деле не в Ruby. ‎- middle out-of-sight
ну, да. но в данном случае _на первый взгляд_ оно ещё и очень «ruby way» (в плохом, в общем, смысле) выглядит: «просто нажимай each, как будто это обычная коллекция, а всё остальное само!» ‎- новомодная имитация мышления
ик. автор библиотеки — Erik Michaels-Ober, известный герой рок-н-ролла, супер-полезный член сообщества и вообще лапонька. не знаю, что сказать. ‎- новомодная имитация мышления
всё нормально, по-моему. .each у активрекорд тоже по всем записям побежит. там же есть .take(n) и тд. .each возвращает в руби не коллекцию, а Enumerator, кстати, которая не делает предположений никаких о размере или возможности этот размер вычислить. .size поэтому может вернуть nil, если энумератор ничо не знает. ‎- адский хардлайн в засаде
Такие кретины где угодно есть. В яве скажем крайне популярно "прозрачно для программиста" работать с сетью. Правда там это обычно всякий RPC. ‎- смешная третья опция
так как по вашему это должно выглядеть было? .each должен был вернуть slice произвольного размера? или вообще не реализовывать Enumerator? ‎- адский хардлайн в засаде
(ну RPC смежная, но отдельная тема, кмк, и про неё уже сказали http://www.eecs.harvard.edu/~waldo/Readings/waldo-94.pdf ) ‎- адский хардлайн в засаде
Сказали, но никто ж не слушает до сих пор. Оба эти кейса про неадекватную любовь к абстракциям и про то, как они неизбежно протекают и заливают клавиатуру. ‎- смешная третья опция
Нууу, в одном случае у тебя Employee.name делает запросы сетевые. А в другом у тебя объект, предназначенный для общения через сеть с сервисом возвращает ленивую коллекцию, представляющую результат. Штуки похожие, но разные. Механизмы языковые одинаковые, ну так явных конструкций для всяких вариантов "удалённого вызова" в руби нету. ‎- адский хардлайн в засаде
И всё ещё неясно, какой API был бы, как вам кажется, правильным, в этом случае. twitter.search('wtf').fetch(limit: N).each ... ? или чтобы вообще не похоже было на коллекцию? ‎- адский хардлайн в засаде
^^ Штуки идентичные -- мы в обоих случаях притворяемся, что никакой сети нет. Вместо того чтобы признаться, что она таки есть и написать руками правдивый интерфейс, с эксплицитными таймаутами, ретраями, обработкой ошибок и пониманием когда данные уже здесь, а когда их ещё надо откуда-то получать. ‎- смешная третья опция
^^ ручной пейджинг в той или иной форме, возвращающий коллекции которые гарантированно локальны. ‎- смешная третья опция
а теперь твой take(n) фейлится на пятой странице из десяти. как ты её поретраишь? если будешь ретраить всё -- получишь ещё один телефонный говноапп, который не умеет работать на плохих сетях, например в Индии. ‎- смешная третья опция
.take не кол-во страниц, а кол-во элементов принимает (то есть сам задаёшь, сколько на "странице"). то есть как раз получишь эксепшн (или nil в стиле руби, гг), и можно ретраить. я читал папиру, которую линканул, мне всё-таки кажется что rpc "классический" с remote objects и данный случай они разные :) ‎- адский хардлайн в засаде
разверну: Я прочитал take(n) как "взять n элементов", как они паджинируются ты при этом не контролируешь. Предположительно API Twitter не позволяет брать скажем тысячу элементов разом, но позволяет взять десять страниц по сто (так очень много где). Итого твоя конструкция в лучшем случае делает десять вызовов. Но! На нашей гипотетической плохой сети вызов фейлится с вероятностью 1/4. Если ты ретраишь всю конструкцию, легко посчитать среднее количество запросов, которое нам придётся выполнить. Оно будет заметно выше, чем если ретраить каждый из десяти запросов индивидуально. ‎- смешная третья опция
дальше -- разумная паджинация для любых оживлённых таймлайнов опирается не на limit/offset по количеству штук, а на before/since по времени. для этого нужен какой-то свой интерфейс, не коллекции (я готов спорить, что именно поэтому автор обёртки его и скрыл, чтобы не пугать бедных юзеров сложностью. а зря!) ‎- смешная третья опция
когда я говорил про RPC, я имел в виду простые method calls на каком-нибудь сервисном интерфейсе, которые на самом деле ремотные вызовы. remote objects это пиздец on so many levels (distributed GC, ахаха) о котором просто не имеет смысла говорить. ‎- смешная третья опция
@larhat, по моему убеждению, это решение «теоретически красиво» (и да, можно take, можно lazy, можно чорта в ступе), но практически катастрофично. потому что конечно можно обосновать, как эти абстракции отражаются на те, но это не отменяет того, что слишком легко, не ожидая этого, написать код, который либо выгребет пол-твиттера, либо (вероятнее) приведёт к бану вашего токена. ‎- новомодная имитация мышления
я убеждён, что обёртки над API должны быть тонкими. и когда нечто под название *Result не просто содержит этот Result, а выполняет какие-то дополнительные запросы (которые, вообще говоря, платные — пусть в данном случае и не долларами) — это хуйня. когда — это уже вот моя практическая ситуация — у меня нет штуки, у которой можно спросить «сколько результатов мы получили с этой страницы и нужна ли нам следующая страница» (и если нужна — зашедулить её получение на через час) — это хуйня. ‎- новомодная имитация мышления
то есть претензия только к методам, которые могут содержать неопределённое количество remote вызовов, без сохранения стейта о прогрессе? если же .take(N).collect всегда делает 1 вызов (возможно, заканчивающийся фейлом, если твитер посчитает, что N большое слишком) то всё ок? (не пытаюсь построить никаких платформ для софистики, если что, а хочу понять мнение :) ) В приватных методах, кстати, у SearchResults пагинация есть (next_page, и тд). ‎- адский хардлайн в засаде
когда ты делаешь SomeDataset.each — у тебя есть некие основания полагать (POLS), что он таки переберёт все элементы данных. когда ты делаешь result = twitter.search('fuck'); result.each — у тебя таких оснований нету. это блять реально пиздец. ‎- новомодная имитация мышления
@larhat, в том и дело, что в приватных. никакой возможности (без манки-патчинга) сказать ему «а дай мне те результаты, которые уже получил»; «а есть у нас там следующая страница?» нету. только забирать у него его to_h (да ебанись ты) и обрабатывать самому. это очень, очень плохая обёртка, я даже не знаю что сказать, если вы этого не понимаете. ‎- новомодная имитация мышления
EPIC MONKEYPATCHING! ‎- псы в рапиде