[quote][…] To the point that smart, experienced hackers reach for a monkey patch as their tool of first resort, even when a simpler, more traditional solution is possible.
I don?t believe this situation to be sustainable. Where I work, we are already seeing subtle, difficult-to-debug problems crop up as the result of monkey patching in plugins. Patches interact in unpredictable, combinatoric ways. And by their nature, bugs caused by monkey patches are more difficult to track down than those introduced by more traditional classes and methods. As just one example: on one project, it was a known caveat that we could not rely on class inheritable attributes as provided by ActiveSupport. No one knew why. Every Model we wrote had to use awkward workarounds. Eventually we tracked it down in a plugin that generated admin consoles. It was overwriting Class.inherited(). It took us months to find this out.[/quote]
Eu acho que monkey patching é algo abusado em Ruby. O problema é que o esquema de bindings em Ruby é muito ruim, você não tem como criar blocos de escopo arbitrários ou fazer como em Scala e limitar o escopo de um patch. Eu já tive problemas sérios com 1.minute e conflito entre patches.
O pessoal do zope/plone é um ótimo exemplo de onde monkey patching pode levar. Na minha opnião utilizar isso é prática ruim e detona não só ruby mas qualque linguagem que suporte isso.
Em Ruby não dá para fazer muito. Você bsicamente pode usar monkey patching para alterar as classes core ou fazer algo no estilo Java onde você tem uma gerência de dependências estáticas, onde um inteiro não pode ser independente de Date em compile time e integrado em runtime.
O problema é que as reras de escopo em Ruby são arcaicas considerando as capacidades de metaprogramação da linguagem. Tudo é muito global e muito irreversível.
Scala tem uma ótima saída para isso, com conversões implícitas, e Lisp tem bloco léxicos hierárquicos com LET há décadas. Acho que simplesmente ningu’m pensou que ia precisar disso e como consequência você tem monkey patching e namespace wars.
Ruby tem duas coisas que melam a vida de quem quer fazer metaprogramação mais hardcode. Não existe como sobrescrever o mecanismo de resolução de nomes e tão pouco como definir escopos no qual alterações a classes acontecem.
Por gentileza, conforme sua explicação, postei a URL abaixo, porque não compreendi tais afirmações sobre Ruby metaprogramação, o que você quer dizer sobre mais hardcode, [b]mecanismo de resolução de nomes , etc …
:idea: Poderia finalizar colocando melhor transparência ao assunto, sitando melhores detalhes sobre tal concepção.[/b]
Simples, crocodilo, como você faz e quiser definir um método seu, que você criou e faz algo que só você precisa, chamado “times” em Fixnum se você usa Rails?
def ei_vc(&bloco)
MeuEscopo.new.instance_eval(&bloco)
end
ei_vc do
qualquer
coisa
end
class MeuEscopo
def qualquer
# ...
end
def coisa
# ...
end
# ...
end
A/C
Louds (Moderador GUJ)
Por gentileza, conforme sua explicação, postei a URL abaixo, porque não compreendi tais afirmações sobre Ruby metaprogramação,[/quote]
O Louds está falando em um nível que é umas duas ordens de grandeza maiores que você pode compreender. Se quiser entender melhor o que ele fala, por favor, sr. Duran, aprenda outras linguagens de programação e um bocadinho de matemática, para que você não reduza Ruby a uma mera “linguagem orientada a objetos”, com você postou aqui no GUJ
E leia um pouco mais - sitar é um instrumento musical de origem árabe; acredito que você queria dizer “citar”.
intance_eval tem resolvido bem a minha vida:
[/quote]
Aind anão adianta. Em outro tópico eu citei uma DSL de testes usando RSpec e Selenium, nessa DSL tivemos que azer os objetos de domínio incluírem módulos do RSpec para que pudéssemos usar pending e outros métodos dentro dos nossos blocos que não são closures.
Ruby precisava ter bindings hierárquicos. Hoje em Ruby você so consegue avaliar algo em dois níveis, o primeiro (como intance_eval) e o Object/Kernel.
intance_eval tem resolvido bem a minha vida:
[/quote]
Aind anão adianta. Em outro tópico eu citei uma DSL de testes usando RSpec e Selenium, nessa DSL tivemos que azer os objetos de domínio incluírem módulos do RSpec para que pudéssemos usar pending e outros métodos dentro dos nossos blocos que não são closures.
Ruby precisava ter bindings hierárquicos. Hoje em Ruby você so consegue avaliar algo em dois níveis, o primeiro (como intance_eval) e o Object/Kernel.[/quote]
Não precisa ter binding hierárquico, basta ter binding extensível.
code = proc {|a| print a.d }
context_eval(proc) do |obj, name|
return "d é mais legal" if name == :d
obj.send (name)
end
Com isso é trivial implementar instance_eval module_eval e por ai vai. Para completar permita configurar um bloco padrão de resolução por Modulo/classe/método e adicione a possibilidade de andar na pilha e recuperar um bloco que resolva nomes de acordo com o método em questão. Com essas três coisas basicamente tudo que reclamam sobre meta-programação em Ruby tem solução simples.
Eu diria que não precisava ter binding extensível, bastava ter binding hierárquico que é mais limitado, provavelmente mais fácil de implementar e ainda assim eficiente na maioria dos casos.