mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-26 07:56:23 +00:00
renombrar archivos
This commit is contained in:
parent
ada14b2294
commit
f7527e7ee3
10 changed files with 146 additions and 35 deletions
|
@ -33,6 +33,7 @@ Metrics/MethodLength:
|
||||||
- 'app/controllers/i18n_controller.rb'
|
- 'app/controllers/i18n_controller.rb'
|
||||||
- 'app/controllers/collaborations_controller.rb'
|
- 'app/controllers/collaborations_controller.rb'
|
||||||
- 'app/controllers/usuaries_controller.rb'
|
- 'app/controllers/usuaries_controller.rb'
|
||||||
|
- 'app/models/post.rb'
|
||||||
|
|
||||||
Metrics/BlockLength:
|
Metrics/BlockLength:
|
||||||
Exclude:
|
Exclude:
|
||||||
|
@ -47,6 +48,7 @@ Metrics/ClassLength:
|
||||||
- 'app/models/site.rb'
|
- 'app/models/site.rb'
|
||||||
- 'app/controllers/posts_controller.rb'
|
- 'app/controllers/posts_controller.rb'
|
||||||
- 'app/controllers/sites_controller.rb'
|
- 'app/controllers/sites_controller.rb'
|
||||||
|
- 'test/models/post_test.rb'
|
||||||
|
|
||||||
Lint/HandleExceptions:
|
Lint/HandleExceptions:
|
||||||
Exclude:
|
Exclude:
|
||||||
|
|
22
app/lib/core_extensions/jekyll/document/path.rb
Normal file
22
app/lib/core_extensions/jekyll/document/path.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module CoreExtensions
|
||||||
|
module Jekyll
|
||||||
|
module Document
|
||||||
|
# Permite cambiar la ubicación del archivo para que podamos leerlo
|
||||||
|
# sin tener que instanciar uno nuevo.
|
||||||
|
module Path
|
||||||
|
def path=(new_path)
|
||||||
|
@path = new_path
|
||||||
|
# Dejar que lo recalcule al releer
|
||||||
|
@cleaned_relative_path =
|
||||||
|
@extname =
|
||||||
|
@basename =
|
||||||
|
@basename_without_ext =
|
||||||
|
@output_ext =
|
||||||
|
@relative_path = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
3
app/models/metadata_date.rb
Normal file
3
app/models/metadata_date.rb
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
class MetadataDate < MetadataTemplate
|
||||||
|
|
||||||
|
end
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# Maneja la fecha del document
|
# Maneja la fecha del document
|
||||||
class MetadataDocumentDate < MetadataTemplate
|
class MetadataDocumentDate < MetadataTemplate
|
||||||
# La fecha por defecto es ahora!
|
# La fecha por defecto es ahora!
|
||||||
|
|
35
app/models/metadata_path.rb
Normal file
35
app/models/metadata_path.rb
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# Este campo representa el archivo donde se almacenan los datos
|
||||||
|
class MetadataPath < MetadataTemplate
|
||||||
|
# :label en este caso es el idioma/colección
|
||||||
|
def default_value
|
||||||
|
File.join(site.path, "_#{lang}", "#{date}-#{slug}#{ext}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def value
|
||||||
|
default_value
|
||||||
|
end
|
||||||
|
alias absolute value
|
||||||
|
alias to_s value
|
||||||
|
|
||||||
|
def relative
|
||||||
|
value.sub(site.path, '').sub(%r{^/}, '')
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def ext
|
||||||
|
document.extname || '.markdown'
|
||||||
|
end
|
||||||
|
|
||||||
|
def lang
|
||||||
|
post.lang
|
||||||
|
end
|
||||||
|
|
||||||
|
def slug
|
||||||
|
post.slug.value
|
||||||
|
end
|
||||||
|
|
||||||
|
def date
|
||||||
|
post.date.value.strftime('%F')
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'jekyll/utils'
|
require 'jekyll/utils'
|
||||||
|
|
||||||
# El slug es el nombre del archivo sin la fecha ni la extensión y se
|
# El slug es el nombre del archivo sin la fecha ni la extensión y se
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#
|
#
|
||||||
# TODO: Validar el tipo de valor pasado a value= según el :type
|
# TODO: Validar el tipo de valor pasado a value= según el :type
|
||||||
MetadataTemplate = Struct.new(:site, :document, :name, :label, :type,
|
MetadataTemplate = Struct.new(:site, :document, :name, :label, :type,
|
||||||
:value, :help, :required, :errors,
|
:value, :help, :required, :errors, :post,
|
||||||
:layout, keyword_init: true) do
|
:layout, keyword_init: true) do
|
||||||
# El valor por defecto
|
# El valor por defecto
|
||||||
def default_value
|
def default_value
|
||||||
|
|
|
@ -13,7 +13,7 @@ class Post < OpenStruct
|
||||||
# XXX: Volver document opcional cuando estemos creando
|
# XXX: Volver document opcional cuando estemos creando
|
||||||
DEFAULT_ATTRIBUTES = %i[site document layout].freeze
|
DEFAULT_ATTRIBUTES = %i[site document layout].freeze
|
||||||
# Otros atributos que no vienen en los metadatos
|
# Otros atributos que no vienen en los metadatos
|
||||||
ATTRIBUTES = %i[content lang date slug attributes errors].freeze
|
ATTRIBUTES = %i[content lang path date slug attributes errors].freeze
|
||||||
|
|
||||||
# Redefinir el inicializador de OpenStruct
|
# Redefinir el inicializador de OpenStruct
|
||||||
#
|
#
|
||||||
|
@ -22,7 +22,6 @@ class Post < OpenStruct
|
||||||
# @param layout: [Layout] la plantilla
|
# @param layout: [Layout] la plantilla
|
||||||
#
|
#
|
||||||
# rubocop:disable Metrics/AbcSize
|
# rubocop:disable Metrics/AbcSize
|
||||||
# rubocop:disable Metrics/MethodLength
|
|
||||||
def initialize(**args)
|
def initialize(**args)
|
||||||
default_attributes_missing(args)
|
default_attributes_missing(args)
|
||||||
super(args)
|
super(args)
|
||||||
|
@ -45,6 +44,7 @@ class Post < OpenStruct
|
||||||
layout.metadata.each_pair do |name, template|
|
layout.metadata.each_pair do |name, template|
|
||||||
send "#{name}=".to_sym,
|
send "#{name}=".to_sym,
|
||||||
MetadataFactory.build(document: document,
|
MetadataFactory.build(document: document,
|
||||||
|
post: self,
|
||||||
site: site,
|
site: site,
|
||||||
name: name,
|
name: name,
|
||||||
layout: layout,
|
layout: layout,
|
||||||
|
@ -56,12 +56,12 @@ class Post < OpenStruct
|
||||||
|
|
||||||
load_slug!
|
load_slug!
|
||||||
load_date!
|
load_date!
|
||||||
|
load_path!
|
||||||
|
|
||||||
# Leer el documento
|
# Leer el documento
|
||||||
read
|
read
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics/AbcSize
|
# rubocop:enable Metrics/AbcSize
|
||||||
# rubocop:enable Metrics/MethodLength
|
|
||||||
|
|
||||||
# Levanta un error si al construir el artículo no pasamos un atributo.
|
# Levanta un error si al construir el artículo no pasamos un atributo.
|
||||||
def default_attributes_missing(**args)
|
def default_attributes_missing(**args)
|
||||||
|
@ -127,13 +127,13 @@ class Post < OpenStruct
|
||||||
#
|
#
|
||||||
# XXX Commit
|
# XXX Commit
|
||||||
def destroy
|
def destroy
|
||||||
FileUtils.rm_f path
|
FileUtils.rm_f path.absolute
|
||||||
|
|
||||||
site.posts(lang: lang).delete_if do |post|
|
site.posts(lang: lang).delete_if do |post|
|
||||||
post.path == path
|
post.path.absolute == path.absolute
|
||||||
end
|
end
|
||||||
|
|
||||||
!File.exist?(path) && !site.posts(lang: lang).include?(self)
|
!File.exist?(path.absolute) && !site.posts(lang: lang).include?(self)
|
||||||
end
|
end
|
||||||
alias destroy! destroy
|
alias destroy! destroy
|
||||||
# rubocop:enable Metrics/AbcSize
|
# rubocop:enable Metrics/AbcSize
|
||||||
|
@ -141,10 +141,12 @@ class Post < OpenStruct
|
||||||
# Guarda los cambios
|
# Guarda los cambios
|
||||||
def save
|
def save
|
||||||
return false unless valid?
|
return false unless valid?
|
||||||
|
# Salir si tenemos que cambiar el nombre del archivo y no pudimos
|
||||||
|
return false if path_changed? && !update_path!
|
||||||
return false unless write
|
return false unless write
|
||||||
|
|
||||||
# Vuelve a leer el post para tomar los cambios
|
# Vuelve a leer el post para tomar los cambios
|
||||||
document.read
|
read
|
||||||
|
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
@ -152,20 +154,15 @@ class Post < OpenStruct
|
||||||
|
|
||||||
# Lee el documento
|
# Lee el documento
|
||||||
def read
|
def read
|
||||||
Dir.chdir(site.path) do
|
document.read
|
||||||
document.read
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Devuelve la ruta del post, si se cambió alguno de los datos,
|
# Actualizar la ubicación del archivo si cambió de lugar y si no
|
||||||
# generamos una ruta nueva para tener siempre la ruta actualizada.
|
# existe el destino
|
||||||
def path
|
def update_path!
|
||||||
document.path
|
!File.exist?(path.absolute) &&
|
||||||
end
|
FileUtils.mv(path_was, path.absolute) &&
|
||||||
alias relative_path path
|
document.path = path.absolute
|
||||||
|
|
||||||
def absolute_path
|
|
||||||
File.join site.path, path
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Detecta si el artículo es válido para guardar
|
# Detecta si el artículo es válido para guardar
|
||||||
|
@ -224,7 +221,7 @@ class Post < OpenStruct
|
||||||
def write
|
def write
|
||||||
return true if persisted?
|
return true if persisted?
|
||||||
|
|
||||||
Site::Writer.new(site: site, file: path,
|
Site::Writer.new(site: site, file: path.absolute,
|
||||||
content: full_content, usuarie: usuarie,
|
content: full_content, usuarie: usuarie,
|
||||||
message: title.value).save
|
message: title.value).save
|
||||||
end
|
end
|
||||||
|
@ -241,25 +238,27 @@ class Post < OpenStruct
|
||||||
|
|
||||||
# Verifica si hace falta escribir cambios
|
# Verifica si hace falta escribir cambios
|
||||||
def persisted?
|
def persisted?
|
||||||
File.exist?(absolute_path) && full_content == File.read(absolute_path)
|
File.exist?(path.absolute) && full_content == File.read(path.absolute)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
# rubocop:disable Metrics/AbcSize
|
||||||
def new_attribute_was(method)
|
def new_attribute_was(method)
|
||||||
attr_was = (attribute_name(method).to_s + '_was').to_sym
|
attr_was = (attribute_name(method).to_s + '_was').to_sym
|
||||||
return attr_was if singleton_class.method_defined? attr_was
|
return attr_was if singleton_class.method_defined? attr_was
|
||||||
|
|
||||||
define_singleton_method(attr_was) do
|
define_singleton_method(attr_was) do
|
||||||
name = attribute_name(attr_was)
|
name = attribute_name(attr_was)
|
||||||
name == :content ? document.content : document.data[name.to_s]
|
if document.respond_to?(name)
|
||||||
|
document.send(name)
|
||||||
|
else
|
||||||
|
document.data[name.to_s]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_was
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Pregunta si el atributo cambió
|
# Pregunta si el atributo cambió
|
||||||
# rubocop:disable Metrics/AbcSize
|
|
||||||
def new_attribute_changed(method)
|
def new_attribute_changed(method)
|
||||||
attr_changed = (attribute_name(method).to_s + '_changed?').to_sym
|
attr_changed = (attribute_name(method).to_s + '_changed?').to_sym
|
||||||
|
|
||||||
|
@ -284,15 +283,25 @@ class Post < OpenStruct
|
||||||
|
|
||||||
def load_slug!
|
def load_slug!
|
||||||
self.slug = MetadataSlug.new(document: document, site: site,
|
self.slug = MetadataSlug.new(document: document, site: site,
|
||||||
layout: layout, name: :slug,
|
layout: layout, name: :slug, type: :slug,
|
||||||
|
post: self,
|
||||||
required: true)
|
required: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_date!
|
def load_date!
|
||||||
self.date = MetadataDocumentDate.new(document: document, site: site,
|
self.date = MetadataDocumentDate.new(document: document, site: site,
|
||||||
layout: layout, name: :date,
|
layout: layout, name: :date,
|
||||||
|
type: :document_date,
|
||||||
|
post: self,
|
||||||
required: true)
|
required: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def load_path!
|
||||||
|
self.path = MetadataPath.new(document: document, site: site,
|
||||||
|
layout: layout, name: :path,
|
||||||
|
type: :path, post: self,
|
||||||
|
required: true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics/ClassLength
|
# rubocop:enable Metrics/ClassLength
|
||||||
# rubocop:enable Style/MethodMissingSuper
|
# rubocop:enable Style/MethodMissingSuper
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'jekyll/document'
|
||||||
|
|
||||||
String.include CoreExtensions::String::StripTags
|
String.include CoreExtensions::String::StripTags
|
||||||
|
Jekyll::Document.include CoreExtensions::Jekyll::Document::Path
|
||||||
|
|
|
@ -34,18 +34,18 @@ class PostTest < ActiveSupport::TestCase
|
||||||
test 'se pueden eliminar' do
|
test 'se pueden eliminar' do
|
||||||
# TODO: cuando esté con git, solo aplicar git reset
|
# TODO: cuando esté con git, solo aplicar git reset
|
||||||
tmp = File.join(Rails.root, 'tmp', 'eliminar.md')
|
tmp = File.join(Rails.root, 'tmp', 'eliminar.md')
|
||||||
FileUtils.cp @post.path, tmp
|
FileUtils.cp @post.path.absolute, tmp
|
||||||
|
|
||||||
assert @post.destroy
|
assert @post.destroy
|
||||||
assert_not File.exist?(@post.path)
|
assert_not File.exist?(@post.path.absolute)
|
||||||
assert_not @site.posts.include?(@post)
|
assert_not @site.posts.include?(@post)
|
||||||
|
|
||||||
FileUtils.mv tmp, @post.path
|
FileUtils.mv tmp, @post.path.absolute
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'se puede ver el contenido completo después de guardar' do
|
test 'se puede ver el contenido completo después de guardar' do
|
||||||
assert @post.save
|
assert @post.save
|
||||||
@post.document.read
|
@post.read
|
||||||
|
|
||||||
# Queremos saber si todos los atributos del post terminaron en el
|
# Queremos saber si todos los atributos del post terminaron en el
|
||||||
# archivo
|
# archivo
|
||||||
|
@ -56,10 +56,10 @@ class PostTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
if metadata.empty?
|
if metadata.empty?
|
||||||
assert_not @post.document.data[attr.to_s].present?
|
assert_not @post.document.data[attr.to_s].present?
|
||||||
elsif attr == :date
|
elsif @post.document.respond_to? attr
|
||||||
assert_equal metadata.value, @post.document.date
|
assert_equal metadata.value, @post.document.send(attr), attr
|
||||||
else
|
else
|
||||||
assert_equal metadata.value, @post.document.data[attr.to_s]
|
assert_equal metadata.value, @post.document.data[attr.to_s], attr
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -83,7 +83,7 @@ class PostTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
Dir.chdir(@site.path) do
|
Dir.chdir(@site.path) do
|
||||||
collection = Jekyll::Collection.new(@site.jekyll, I18n.locale.to_s)
|
collection = Jekyll::Collection.new(@site.jekyll, I18n.locale.to_s)
|
||||||
document = Jekyll::Document.new(@post.path,
|
document = Jekyll::Document.new(@post.path.value,
|
||||||
site: @site.jekyll,
|
site: @site.jekyll,
|
||||||
collection: collection)
|
collection: collection)
|
||||||
document.read
|
document.read
|
||||||
|
@ -128,4 +128,37 @@ class PostTest < ActiveSupport::TestCase
|
||||||
assert @post.date_changed?
|
assert @post.date_changed?
|
||||||
assert @post.date.valid?
|
assert @post.date.valid?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test 'al cambiar slug o fecha cambia el archivo de ubicacion' do
|
||||||
|
hoy = Date.today.to_time
|
||||||
|
path_was = @post.path.absolute
|
||||||
|
@post.slug.value = 'test'
|
||||||
|
@post.date.value = hoy
|
||||||
|
|
||||||
|
assert @post.path_changed?
|
||||||
|
assert_equal "_es/#{hoy.strftime('%F')}-test.markdown",
|
||||||
|
@post.path.relative
|
||||||
|
|
||||||
|
assert @post.save
|
||||||
|
assert_equal "_es/#{hoy.strftime('%F')}-test.markdown",
|
||||||
|
@post.document.relative_path
|
||||||
|
assert_not File.exist?(path_was)
|
||||||
|
assert File.exist?(@post.path.absolute)
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'no podemos pisar otros archivos' do
|
||||||
|
# Elegir un post al azar que no sea el que usamos
|
||||||
|
# rubocop:disable Lint/Loop
|
||||||
|
begin
|
||||||
|
post = @site.posts.sample
|
||||||
|
end until post != @post
|
||||||
|
# rubocop:enable Lint/Loop
|
||||||
|
|
||||||
|
@post.slug.value = post.slug.value
|
||||||
|
@post.date.value = post.date.value
|
||||||
|
|
||||||
|
assert_not @post.save
|
||||||
|
assert File.exist?(@post.path.absolute)
|
||||||
|
assert File.exist?(@post.path_was)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue