Skip to content

Instantly share code, notes, and snippets.

@quarkgluant
Last active November 14, 2019 19:16
Show Gist options
  • Save quarkgluant/76b9fa9d2df62fa23f94a89b3a666331 to your computer and use it in GitHub Desktop.
Save quarkgluant/76b9fa9d2df62fa23f94a89b3a666331 to your computer and use it in GitHub Desktop.
Pistes de réflexion sur le kata ActiveRecord like
module ClassMethods
# ce module sera "inclus" avec extend, donc
# toutes les méthodes de ce module seront des méthodes de classe
# les 2 méthodes ci-dessous, ressemblent à attr_accessor mais "de classe".
# l'idée est d'utiliser non pas des variables de classe (@@ids) mais des
# variables d'instances de classe (à ne pas confondre avec les variables d'instance)
# puisque une classe est aussi un objet en Ruby
def ids
@ids ||= 0
end
def ids=(number)
@ids = number
end
def new_id
self.ids = (ids + 1)
end
# la méthode all, au lieu d'utiliser une variable de classe telle @@all, dans
# laquelle on mettrai chaque nouvel instance de Car lors de l'instantiation dans la
# méthode initialize de Car, utilise ObjectSpace#each_object
def all
ObjectSpace.each_object(self).to_a
end
def find(id:)
all.select { |instance| instance.id == id }&.first
end
# cette méthode génère dynamiquement les méthodes find_by_TRUC
def make_attr_finders
new.public_methods(false).each do |meth|
next if meth.to_s.end_with? '='
define_singleton_method "find_by_#{meth}" do |arg|
all.select { |instance| instance.send(meth) == arg }
end
end
end
# ce hook de Ruby n'est pas utilisé ici, juste pour info
def self.extended(base)
puts "#{self} (ClassMethods) a été inclus/étendu dans #{base}"
end
end
module InstanceMethods
# ce module étant ensuite inclus avec "include", toutes ses méthodes seront des méthodes d'instance
def initialize
klass = self.class
self.id = klass.send :new_id
end
# but esthétique, pas utile pour le fonctionnement du kata
def to_s
"#{self.class} #{id}"
end
# ce hook de Ruby n'est pas utilisé ici, juste pour info
def self.included(base)
puts "#{self} (ClassMethods) a été inclus/étendu dans #{base}"
end
end
class Car
extend ClassMethods
include InstanceMethods
attr_accessor :id, :color, :nb_portes
def motor
%w[diesel gazoline electric].sample
end
end
first_car = Car.new
second_car = Car.new
third_car = Car.new
puts "first_car.id: #{first_car.id}" #=> 1
puts "third_car.id: #{third_car.id}" #=> 3
puts "Car.all: #{Car.all}" #=> [#<Car:0x00000000013f3210 @id=1>, #<Car:0x00000000013f37b0 @id=3>, #<Car:0x00000000013f38a0 @id=2>]
puts "Car.find(id: 3): #{Car.find(id: 3)}" #=> Car 3
Car.make_attr_finders
puts "Car.find_by_motor('electric'): #{Car.find_by_motor('electric')}"
puts "Car.find_by_id(3): #{Car.find_by_id(3)}" #=>[#<Car:0x000000000200ab70 @id=3>]
puts first_car.methods(false)
@quarkgluant
Copy link
Author

quarkgluant commented Nov 14, 2019

Ceci n'est PAS LA solution, ni même UNE solution, juste quelques pistes de réflexion qui ne demandent qu'à être améliorées ou radicalement modifiées. Par exemple, on est obligé d'avoir (ligne 85) Car.make_attr_finders, ce qui n'est pas beau

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment