ByteConverter (ruby)

mikka 12.06.04 18:51

Luokka muuttaa tavut luettavaan muotoon, käytännöllinen esim. tiedostolistauksissa. Testattu ruby 1.8.1.

 Tekstiversio  Arvo: 0 (0 ääntä)  Äänestä: +  -
# Tiedosto: byteconverter.rb
# --------------------------

# Muuntaa annetun numeron (tavuja) pienimpään mahdolliseen
# liukulukuun joka on kuitenkin suurempi kuin yksi. Palauttaa
# muunnetun liukuluvun xB päätteellä, missä x on laskettu etuliite.
#
# Vaihtoehtoinen käyttötapa on antaa tavumäärän lisäksi haluttu
# lyhennös jonka mukaan annettu tavumäärä muunnetaan. Tämä
# käyttötapa palauttaa ainoastaan muunnetun liukuluvun.
#
#--
# Name    Abbr  Factor
# ------------------------
# kilo    K     2^10 = 1024
# mega    M     2^20 = 1 048 576
# giga    G     2^30 = 1 073 741 824
# tera    T     2^40 = 1 099 511 627 776
# peta    P     2^50 = 1 125 899 906 842 624
# exa     E     2^60 = 1 152 921 504 606 846 976
# zetta   Z     2^70 = 1 180 591 620 717 411 303 424
# yotta   Y     2^80 = 1 208 925 819 614 629 174 706 176
#++


class ByteConverter

    attr_reader :decimalCount

    # Konstruktori määrittelee muunnostaulukon sekä
    # oletusdesimaalimäärän.
    def initialize()
        @conversionArray = %w{ K M G T P E Z Y }
        @conversionArray.freeze

        @decimalCount = 0
        @precisionHelper = 0
        self.decimalCount = 2
    end

    # Sijoitusoperaattori, pitää yllä apumuuttujaa muunnoslaskujen
    # pyöristystä varten.
    def decimalCount=(newDecimalCount)
        @decimalCount = newDecimalCount
        @decimalCount = 0 if @decimalCount < 0
        @precisionHelper = (10**@decimalCount).to_f
    end

    # Ohjaa kutsun oikealle metodille, riippuen siitä onko
    # toinen atribuutti 'p_abbr' annettu.
    def convert(p_bytes, p_abbr = nil)
        if p_abbr
            convertToDefined(p_bytes, p_abbr)
        else
            convertToUndefined(p_bytes)
        end
    end

  private

    # Muuntaa annetun 'p_bytes' määrättyyn etuliitteeseen 'p_abbr'.
    def convertToDefined(p_bytes, p_abbr)
        return nil unless @conversionArray.include?(p_abbr)

        divider = 2**((@conversionArray.index(p_abbr)+1)*10)
        if @decimalCount == 0
            (p_bytes.to_f / divider).round
        else
            ( @precisionHelper * (p_bytes.to_f / divider) ).round / @precisionHelper
        end
    end

    # Muuntaa annetun 'p_bytes' sopivimpaan etuliitteeseen.
    def convertToUndefined(p_bytes)
        i=0
        bytes = p_bytes.to_f
        return "#{bytes.to_i} B" if bytes < 1024

        while (bytes = bytes / 1024) >= 1024
            i = i.next
        end

        if @decimalCount == 0
            bytes.round.to_s + " #{@conversionArray.at(i)}B"
        else
            ( (@precisionHelper * bytes).round / @precisionHelper ).to_s + " #{@conversionArray.at(i)}B"
        end
    end

end



------------------------------------------------------------------------------

# Tiedosto: test.rb
# -----------------

#! /usr/local/bin/ruby -w

# Esittelee ByteConverter-luokan käyttöä

require "byteconverter.rb"

def showFiles
    Dir.foreach(".") do |fname|
        if FileTest.file?(fname)
            yield fname
        end
    end
end

bc = ByteConverter.new

puts "-"*79
puts "Tiedostojen koot 'human-readable', oletusdesimaalit (2)"
puts "-"*79
showFiles { |fname| puts "#{fname}\t#{bc.convert(FileTest.size(fname))}" }

puts "-"*79
puts "Tiedostojen koot 'human-readable', pyöristettyinä"
puts "-"*79
bc.decimalCount = 0
showFiles { |fname| puts "#{fname}\t#{bc.convert(FileTest.size(fname))}" }

puts "-"*79
puts "Tiedostojen koot megatavuina, neljällä desimaalilla"
puts "-"*79
bc.decimalCount = 4
showFiles { |fname| puts "#{fname}\t#{bc.convert(FileTest.size(fname), 'M')} MB" }


rubisti 05:15 3.7.06 
Faktoista:

Kilon etuliite on pieni "k", esim. kB. Toisaalta kakkosen potensseja käyttävät etuliitteet on tarkemmin sanottuna kibi, mebi, gibi jne (kiB, MiB, GiB), mutta itse suosin perinteisiä väärinkäytettyjä SI-etuliitteitä :)

Tyylistä:

Aika huvittava tuo "i = i.next", pelkkä "i += 1" olisi paljon selkeämpi. Myöskin hienosteleva "@conversionArray.at(i)" sotii luettavuutta vastaan, normaali "@conversionArray[ i ]" olisi parempi.

Optimoinnista:

Tuo conversionArray voisi olla luokkamuuttuja, @@conversionArray. Numeron käyttämä bittimäärä saadaan kaavalla
(Math.log(x)/Math.log(2)).ceil
jolloin ei tarvitse iteroida 1024:llä jakamista.