From f7527e7ee3e285ba84b467370bce07210213abad Mon Sep 17 00:00:00 2001 From: f Date: Thu, 8 Aug 2019 15:28:23 -0300 Subject: [PATCH] renombrar archivos --- .rubocop.yml | 2 + .../core_extensions/jekyll/document/path.rb | 22 +++++++ app/models/metadata_date.rb | 3 + app/models/metadata_document_date.rb | 2 + app/models/metadata_path.rb | 35 +++++++++++ app/models/metadata_slug.rb | 2 + app/models/metadata_template.rb | 2 +- app/models/post.rb | 61 +++++++++++-------- config/initializers/core_extensions.rb | 3 + test/models/post_test.rb | 49 ++++++++++++--- 10 files changed, 146 insertions(+), 35 deletions(-) create mode 100644 app/lib/core_extensions/jekyll/document/path.rb create mode 100644 app/models/metadata_date.rb create mode 100644 app/models/metadata_path.rb diff --git a/.rubocop.yml b/.rubocop.yml index fad6db4..5e07d37 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -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: diff --git a/app/lib/core_extensions/jekyll/document/path.rb b/app/lib/core_extensions/jekyll/document/path.rb new file mode 100644 index 0000000..fb90d5f --- /dev/null +++ b/app/lib/core_extensions/jekyll/document/path.rb @@ -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 diff --git a/app/models/metadata_date.rb b/app/models/metadata_date.rb new file mode 100644 index 0000000..2c4741f --- /dev/null +++ b/app/models/metadata_date.rb @@ -0,0 +1,3 @@ +class MetadataDate < MetadataTemplate + +end diff --git a/app/models/metadata_document_date.rb b/app/models/metadata_document_date.rb index 425e893..3d98885 100644 --- a/app/models/metadata_document_date.rb +++ b/app/models/metadata_document_date.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Maneja la fecha del document class MetadataDocumentDate < MetadataTemplate # La fecha por defecto es ahora! diff --git a/app/models/metadata_path.rb b/app/models/metadata_path.rb new file mode 100644 index 0000000..ec0467e --- /dev/null +++ b/app/models/metadata_path.rb @@ -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 diff --git a/app/models/metadata_slug.rb b/app/models/metadata_slug.rb index 905ba0c..19206fc 100644 --- a/app/models/metadata_slug.rb +++ b/app/models/metadata_slug.rb @@ -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 diff --git a/app/models/metadata_template.rb b/app/models/metadata_template.rb index 96bc7b5..2a48983 100644 --- a/app/models/metadata_template.rb +++ b/app/models/metadata_template.rb @@ -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 diff --git a/app/models/post.rb b/app/models/post.rb index 59580d2..af88d37 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -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 diff --git a/config/initializers/core_extensions.rb b/config/initializers/core_extensions.rb index 2207fe8..95cf957 100644 --- a/config/initializers/core_extensions.rb +++ b/config/initializers/core_extensions.rb @@ -1,3 +1,6 @@ # frozen_string_literal: true +require 'jekyll/document' + String.include CoreExtensions::String::StripTags +Jekyll::Document.include CoreExtensions::Jekyll::Document::Path diff --git a/test/models/post_test.rb b/test/models/post_test.rb index 4d0cb65..10429e1 100644 --- a/test/models/post_test.rb +++ b/test/models/post_test.rb @@ -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,37 @@ 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 + # 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