From 7d13e986896a0cd8c7c6945015c7958c4ac419be Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Sat, 17 Mar 2007 11:05:40 +0100 Subject: [PATCH] Start scripting the volume creation --- crea_numero.rb | 77 +++++++++++++++++++ roman_numerals.rb | 187 ++++++++++++++++++++++++++++++++++++++++++++++ test/indice | 6 ++ 3 files changed, 270 insertions(+) create mode 100755 crea_numero.rb create mode 100644 roman_numerals.rb create mode 100644 test/indice diff --git a/crea_numero.rb b/crea_numero.rb new file mode 100755 index 0000000..dbe8cee --- /dev/null +++ b/crea_numero.rb @@ -0,0 +1,77 @@ +#!/usr/bin/ruby +# +# Le Matematiche +# +# Crea un numero per la rivista Le Matematiche, usando le informazioni contenute in una specifica cartella +# +# Author: Giuseppe Bilotta +# +# Created: 20070317 +# +# Last Modified: 20070317 +# +# Copyright: (C) 2007 Giuseppe Bilotta +# + +require 'yaml' +require 'roman_numerals' + +def uso + puts "#{$0} " + puts "\tcrea un numero per la rivista Le Matematiche, usando le informazioni contenute nella cartella" +end + +def errore(msg) + $stderr.puts "ERRORE: %s" % msg + exit 2 +end + +cartella = ARGV[0] + +if !cartella or cartella.empty? + uso + exit 1 +end + +begin + Dir.chdir(cartella) +rescue + errore "Impossibile accedere alla cartella \"#{cartella}\"" +end + +indice = './indice' + +if not File.exists?(indice) + errore "La cartella \"%s\" non contiene il file di indice!" % cartella +end + +begin + info = YAML.load(File.read(indice)) +rescue + errore "Impossibile leggere il file di indice in \"%s\"" % cartella +end + +if info.has_key?(:anno) + anno = info[:anno].to_i +else + errore "Il file di indice in \"%s\" non specifica l'anno!" % cartella +end +if info.has_key?(:volume) + vol = info[:volume].to_i + vol_rm = vol.to_s_roman +else + errore "Il file di indice in \"%s\" non specifica il volume!" % cartella +end +if info.has_key?(:numero) + num = info[:numero].to_i + num_rm = num.to_s_roman +else + errore "Il file di indice in \"%s\" non specifica il numero!" % cartella +end +if info.has_key?(:articoli) + articoli = info[:articoli] +else + errore "Il file di indice in \"%s\" non specifica alcun articolo!" % cartella +end + +puts "Preparazione: Le Matematiche, volume #{vol_rm}, numero #{num_rm}, anno #{anno}" diff --git a/roman_numerals.rb b/roman_numerals.rb new file mode 100644 index 0000000..43d1409 --- /dev/null +++ b/roman_numerals.rb @@ -0,0 +1,187 @@ +#!/usr/bin/ruby +# +# Roman numerals +# +# Generates roman numerals from integers and vice-versa +# +# A response to Ruby Quiz of the Week #22 - Roman Numerals [ruby-talk:132925] +# +# Author: Dave Burt +# +# Created: 7 Mar 2005 +# +# Last modified: 8 Mar 2005 +# +# Fine print: Provided as is. Use at your own risk. Unauthorized copying is +# not disallowed. Credit's appreciated if you use my code. I'd +# appreciate seeing any modifications you make to it. +# + +# Contains methods to convert integers to roman numeral strings and vice-versa. +module RomanNumerals + + # Maps roman numeral digits to their integer values + DIGITS = { + 'I' => 1, + 'V' => 5, + 'X' => 10, + 'L' => 50, + 'C' => 100, + 'D' => 500, + 'M' => 1000, + } + + # The largest integer representable as a roman numerable by this module + MAX = 3999 + + # Maps some integers to their roman numeral values + @@digits_lookup = DIGITS.inject({ + 4 => 'IV', + 9 => 'IX', + 40 => 'XL', + 90 => 'XC', + 400 => 'CD', + 900 => 'CM',}) do |memo, pair| + memo.update({pair.last => pair.first}) + end + + # Stolen from O'Reilly's Perl Cookbook 6.23. Regular Expression Grabbag + REGEXP = /^M*(D?C{0,3}|C[DM])(L?X{0,3}|X[LC])(V?I{0,3}|I[VX])$/i + + # Converts +int+ to a roman numeral + def self.from_integer(int) + return nil if int < 0 || int > MAX + remainder = int + result = '' + @@digits_lookup.keys.sort.reverse.each do |digit_value| + while remainder >= digit_value + remainder -= digit_value + result += @@digits_lookup[digit_value] + end + break if remainder <= 0 + end + result + end + + # Converts +roman_string+, a roman numeral, to an integer + def self.to_integer(roman_string) + return nil unless roman_string.is_roman_numeral? + last = nil + roman_string.to_s.upcase.split(//).reverse.inject(0) do |memo, digit| + if digit_value = DIGITS[digit] + if last && last > digit_value + memo -= digit_value + else + memo += digit_value + end + last = digit_value + end + memo + end + end + + # Returns true iif +string+ is a roman numeral. + def self.is_roman_numeral?(string) + REGEXP =~ string + end +end + +class String + # Considers string a roman numeral numeral, + # and converts it to the corresponding integer. + def to_i_roman + RomanNumerals.to_integer(self) + end + # Returns true iif the subject is a roman numeral. + def is_roman_numeral? + RomanNumerals.is_roman_numeral?(self) + end +end +class Integer + # Converts this integer to a roman numeral. + def to_s_roman + RomanNumerals.from_integer(self) || '' + end +end + + +# Integers that look like roman numerals +class RomanNumeral + attr_reader :to_s, :to_i + + @@all_roman_numerals = [] + + # May be initialized with either a string or an integer + def initialize(value) + case value + when Integer + @to_s = value.to_s_roman + @to_i = value + else + @to_s = value.to_s + @to_i = value.to_s.to_i_roman + end + @@all_roman_numerals[to_i] = self + end + + # Factory method: returns an equivalent existing object if such exists, + # or a new one + def self.get(value) + if value.is_a?(Integer) + to_i = value + else + to_i = value.to_s.to_i_roman + end + @@all_roman_numerals[to_i] || RomanNumeral.new(to_i) + end + + def inspect + to_s + end + + # Delegates missing methods to Integer, converting arguments to Integer, + # and converting results back to RomanNumeral + def method_missing(sym, *args) + unless to_i.respond_to?(sym) + raise NoMethodError.new( + "undefined method '#{sym}' for #{self}:#{self.class}") + end + result = to_i.send(sym, + *args.map {|arg| arg.is_a?(RomanNumeral) ? arg.to_i : arg }) + case result + when Integer + RomanNumeral.get(result) + when Enumerable + result.map do |element| + element.is_a?(Integer) ? RomanNumeral.get(element) : element + end + else + result + end + end +end + +# Enables uppercase roman numerals to be used interchangeably with integers. +# They are auto-vivified RomanNumeral constants +# Synopsis: +# 4 + IV #=> VIII +# VIII + 7 #=> XV +# III ** III #=> XXVII +# VIII.divmod(III) #=> [II, II] +def Object.const_missing sym + raise NameError.new("uninitialized constant: #{sym}") unless RomanNumerals::REGEXP === sym.to_s + const_set(sym, RomanNumeral.get(sym)) +end + + +# Quiz solution: filter that swaps roman and arabic numbers +if __FILE__ == $0 + ARGF.each do |line| + line.chomp! + if line.is_roman_numeral? + puts line.to_i_roman + else + puts line.to_i.to_s_roman + end + end +end diff --git a/test/indice b/test/indice new file mode 100644 index 0000000..e95c292 --- /dev/null +++ b/test/indice @@ -0,0 +1,6 @@ +:anno: 2007 +:volume: 121 +:numero: 1 + +:articoli: + - lematest -- 2.32.0.93.g670b81a890