Skip to content

Instantly share code, notes, and snippets.

@oinak
Last active March 21, 2024 11:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oinak/683894b18377f4ebed54b03e4938ba76 to your computer and use it in GitHub Desktop.
Save oinak/683894b18377f4ebed54b03e4938ba76 to your computer and use it in GitHub Desktop.
A meditation on Sandi Metz's "Make Everything the Same" blog post

Sandi Metz's blog post:

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
@oinak
Copy link
Author

oinak commented Mar 21, 2024

If you want to see this problem on js with reduce ... https://dev.to/oinak/understanding-js-reduce-with-roman-numerals-2ak

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment