Existe-t-il un moyen de changer le format par défaut des décimales lorsque je les imprime?

irb(main):521:0> pp 10.to_d / 2.5   
0.4e1

Je voudrais le formater comme:

irb(main):521:0> pp 10.to_d / 2.5   
4.0

Je ne me soucie pas vraiment de la perte de précision potentielle. Le format par défaut est particulièrement ennuyeux à lire lorsque vous imprimez de jolis enregistrements Rails:

<
  ...  
  id: 49391,  
  operator_id: 1,  
  tax_rate: 0.10e2,  
  sales_price: 0.1e2,  
  unit_price: 0.2e1,  
  >

Je sais que je peux faire to_s ou to_f, etc., mais le but de la jolie impression est que je n'ai pas à convertir mes enregistrements avant de pouvoir les jeter un coup d'œil rapide.

1
Zyphrax 20 avril 2017 à 00:59

3 réponses

Meilleure réponse

Vous pouvez modifier la méthode utilisée par la jolie imprimante. "Normal" IRb utilise inspect, mais la plupart des bibliothèques de jolies imprimantes ont leurs propres méthodes.

Par exemple, la pp bibliothèque du la bibliothèque standard utilise une méthode appelée pretty_print. BigDecimal n'a pas sa propre implémentation de pretty_print malheureusement, il hérite simplement de celle de Numeric qui délègue simplement à inspect.

Ainsi, nous pouvons écrire le nôtre!

class BigDecimal
  def pretty_print(pp)
    pp.text to_s('F')
  end
end

pp 10.to_d / 2.5
# 4.0
3
Jörg W Mittag 19 avril 2017 à 22:46

Lorsque vous utilisez to_d ou to_f, vous dites à Ruby de convertir la valeur en BigDouble ou Float, mais cela ne spécifie pas le format de sortie, ce qui est un problème différent.

Ruby prend en charge le formatage des chaînes dans quelques saveurs, mais généralement vous définissez un format qui est ensuite utilisé pour "imprimer" la sortie:

foo = 0.4e1
'%1.1f' % foo # => "4.0"

Notez que la sortie est une chaîne, pas un Float ou BigDecimal. Tout est converti en chaîne avant d'être sorti vers la console. Les chaînes de format Ruby suivent les chaînes de format sprintf utilisées par C, Perl et de nombreux autres langages. Voir sprintf pour en savoir plus information.

Et, bien que sprintf existe, je le vois rarement utilisé. Méthode % de String est utilisé plus souvent, suivi de {{X2} du noyau } méthode.

Notez également que 10.to_d / 2.5 n'est pas valide car 10 est un entier, et Integer ne sait pas comment to_d:

10.class # => Integer
10.respond_to?(:to_d) # => false
10.to_d / 2.5    # => NoMethodError: undefined method `to_d' for 10:Integer

Exiger BigDecimal est nécessaire pour obtenir to_d:

require 'bigdecimal'
require 'bigdecimal/util'

10.to_d / 2.5    # => 0.4e1
2
the Tin Man 19 avril 2017 à 22:47

Dans Ruby 2.4, BigDecimal#inspect est équivalent à BigDecimal#to_s qui utilise toujours par défaut la notation scientifique.

decimal = 10.to_d / 2.5
decimal.inspect
# => "0.4e1"

# equivalent to
decimal.to_s
# => "0.4e1"

Heureusement, la classe accepte un argument de sa méthode to_s qui vous permet de spécifier le format de la chaîne résultante. Entre autres options, vous pouvez spécifier si vous voulez la notation scientifique ou la notation conventionnelle à virgule flottante. Ainsi, en l'utilisant comme suit, vous pouvez obtenir le résultat souhaité:

decimal.to_s("F")
# => "4.0"

La documentation de BigDecimal # to_s explique en détail comment vous pouvez définir d'autres options de formatage.

Malheureusement pour votre cas d'utilisation apparent, il n'y a aucun moyen dans Ruby de changer le format par défaut. Pour obtenir la notation en virgule flottante, vous devez toujours ajouter explicitement l'argument "F" à la méthode to_s.

1
Holger Just 19 avril 2017 à 22:36