Forum: Italian Ruby user group Be Brave

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2015-08-06 12:12
(Received via mailing list)
Un altro episodio della serie "cose che solo io trovo utili"

http://playersgonnaplay.it/be-brave-in-ruby-land
C82630c82a3c675d2928804f432fcf17?d=identicon&s=25 Elia Schito (Guest)
on 2015-08-06 12:15
(Received via mailing list)
Conosco almeno un altro sviluppatore che lo avrebbe trovato utile HINT
HINT
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2015-08-06 12:16
(Received via mailing list)
:high-five:

2015-08-06 12:14 GMT+02:00 Elia Schito <elia@schito.me>:
5ffafe70176a99f175d16192fd5be69e?d=identicon&s=25 Luca P. (luca_p)
on 2015-08-06 14:05
(Received via mailing list)
Fino a poco tempo fa lavoravo su una code base Rails 3 composta per un
terzo di rescue nil, perché il capo si lamentava che c'erano troppi
errori... una tortura.
Insomma, questa è roba da professionisti, i niubbi non provino a rifarla
a casa! :)

Inviato da iPhone
Dc70f4a04726fada8b9db8a18ff40412?d=identicon&s=25 Maurizio De Santis (succhiateste)
on 2015-08-06 14:11
(Received via mailing list)
Più che da professionisti, è una cosa da fuori di testa xD fin quando si
scherza si scherza, ma exceptions as control flow... brividi!

Il giorno gio 6 ago 2015 14:05 Luca Pradovera <luca.pradovera@gmail.com>
ha
scritto:
C82630c82a3c675d2928804f432fcf17?d=identicon&s=25 Elia Schito (Guest)
on 2015-08-06 14:14
(Received via mailing list)
Mi permetto di correggere, perché qui stiamo parlato di missed exception
control to keep the flow  ◕ ◡ ◔
Dc70f4a04726fada8b9db8a18ff40412?d=identicon&s=25 Maurizio De Santis (succhiateste)
on 2015-08-06 14:24
(Received via mailing list)
Giusto, ascrivibili al gruppo "usare le eccezioni per far altro che non
sia
gestire eccezioni"

Il giorno gio 6 ago 2015 14:14 Elia Schito <elia@schito.me> ha scritto:
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2015-08-06 14:25
(Received via mailing list)
Mah, sono abbastanza serio :-)
Il caso d'uso è ben circoscritto e sarei ben lieto di usare soluzioni
altrettanto concise anche se ad ora non ne vedo.
La try chain è scomoda e poco leggibile quando si gestiscono accessi ad
Hash:

params.try(:[], :profile).try(:[], :resume).try(:tempfile).try(:path)

Così come la boolean chain:

if params[:profile] && params[:profile][:resume] &&
params[:profile][:resume].try(:tempfile).try(:path)

Come affronteresti questo specifico caso?

@luca: da maneggiare con attenzione, ovviamente :-) Un uso ad-minchiam è
potenzialmente letale.

2015-08-06 14:10 GMT+02:00 Maurizio De Santis
<desantis.maurizio@gmail.com>:
C82630c82a3c675d2928804f432fcf17?d=identicon&s=25 Elia Schito (Guest)
on 2015-08-06 14:27
(Received via mailing list)
class NilClass
  def method_missing(*)
    self
  end
end
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2015-08-06 14:30
(Received via mailing list)
Ecco, monkey patch di questo tipo mi fanno davvero paura :-D
Preferisco un approccio meno invasivo :-)

2015-08-06 14:26 GMT+02:00 Elia Schito <elia@schito.me>:
Dc70f4a04726fada8b9db8a18ff40412?d=identicon&s=25 Maurizio De Santis (succhiateste)
on 2015-08-06 15:13
(Received via mailing list)
Ok, allora rispondo seriamente :)

Usare le eccezioni per controllare il flusso è un noto antipattern:
http://programmers.stackexchange.com/questions/189...

Ho avuto a che fare con questo tipo di approccio con un collega a cui
piaceva, e l'aveva usato un bel po' in giro nel codice di un progetto.
Dopo
averne parlato siamo giunti alla conclusione che crea più problemi che
altro, per i seguenti motivi:

- viola il principio di minima sorpresa: le eccezioni sono fatte per
gestire errori, non per gestire un flusso previsto
- la logica ha la priorità sulla concisione: se del codice richiede
della
complessità logica in sé, non puoi sacrificarla per amor di concisione
- ti perdi le eccezioni rescuate: questo è un grande problema, perché se
la
parte di codice wrappata genera un'eccezione che non pensavi potesse
spuntare fuori te la perdi, non viene loggata e cominciano a verificarsi
i
tanto classici quanto temuti fenomeni paranormali informatici

Inoltre, nel codice postato usi rescue Exception, che rescua anche da
eccezioni di sistema:
http://stackoverflow.com/questions/10048173/why-is...

Nel caso da te citato userei una delle soluzioni che hai scritto, magari
estraendola a metodo privato. Sarà meno elegante, ma è più logica e
manutenibile.

Il giorno gio 6 ago 2015 14:29 maurizio de magnis <
maurizio.demagnis@gmail.com> ha scritto:
55ed99e505f73461bada1ecb80cedd93?d=identicon&s=25 Andrea Pigato (Guest)
on 2015-08-06 15:26
(Received via mailing list)
FY(possible?)I: https://youtu.be/J1jYlPtkrqQ?t=6m57s

-- 
:: Andrea Pigato
:: email: andreapigato@gmail.com
:: mobile: +44 747 3090534

On 6 August 2015 at 14:13:46, Maurizio De Santis
(desantis.maurizio@gmail.com) wrote:

Ok, allora rispondo seriamente :)

Usare le eccezioni per controllare il flusso è un noto antipattern:
http://programmers.stackexchange.com/questions/189...

Ho avuto a che fare con questo tipo di approccio con un collega a cui
piaceva, e l'aveva usato un bel po' in giro nel codice di un progetto.
Dopo
averne parlato siamo giunti alla conclusione che crea più problemi che
altro, per i seguenti motivi:

- viola il principio di minima sorpresa: le eccezioni sono fatte per
gestire errori, non per gestire un flusso previsto
- la logica ha la priorità sulla concisione: se del codice richiede
della
complessità logica in sé, non puoi sacrificarla per amor di concisione
- ti perdi le eccezioni rescuate: questo è un grande problema, perché se
la
parte di codice wrappata genera un'eccezione che non pensavi potesse
spuntare fuori te la perdi, non viene loggata e cominciano a verificarsi
i
tanto classici quanto temuti fenomeni paranormali informatici

Inoltre, nel codice postato usi rescue Exception, che rescua anche da
eccezioni di sistema:
http://stackoverflow.com/questions/10048173/why-is...

Nel caso da te citato userei una delle soluzioni che hai scritto, magari
estraendola a metodo privato. Sarà meno elegante, ma è più logica e
manutenibile.

Il giorno gio 6 ago 2015 14:29 maurizio de magnis <
maurizio.demagnis@gmail.com> ha scritto:

> >
> > > params.try(:[], :profile).try(:[], :resume).try(:tempfile).try(:path)
> > > potenzialmente letale.
> > >
> > >>> casa! :)
> > >>>>> Conosco almeno un altro sviluppatore che lo avrebbe trovato utile
> > >>>>>> Maurizio ಠ_ಠ My profile
> > >>>>
> > >>> Ml mailing list
> > >
> > Ml@lists.ruby-it.org
> Ml@lists.ruby-it.org
> http://lists.ruby-it.org/mailman/listinfo/ml
>
_______________________________________________
Ml mailing list
Ml@lists.ruby-it.org
http://lists.ruby-it.org/mailman/listinfo/ml
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2015-08-06 15:36
(Received via mailing list)
+1 per StandardError al posto di Error (ho aggiornato il post) e +1
anche
per il fatto di non usare le eccezioni come strumento di gestione del
flusso di codice.

Ora, nel caso menzionato gestisco *solo* questi fallimenti:

- NoMethodError: undefined method `[]' for nil:NilClass
- NoMethodError: undefined method `XXX' for "YYY":String

L'obiettivo che mi sono posto, limitando volontariamente lo scope di
Brave.be, è ottenere una syntactic sugar per recuperare un valore
nestato
in una struttura dati. Di fatto, a parte l'essere più o meno bello da
vedere, non comporta le stesse sorprese della magia nera da
Metaprogrammazione.

2015-08-06 15:13 GMT+02:00 Maurizio De Santis
<desantis.maurizio@gmail.com>:
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2015-08-06 16:00
(Received via mailing list)
Ecco, questa è una soluzione molto, molto elegante :-)
Nonostante non sia un patito di method_missing, lo preferisco ad un
begin/rescue
+1

2015-08-06 15:26 GMT+02:00 Andrea Pigato <andreapigato@gmail.com>:
Ff2c5ef7c7d38d18c3cd39d951cc5a07?d=identicon&s=25 Stefano Pigozzi (Guest)
on 2015-08-06 16:03
(Received via mailing list)
La mancanza di Optional/Maybe nel 2015 in un linguaggio come Ruby è
piuttosto preoccupante.

2015-08-06 15:59 GMT+02:00 maurizio de magnis
<maurizio.demagnis@gmail.com>:
Dc70f4a04726fada8b9db8a18ff40412?d=identicon&s=25 Maurizio De Santis (succhiateste)
on 2015-08-06 16:10
(Received via mailing list)
Comics time: http://existentialcomics.com/comic/49

Il giorno gio 6 ago 2015 16:03 Stefano Pigozzi
<stefano.pigozzi@gmail.com>
ha scritto:
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2015-08-06 16:52
(Received via mailing list)
@maurizio: Revolution! XD

ecco il repository con l'implementazione di Tom Stuart delle monad
Optional, Many ed Eventually:

https://github.com/tomstuart/monads

2015-08-06 16:09 GMT+02:00 Maurizio De Santis
<desantis.maurizio@gmail.com>:
C82630c82a3c675d2928804f432fcf17?d=identicon&s=25 Elia Schito (Guest)
on 2015-08-06 17:00
(Received via mailing list)
O se vuoi solo un wrapper per quei due casi… fai un wrapper!

comunque +1 per Tom Stuart

PS. il tuo post oramai è una wiki :P
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2015-08-06 17:06
(Received via mailing list)
Piccola nota: dovrei convertire params in una OpenStruct (o similare)
per
poter gestire la chain tramite Optional.

2015-08-06 16:59 GMT+02:00 Elia Schito <elia@schito.me>:

> O se vuoi solo un wrapper per quei due casi… fai un wrapper!
>

Mmh, espandi un po'. Cosa intendi?

comunque +1 per Tom Stuart
>

Già, tanta roba. :-)

PS. il tuo post oramai è una wiki :P
>

ghgh, lo prendo come un complimento :-)
C82630c82a3c675d2928804f432fcf17?d=identicon&s=25 Elia Schito (Guest)
on 2015-08-06 17:20
(Received via mailing list)
class InfiniteHash
  def initialize(hash = nil)
    @hash = hash
  end

  def value
    @hash
  end

  def [] key
    value = @hash[key]
    return Value.new(value) unless value.nil? or value.is_a?(Hash)
    InfiniteHash.new(value)
  end

  class Value < Struct.new(:value)
    def [] key
      self
    end
  end
end

hash = {a: 1, b: {c: 2}}
p InfiniteHash.new(hash)[:a].value
p InfiniteHash.new(hash)[:b][:c].value
p InfiniteHash.new(hash)[:b][:c][:d][:e][:f].value
# >> 1
# >> 2
# >> 2
Ma tutto sommato mi sa che  una specializzazione di quello che fa TS
E555a767a33427bfee0bb0878566293c?d=identicon&s=25 gabriele renzi (Guest)
on 2015-08-07 09:39
(Received via mailing list)
my 2c da bastian contrario, rispetto a quello che dice Maurizio De
Santis :)

L'esempio specifico secondo me non  "eccezioni come control flow", in
quanto non
necessariamente sei tu che stai facendo raise dell'eccezione per avere
un
control flow non lineare.

Ovvero: eccezioni come control flow


def fetch(url)
  body, status = _fetch(url)
  raise HttpError if status == 4xx
  raise EmptyBody if body.empty?
  raise InvalidJson unless  body.valid_json?
end

mentre

data =  fetch(url) rescue {}

 solo "gestisci libreria".

Ma concordo invece con il problema che l'esempio per come  scritto
pericoloso perch non c' controllo su cosa dovrebbe gestire.


Per, ad esempio avendo a che fare con librerie che usano eccezioni in
modo
abbastanza liberale (praticamente tutte quelle che hanno a che fare con
http), io ho spesso usato roba tipo

  def ignoring(exception_classes)

    begin

      yield

    rescue *exception_classes => e

      log_exception "error ", e

      # e per esempio in rails, qua metti anche un @error = ...

    end

  end
  ...
  ignoring(RequestTimeOut, ConnectionError) {
    data = fetch_data()
    do_stuff_with(data)
  }


Che altro non  che "if", con un altro nome.

YMMV :)
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2015-08-07 10:33
(Received via mailing list)
Ottima l'idea di limitare le eccezioni ignorate [gist](
https://gist.github.com/olistik/bb3b2ebce1a72913d5a6) :-)
Ho aggiornato il post con questa implementazione.

2015-08-07 9:38 GMT+02:00 gabriele renzi <rff.rff@gmail.com>:
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2015-08-07 10:40
(Received via mailing list)
Ok, ma fallisce nei casi ibridi in cui la navigazione passa accesso
tramite
hash *e* metodi, come nell'esempio originale:

    params[:profile][:resume].tempfile.path

Al posto di creare un Optional ancora più complesso posso semplicemente
usare l'implementazione di base con un wrap iniziale su una OpenStruct:

    require 'ostruct'
    require 'monads/optional'
    include Monads

    Optional.new(OpenStruct.new(params)).profile.resume.tempfile.path.value
C82630c82a3c675d2928804f432fcf17?d=identicon&s=25 Elia Schito (Guest)
on 2015-08-07 10:42
(Received via mailing list)
+1
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2015-08-07 10:44
(Received via mailing list)
Monadic Bravery ^_^

2015-08-07 10:39 GMT+02:00 maurizio de magnis
<maurizio.demagnis@gmail.com>:
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2015-08-07 11:18
(Received via mailing list)
Se non fosse che `Monads` sembra fare a botte con `OpenStruct`:

    [25] pry(main)> Monads::Optional.new(OpenStruct.new({foo: 'bar',
spam:
{egg: 'rick'}})).spam.egg.value
    NoMethodError: undefined method `egg' for {:egg=>"rick"}:Hash
    from
/Users/olistik/.rvm/gems/ruby-2.2.2/gems/monads-0.0.1/lib/monads/monad.rb:11:in
`public_send'

mentre con `Hashie::Mash` sembra andare d'amore e d'accordo:

    [26] pry(main)> Monads::Optional.new(Hashie::Mash.new({foo: 'bar',
spam: {egg: 'rick'}})).spam.egg.value
    => "rick"

2015-08-07 10:41 GMT+02:00 Elia Schito <elia@schito.me>:
This topic is locked and can not be replied to.