Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions exercises/etl/.meta/.version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
115 changes: 85 additions & 30 deletions exercises/etl/etl_test.rb
Original file line number Diff line number Diff line change
@@ -1,58 +1,113 @@
#!/usr/bin/env ruby
gem 'minitest', '>= 5.0.0'
require 'minitest/autorun'
require_relative 'etl'

class TransformTest < Minitest::Test
def test_transform_one_value
old = { 1 => ['A'] }
expected = { 'a' => 1 }
# Test data version: 040a24f
class EtlTest < Minitest::Test
def test_a_single_letter
# skip
old = {
'1' => ["A"],
}
expected = {
'a' => '1',
}

assert_equal expected, ETL.transform(old)
end

Copy link
Copy Markdown
Contributor Author

@ajwann ajwann Feb 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous test was arbitrarily placing key/value pairs on newlines. I decided it was easiest to just check if there was more than one key/value pair in a hash and if so, print each key value pair on a separate line.

def test_transform_more_values
def test_single_score_with_multiple_letters
skip
old = { 1 => %w(A E I O U) }
expected = { 'a' => 1, 'e' => 1, 'i' => 1, 'o' => 1, 'u' => 1 }
old = {
'1' => ["A", "E", "I", "O", "U"],
}
expected = {
'a' => '1',
'e' => '1',
'i' => '1',
'o' => '1',
'u' => '1',
}

assert_equal expected, ETL.transform(old)
end

def test_more_keys
def test_multiple_scores_with_multiple_letters
skip
old = { 1 => %w(A E), 2 => %w(D G) }
old = {
'1' => ["A", "E"],
'2' => ["D", "G"],
}
expected = {
'a' => 1,
'e' => 1,
'd' => 2,
'g' => 2
'a' => '1',
'e' => '1',
'd' => '2',
'g' => '2',
Copy link
Copy Markdown
Contributor Author

@ajwann ajwann Feb 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous test was also arbitrarily using the shorthand %w() syntax for arrays. Personally I think it's best if all tests just use one syntax or another, so I went with the standard bracket syntax. I can definitely switch everything to the %w() syntax though if that's the consensus.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I think it's best if all tests just use one syntax or another

Yes! Agreed 👍

I can definitely switch everything to the %w() syntax though if that's the consensus.

Personally, I think the longer examples are a bit easier to read when using %w(), but I'm not sure if everyone else will agree with that. This is likely a question of preference, so a weigh in from @Insti and @kotp would be great. I don't think its much of a big deal though 😄

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsure it was 'arbitrary' as it does save some typing... like 2/3rds for each single character "word", after the first element. For a single element entry, it is identical in character length. It was probably a convenience of typing, and something that is idiomatic (even encouraged in the style guide).

Consistency is good though.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I think that new Ruby users coming from other languages would be able to recognize and understand the bracket syntax faster than the %w() syntax. But that's just my opinion and I'm happy to change the generator to use only the %w() syntax.

}

assert_equal expected, ETL.transform(old)
end

def test_full_dataset
def test_multiple_scores_with_differing_numbers_of_letters
skip
old = {
1 => %w(A E I O U L N R S T),
2 => %w(D G),
3 => %w(B C M P),
4 => %w(F H V W Y),
5 => %w(K),
8 => %w(J X),
10 => %w(Q Z)
'1' => ["A", "E", "I", "O", "U", "L", "N", "R", "S", "T"],
'2' => ["D", "G"],
'3' => ["B", "C", "M", "P"],
'4' => ["F", "H", "V", "W", "Y"],
'5' => ["K"],
'8' => ["J", "X"],
'10' => ["Q", "Z"],
}

expected = {
'a' => 1, 'b' => 3, 'c' => 3, 'd' => 2, 'e' => 1,
'f' => 4, 'g' => 2, 'h' => 4, 'i' => 1, 'j' => 8,
'k' => 5, 'l' => 1, 'm' => 3, 'n' => 1, 'o' => 1,
'p' => 3, 'q' => 10, 'r' => 1, 's' => 1, 't' => 1,
'u' => 1, 'v' => 4, 'w' => 4, 'x' => 8, 'y' => 4,
'z' => 10
'a' => '1',
'b' => '3',
'c' => '3',
'd' => '2',
'e' => '1',
'f' => '4',
'g' => '2',
'h' => '4',
'i' => '1',
'j' => '8',
'k' => '5',
'l' => '1',
'm' => '3',
'n' => '1',
'o' => '1',
'p' => '3',
'q' => '10',
'r' => '1',
's' => '1',
't' => '1',
'u' => '1',
'v' => '4',
'w' => '4',
'x' => '8',
'y' => '4',
'z' => '10',
}

assert_equal expected, ETL.transform(old)
end

# Problems in exercism evolve over time, as we find better ways to ask
# questions.
# The version number refers to the version of the problem you solved,
# not your solution.
#
# Define a constant named VERSION inside of the top level BookKeeping
# module, which may be placed near the end of your file.
#
# In your file, it will look like this:
#
# module BookKeeping
# VERSION = 1 # Where the version number matches the one in the test.
# end
#
# If you are curious, read more about constants on RubyDoc:
# http://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/constants.html
def test_bookkeeping
skip
assert_equal 1, BookKeeping::VERSION
end
end
4 changes: 4 additions & 0 deletions exercises/etl/example.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
module BookKeeping
VERSION = 1
end

class ETL
def self.transform(old)
data = {}
Expand Down
17 changes: 17 additions & 0 deletions exercises/etl/example.tt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
require 'minitest/autorun'
require_relative 'etl'

# Test data version: <%= abbreviated_commit_hash %>
class EtlTest < Minitest::Test<% test_cases.each do |test_case| %>
def <%= test_case.test_name %>
<%= test_case.skipped %>
<%= test_case.workload %>
end
<% end %>

<%= IO.read(XRUBY_LIB + '/bookkeeping.md') %>
def test_bookkeeping
skip
assert_equal <%= version.next %>, BookKeeping::VERSION
end
end
48 changes: 48 additions & 0 deletions lib/etl_cases.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
require 'exercise_cases'

class EtlCase < OpenStruct
def test_name
'test_%s' % description.tr(' ,-', '_').downcase
end

def workload
[
"old = #{format_hash(integerize_keys(input))}",
" expected = #{format_hash(expected)}\n",
indent(4, assertion),
].join("\n")
end

def skipped
index.zero? ? '# skip' : 'skip'
end

private

def indent(size, text)
text.lines.each_with_object('') { |line, obj| obj << ' ' * size + line }
end

def assertion
"assert_equal expected, ETL.transform(old)"
end

def integerize_keys(input)
input.reduce({}) { |hash, (k, v)| hash[k.to_i] = v; hash }
end

def format_hash(hash)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this method can be simplified a bit.

Try operating on the hash as a hash, rather than as a string.

Copy link
Copy Markdown
Contributor Author

@ajwann ajwann Feb 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created this method to format the hash neatly across multiple lines; adding newlines and indentation. Without it, each hash is printed on one line, and those lines are really long. I'm not sure how I can achieve the same result without converting it to a string.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ajwann I think @tommyschaefer is hinting at something like:

  middle = hash.each_pair.with_object('') do |(k, v), obj|
    obj << " :#{k} => #{v},\n "
  end
  " {\n#{middle}}"

middle = hash.each_pair.with_object('') do |(k, v), obj|
value = v.class == Array ? v : "'#{v}'"
obj << " '#{k}' => #{value},\n "
end
"{\n #{middle} }"
end

end

EtlCases = proc do |data|
JSON.parse(data)['transform']['cases'].map.with_index do |row, i|
EtlCase.new(row.merge(index: i))
end
end