Fanclub
et fan_club
sont mélangés dans le code ... Je pense que c'est courant. J'aimerais l'unifier à ceux qui disent que c'est celui de l'équipe, mais je n'ai pas assez de mémoire dans ma tête pour me souvenir de telles règles ... C'est aussi une bonne idée de faire remarquer les gens, et j'aimerais laisser cela à un ordinateur qui le souligne patiemment à plusieurs reprises.
J'ai donc créé un custom_cop pour Rubocop.
Au fait, même si vous n'utilisez pas un travail aussi gênant, grep au diff avec la branche master semble être plus facile. Mais je voulais écrire custom_cop
. C'est un programme du dimanche, non?
Si vous essayez de définir ce que vous voulez pour autant que vous puissiez comprendre ... Est-ce que c'est comme ça? Les mots clés augmentent plusieurs fois pendant le développement de l'application, je souhaite donc les définir dans un fichier externe.
Répertoriez les mauvais mots et les mots que vous souhaitez corriger dans le fichier YAML, indiquez les mauvais mots et corrigez-les.
Quoi qu'il en soit, ce n'est pas intéressant si cela ne fonctionne pas, donc je ferai de mon mieux pour viser: point_down:.
Faites remarquer si la valeur que vous mettez dans la variable est le mauvais mot fanclub
Préparez du code qui peut être vérifié lors de l'exécution de rubocop. Je pense que le code de l'application que vous utilisez est correct.
target.rb
a = 'fanclub'
custom_cop :cop:
Je l'ai fait presque en copiant. Quoi qu'il en soit, j'espère que vous pourrez vous déplacer comme ça.
lib/custom_cops/spell_inconsistency.rb
# frozen_string_literal: true
module CustomCops
class SpellInconsistency < RuboCop::Cop::Cop
WRONG_KEYWORD = 'fanclub'.freeze
def on_str(node)
add_offense(node, message: "Use 'fan_club' instead of 'fanclub'.") if node.source.include?(WRONG_KEYWORD)
end
end
end
.rubocop.yml :wrench:
Définissez le custom_cop créé pour qu'il puisse être utilisé par rubocop.
yaml:.rubocop.yml
require:
- './lib/custom_cops/spell_inconsistency'
Lorsqu'il est exécuté avec rubocop target.rb
...
En plus de signaler «Je n'utilise pas de variables uniquement pour la définition» ou «Parce que c'est une constante, veuillez la figer» ... «CustomCops / SpellInconsistency: Utilisez« fan_club »au lieu de« fanclub ». !!
Je voudrais l'étendre à celui enregistré dans YAML.
Faites remarquer si la valeur que vous mettez dans la variable est le mauvais mot dans le fichier YAML
spell_inconsistency.yml :wrench:
Ici, enregistrez fanclub
, Fanclub
et FANCLUB
.
À l'avenir, j'aimerais les écrire en deux mots, respectivement fan_club
, FanClub
et FAN_CLUB
.
lib/custom_cops/spell_inconsistency.yml
# Wrong: Correct
fanclub: fan_club
Fanclub: Fanclub
FANCLUB: FAN_CLUB
target.rb
a = 'fanclub'
b = 'Fanclub'
c = 'FANCLUB'
custom_cop :cop:
Le fichier dans lequel le mot est enregistré est lu par YAML.load_file
, et il est vérifié en le tournant par ʻeach`.
lib/custom_cops/spell_inconsistency.rb
# frozen_string_literal: true
require 'yaml'
module CustomCops
class SpellInconsistency < RuboCop::Cop::Cop
MESSAGE_TEMPLATE = "Use '%s' instead of '%s'."
SPELL_INCONSISTENCIES = YAML.load_file(Pathname(__dir__).join('spell_inconsistency.yml'))
def on_str(node)
SPELL_INCONSISTENCIES.each do |wrong_keyword, correct_keyword|
add_offense(node, message: message(wrong_keyword, correct_keyword)) if node.source.include?(wrong_keyword)
end
end
private
def message(wrong_keyword, correct_keyword)
MESSAGE_TEMPLATE % [correct_keyword, wrong_keyword]
end
end
end
Si vous l'exécutez avec rubocop target.rb
, il y a beaucoup de messages supplémentaires, donc si vous spécifiez uniquement votre propre custom_cop comme rubocop --only CustomCops / SpellInconsistency target.rb
et exécutez-le ...
Oh, ça a l'air bien: pouce levé:
Faites de même lorsque vous remplacez des symboles ou des constantes qui ressemblent beaucoup à une chaîne.
target.rb
a = 'Fanclub'
b = :fanclub
c = FANCLUB
custom_cop :cop:
Avant d'écrire, jetez un œil à RuboCop :: AST :: Traversal
.
Immédiatement après avoir vu # walk
On dirait que vous appelez une méthode par ce nom, en regardant le type de nœud que vous avez traversé.
Il semble donc que mon # on_str
ait également été appelé.
lib/rubocop/ast/traversal.rb
def walk(node)
return if node.nil?
send(:"on_#{node.type}", node)
nil
end
J'ai cherché partout dans le fichier et j'ai trouvé const
et sym
qui lui ressemblaient, alors j'ai décidé d'implémenter # on_sym
et on_const
également. La méthode d'inspection est exactement la même, alors définissez-la avec define_method
.
lib/custom_cops/spell_inconsistency.rb
# frozen_string_literal: true
require 'yaml'
module CustomCops
class SpellInconsistency < RuboCop::Cop::Cop
MESSAGE_TEMPLATE = "Use '%s' instead of '%s'."
SPELL_INCONSISTENCIES = YAML.load_file(Pathname(__dir__).join('spell_inconsistency.yml'))
NODE_TYPES = %I[str const sym].freeze
NODE_TYPES.each do |node_type|
define_method "on_#{node_type}" do |node|
SPELL_INCONSISTENCIES.each do |wrong_keyword, correct_keyword|
add_offense(node, message: message(wrong_keyword, correct_keyword)) if node.source.include?(wrong_keyword)
end
end
end
def message(wrong_keyword, correct_keyword)
MESSAGE_TEMPLATE % [correct_keyword, wrong_keyword]
end
end
end
Lorsqu'il est exécuté en tant que rubocop --only CustomCops / SpellInconsistency target.rb
...
Ça a l'air bien: +1:
Maintenant que nous avons des chaînes, des symboles et des constantes, faisons-leur remarquer si nous utilisons le mauvais mot pour le nom de la variable.
target.rb
a = 'Fanclub'
b = :fanclub
c = FANCLUB
fanclub = 'a'
En parlant de variables, variable
serait var
... Donc, [ RuboCop :: AST :: Traversal
](https://github.com/rubocop-hq/rubocop-ast/blob/master/lib J'ai jeté un coup d'œil à /rubocop/ast/traversal.rb), mais ... il n'y en a pas beaucoup, et il y en a beaucoup ...
En regardant Development Basic de la documentation officielle RuboCop, il est dit d'utiliser ruby-parse
sur la ligne de commande. Je comprends.
C'était «lvasgn».
Ajouter à NODE_TYPES
...
lib/custom_cops/spell_inconsistency.rb
(réduction)
module CustomCops
class SpellInconsistency < RuboCop::Cop::Cop
(réduction)
NODE_TYPES = %I[str const sym lvasgn].freeze
NODE_TYPES.each do |node_type|
define_method "on_#{node_type}" do |node|
SPELL_INCONSISTENCIES.each do |wrong_keyword, correct_keyword|
add_offense(node, message: message(wrong_keyword, correct_keyword)) if node.source.include?(wrong_keyword)
end
end
end
(réduction)
end
end
Lorsque vous exécutez rubocop --only CustomCops / SpellInconsistency target.rb
...
fanclub = 'a'
a été détecté ... ʻa =' FanClub` a également été détecté ...
Examinons de plus près le code original et la sortie de ruby-parse.
(lvasgn :fanclub
(str "a"))
L'affectation à une variable est «nom de variable = expression», n'est-ce pas? Je me demande si l'expression correspond à la chaîne de caractères «a».
Si vous le regardez comme ceci, lvasgn
est la valeur de gauche un signe
de l'affectation du côté gauche.
(Puisqu'il y a eu une analyse de syntaxe dans une classe universitaire il y a longtemps, je ne peux pas l'expliquer, mais je ne peux pas l'expliquer à un niveau que je peux comprendre ... je suis désolé.)
(Substitution côté gauche:fanclub
(Chaîne"a"))
La raison pour laquelle j'ai été coincé deux fois avec fanclub = 'a'
était qu'il répondait à" fanclub "ʻof
str et à" "fanclub" "de
str in
lvasgn`. Probablement de.
(lvasgn :a
(str "fanclub"))
Il semble que vous ne devriez le prendre qu'immédiatement après lvasgn
.
Si vous passez en revue Development Basic of RuboCop official documentation, vous trouverez les méthodes qui sont souvent utilisées dans l'argument node
de ʻon_ ~. Était là. Vous devez utiliser
children` et utiliser son premier enfant.
node.type # => :send
node.children # => [s(:send, s(:send, nil, :something), :empty?), :!]
node.source # => "!something.empty?"
custom_cop :cop:
A part str
, const
, sym
, j'ai fait ʻon_lvasgn` pour inspecter le premier enfant.
lib/custom_cops/spell_inconsistency.rb
(réduction)
module CustomCops
class SpellInconsistency < RuboCop::Cop::Cop
(réduction)
NODE_TYPES = %I[str const sym].freeze
NODE_TYPES.each do |node_type|
define_method "on_#{node_type}" do |node|
SPELL_INCONSISTENCIES.each do |wrong_keyword, correct_keyword|
add_offense(node, message: message(wrong_keyword, correct_keyword)) if node.source.include?(wrong_keyword)
end
end
end
def on_lvasgn(node)
target = node.children.first
SPELL_INCONSISTENCIES.each do |wrong_keyword, correct_keyword|
add_offense(node, message: message(wrong_keyword, correct_keyword)) if target.match?(/#{wrong_keyword}/)
end
end
(réduction)
end
end
Lorsqu'il est exécuté en tant que rubocop --only CustomCops / SpellInconsistency target.rb
...
Ça a l'air bien: tada:
Ce que nous avons fait jusqu'à présent, c'est ... vérifier les chaînes, les symboles, les constantes et les noms de variables. Compte tenu de la syntaxe de Ruby ... Il y a des noms de méthodes et des noms de classes juste pour trouver les parties à traiter. Vous remarquerez quelque chose après cela ... Ensuite, il était difficile d'exécuter le code pour l'inspection un par un, alors j'ai voulu écrire un test.
Les fichiers sous «spec / support» sont «obligatoires». Il semble que les personnes qui essaient d'entrer dans l'application plus tard sont souvent déjà configurées.
spec/spec_helper.rb
RSpec.configure do |config|
(réduction)
Dir["#{__dir__}/support/**/*.rb"].sort.each { |f| require f }
end
Je charge le support RSpec pour rubocop et je charge custom_cop que j'ai ajouté.
spec/support/rubocop.rb
# frozen_string_literal: true
require 'rubocop'
require 'rubocop/rspec/support'
Dir["#{__dir__}/../../lib/**/*.rb"].sort.each { |f| require f }
RSpec.configure do |config|
config.include(RuboCop::RSpec::ExpectOffense)
end
Le code écrit dans le code cible de vérification est transcrit dans le test, et la manière dont la sortie lorsque rubocop est exécutée est également décrite.
spec/lib/custom_cops/spell_inconstency_spec.rb
# frozen_string_literal: true
RSpec.describe CustomCops::SpellInconsistency do
subject(:cop) { described_class.new }
it 'Être capable de détecter les erreurs dans les chaînes de caractères' do
expect_offense(<<-RUBY)
fan_club = 'fanclub'
^^^^^^^^^ Use 'fan_club' instead of 'fanclub'.
RUBY
end
it 'Être capable de détecter les erreurs dans les symboles' do
expect_offense(<<-RUBY)
fan_club = :fanclub
^^^^^^^^ Use 'fan_club' instead of 'fanclub'.
RUBY
end
it 'Être capable de détecter des erreurs constantes' do
expect_offense(<<-RUBY)
fan_club = FANCLUB
^^^^^^^ Use 'FAN_CLUB' instead of 'FANCLUB'.
RUBY
end
it 'Être capable de détecter les erreurs dans les noms de variables' do
expect_offense(<<-RUBY)
fanclub = 'fan_club'
^^^^^^^^^^^^^^^^^^^^ Use 'fan_club' instead of 'fanclub'.
RUBY
end
end
Lorsqu'il est exécuté avec rspec spec / lib / custom_cops / spell_inconstency_spec.rb
...
Ça a l'air bien: pouce levé:
J'ai défini les variables, mais je n'ai pas encore défini les constantes, alors je vais le faire.
Code court pour les définitions de constante et de méthode.
target.rb
FANCLUB = 'a'
ruby-parse
Analysez avec ruby-parse
.
La définition constante est «casgn», qui est un format différent de «lvasgn». C'était la seconde.
custom_cop :cop:
J'ai fait une méthode de vérification pour casgn
.
lib/custom_cops/spell_inconsistency.rb
(réduction)
module CustomCops
class SpellInconsistency < RuboCop::Cop::Cop
(réduction)
def on_casgn(node)
target = node.children[1]
SPELL_INCONSISTENCIES.each do |wrong_keyword, correct_keyword|
add_offense(node, message: message(wrong_keyword, correct_keyword)) if target.match?(/#{wrong_keyword}/)
end
end
(réduction)
end
end
Lorsqu'il est exécuté en tant que rubocop --only CustomCops / SpellInconsistency target.rb
...
Ça a l'air bien: pouce levé:
Ajoutez-le au test pour que vous remarquiez s'il casse.
spec/lib/custom_cops/spell_inconstency_spec.rb
# frozen_string_literal: true
RSpec.describe CustomCops::SpellInconsistency do
subject(:cop) { described_class.new }
(réduction)
it 'Être capable de détecter les erreurs dans les noms constants' do
expect_offense(<<-RUBY)
FANCLUB = 'fan_club'
^^^^^^^^^^^^^^^^^^^^ Use 'FAN_CLUB' instead of 'FANCLUB'.
RUBY
end
end
À ce stade, j'ai en quelque sorte compris la procédure.
Répétez cette opération pour améliorer la précision de détection.
Nous lui donnerons un nom lors de la définition de la méthode, alors jetons un œil. Comme il y a de nombreux éléments dans une ligne et qu'il existe de nombreux types d'éléments, nous les découperons en petits morceaux.
Considérant un petit morceau de code, il ressemble à def set_fanclub; hoge; end
.
En regardant ruby-parse ...
Le premier «enfant» de «def» est comme ça. Il est similaire au lvasgn
utilisé lors de l'assignation à une variable.
Comme pour str
et const
, utilisez define_method
dans une boucle pour les regrouper.
lib/custom_cops/spell_inconsistency.rb
(réduction)
module CustomCops
class SpellInconsistency < RuboCop::Cop::Cop
(réduction)
NODE_TYPES_ONE = %I[str const sym].freeze
NODE_TYPES_FIRST_CHILD = %I[lvasgn def].freeze
NODE_TYPES_ONE.each do |node_type|
define_method "on_#{node_type}" do |node|
SPELL_INCONSISTENCIES.each do |wrong_keyword, correct_keyword|
add_offense(node, message: message(wrong_keyword, correct_keyword)) if node.source.include?(wrong_keyword)
end
end
end
NODE_TYPES_FIRST_CHILD.each do |node_type|
define_method "on_#{node_type}" do |node|
target = node.children.first
SPELL_INCONSISTENCIES.each do |wrong_keyword, correct_keyword|
add_offense(node, message: message(wrong_keyword, correct_keyword)) if target.match?(/#{wrong_keyword}/)
end
end
end
(réduction)
end
end
L'argument est ʻarg, qui a la même forme que
lvasgn`, nous allons donc le résumer.
lib/custom_cops/spell_inconsistency.rb
(réduction)
module CustomCops
class SpellInconsistency < RuboCop::Cop::Cop
(réduction)
NODE_TYPES_FIRST_CHILD = %I[lvasgn def arg].freeze
(réduction)
end
end
Vous pouvez donner des valeurs par défaut aux arguments, mais comme ils étaient les mêmes que «str», «sym» et «const», respectivement, n'ajoutez rien.
L'argument mot-clé est kwarg
, qui a la même forme que lvasgn
, nous allons donc le résumer.
lib/custom_cops/spell_inconsistency.rb
(réduction)
module CustomCops
class SpellInconsistency < RuboCop::Cop::Cop
(réduction)
NODE_TYPES_FIRST_CHILD = %I[lvasgn def arg kwarg].freeze
(réduction)
end
end
Lorsque la valeur par défaut est donnée à l'argument mot-clé, le nom de l'argument est kwoptarg
, qui est de la même forme que lvasgn
, nous allons donc le résumer.
lib/custom_cops/spell_inconsistency.rb
(réduction)
module CustomCops
class SpellInconsistency < RuboCop::Cop::Cop
(réduction)
NODE_TYPES_FIRST_CHILD = %I[lvasgn def arg kwarg kwoptarg].freeze
(réduction)
end
end
Je me suis souvenu avoir fait l'argument mot-clé de la définition de méthode. Il était soutenu par le même symbole.
Le nom de la classe et le nom du module étaient «const».
Je suis arrivé jusqu'ici ... J'ai l'impression qu'il y a encore beaucoup d'omissions. Cependant, depuis que j'écris un test, je sens que je peux le faire évoluer progressivement en fonction de ce que j'ai remarqué.
Mais ... c'était super facile à faire, mais c'était incroyablement difficile. Pas question, je vais mordre l'analyse syntaxique ... Cependant, je me suis lié d'amitié avec Rubocop. De plus, si vous souhaitez créer une règle dont vous ne vous souvenez pas avec votre code de travail, je vais l'essayer.
Recommended Posts