Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

219
Views
Clases dinámicas en Ruby, Class.new, desempaquetando Sequel::Model

Soy nuevo en Ruby y trato de descubrir cómo funciona la declaración de clase a continuación de Sequel gem detrás de escena.

 class Enumeration < Sequel::Model(DB[:enumerations]); end

Tras una rápida investigación del código de Sequel gem, me parece que el método del módulo Sequel::Model devuelve una instancia de clase con un atributo de clase configurado. La instancia de retorno de Class se usa luego en la jerarquía de herencia, así que traté de probar mi comprensión a través del código;

 module MySequel class MyModel module ClassMethods attr_accessor :table_name def model(table_name) klass = Class.new(self) klass.table_name = table_name puts klass.table_name # prints table_name, it does get set for the first class Class object klass klass end end extend ClassMethods end end class Enumeration < MySequel::MyModel.model(:enumerations); end class EnumerationValue < MySequel::MyModel.model(:enumeration_values); end p Enumeration.table_name # prints nil p EnumerationValue.table_name # prints nil

Según mi comprensión, la variable de clase table_name se establece al crear una instancia de Class y se propaga a su clase secundaria. Sin embargo, ese no parece ser el caso.

¿Puede alguien explicar el concepto detrás de Sequel::Model y el problema con mi implementación de muestra para lograr el mismo resultado?

El comportamiento en este ejemplo es similar al uso de las clases anónimas anteriores.

 class TestModel @@table_name = 'test' def TestModel.table_name @@table_name end def TestModel.table_name=(value) @@table_name = value end end TestModel.table_name = 'posts' p TestModel.table_name # prints posts class ChildTestModel < TestModel; end puts Enumeration.table_name # prints nil

La biblioteca Sequel aparentemente está propagando la información sobre el conjunto de datos a través del método de llamada al módulo a la clase secundaria (a través de la clase anónima).

Sin embargo, no puedo entender; qué construcción del lenguaje Ruby permite que la clase de estado a continuación sepa que está restringida a un registro en las enumeraciones de tablas con el nombre establecido en 'estado'.

 class Status < Sequel::Model(DB[:enumerations].where(name: 'status')); end
over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

La biblioteca Sequel aparentemente está propagando la información sobre el conjunto de datos a través del método de llamada al módulo a la clase secundaria

Sí, de hecho. Sequel usa la devolución de llamada inherited para copiar las variables de instancia de clase a la subclase (ver lib/sequel/model/base.rb#843 ).

Aquí hay una versión muy básica para su clase de ejemplo:

 module MySequel class MyModel module ClassMethods attr_accessor :table_name def model(table_name) klass = Class.new(self) klass.table_name = table_name klass end def inherited(subclass) instance_variables.each do |var| value = instance_variable_get(var) subclass.instance_variable_set(var, value) end end end extend ClassMethods end end

Como resultado, las subclases tendrán sus variables de instancia de clase (aquí @table_name ) establecidas en los mismos valores que la clase principal (anónima):

 class Enumeration < MySequel::MyModel.model(:enumerations); end class EnumerationValue < MySequel::MyModel.model(:enumeration_values); end p Enumeration.table_name #=> :enumerations p EnumerationValue.table_name #=> :enumeration_values
over 4 years ago · Santiago Trujillo Report

0

Entonces, la mayoría del código es correcto y su suposición sobre cómo funciona todo es correcta. ¡Lo cual es realmente genial y definitivamente no es un nivel de principiante de Ruby!

Entonces, lo que no funciona. Cuando define una subclase de alguna clase, la subclase hereda todos los "métodos de clase" (entre comillas, ya que en realidad no existe tal cosa), pero las variables de instancia no se heredan (es decir, la variable de instancia de una instancia de una clase Clase ):

 class A @foo = 1 end A.instance_variables #=> [:@foo] class B < A; end B.instance_variables #=> []

Eso significa que si invoca un setter en la clase anónima que creó en su método de model , establece la variable de instancia solo en esa clase. Y las subclases de esa clase anónima no heredan eso. Podrías ver que esto funcionaría:

 Enumeration = MySequel::MyModel.model(:enumerations) EnumerationValue = MySequel::MyModel.model(:enumeration_values) Enumeration.table_name #=> :enumerations EnumerationValue.table_name #=> :enumeration_values

Y para ser honesto, realmente no hay mucha ganancia subclasificando sus clases anónimas aquí. Esto solo tendría sentido si también hubiera estado almacenando en caché esas clases y cuando llamadas separadas a ese método hubieran devuelto el mismo objeto Class dos veces.

Si aún desea que table_name sea heredable, debe ser muy explícito al respecto y, en lugar de usar attr_accessor , debe buscar directamente en una superclase:

 attr_setter :table_name def table_name @table_name || (superclass.table_name if superclass.respond_to?(:table_name)) end

Hay algunos ajustes que tal vez quieras considerar aquí. La versión anterior

over 4 years ago · Santiago Trujillo Report

0

El nombre de la tabla se establece al definir Enumeration o EnumerationValue y se mantiene dentro de la clase principal (que es una clase anónima).

Es mucho más simple comprender el concepto, para mí personalmente, cuando lo comparo con la herencia prototípica de javascript.

Se puede acceder a través de la superclase de la clase Enumeration y EnumerationValue.

 # frozen_string_literal: true module MySequel class MyModel module ClassMethods attr_accessor :table_name def model(table_name) klass = Class.new(self) klass.table_name = table_name klass end end extend ClassMethods end end class Enumeration < MySequel::MyModel.model(:enumerations); end class EnumerationValue < MySequel::MyModel.model(:enumeration_values); end p Enumeration.superclass.table_name # prints :enumerations p EnumerationValue.superclass.table_name # prints :enumeration_values
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!