[Off-topic] Como funciona el [include]


#1

Hola a todos, veréis, estoy siguiendo un tutorial de ruby a pelo, nada
de
rails. Pero voy a hacer la consulta aqui por tres motivos:
1-es una pregunta super rápida.
2-Es de interés para la gente que esta empezando con Rails (creo).
3-Esta es la única lista a la que estoy apuntado sobre (ruby, rails). De
momento. Si me surgen muchas dudas de puro ruby, prometo apuntarme a la
lista de Ruby

Bueno, al grano, que seguro que es una chorrada.
Estoy leyendo sobre la seudo-herencia multiple en ruby, y me he topado
con
los mixins (modulos)
La pregunta:
Cuando yo incluyo un modulo en mi clase asi :

module Movement
def run
puts “I’m running!”
end
def walk
puts “I’m walking a bit briskly!”
end
def crawl
puts “I’m so slowwww!”
end
end

class Man
include Movement
def jump
puts “I’m bipedal and I can jump like a fool!”
end
end

¿Como sabe mi clase donde encontrar al modulo [Movement ]? ¿O donde he
de
poner el modulo [Movement ] para que mi clase lo encuentre?
Me refiero a Ruby en general, no a una App rails, aunque si me decis
como se
hace en Rails también perfecto

Saludos


#2

Quizás la disertación de guillermo te ayude a comprender algo:

http://cientifico.net/post/2008/12/30/diferencia-entre-extend-e-include-extend-vs-include

Saludos
f.

El día 14 de enero de 2009 15:49, Andrés gutiérrez
removed_email_address@domain.invalid
escribió:> Hola a todos, veréis, estoy siguiendo un tutorial de ruby a pelo, nada de


#3

Andrés,

Rails añade toda una magia de auto-load de ficheros que engaña un
poco, ya que no es como funciona ruby realmente.

Básicamente rails se apaña con el método const_missing de la classe
Object, de forma que cuando llamas a una constante [Movement] que no
existe, busca en todo el load_path un fichero llamado movement.rb y le
hace un require. (Explicado a grosso modo).

En el caso concreto de rails, se trata de poner el fichero movement.rb
en un directorio que esté en el load_path de rails, ya sea en /lib, o
en /app/models /app/controllers, etc…

En el caso de rails puro, debes hacer un require manual del fichero
movement.rb antes de poder declarar el include, o ruby te dará un
error indicándote que no existe la constante Moevement.

Espero haber aclarado algo tus dudas, para mirar el tema del
const_missing, te passo la url a la
documentación:
http://www.ruby-doc.org/core/classes/Module.html#M001716

Saludos,

Isaac Feliu


#4

2009/1/14 Andrés gutiérrez removed_email_address@domain.invalid:

¿Como sabe mi clase donde encontrar al modulo [Movement ]? ¿O donde he de
poner el modulo [Movement ] para que mi clase lo encuentre?
Me refiero a Ruby en general, no a una App rails, aunque si me decis como se
hace en Rails también perfecto

Ruby no lo sabe.

El modulo Movement ha de estar definido en un fichero del cual hay que
hacer un require en algun punto de la aplicacion.

En cuanto al nombre del fichero lo tienes que saber tu (que eres quien
hace el require) y es arbitrario. Un .rb puede tecnicamente definir
tantas clases o modulos como quiera (incluidos ninguno :-). Si
Movement esta definido en foo.rb, como efecto secundario de
interpretar

require “foo”

quedara Movement definido (para completar la ronda, Movement
tecnicamente es una constante normal y corriente que almacena un
objeto de tipo Module).

Ruby busca esos ficheros en un path que queda definido hard-coded en
tiempo de compilacion, que puedes consultar en la variable $:.

$ irb
irb(main):001:0> $:
=> ["/Users/fxn/prj/mizuho/lib", “/opt/local/lib/ruby/site_ruby/1.8”,
“/opt/local/lib/ruby/site_ruby/1.8/i686-darwin9”,
“/opt/local/lib/ruby/site_ruby”,
“/opt/local/lib/ruby/vendor_ruby/1.8”,
“/opt/local/lib/ruby/vendor_ruby/1.8/i686-darwin9”,
“/opt/local/lib/ruby/vendor_ruby”, “/opt/local/lib/ruby/1.8”,
“/opt/local/lib/ruby/1.8/i686-darwin9”, “.”]

Se puede extender con la variable de entorno RUBYLIB, o bien
modificando $: a pelómetro (es un array de cadenas), y tambien en
linea de comandos con la opcion -I.


#5

Gracias a los dos, en un par de horas me pondre con el tema y me mirare
detenidamente vuestros enlaces. Gracias por el interes.

El 14 de enero de 2009 15:57, Isaac Feliu Pérez
removed_email_address@domain.invalidescribió:


#6

def Object.const_missing(name)
@looked_for ||= {}
str_name = name.to_s
raise “Class not found: #{name}” if @looked_for[str_name]
@looked_for[str_name] = 1
file = str_name.downcase
require file
klass = const_get(name)
return klass if klass
raise “Class not found: #{name}”
end
Vale Isaac, me he mirado el metodo const_missing(name), que es como
lo hace rails no?
A ver, con mis propias palabras diria “rails usa const_missing(name)
para busar la constante que yo paso a mi clase al hacer: include
Mimodulo”
Pregunta:
Cuando hago un include, el modulo que estoy llamando lo busca en el
archivo del mismo nombre en minusculas en el load_path que tiene
definido rails?
Como dice en la document. cuando yo llamo al modulo con include, ruby
llama al metodo append_features
http://www.ruby-doc.org/core/classes/Module.html#M001659 y este
metodo carga todos los: ( the constants
http://www.ruby-doc.org/core/classes/Module.html#M001679, methods,
and module variables of
this module ) Y en este momento es cuando rails llama a
const_missing???para saber si el modulo esta en el load_path?

Como ves no tengo el camino claro, pero sigo mirando, a ver si soy
capaz de explicarlo y explicarmelo claramente.

Esto de arriba muestra lo confuso que tengo de momento la vision
general de lo que es el funcionamiento del include. Pero volviendo al
codigo de arriba El const_missing, hay cosas que no entiendo en el
codigo
@looked_for ||= {}. Esto es un operado de ruby que es equivalente a
esto p.ej.:
if not @looked_for
@looked_for = {}
end
Es esto correcto, la variable @looked_for se asigna a un hash vacio si
no esta definida???

Y esto:
raise “Class not found: #{name}” if @looked_for[str_name]
Se produce un error si el name que se le pasa a const_missing no esta
en la variable @looked_for???
Esto si que no veo por donde me da el aire…

@looked_for[str_name] = 1 Por que se le asigna valor 1???
klass = const_get(name) esto lo que hace es retornar el valor de NAME.

return klass if klass. ESTO QUE??? retorna la Klass si la Klass que
(if Klass)??? ¿Que tiene que pasar para que la retorne?
Bueno, no os agobies con mis preguntas, que sólo expongo todas mis
dudas juntas, para que escojais alguna :slight_smile: si os apetece y me voy
aclarando una por una
Gracias,

NOTA:
Si hay premio para el mensaje peor redactado y confuso del 2009,
seguro que lo gano. Espero ir aclarando el hilo para que quede
legible, pero ahora mismo esta confuso y es tarde y mi cabeza,…

Bueno, gracias de nuevo

El 14 de enero de 2009 16:38, Xavier N. removed_email_address@domain.invalid escribió:

2009/1/14 Andrés gutiérrez removed_email_address@domain.invalid:


#7

Perdón por ser tan pesado, prometo que por hoy lo dejo, solo una cosa.
Googleando he visto que este tio [1], ha puesto una script en su
directorio
/public con lo siguiente:

#!/bin/bash
export
RUBYLIB=/usr/local/lib/ruby/ruby/1.8/:/usr/local/lib/ruby/ruby/1.8/i386-linux/
/usr/bin/ruby $*

Esto lo hizo. Segun explica porque en su server le cambiaron el PATH a
las
librerías de ruby.
El tenía: /usr/local/lib/ruby/1.8
Y de repente pusieron: /usr/local/lib/ruby/ruby/1.8

Como veis han añadido un directorio más de profundidad.

Despues en “dispach.fcgi” [Que esto es una forma de hacer funcionar
Rails en
produccion no? igual que ningx+mongrelitos o mod_rails+apache no?
Pone esto en “dispach.fcgi”:

#!/usr/bin/env [PATH TO YOUR RAILS APP]/public/myruby

Lo hace para decir a rails “He cuidado! ve a buscar lo que quieras
aquí(/usr/local/lib/ruby/ruby/1.8), porque lo han movido de sitio”

Vale, todo lo de arriba es lo que he entendido del link[1], ¿lo he
entendido
bien?

Suponiendo que lo he entendido bien, como puedo hacer yo para cambiar el
RUBYLIB y hacer lo que explicado arriba???

Ahora para hacerlo un poco más centralizado y si es posible al estilo
rails, es decir. Yo estoy siguiendo un tutorial en el que voy haciendo
minicodigo como “man.rb”

Si me quiero crear modulos que luego pueda usar para estos archivos y que
todos estos modulos esten en un unico directorio “lib”. Como lo hago???

Ya está, por hoy me planto. Espero no haber resultado muy pesado

Un saludo

[1]
http://blog.nanorails.com/articles/2006/5/19/arghhhhh-the-path-to-ruby-lib-is-wrong

El 14 de enero de 2009 22:11, Andrés gutiérrez
removed_email_address@domain.invalidescribió:


#8

2009/1/14 Andrés gutiérrez removed_email_address@domain.invalid:

Pregunta:
Cuando hago un include, el modulo que estoy llamando lo busca en el archivo
del mismo nombre en minusculas en el load_path que tiene definido rails?
Como dice en la document. cuando yo llamo al modulo con include, ruby llama
al metodo append_features y este metodo carga todos los: ( the constants,
methods, and module variables of

this module ) Y en este momento es cuando rails llama a
const_missing???para saber si el modulo esta en el load_path?

La ejecucion de

module Foo
  ...
end

crea una constante corriente y moliente Foo que almacena un objeto de
tipo Module. Es muy parecido a lo que sucede en

Bar = 0

que define una constante Bar y le asigna un 0.

Cuando escribes

include Foo

Foo no es ningun token especial del lenguaje, es una constante pura y
dura. Cuando una constante se trata de leer y no ha sido definida
previamente Ruby lanza un error. Esto no tiene relacion con el
include, pasaria igual si pones un

Zoo

ahi silvestre:

$ irb
irb(main):001:0> Zoo
NameError: uninitialized constant Zoo
    from (irb):1

La variable importante aqui es el ser una constante no definida.

Bien, tu puedes decirle a Ruby que cuando eso suceda ejecute cierto
codigo tuyo en lugar de petar miserablemente. Eso es const_missing.

const_missing puede hacer lo que le plazca. Puede no hacer nada, puede
hacer algo y relanzar el error… no se le asume nada.

En particular, puedes escribir un const_missing para implementar
autoload de cosas, y eso es lo que hace Rails. Por convenio, si se
invoco a const_missing porque la constante User no se conoce, el se
patea su load_path en busca de user.rb. Si encuentra uno lo carga (y
espera que como efecto secundario, al volver de la carga la constante
User haya resultado definida). La implementacion de esto es un poco
mas complicada porque soporta namespaces, pero esa es la idea.


#9

Vale!!!

Una cosa clara. Según lo que me ha dicho Xavier (±)
#man.rb

class Man
require “fightervalues”
include FighterValues
def jump
puts “I’m bipedal and I can jump like a fool!”
end
end

mister_man = Man.new
mister_man.run

Esto funciona porque tengo un archivo “fightervalues.rb” en el mismo
directorio que “man.rb”. Con el requiere no hace falta poner la
extensión(.rb). ¿NO?, en PHP me parece que SI.

Ahora para hacerlo un poco más centralizado y si es posible al estilo
rails,
es decir. Yo estoy siguiendo un tutorial en el que voy haciendo
minicodigo
como “man.rb”
Si me quiero crear modulos que luego pueda usar para estos archivos y
que
todos estos modulos esten en un unico directorio “lib”. Como lo hago???

Y como lo hago para hacerlo al estilo rails, es decir sin que me haga
falta
hacer el requiere en todas las clases-archivos-ejemplos que haga y en
las
que quiera usar los modulos que tengo en “lib”

Xavier, creo que estas preguntas ya me las has respondido, era lo de:

Se puede extender con la variable de entorno RUBYLIB, o bien
modificando $: a pelómetro (es un array de cadenas), y tambien en
linea de comandos con la opcion -I.

Pero es que no me aclaro con el tema de modificar PATH’s. Es algo que no
me
entra en la cabeza, y ademas me falta base(comandos) para funcionar con
el
terminal

Bueno, en resumen, lo que ahora me funciona es mas o menos como funciono
en
PHP(cutre y sin OOP). Incluyo archivos y gracias a eso me sirvo de sus
constantes, variables y funciones.
En ruby por lo que veo, para aprovecharme de lo que tengo en
“fightervalues.rb” debo poner: [include FighterValues], de lo contrario
me
salta este error:
man.rb:9: undefined method `run’ for #Man:0x29220 (NoMethodError)

Lo tengo requiereADO, pero NO includeADO asi que Class man no pilla los
metodos de module FighterValues. Si vuelvo a poner el include, ya me
puedo
volver a aprovechar de los metodos de FighterValues

El 14 de enero de 2009 21:46, Andrés gutiérrez
removed_email_address@domain.invalidescribió:


#10

Vale, Xavier, te he pillado. Y dices que implementar esto o algo
parecido es
dificil. No me podrías poner en el buen camino. Que quede claro que lo
que
es el concepto me queda claro
pero me sigue uedando la sensación de que si yo me quiero montar una App
churrera en ruby sin rails, No sabría como montarmelo para organizar las
cosas y que pueda acceder a esas constantes (modulos) para usarlos en
mis
clases. Esta App la usaría para ejecutar codigo por consola, para
aprender,
pero a la vez me gustaría tener este codigo centralizado y con librerias
que
pueda usar en otras clases

Un saludo

El 14 de enero de 2009 23:11, Xavier N. removed_email_address@domain.invalid escribió:


#11

2009/1/14 Andrés gutiérrez removed_email_address@domain.invalid:

Vale, Xavier, te he pillado. Y dices que implementar esto o algo parecido es
dificil. No me podrías poner en el buen camino. Que quede claro que lo que
es el concepto me queda claro
pero me sigue uedando la sensación de que si yo me quiero montar una App
churrera en ruby sin rails, No sabría como montarmelo para organizar las
cosas y que pueda acceder a esas constantes (modulos) para usarlos en mis
clases. Esta App la usaría para ejecutar codigo por consola, para aprender,
pero a la vez me gustaría tener este codigo centralizado y con librerias que
pueda usar en otras clases

Me parecia entender el objetivo hasta que he llegado a “codigo
centralizado y con librerias que
pueda usar en otras clases”. Rails no ofrece eso. Las librerias de
sistema no tienen autoload, solo los ficheros de la aplicacion misma.
Si quieres usar una libreria de sistema has de hacer un require a
mano.


#12

Buenos dias Xavier, primero de todo perdoname si no te parezco del todo
coherente. Pero has de entender que en un aprendizaje autodidacta muchas
veces se dan palos de ciego (al menos yo). cuando las cosas no estan
claras.
pero creo que algo he sacado en claro de este hilo:
-Rails si hace el magico autoload con const_missing.
-Las lib de ruby a pelo no se cargan magicamente, sino haciendo un
requiere
“rubygems”, require “mysql”

Eso es asi?
Pero mi duda es, haciendolo con requiere. ¿Como sabe mi archivo man.rb
donde
esta “mysql” cuando hago un require?
¿Es algo de los paths?
¿Que quieres decir con “requiere a mano”? Puede sonar como que no me
entero
de nada, pero confia en mi cuando te digo que voy dando micro-pasitos
hacia
delante :slight_smile:

Un saludo y gracias de nuevo

El 14 de enero de 2009 23:55, Xavier N. removed_email_address@domain.invalid escribió:


#13

Ror-es mailing list
removed_email_address@domain.invalid
http://lists.simplelogica.net/mailman/listinfo/ror-es


#14

2009/1/15 Andrés gutiérrez removed_email_address@domain.invalid:

Buenos dias Xavier, primero de todo perdoname si no te parezco del todo
coherente. Pero has de entender que en un aprendizaje autodidacta muchas
veces se dan palos de ciego (al menos yo). cuando las cosas no estan claras.

Nada, nada.

pero creo que algo he sacado en claro de este hilo:
-Rails si hace el magico autoload con const_missing.
-Las lib de ruby a pelo no se cargan magicamente, sino haciendo un requiere
“rubygems”, require “mysql”

Asi es.

Pero mi duda es, haciendolo con requiere. ¿Como sabe mi archivo man.rb donde
esta “mysql” cuando hago un require?
¿Es algo de los paths?
¿Que quieres decir con “requiere a mano”? Puede sonar como que no me entero
de nada, pero confia en mi cuando te digo que voy dando micro-pasitos hacia
delante :slight_smile:

Con require a mano quiero decir que tu escribes en un fichero

require "algo"

en lugar de dejar que automagicamente se carge el fichero. No es
“man.rb” quien sabe donde esta, es Ruby que busca “algo.rb” en $: y
las otras opciones que explique en el primer mail.


#15

On Thu, Jan 15, 2009 at 11:04 AM, Guillermo Álvarez Fernández
removed_email_address@domain.invalid wrote:

Yo en plugins suelo tirar bastante de autoload. Es muy sencillo de usar y es
del core.
Es tan simple como:
ModName.autoload(:Feature,‘new_feature’)

Yep, autoload es de Ruby es una posibilidad que ofrece el lenguaje
para que “configures” la autocarga.

De hecho estuve jugando con la idea de reescribir dependencies.rb (que
es un poco liado) con una aproximacion basada en autoload. Pero una
vez te pones salen cosas que parecen stoppers:

http://groups.google.com/group/rubyonrails-core/browse_thread/thread/100f50cb92afd83b/b8f6b429fc822782?lnk=gst&q=autoload#b8f6b429fc822782


#16

2009/1/15 Andrés gutiérrez removed_email_address@domain.invalid:

que mis modulos los carge cualquier fichero que tenga
en mi SO, tengo que meterlos en este PATH o añadir un directorio mio (lib) a
ese PATH?
Esto es asi? se puede hacer lo que digo arriba?

Eso es. De hecho normalmente solo se instalan librerias empaquetadas a
nivel de sistema.

Si tu intencion es que unas tuyas sean visibles en todo el sistema te
recomiendo que o bien sigas por el camino de RUBYLIB, o bien hagas una
gema de ellas (mirate como hacer un .gemspec + gem build) e instalar
esa gema.

Ese segundo camino necesita de mas background de todos modos,
empezaria por entender bien $: y RUBYLIB y el primer mail solo-Ruby.


#17

Con require a mano quiero decir que tu escribes en un fichero

require “algo”

en lugar de dejar que automagicamente se carge el fichero. No es
“man.rb” quien sabe donde esta, es Ruby que busca “algo.rb” en $: y
las otras opciones que explique en el primer mail.

Vale, me queda claro, me tengo que mirar lo de $: y RUBYLIB. Si yo
quiero
que mis modulos los carge cualquier fichero que tenga
en mi SO, tengo que meterlos en este PATH o añadir un directorio mio
(lib) a
ese PATH?
Esto es asi? se puede hacer lo que digo arriba?

Lo de autoload, me lo miro con más calma y os cuento

Gracias a los dos

El 15 de enero de 2009 11:07, Xavier N. removed_email_address@domain.invalid escribió:


#18

Ese segundo camino necesita de mas background de todos modos,
empezaria por entender bien $: y RUBYLIB y el primer mail solo-Ruby

Por ahi tiro, gracias

El 15 de enero de 2009 11:25, Xavier N. removed_email_address@domain.invalid escribió: