Welcome, guest! Login / Register - Why register?
Psst.. new poll here.
Psst.. new forums here.
Microsoft is blocking us again (TY IP Reputation!) so just use oauth login instead. :)

Paste

Pasted as Ruby by Anonymous ( 16 years ago )
require 'rubygems'
gem 'facets'
require 'facets'
require 'fileutils'
include FileUtils

files = Hash.new { |hash, filename| hash[filename] = "" }
File.read(__FILE__).newlines.inject(nil) do |filename, line|
  if line =~ /^# ---- File\: .*? ----$/ then filename = line[/^# ---- File\: (.*?) ----$/, 1]
  else files[filename] << "#{line}\n"; end
  filename
end
files.each do |filename, content|
  next if filename.nil?
  mkdir_p File.dirname(filename)
  File.open(filename, "w") { |io| io.print content }
end
exit

# ---- File: comments.txt ----

<<TEXT
Ну что, динамические петушки успешно соснули. Даже с такой проверкой типов, как
сейчас, по эксепшенам хуй проссышь, где конкретно упало. Тесты приходится
проходить по полчаса. Представляю, что было бы, если б я вообще типы не
проверял. И даже думать страшно, что было бы, если бы рубиновый stdlib не
содержал бы в себе проверок типов или (что то же самое) был бы
слаботипизированным. Смотрите "TODO" c пометкой "[!]".

Вывод: Ruby для энтерпрайза если и подходит, то только обвешенный тоннами
статикоблядства.
TEXT

# ---- File: issues.rb ----
require 'yaml'

YAML.load <<YAML
# По умолчанию тип равен "Задача".
- 
  Приоритет: -1
  Описание: |
    Выполнить все задачи, помеченные в исходнике меткой "XXX".
- 
  Приоритет: 0
  Название: |
    Выполнить все задачи, помеченные в исходнике меткой "TODO".
- 
  Приоритет: 0
  Тип: Улучшение
  Описание: |
    Может, сделать автоматический перевод валют в бинарных операциях?
YAML

# ---- File: lib/deps.rb ----
# Dependencies of the application are described here.
require 'rubygems'
gem 'facets'


# ---- File: lib/every.rb ----
# This file contains what every module requires.
require 'deps'
require 'mathn'


# ---- File: lib/currency.rb ----
require 'every'
require 'facets'
require 'facets/equitable'
require 'csv'


class Currency
  
  # XXX: Check for duplicate entries in currencies collection.
  
  # TODO: Redesign. "to_sign" really disturbs!
  
  @@currencies = []
  
  # +sign+ - value for #sign.
  # 
  # +to_sign+ - value for #to_sign.
  # 
  # +rates+ - Hash of +to_sign+ to coefficient. Example for euro:
  #   { "toDollar" => 0.75 }
  # 
  def initialize(sign, to_sign, rates)
    #
    @sign = sign
    @to_sign = to_sign
    @rates = rates
    #
    @@currencies << self
  end
  
  # Sign denoting this Currency. For example, "$" or "eur"
  attr_reader :sign
  
  # Name of function used to convert from other Currency to this one.
  # For example, "toDollar", "toEuro".
  attr_reader :to_sign
  
  # Coefficient of conversion from this Currency to Currency denoted by
  # specified +to_sign+.
  def rate(currency_or_currency_to_sign)
    to_sign =
        case currency = to_sign = currency_or_currency_to_sign
        when String then to_sign
        when Currency then currency.to_sign
        else raise TypeError, currency_or_currency_to_sign.inspect
        end
    return 1 if to_sign == self.to_sign
    @rates[to_sign] or raise RateNotDefined.new(self, Currency.with_to_sign(to_sign))
  end
  
  # TODO: [!] Type check. Everywhere. And with standard style for overloaded
  #   methods.
  
  def ==(other)
    raise TypeError, other.inspect unless other.is_a? Currency
    return self.sign == other.sign
  end
  
  def to_s
    "#{sign}"
  end
  
  # Returns Currency with specified #sign.
  def self.with_sign(sign)
    @@currencies.find { |c| c.sign == sign } or raise(NoSuchCurrency.new(:sign, sign))
  end
  
  def self.by_sign(sign); with_sign(sign); end
  def self.[](sign); with_sign(sign); end
  
  # Returns Currency with specified #to_sign.
  def self.with_to_sign(to_sign)
    @@currencies.find { |c| c.to_sign == to_sign } or raise(NoSuchCurrency.new(:to_sign, to_sign))
  end
  
  def self.by_to_sign(to_sign); with_to_sign(to_sign); end
  
  def self.load(currencies_description)
    # 
    @@currencies.clear
    # Parse the description!
    begin
      # Normalize the description.
      currencies_description = currencies_description.gsub(" ", "")
      # Parse as CSV.
      currencies_description =
          begin
            CSV.parse(currencies_description)
          rescue CSV::IllegalFormatError => e
            raise CurrenciesDescriptionSyntaxError.new("???", e.message)
          end
      # Check if the table is formed well.
      raise CurrenciesDescriptionSyntaxError.new(0, "Currencies description must not be empty") if currencies_description.empty?
      # 
      to_signs = currencies_description[0][1..-1]
      # Parse currencies.
      currencies_description[1..-1].map_with_index do |currency_row, row_no|
        line_no = row_no + 1
        Currency.new(
          #
          sign = currency_row[0],
          #
          current_currency_to_sign = to_signs[row_no],
          # Parse rates.
          # XXX: This may be done simpler.
          to_signs.zip(currency_row[1..-1]).
            # Reject not specified rates.
            reject { |to_sign, rate_str| rate_str == nil or rate_str.blank? or rate_str == "-" }.
            # Parse the rates!
            map do |to_sign, rate_str|
              rate = rate_str.to_f
              raise CurrenciesDescriptionSyntaxError.new(line_no, %Q{Invalid conversion rate for "#{sign}" and "#{to_sign}": #{rate_str}}) if rate <= 0
              raise CurrenciesDescriptionSyntaxError.new(line_no, %Q{Conversion rate from "#{sign}" to itself (with "#{to_sign}") must be equal to 1 but it is #{rate}}) if current_currency_to_sign == to_sign and rate != 1
              [to_sign, rate]
            end.
            #
            to_h
        )
      end
    end
  end
  
  def self.delete_all
    @@currencies.clear
  end
  
  class CurrenciesDescriptionSyntaxError < Exception
    
    def initialize(line_no, error_description)
      @error_description = error_description
      @line_no = line_no
    end
    
    attr_reader :line_no
    
    attr_reader :error_description
    
    def to_s
      "Error in currencies description at line #{line_no}: #{error_description}"
    end
    
  end
  
  class RateNotDefined < Exception
    
    def initialize(from_currency, to_currency)
      super("Rate of #{from_currency} to #{to_currency} is not defined")
      @from_currency = from_currency
      @to_currency = to_currency
    end
    
    attr_reader :from_currency
    
    attr_reader :to_currency
    
  end
  
  class NoSuchCurrency < Exception
    
    def initialize(property, value)
      case property
      when :sign then super(%Q{No currency signed as "#{value}"})
      when :to_sign then super(%Q{No currency with conversion function "#{value}"})
      else raise %Q{Property "#{property}" is not recognized}
      end
      @property = property
      @value = value
    end
    
    # By which property the Currency was tried to be found.
    attr_reader :property
    
    # Value of the property.
    attr_reader :value
    
  end
  
end


# ---- File: test/currency_test.rb ----
require 'test/unit'
require 'currency'


class CurrencyTest < Test::Unit::TestCase
  
  def test_finding_currency
    a = Currency.new("a", "toA", {})
    assert_equal a, Currency.with_sign("a")
    assert_equal a, Currency.with_to_sign("toA")
    assert_raise Currency::NoSuchCurrency do Currency.with_sign "toA"; end
    assert_raise Currency::NoSuchCurrency do Currency.with_to_sign "a"; end
  end
  
  def test_rate_to_self
    assert Currency.new("a", "toA", {}).rate("toA") == 1
  end
  
  def test_rate
    a = Currency.new("a", "toA", { "toB" => 10 })
    b = Currency.new("b", "toB", {})
    assert a.rate("toB") == 10
    assert_raise Currency::RateNotDefined do b.rate("toA"); end
    assert_raise Currency::NoSuchCurrency do b.rate("toC"); end
  end
  
  def test_load
    assert_nothing_raised do
      Currency.load <<-CURRENCY_DESCRIPTION
        "",    "toDollar", "toEuro", "toFrank"
        "$",   "1",        "0.75",   ""
        "eur", "1.25",     "",       ""
        "fr",  "5",        "10",     "1"
      CURRENCY_DESCRIPTION
    end
    assert Currency.with_sign("$").rate("toEuro") == 0.75
    assert_raise Currency::RateNotDefined do Currency.with_sign("eur").rate("toFrank"); end
  end
  
  def test_load_error_rate_sintactically_invalid
    begin
      Currency.load <<-X
        "",    "toDollar", "toEuro"
        "$",   "1",        "abc"
        "eur", "1.25",     ""
      X
      assert false
    rescue Currency::CurrenciesDescriptionSyntaxError => e
      assert e.line_no == 1
    end
  end
  
  def test_load_error_rate_is_not_1
    begin
      Currency.load <<-X
        "",    "toDollar", "toEuro"
        "$",   "5",        "0.75"
        "eur", "1.25",     ""
      X
      assert false
    rescue Currency::CurrenciesDescriptionSyntaxError => e
      assert e.line_no == 1
    end
  end
  
  def teardown
    Currency.delete_all
  end
  
end


# ---- File: money_sum.rb ----
require 'every'
require 'currency'
require 'facets'
require 'facets/equitable'


# Not inheritable.
class MoneySum
  
  # :call_seq:
  #   new(sum, currency)
  #   new(sum, currency_sign)
  def initialize(sum, currency_or_sign)
    #
    raise TypeError if self.class != MoneySum
    currency = to_currency(currency_or_sign)
    raise TypeError, currency.inspect unless currency.is_a? Currency
    #
    @sum = sum
    @currency = currency
  end
  
  # :call_seq:
  #   new(sum, currency)
  #   new(sum, currency_sign)
  def to(currency_or_sign)
    currency = to_currency(currency_or_sign)
    MoneySum.new(self.sum * self.currency.rate(currency), currency)
  end
  
  def +(other)
    raise TypeError, other.inspect unless other.is_a? MoneySum
    raise WrongCurrency.new(other, self.currency) unless other.currency == self.currency
    return MoneySum.new(self.sum + other.sum, currency)
  end
  
  def -@
    MoneySum.new(-sum, currency)
  end
  
  def -(other)
    raise TypeError, other.inspect unless other.is_a? MoneySum
    self + (-other)
  end
  
  def ==(other)
    raise TypeError, other.inspect unless other.is_a? MoneySum
    raise WrongCurrency.new(other, self.currency) unless other.currency == self.currency
    return self.sum == other.sum
  end
  
  class WrongCurrency < Exception
    
    def initialize(money_sum, required_currency)
      super(%Q{#{required_currency} is required but #{money_sum} is got})
      @money_sum = money_sum
      @required_currency = required_currency
    end
    
    attr_reader :money_sum
    
    attr_reader :required_currency
    
  end
  
  protected
  
  attr_reader :currency
  
  attr_reader :sum
  
  private
  
  def to_currency(currency_or_currency_sign)
    currency = sign = currency_or_currency_sign
    return Currency[sign] if currency_or_currency_sign.is_a? String
    return currency
  end
  
end

# ---- File: test/money_sum_test.rb ----
require 'test/unit'
require 'money_sum'


class MoneySumTest < Test::Unit::TestCase
  
  def setup
    Currency.load <<-X
      "",    "toDollar", "toEuro", "toFrank"
      "$",   "1",        "0.75",   ""
      "eur", "1.25",     "",       ""
      "fr",  "5",        "10",     "1"
    X
  end
  
  def test_plus
    assert MoneySum.new(1, "$") + MoneySum.new(2, "$") == MoneySum.new(3, "$")
    assert MoneySum.new(2, "$") - MoneySum.new(1, "$") == MoneySum.new(1, "$")
  end
  
  def test_equal
    assert MoneySum.new(1, "eur") == MoneySum.new(1, "eur")
  end
  
  def test_plus_incorrect_currency
    assert_raise MoneySum::WrongCurrency do MoneySum.new(1, "$") + MoneySum.new(2, "eur"); end
  end
  
  def test_equal_incorrect_currency
    assert_raise MoneySum::WrongCurrency do MoneySum.new(1, "$") == MoneySum.new(2, "eur"); end
  end
  
end


# ---- File: Rakefile ----
require 'rubygems'
require 'rake'
require 'rake/clean'
require 'rake/gempackagetask'
require 'rake/rdoctask'
require 'rake/testtask'

spec = Gem::Specification.new do |s|
  s.name = 'Currency Calculator'
  s.version = '0.0.1'
  s.has_rdoc = true
  s.extra_rdoc_files = ['README']
  s.summary = 'Currency calculator for 0chan special olympics'
  s.description = s.summary
  s.files = %w(README) + Dir.glob("{bin,lib}/**/*")
  s.require_path = "lib"
end

Rake::GemPackageTask.new(spec) do |p|
  p.gem_spec = spec
  p.need_tar = false
  p.need_zip = false
end

Rake::RDocTask.new do |rdoc|
  files =['README', 'lib/**/*.rb']
  rdoc.rdoc_files.add(files)
  rdoc.main = "README" # page to start on
  rdoc.title = "Currency Calculator"
  rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
  rdoc.options << '--line-numbers'
end

Rake::TestTask.new do |t|
  t.test_files = FileList['test/**/*.rb']
  t.libs = ["lib"]
end

 

Revise this Paste

Your Name: Code Language: