-
-
Notifications
You must be signed in to change notification settings - Fork 531
etl: added generator #549
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
etl: added generator #549
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 1 |
| 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 | ||
|
|
||
| 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', | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The previous test was also arbitrarily using the shorthand
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes! Agreed 👍
Personally, I think the longer examples are a bit easier to read when using
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
| } | ||
|
|
||
| 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 | ||
| 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 = {} | ||
|
|
||
| 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 |
| 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) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
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.