Discussion:
Ruby Quiz - Challenge #7 - Type Inference - Convert Strings to Null, Number, Not a Number (NaN), Date & More
Gerald Bauer
2018-11-30 14:34:32 UTC
Permalink
Hello,

It's Friday. Ruby Quiz time! Join us. Let's keep going with a new
Ruby Quiz [1] every Friday. Here we go:

Challenge #7 - Type Inference - Convert Strings to Null, Number, Not a
Number (NaN), Date & More

Type inference is the new hotness.
Let's (auto)-convert a list of strings into properly typed values.

The challenge: Code a `convert` method that passes the RubyQuizTest :-) [2].

def convert( values )
# ...
end

For the starter level 1 turn a random list of strings:

["2018", "2018.12", "2018.12.25", "25 Gems", "NaN", "1820",
"18.20", "Nil", "Null"]


into a properly typed list of values:

[2018, 2018.12, Date.new(2018,12,25), "25 Gems", Float::NAN, 1820,
18.2, nil, nil]
# => [2018, 2018.12, #<Date: 2018-12-25>, "25 Gems", NaN, 1820,
18.2, nil, nil]

Note: `NaN` is short for Not a Number (that is, `Float::NAN`).
To pass the RubyQuizTest all type classes must match too, that is:

[Integer, Float, Date, String, Float, Integer, Float, NilClass, NilClass]

To make sure the order in the list doesn't matter, that is, integer
before float numbers
or float before integer numbers or date before integer numbers
and so on -
convert gets called five times
with a shuffled sample with a different "randomized" order every time.


Start from scratch or, yes, use any library / gem you can find.

To qualify for solving the code challenge / puzzle you must pass the test:

```
require 'minitest/autorun'
require 'date'

class RubyQuizTest < MiniTest::Test

def test_convert

pairs = [
["2018", 2018],
["2018.12", 2018.12],
["2018.12.25", Date.new(2018,12,25)],
["25 Gems", "25 Gems"],
["NaN", Float::NAN],
["1820", 1820],
["18.20", 18.2],
["Nil", nil],
["Null", nil]]

5.times do
values, exp_values = pairs.shuffle.reduce( [[],[]]) { |acc,pair|
acc[0] << pair[0]; acc[1] << pair[1]; acc }

assert_equal exp_values, convert( values )
assert_equal exp_values.map { |v| v.class }, convert( values
).map { |v| v.class }
end


end # method test_convert
end # class RubyQuizTest
```

Post your code snippets on the "official" Ruby Quiz Channel,
that is, the ruby-talk mailing list right here.

Happy data wrangling and type inferencing with Ruby.


[1] https://github.com/planetruby/quiz/tree/master/007
[2] https://github.com/planetruby/quiz/blob/master/007/test.rb

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Frank J. Cameron
2018-12-01 23:32:18 UTC
Permalink
Post by Gerald Bauer
Challenge #7 - Type Inference - Convert Strings to Null, Number, Not a
Number (NaN), Date & More
$ ruby lib/007.rb
Run options: --seed 42919
# Running:
.
Finished in 0.015037s, 66.5023 runs/s, 665.0233 assertions/s.
1 runs, 10 assertions, 0 failures, 0 errors, 0 skips

$ cat lib/007.rb
require_relative '../007/test.rb'

gem 'parslet', '~> 1.8.2'
require 'parslet'

class RubyQuizTest
@@parser = Class.new(Parslet::Parser) do
rule(:dte) {
(
match('[0-9]').repeat(4)>>(
match('[.]')>>match('[0-9]').repeat(2)
).repeat(2)
).as(:dte)
}
rule(:flt) {
(
match('[0-9]').repeat>>match('\.')>>match('[0-9]').repeat
).as(:flt)
}
rule(:int) {
match('[0-9]').repeat.as(:int)
}
rule(:nan) {
(
match('N')>>match('a')>>match('N')
).as(:nan)
}
rule(:nul) {
(
match('N')>>match('i')>>match('l') |
match('N')>>match('u')>>match('l')>>match('l')
).as(:nul)
}
rule(:str) {
match('.').repeat.as(:str)
}
rule(:foo) { nul | nan | dte | flt | int | str }
root(:foo)
end.new

@@transf = Class.new(Parslet::Transform) do
rule(:dte => simple(:dte)) { Date.strptime(dte, '%Y.%m.%d') }
rule(:flt => simple(:flt)) { flt.to_f }
rule(:int => simple(:int)) { int.to_i }
rule(:nan => simple(:nan)) { Float::NAN }
rule(:nul => simple(:nan)) { nil }
rule(:str => simple(:str)) { str.to_s }
end.new

def convert(values)
values.map{|v|
@@transf.apply(@@parser.parse(v))
}
end
end

RubyQuizTest.new('fjc')



Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
o***@posteo.li
2018-12-03 16:18:03 UTC
Permalink
It seems that my previous message wasn't delivered due to a couple of MIME
headers or for some other reason. At least I can't see it on either marc.info
or rubytalk.org. So I'm sending it again, sorry if you have received it twice.


Why not use regular expressions?

```
PATTERNS = {
nan: /\ANaN\z/,
null: /\An[iu]ll?\z/i,
date: /\A\d{4}\.\d{2}\.\d{2}\z/,
float: /\A\d+\.\d+\z/,
int: /\A\d+\z/
}

def convert(values)
values.map do |v|
case v
when PATTERNS[:nan] then Float::NAN
when PATTERNS[:null] then nil
when PATTERNS[:date] then Date.strptime(v, '%Y.%m.%d')
when PATTERNS[:float] then v.to_f
when PATTERNS[:int] then v.to_i
else v.to_s
end
end
end
```


Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Gerald Bauer
2018-12-03 17:26:36 UTC
Permalink
Hello,
Post by o***@posteo.li
Why not use regular expressions?
Good question.Welcome to the Ruby Quiz. Why not? Looks great. Passes
the test. Thanks for sharing your coding puzzle snippet / script. Keep
it up. Cheers. Prost.

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>

Loading...