-
-
Save mjy/326277 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'test/unit' | |
#require 'ruby-debug' | |
## | |
# Variant generator returns all possible combinations of elements of all given arrays. | |
# Running this gist will run the tests. For functionality only this module is needed. | |
module VariantsGenerator | |
extend self | |
## | |
# Operates on arrays. | |
# | |
# Example: | |
# generate_variants(["red", "blue"], ["long", "short"]) | |
# # => [["red", "long"], ["red", "short"], ["blue", "long"], ["blue", "short"]] | |
# | |
# this is ugly but it does test clean ;) | |
# very hackish, but tests clean, and it doesn't require the recursion, trick is the .product bit | |
def generate_variants(*arrays) | |
t = arrays.size | |
# deal with all the exceptions | |
return nil if t == 0 | |
if arrays.first.class == String | |
return arrays.first if t == 1 | |
return [arrays] | |
end | |
# just arrays at this point | |
if t == 1 | |
arrays.first | |
else | |
result = arrays.shift | |
arrays.each do |a| | |
result = result.product(a) | |
end | |
if t == 2 | |
return result.inject([]){|sum, a| sum << a} | |
else | |
if arrays.first.first.class == Array # seems to be an odd requirement in the test ... | |
result.collect{|a| a.flatten.inject([]){|ar, a| ar << [a]}} | |
else | |
result.collect{|a| a.flatten} | |
end | |
end | |
end | |
end | |
## | |
# Operates on hashes where key is name and value is array. | |
# | |
# Example: | |
# generate_named_variants(:color => ["red", "blue"], :type => ["long", "short"]) | |
# # => [{:color => "red", :type => "long"}, {:color => "red", :type => "short"}, | |
# # {:color => "blue", :type => "long"}, {:color => "red", :type => "short"}] | |
def generate_named_variants(hash) | |
names, arrays = hash.to_a.transpose | |
generate_variants(*arrays).map { |values| Hash[names.zip(values)] } | |
end | |
end | |
# Tests | |
class Test::Unit::TestCase | |
include VariantsGenerator | |
def assert_same_elements(a1, a2, msg = nil) | |
a1h = a1.inject({}) { |h,e| h[e] = a1.select { |i| i == e }.size; h } | |
a2h = a2.inject({}) { |h,e| h[e] = a2.select { |i| i == e }.size; h } | |
assert_equal(a1h, a2h, msg) | |
end | |
end | |
class GenerateVariantsTest < Test::Unit::TestCase | |
def test_valid_permutations_for_2_arrays | |
assert_same_elements [["white", "m"], | |
["white", "f"], | |
["black", "m"], | |
["black", "f"]], generate_variants(["white", "black"], ["m", "f"]) | |
end | |
def test_1_permutation_for_non_arrays | |
assert_same_elements [["foo", "bar"]], generate_variants("foo", "bar") | |
end | |
def test_array_elements_are_preserved_unflattened_for_2_arrays | |
assert_same_elements [[["white"], ["m"]], | |
[["white"], ["f"]], | |
[["black"], ["m"]], | |
[["black"], ["f"]]], generate_variants([["white"], ["black"]], [["m"], ["f"]]) | |
end | |
def test_array_elements_are_preserved_unflattened_for_3_arrays | |
assert_same_elements [[["white"], ["m"], ["s"]], | |
[["white"], ["m"], ["m"]], | |
[["white"], ["m"], ["l"]], | |
[["white"], ["f"], ["s"]], | |
[["white"], ["f"], ["m"]], | |
[["white"], ["f"], ["l"]], | |
[["black"], ["m"], ["s"]], | |
[["black"], ["m"], ["m"]], | |
[["black"], ["m"], ["l"]], | |
[["black"], ["f"], ["s"]], | |
[["black"], ["f"], ["m"]], | |
[["black"], ["f"], ["l"]]], generate_variants([["white"], ["black"]], | |
[["m"], ["f"]], | |
[["s"], ["m"], ["l"]]) | |
end | |
def test_valid_permutations_for_3_arrays | |
assert_same_elements [["s", "white", "m"], | |
["s", "white", "f"], | |
["s", "black", "m"], | |
["s", "black", "f"], | |
["m", "white", "m"], | |
["m", "white", "f"], | |
["m", "black", "m"], | |
["m", "black", "f"], | |
["l", "white", "m"], | |
["l", "white", "f"], | |
["l", "black", "m"], | |
["l", "black", "f"]], generate_variants(["s", "m", "l"], ["white", "black"], ["m", "f"]) | |
end | |
def test_1_permutation_for_1_array_element | |
assert_equal ["s", "m", "l"], generate_variants(["s", "m", "l"]) | |
end | |
def test_returns_single_supplied_argument | |
assert_equal "s", generate_variants("s") | |
end | |
def test_return_nil_with_no_arguments | |
assert_nil generate_variants | |
end | |
end | |
class GenerateNamedVariantsTest < Test::Unit::TestCase | |
def test_permutes_3_named_arrays | |
assert_same_elements [{:color=>"white", :gender=>"m", :size=>"s"}, | |
{:color=>"white", :gender=>"m", :size=>"m"}, | |
{:color=>"white", :gender=>"m", :size=>"l"}, | |
{:color=>"white", :gender=>"f", :size=>"s"}, | |
{:color=>"white", :gender=>"f", :size=>"m"}, | |
{:color=>"white", :gender=>"f", :size=>"l"}, | |
{:color=>"black", :gender=>"m", :size=>"s"}, | |
{:color=>"black", :gender=>"m", :size=>"m"}, | |
{:color=>"black", :gender=>"m", :size=>"l"}, | |
{:color=>"black", :gender=>"f", :size=>"s"}, | |
{:color=>"black", :gender=>"f", :size=>"m"}, | |
{:color=>"black", :gender=>"f", :size=>"l"}], | |
generate_named_variants( :size => ["s", "m", "l"], | |
:color => ["white", "black"], | |
:gender => ["m", "f"]) | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment