mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-18 00:36:23 +00:00
Merge branch 'belongs-to' into staging
This commit is contained in:
commit
0f92cf193f
17 changed files with 292 additions and 46 deletions
|
@ -3,13 +3,6 @@
|
|||
# Almacena el UUID de otro Post y actualiza el valor en el Post
|
||||
# relacionado.
|
||||
class MetadataBelongsTo < MetadataRelatedPosts
|
||||
def value_was=(new_value)
|
||||
@belongs_to = nil
|
||||
@belonged_to = nil
|
||||
|
||||
super(new_value)
|
||||
end
|
||||
|
||||
# TODO: Convertir algunos tipos de valores en módulos para poder
|
||||
# implementar varios tipos de campo sin repetir código
|
||||
#
|
||||
|
@ -39,10 +32,14 @@ class MetadataBelongsTo < MetadataRelatedPosts
|
|||
|
||||
# Si estamos cambiando la relación, tenemos que eliminar la relación
|
||||
# anterior
|
||||
belonged_to[inverse].value.delete post.uuid.value if changed? && belonged_to.present?
|
||||
if belonged_to.present?
|
||||
belonged_to[inverse].value = belonged_to[inverse].value.reject do |rej|
|
||||
rej == post.uuid.value
|
||||
end
|
||||
end
|
||||
|
||||
# No duplicar las relaciones
|
||||
belongs_to[inverse].value << post.uuid.value unless belongs_to.blank? || included?
|
||||
belongs_to[inverse].value = (belongs_to[inverse].value.dup << post.uuid.value) unless belongs_to.blank? || included?
|
||||
|
||||
true
|
||||
end
|
||||
|
@ -63,20 +60,13 @@ class MetadataBelongsTo < MetadataRelatedPosts
|
|||
end
|
||||
|
||||
# El Post relacionado con este artículo
|
||||
#
|
||||
# XXX: Memoizamos usando el valor para tener el valor siempre
|
||||
# actualizado.
|
||||
def belongs_to
|
||||
return if value.blank?
|
||||
|
||||
@belongs_to ||= posts.find(value, uuid: true)
|
||||
posts.find(value, uuid: true) if value.present?
|
||||
end
|
||||
|
||||
# El artículo relacionado anterior
|
||||
def belonged_to
|
||||
return if value_was.blank?
|
||||
|
||||
@belonged_to ||= posts.find(value_was, uuid: true)
|
||||
posts.find(value_was, uuid: true) if value_was.present?
|
||||
end
|
||||
|
||||
def related_posts?
|
||||
|
|
|
@ -18,6 +18,7 @@ class MetadataHasAndBelongsToMany < MetadataHasMany
|
|||
#
|
||||
# Buscamos en belongs_to la relación local, si se eliminó hay que
|
||||
# quitarla de la relación remota, sino hay que agregarla.
|
||||
#
|
||||
def save
|
||||
# XXX: No usamos super
|
||||
self[:value] = sanitize value
|
||||
|
@ -25,27 +26,21 @@ class MetadataHasAndBelongsToMany < MetadataHasMany
|
|||
return true unless changed?
|
||||
return true unless inverse?
|
||||
|
||||
# XXX: Usamos asignación para aprovechar value= que setea el valor
|
||||
# anterior en @value_was
|
||||
(had_many - has_many).each do |remove|
|
||||
remove[inverse]&.value&.delete post.uuid.value
|
||||
remove[inverse].value = remove[inverse].value.reject do |rej|
|
||||
rej == post.uuid.value
|
||||
end
|
||||
end
|
||||
|
||||
(has_many - had_many).each do |add|
|
||||
next unless add[inverse]
|
||||
next if add[inverse].value.include? post.uuid.value
|
||||
|
||||
add[inverse].value << post.uuid.value
|
||||
add[inverse].value = (add[inverse].value.dup << post.uuid.value)
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Igual que en MetadataRelatedPosts
|
||||
# TODO: Mover a un módulo
|
||||
def sanitize(uuid)
|
||||
super(uuid.map do |u|
|
||||
u.to_s.gsub(/[^a-f0-9\-]/i, '')
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,14 +6,6 @@
|
|||
# Localmente tenemos un Array de UUIDs. Remotamente tenemos una String
|
||||
# apuntando a un Post, que se mantiene actualizado como el actual.
|
||||
class MetadataHasMany < MetadataRelatedPosts
|
||||
# Invalidar la relación anterior
|
||||
def value_was=(new_value)
|
||||
@had_many = nil
|
||||
@has_many = nil
|
||||
|
||||
super(new_value)
|
||||
end
|
||||
|
||||
def validate
|
||||
super
|
||||
|
||||
|
@ -24,14 +16,16 @@ class MetadataHasMany < MetadataRelatedPosts
|
|||
|
||||
# Todos los Post relacionados
|
||||
def has_many
|
||||
@has_many ||= posts.where(uuid: value)
|
||||
return default_value if value.blank?
|
||||
|
||||
posts.where(uuid: value)
|
||||
end
|
||||
|
||||
# La relación anterior
|
||||
def had_many
|
||||
return [] if value_was.blank?
|
||||
return default_value if value_was.blank?
|
||||
|
||||
@had_many ||= posts.where(uuid: value_was)
|
||||
posts.where(uuid: value_was)
|
||||
end
|
||||
|
||||
def inverse?
|
||||
|
|
|
@ -30,7 +30,7 @@ class MetadataRelatedPosts < MetadataArray
|
|||
|
||||
# Obtiene todos los posts y opcionalmente los filtra
|
||||
def posts
|
||||
@posts ||= site.posts(lang: lang).where(**filter)
|
||||
site.posts(lang: lang).where(**filter)
|
||||
end
|
||||
|
||||
def title(post)
|
||||
|
|
|
@ -238,12 +238,14 @@ class Post
|
|||
template = public_send attr
|
||||
|
||||
unless template.front_matter?
|
||||
body += "\n\n"
|
||||
body += "\n\n" if body.present?
|
||||
body += template.value
|
||||
next
|
||||
end
|
||||
|
||||
next if template.empty?
|
||||
# Queremos mantener los Array en el resultado final para que
|
||||
# siempre respondan a {% for %} en Liquid.
|
||||
next if template.empty? && !template.value.is_a?(Array)
|
||||
|
||||
[attr.to_s, template.value]
|
||||
end.compact.to_h
|
||||
|
@ -301,6 +303,7 @@ class Post
|
|||
end
|
||||
|
||||
# Vuelve a leer el post para tomar los cambios
|
||||
document.reset
|
||||
read
|
||||
|
||||
written?
|
||||
|
|
|
@ -93,8 +93,7 @@ class PostRelation < Array
|
|||
def where(**args)
|
||||
return self if args.empty?
|
||||
|
||||
@where ||= {}
|
||||
@where[args.hash.to_s] ||= begin
|
||||
begin
|
||||
PostRelation.new(site: site, lang: lang).concat(select do |post|
|
||||
result = args.map do |attr, value|
|
||||
next unless post.attribute?(attr)
|
||||
|
|
|
@ -73,6 +73,15 @@ module Jekyll
|
|||
Document.class_eval do
|
||||
alias_method :read!, :read
|
||||
def read; end
|
||||
|
||||
# Permitir restablecer el documento sin crear uno nuevo
|
||||
def reset
|
||||
@path = @extname = @has_yaml_header = @relative_path = nil
|
||||
@basename_without_ext = @data = @basename = nil
|
||||
@renderer = @url_placeholders = @url = nil
|
||||
@to_liquid = @write_p = @excerpt_separator = @id = nil
|
||||
@related_posts = @cleaned_relative_path = self.content = nil
|
||||
end
|
||||
end
|
||||
|
||||
# Prevenir la instanciación de Time
|
||||
|
|
2
test/fixtures/site_with_relationships/README.md
vendored
Normal file
2
test/fixtures/site_with_relationships/README.md
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
This is site where posts can have many authors and viceversa and posts
|
||||
can be replies to others.
|
2
test/fixtures/site_with_relationships/_config.yml
vendored
Normal file
2
test/fixtures/site_with_relationships/_config.yml
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
locales:
|
||||
- en
|
9
test/fixtures/site_with_relationships/_data/layouts/author.yml
vendored
Normal file
9
test/fixtures/site_with_relationships/_data/layouts/author.yml
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
title:
|
||||
type: 'string'
|
||||
required: true
|
||||
posts:
|
||||
type: 'has_and_belongs_to_many'
|
||||
inverse: 'authors'
|
||||
filter:
|
||||
layout: 'post'
|
23
test/fixtures/site_with_relationships/_data/layouts/post.yml
vendored
Normal file
23
test/fixtures/site_with_relationships/_data/layouts/post.yml
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
title:
|
||||
type: 'string'
|
||||
required: true
|
||||
authors:
|
||||
type: 'has_and_belongs_to_many'
|
||||
inverse: 'posts'
|
||||
filter:
|
||||
layout: 'author'
|
||||
posts:
|
||||
type: 'has_many'
|
||||
inverse: 'in_reply_to'
|
||||
filter:
|
||||
layout: 'post'
|
||||
in_reply_to:
|
||||
type: 'belongs_to'
|
||||
inverse: 'posts'
|
||||
filter:
|
||||
layout: 'post'
|
||||
recommended_posts:
|
||||
type: 'related_posts'
|
||||
filter:
|
||||
layout: 'post'
|
0
test/fixtures/site_with_relationships/_en/.keep
vendored
Normal file
0
test/fixtures/site_with_relationships/_en/.keep
vendored
Normal file
1
test/fixtures/site_with_relationships/_posts
vendored
Symbolic link
1
test/fixtures/site_with_relationships/_posts
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
_en
|
62
test/models/metadata_belongs_to_test.rb
Normal file
62
test/models/metadata_belongs_to_test.rb
Normal file
|
@ -0,0 +1,62 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'test_helper'
|
||||
require_relative 'metadata_test'
|
||||
|
||||
class MetadataBelongsToTest < ActiveSupport::TestCase
|
||||
include MetadataTest
|
||||
|
||||
test 'se pueden relacionar artículos' do
|
||||
post = @site.posts.create(layout: :post, title: SecureRandom.hex)
|
||||
reply = @site.posts.create(layout: :post, title: SecureRandom.hex, in_reply_to: post.uuid.value)
|
||||
|
||||
assert_equal post, reply.in_reply_to.belongs_to
|
||||
assert_includes post.posts.has_many, reply
|
||||
|
||||
assert post.save
|
||||
|
||||
assert_equal reply.document.data['in_reply_to'], post.document.data['uuid']
|
||||
assert_includes post.document.data['posts'], reply.document.data['uuid']
|
||||
end
|
||||
|
||||
test 'se puede eliminar la relación' do
|
||||
post = @site.posts.create(layout: :post, title: SecureRandom.hex)
|
||||
reply = @site.posts.create(layout: :post, title: SecureRandom.hex, in_reply_to: post.uuid.value)
|
||||
|
||||
reply.in_reply_to.value = ''
|
||||
assert reply.save
|
||||
|
||||
assert_not_equal post, reply.in_reply_to.belongs_to
|
||||
assert_equal post, reply.in_reply_to.belonged_to
|
||||
assert_nil reply.in_reply_to.belongs_to
|
||||
assert_not_includes post.posts.has_many, reply
|
||||
|
||||
assert post.save
|
||||
|
||||
assert_nil reply.document.data['in_reply_to']
|
||||
assert_not_includes post.document.data['posts'], reply.document.data['uuid']
|
||||
end
|
||||
|
||||
test 'se puede cambiar la relación' do
|
||||
post1 = @site.posts.create(layout: :post, title: SecureRandom.hex)
|
||||
post2 = @site.posts.create(layout: :post, title: SecureRandom.hex)
|
||||
reply = @site.posts.create(layout: :post, title: SecureRandom.hex, in_reply_to: post1.uuid.value)
|
||||
|
||||
reply.in_reply_to.value = post2.uuid.value
|
||||
assert reply.save
|
||||
|
||||
assert_not_equal post1, reply.in_reply_to.belongs_to
|
||||
assert_equal post1, reply.in_reply_to.belonged_to
|
||||
assert_not_includes post1.posts.has_many, reply
|
||||
|
||||
assert_equal post2, reply.in_reply_to.belongs_to
|
||||
assert_includes post2.posts.has_many, reply
|
||||
|
||||
assert post1.save
|
||||
assert post2.save
|
||||
|
||||
assert_equal post2.document.data['uuid'], reply.document.data['in_reply_to']
|
||||
assert_includes post2.document.data['posts'], reply.document.data['uuid']
|
||||
assert_not_includes post1.document.data['posts'], reply.document.data['uuid']
|
||||
end
|
||||
end
|
76
test/models/metadata_has_and_belongs_to_many_test.rb
Normal file
76
test/models/metadata_has_and_belongs_to_many_test.rb
Normal file
|
@ -0,0 +1,76 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'test_helper'
|
||||
require_relative 'metadata_test'
|
||||
|
||||
class MetadataHasAndBelongsManyTest < ActiveSupport::TestCase
|
||||
include MetadataTest
|
||||
|
||||
test 'se pueden relacionar artículos' do
|
||||
author = @site.posts.create(layout: :author, title: SecureRandom.hex)
|
||||
post = @site.posts.create(layout: :post, title: SecureRandom.hex)
|
||||
|
||||
post.authors.value = [author.uuid.value]
|
||||
assert post.save
|
||||
|
||||
assert_includes author.posts.has_many, post
|
||||
assert_includes post.authors.has_many, author
|
||||
|
||||
assert author.save
|
||||
|
||||
assert_includes author.document.data['posts'], post.document.data['uuid']
|
||||
assert_includes post.document.data['authors'], author.document.data['uuid']
|
||||
end
|
||||
|
||||
test 'se puede eliminar la relación' do
|
||||
author = @site.posts.create(layout: :author, title: SecureRandom.hex)
|
||||
post = @site.posts.create(layout: :post, title: SecureRandom.hex, authors: [author.uuid.value])
|
||||
|
||||
assert_includes post.authors.value, author.uuid.value
|
||||
assert_includes author.posts.value, post.uuid.value
|
||||
|
||||
post.authors.value = []
|
||||
assert post.save
|
||||
|
||||
assert_not_includes author.posts.has_many, post
|
||||
assert_not_includes post.authors.has_many, author
|
||||
|
||||
assert_includes author.posts.had_many, post
|
||||
assert_includes post.authors.had_many, author
|
||||
|
||||
assert author.save
|
||||
|
||||
assert_not_includes author.document.data['posts'], post.document.data['uuid']
|
||||
assert_not_includes post.document.data['authors'], author.document.data['uuid']
|
||||
end
|
||||
|
||||
test 'se puede cambiar la relación' do
|
||||
author = @site.posts.create(layout: :author, title: SecureRandom.hex)
|
||||
post1 = @site.posts.create(layout: :post, title: SecureRandom.hex, authors: [author.uuid.value])
|
||||
post2 = @site.posts.create(layout: :post, title: SecureRandom.hex)
|
||||
|
||||
author.posts.value = [post2.uuid.value]
|
||||
assert author.save
|
||||
|
||||
assert_not_includes author.posts.has_many, post1
|
||||
assert_not_includes post1.authors.has_many, author
|
||||
|
||||
assert_includes author.posts.had_many, post1
|
||||
assert_includes post1.authors.had_many, author
|
||||
|
||||
assert_not_includes author.posts.had_many, post2
|
||||
assert_not_includes post2.authors.had_many, author
|
||||
|
||||
assert_includes author.posts.has_many, post2
|
||||
assert_includes post2.authors.has_many, author
|
||||
|
||||
assert post1.save
|
||||
assert post2.save
|
||||
|
||||
assert_not_includes author.document.data['posts'], post1.document.data['uuid']
|
||||
assert_not_includes post1.document.data['authors'], author.document.data['uuid']
|
||||
|
||||
assert_includes author.document.data['posts'], post2.document.data['uuid']
|
||||
assert_includes post2.document.data['authors'], author.document.data['uuid']
|
||||
end
|
||||
end
|
62
test/models/metadata_has_many_test.rb
Normal file
62
test/models/metadata_has_many_test.rb
Normal file
|
@ -0,0 +1,62 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'test_helper'
|
||||
require_relative 'metadata_test'
|
||||
|
||||
class MetadataHasManyTest < ActiveSupport::TestCase
|
||||
include MetadataTest
|
||||
|
||||
test 'se pueden relacionar artículos' do
|
||||
reply = @site.posts.create(layout: :post, title: SecureRandom.hex)
|
||||
post = @site.posts.create(layout: :post, title: SecureRandom.hex, posts: [reply.uuid.value])
|
||||
|
||||
assert_equal post, reply.in_reply_to.belongs_to
|
||||
assert_includes post.posts.has_many, reply
|
||||
|
||||
assert reply.save
|
||||
|
||||
assert_equal reply.document.data['in_reply_to'], post.document.data['uuid']
|
||||
assert_includes post.document.data['posts'], reply.document.data['uuid']
|
||||
end
|
||||
|
||||
test 'se puede eliminar la relación' do
|
||||
reply = @site.posts.create(layout: :post, title: SecureRandom.hex)
|
||||
post = @site.posts.create(layout: :post, title: SecureRandom.hex, posts: [reply.uuid.value])
|
||||
|
||||
post.posts.value = []
|
||||
assert post.save
|
||||
|
||||
assert_not_equal post, reply.in_reply_to.belongs_to
|
||||
assert_equal post, reply.in_reply_to.belonged_to
|
||||
assert_nil reply.in_reply_to.belongs_to
|
||||
assert_not_includes post.posts.has_many, reply
|
||||
|
||||
assert reply.save
|
||||
|
||||
assert_nil reply.document.data['in_reply_to']
|
||||
assert_not_includes post.document.data['posts'], reply.document.data['uuid']
|
||||
end
|
||||
|
||||
test 'se puede cambiar la relación' do
|
||||
reply = @site.posts.create(layout: :post, title: SecureRandom.hex)
|
||||
post1 = @site.posts.create(layout: :post, title: SecureRandom.hex, posts: [reply.uuid.value])
|
||||
post2 = @site.posts.create(layout: :post, title: SecureRandom.hex)
|
||||
|
||||
reply.in_reply_to.value = post2.uuid.value
|
||||
assert reply.save
|
||||
|
||||
assert_not_equal post1, reply.in_reply_to.belongs_to
|
||||
assert_equal post1, reply.in_reply_to.belonged_to
|
||||
assert_not_includes post1.posts.has_many, reply
|
||||
|
||||
assert_equal post2, reply.in_reply_to.belongs_to
|
||||
assert_includes post2.posts.has_many, reply
|
||||
|
||||
assert post1.save
|
||||
assert post2.save
|
||||
|
||||
assert_equal post2.document.data['uuid'], reply.document.data['in_reply_to']
|
||||
assert_includes post2.document.data['posts'], reply.document.data['uuid']
|
||||
assert_not_includes post1.document.data['posts'], reply.document.data['uuid']
|
||||
end
|
||||
end
|
19
test/models/metadata_test.rb
Normal file
19
test/models/metadata_test.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module MetadataTest
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
setup do
|
||||
name = SecureRandom.hex
|
||||
# TODO: Poder cambiar el nombre
|
||||
FileUtils.cp_r(Rails.root.join('test', 'fixtures', 'site_with_relationships'), Rails.root.join('_sites', name))
|
||||
|
||||
@site = create :site, name: name
|
||||
end
|
||||
|
||||
teardown do
|
||||
@site&.destroy
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue