renombrar archivos
This commit is contained in:
parent
ada14b2294
commit
67a99bce1b
10 changed files with 145 additions and 35 deletions
|
@ -33,6 +33,7 @@ Metrics/MethodLength:
|
|||
- 'app/controllers/i18n_controller.rb'
|
||||
- 'app/controllers/collaborations_controller.rb'
|
||||
- 'app/controllers/usuaries_controller.rb'
|
||||
- 'app/models/post.rb'
|
||||
|
||||
Metrics/BlockLength:
|
||||
Exclude:
|
||||
|
@ -47,6 +48,7 @@ Metrics/ClassLength:
|
|||
- 'app/models/site.rb'
|
||||
- 'app/controllers/posts_controller.rb'
|
||||
- 'app/controllers/sites_controller.rb'
|
||||
- 'test/models/post_test.rb'
|
||||
|
||||
Lint/HandleExceptions:
|
||||
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
|
||||
class MetadataDocumentDate < MetadataTemplate
|
||||
# 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'
|
||||
|
||||
# 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
|
||||
MetadataTemplate = Struct.new(:site, :document, :name, :label, :type,
|
||||
:value, :help, :required, :errors,
|
||||
:value, :help, :required, :errors, :post,
|
||||
:layout, keyword_init: true) do
|
||||
# El valor por defecto
|
||||
def default_value
|
||||
|
|
|
@ -13,7 +13,7 @@ class Post < OpenStruct
|
|||
# XXX: Volver document opcional cuando estemos creando
|
||||
DEFAULT_ATTRIBUTES = %i[site document layout].freeze
|
||||
# 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
|
||||
#
|
||||
|
@ -22,7 +22,6 @@ class Post < OpenStruct
|
|||
# @param layout: [Layout] la plantilla
|
||||
#
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
def initialize(**args)
|
||||
default_attributes_missing(args)
|
||||
super(args)
|
||||
|
@ -45,6 +44,7 @@ class Post < OpenStruct
|
|||
layout.metadata.each_pair do |name, template|
|
||||
send "#{name}=".to_sym,
|
||||
MetadataFactory.build(document: document,
|
||||
post: self,
|
||||
site: site,
|
||||
name: name,
|
||||
layout: layout,
|
||||
|
@ -56,12 +56,12 @@ class Post < OpenStruct
|
|||
|
||||
load_slug!
|
||||
load_date!
|
||||
load_path!
|
||||
|
||||
# Leer el documento
|
||||
read
|
||||
end
|
||||
# rubocop:enable Metrics/AbcSize
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
|
||||
# Levanta un error si al construir el artículo no pasamos un atributo.
|
||||
def default_attributes_missing(**args)
|
||||
|
@ -127,13 +127,13 @@ class Post < OpenStruct
|
|||
#
|
||||
# XXX Commit
|
||||
def destroy
|
||||
FileUtils.rm_f path
|
||||
FileUtils.rm_f path.absolute
|
||||
|
||||
site.posts(lang: lang).delete_if do |post|
|
||||
post.path == path
|
||||
post.path.absolute == path.absolute
|
||||
end
|
||||
|
||||
!File.exist?(path) && !site.posts(lang: lang).include?(self)
|
||||
!File.exist?(path.absolute) && !site.posts(lang: lang).include?(self)
|
||||
end
|
||||
alias destroy! destroy
|
||||
# rubocop:enable Metrics/AbcSize
|
||||
|
@ -141,10 +141,12 @@ class Post < OpenStruct
|
|||
# Guarda los cambios
|
||||
def save
|
||||
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
|
||||
|
||||
# Vuelve a leer el post para tomar los cambios
|
||||
document.read
|
||||
read
|
||||
|
||||
true
|
||||
end
|
||||
|
@ -152,20 +154,15 @@ class Post < OpenStruct
|
|||
|
||||
# Lee el documento
|
||||
def read
|
||||
Dir.chdir(site.path) do
|
||||
document.read
|
||||
end
|
||||
document.read
|
||||
end
|
||||
|
||||
# Devuelve la ruta del post, si se cambió alguno de los datos,
|
||||
# generamos una ruta nueva para tener siempre la ruta actualizada.
|
||||
def path
|
||||
document.path
|
||||
end
|
||||
alias relative_path path
|
||||
|
||||
def absolute_path
|
||||
File.join site.path, path
|
||||
# Actualizar la ubicación del archivo si cambió de lugar y si no
|
||||
# existe el destino
|
||||
def update_path!
|
||||
!File.exist?(path.absolute) &&
|
||||
FileUtils.mv(path_was, path.absolute) &&
|
||||
document.path = path.absolute
|
||||
end
|
||||
|
||||
# Detecta si el artículo es válido para guardar
|
||||
|
@ -224,7 +221,7 @@ class Post < OpenStruct
|
|||
def write
|
||||
return true if persisted?
|
||||
|
||||
Site::Writer.new(site: site, file: path,
|
||||
Site::Writer.new(site: site, file: path.absolute,
|
||||
content: full_content, usuarie: usuarie,
|
||||
message: title.value).save
|
||||
end
|
||||
|
@ -241,25 +238,27 @@ class Post < OpenStruct
|
|||
|
||||
# Verifica si hace falta escribir cambios
|
||||
def persisted?
|
||||
File.exist?(absolute_path) && full_content == File.read(absolute_path)
|
||||
File.exist?(path.absolute) && full_content == File.read(path.absolute)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
def new_attribute_was(method)
|
||||
attr_was = (attribute_name(method).to_s + '_was').to_sym
|
||||
return attr_was if singleton_class.method_defined? attr_was
|
||||
|
||||
define_singleton_method(attr_was) do
|
||||
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
|
||||
|
||||
attr_was
|
||||
end
|
||||
|
||||
# Pregunta si el atributo cambió
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
def new_attribute_changed(method)
|
||||
attr_changed = (attribute_name(method).to_s + '_changed?').to_sym
|
||||
|
||||
|
@ -284,15 +283,25 @@ class Post < OpenStruct
|
|||
|
||||
def load_slug!
|
||||
self.slug = MetadataSlug.new(document: document, site: site,
|
||||
layout: layout, name: :slug,
|
||||
layout: layout, name: :slug, type: :slug,
|
||||
post: self,
|
||||
required: true)
|
||||
end
|
||||
|
||||
def load_date!
|
||||
self.date = MetadataDocumentDate.new(document: document, site: site,
|
||||
layout: layout, name: :date,
|
||||
type: :document_date,
|
||||
post: self,
|
||||
required: true)
|
||||
end
|
||||
|
||||
def load_path!
|
||||
self.path = MetadataPath.new(document: document, site: site,
|
||||
layout: layout, name: :path,
|
||||
type: :path, post: self,
|
||||
required: true)
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/ClassLength
|
||||
# rubocop:enable Style/MethodMissingSuper
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'jekyll/document'
|
||||
|
||||
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
|
||||
# TODO: cuando esté con git, solo aplicar git reset
|
||||
tmp = File.join(Rails.root, 'tmp', 'eliminar.md')
|
||||
FileUtils.cp @post.path, tmp
|
||||
FileUtils.cp @post.path.absolute, tmp
|
||||
|
||||
assert @post.destroy
|
||||
assert_not File.exist?(@post.path)
|
||||
assert_not File.exist?(@post.path.absolute)
|
||||
assert_not @site.posts.include?(@post)
|
||||
|
||||
FileUtils.mv tmp, @post.path
|
||||
FileUtils.mv tmp, @post.path.absolute
|
||||
end
|
||||
|
||||
test 'se puede ver el contenido completo después de guardar' do
|
||||
assert @post.save
|
||||
@post.document.read
|
||||
@post.read
|
||||
|
||||
# Queremos saber si todos los atributos del post terminaron en el
|
||||
# archivo
|
||||
|
@ -56,10 +56,10 @@ class PostTest < ActiveSupport::TestCase
|
|||
|
||||
if metadata.empty?
|
||||
assert_not @post.document.data[attr.to_s].present?
|
||||
elsif attr == :date
|
||||
assert_equal metadata.value, @post.document.date
|
||||
elsif @post.document.respond_to? attr
|
||||
assert_equal metadata.value, @post.document.send(attr), attr
|
||||
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
|
||||
|
@ -83,7 +83,7 @@ class PostTest < ActiveSupport::TestCase
|
|||
|
||||
Dir.chdir(@site.path) do
|
||||
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,
|
||||
collection: collection)
|
||||
document.read
|
||||
|
@ -128,4 +128,36 @@ class PostTest < ActiveSupport::TestCase
|
|||
assert @post.date_changed?
|
||||
assert @post.date.valid?
|
||||
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
|
||||
loop do
|
||||
post = @site.posts.sample
|
||||
break if post != @post
|
||||
end
|
||||
|
||||
@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
|
||||
|
|
Loading…
Reference in a new issue