ruby 对Sandi Metz的“Make Everything the same”博客文章进行冥想

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ruby 对Sandi Metz的“Make Everything the same”博客文章进行冥想相关的知识,希望对你有一定的参考价值。

## Sandi Metz's blog post:

[Make Everything The Same](http://www.sandimetz.com/blog/2016/6/9/make-everything-the-same)

Upon reading I decided to try an implement Sandi's concept before lookig at her code.

It wasn't worth a dime in comparison, but _after_ reading her code, I decided to try and improvise from there.

Of course, this is no more than remixing the composition from a genius to feel your own style on it. But it was a interesting exercise. I opted for a module with no state and pure functions.

I changed my naming towards hers for easier comparison. And I had to modify the test, to include reverse conversions, remove Minitest constant rename warnings, and call 'using' from the test instead of from the module as Sandi does, which does not work for me. (Any hints appreciated)
module Roman
  refine Fixnum do
    def to_roman
      Numeral.i_to_r(self)
    end
  end

  refine String do
    def from_roman
      Numeral.r_to_i(self)
    end
  end

  module Numeral
    extend self

    def i_to_r(number)
      to_subtractive(to_roman(number))
    end

    def r_to_i(string)
      to_number(to_additive(string))
    end

    private

    ROMAN_NUMERALS = {
      1000 => 'M',
      500  => 'D',
      100  => 'C',
      50   => 'L',
      10   => 'X',
      5    => 'V',
      1    => 'I'
    }.freeze

    LONG_TO_SHORT_MAP = {
      'DCCCC' => 'CM', # 900
      'CCCC'  => 'CD', # 400
      'LXXXX' => 'XC', # 90
      'XXXX'  => 'XL', # 40
      'VIIII' => 'IX', # 9
      'IIII'  => 'IV'  # 4
    }.freeze


    def to_roman(number)
      ROMAN_NUMERALS.inject('') do |converted, (value, letter)|
        times, number = number.divmod(value)
        converted << letter * times
      end
    end

    def to_number(roman)
      to_additive(roman).chars.reduce(0) do |total, letter|
        total + ROMAN_NUMERALS.invert[letter]
      end
    end

    def convert(map, string)
      map.inject(string) do |out, (group, short)|
        out.gsub(group, short)
      end
    end

    def to_additive(string)
      convert(LONG_TO_SHORT_MAP.invert, string)
    end

    def to_subtractive(string)
      convert(LONG_TO_SHORT_MAP, string)
    end
  end
end
require 'minitest/autorun'
require_relative 'roman'

class RomanTest < MiniTest::Test
  using Roman
  def test_1
    assert_equal 'I', 1.to_roman
    assert_equal 'I'.from_roman, 1
  end

  def test_2
    assert_equal 'II', 2.to_roman
    assert_equal 'II'.from_roman, 2
  end

  def test_3
    assert_equal 'III', 3.to_roman
    assert_equal 'III'.from_roman, 3
  end

  def test_4
    assert_equal 'IV', 4.to_roman
    assert_equal 'IV'.from_roman, 4
  end

  def test_5
    assert_equal 'V', 5.to_roman
    assert_equal 'V'.from_roman, 5
  end

  def test_6
    assert_equal 'VI', 6.to_roman
    assert_equal 'VI'.from_roman, 6
  end

  def test_9
    assert_equal 'IX', 9.to_roman
    assert_equal 'IX'.from_roman, 9
  end

  def test_27
    assert_equal 'XXVII', 27.to_roman
    assert_equal 'XXVII'.from_roman, 27
  end

  def test_48
    assert_equal 'XLVIII', 48.to_roman
    assert_equal 'XLVIII'.from_roman, 48
  end

  def test_59
    assert_equal 'LIX', 59.to_roman
    assert_equal 'LIX'.from_roman, 59
  end

  def test_93
    assert_equal 'XCIII', 93.to_roman
    assert_equal 'XCIII'.from_roman, 93
  end

  def test_141
    assert_equal 'CXLI', 141.to_roman
    assert_equal 'CXLI'.from_roman, 141
  end

  def test_163
    assert_equal 'CLXIII', 163.to_roman
    assert_equal 'CLXIII'.from_roman, 163
  end

  def test_402
    assert_equal 'CDII', 402.to_roman
    assert_equal 'CDII'.from_roman, 402
  end

  def test_575
    assert_equal 'DLXXV', 575.to_roman
    assert_equal 'DLXXV'.from_roman, 575
  end

  def test_911
    assert_equal 'CMXI', 911.to_roman
    assert_equal 'CMXI'.from_roman, 911
  end

  def test_1024
    assert_equal 'MXXIV', 1024.to_roman
    assert_equal 'MXXIV'.from_roman, 1024
  end

  def test_3000
    assert_equal 'MMM', 3000.to_roman
    assert_equal 'MMM'.from_roman, 3000
  end
end

以上是关于ruby 对Sandi Metz的“Make Everything the same”博客文章进行冥想的主要内容,如果未能解决你的问题,请参考以下文章

漏洞利用查询工具sandi

ruby 查找Ruby数组中添加到给定数字的所有数字对

ruby 查找Ruby数组中添加到给定数字的所有数字对

如何在 Ruby 中对数字数组求和?

ruby:对符号数组进行排序

如何在Ruby中对数组中对象的属性求和