diff options
| -rw-r--r-- | challenge-019/randy-lauen/perl6/ch-1.p6 | 70 | ||||
| -rw-r--r-- | challenge-019/randy-lauen/perl6/ch-2.p6 | 61 | ||||
| -rw-r--r-- | challenge-019/randy-lauen/perl6/ch-3.p6 | 85 |
3 files changed, 216 insertions, 0 deletions
diff --git a/challenge-019/randy-lauen/perl6/ch-1.p6 b/challenge-019/randy-lauen/perl6/ch-1.p6 new file mode 100644 index 0000000000..121f603290 --- /dev/null +++ b/challenge-019/randy-lauen/perl6/ch-1.p6 @@ -0,0 +1,70 @@ +#!/usr/bin/env perl6 + +=begin SYNOPSIS + +Write a script to display months from the year 1900 to 2019 where you find 5 weekends +i.e. 5 Friday, 5 Saturday and 5 Sunday. + +Usage: + $ perl6 ch-1.p6 --from=YYYY --to=YYYY + +Example output: + $ perl6 ch-1.p6 --from=1900 --to=2019 + Found 119 months with 5 full weekends + 1901: Mar + 1902: Aug + 1903: May + 1904: Jan, Jul + ... + 2017: Dec + 2019: Mar + +=end SYNOPSIS + +role MonthRole { + method has-five-full-weekends { + # The month must have 31 days. + return False unless self.days-in-month == 31; + # The month must begin on a Friday. + my $date = self.day == 1 ?? self !! Date.new( self.year, self.month, 1 ); + return $date.day-of-week == 5; + } + + method month-name-short { + given self.month { + when 1 { 'Jan' } + when 2 { 'Feb' } + when 3 { 'Mar' } + when 4 { 'Apr' } + when 5 { 'May' } + when 6 { 'Jun' } + when 7 { 'Jul' } + when 8 { 'Aug' } + when 9 { 'Sep' } + when 10 { 'Oct' } + when 11 { 'Nov' } + when 12 { 'Dec' } + } + } +} + +sub find-months( $from, $to ) { + my @matches; + for $from .. $to -> $year { + for 1 .. 12 -> $month { + my $date = Date.new($year,$month,1) but MonthRole; + push @matches, $date if $date.has-five-full-weekends; + } + } + return @matches; +} + +sub MAIN( :$from!, :$to! ) { + my @matches = find-months( $from, $to ); + say "Found @matches.elems() months with 5 full weekends"; + for @matches.classify( { .year } ).pairs.sort({ .key }) -> $pair { + say "{$pair.key}: { $pair.value>>.month-name-short.join(', ') }"; + } +} + + diff --git a/challenge-019/randy-lauen/perl6/ch-2.p6 b/challenge-019/randy-lauen/perl6/ch-2.p6 new file mode 100644 index 0000000000..d4814ce564 --- /dev/null +++ b/challenge-019/randy-lauen/perl6/ch-2.p6 @@ -0,0 +1,61 @@ +#!/usr/bin/env perl6 + +=begin SYNOPSIS + +Write a script that can wrap the given paragraph at a specified column using the greedy algorithm. + +Usage: + # Output the default paragraph wrapped at 40 characters + $ perl6 ch-2.p6 --line-width=40 + + # Execute tests to prove the paragraph is wrapped correctly. + $ perl6 ch-2.p6 --line-width=40 --test + +=end SYNOPSIS + +# Text taken from https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap#Minimum_number_of_lines +constant $paragraph = q:to/END/; +A simple way to do word wrapping is to use a greedy algorithm that puts as many words on a line as possible, then moving on to the next line to do the same until there are no more words left to place. This method is used by many modern word processors, such as OpenOffice.org Writer and Microsoft Word[citation needed]. This algorithm always uses the minimum possible number of lines but may lead to lines of widely varying lengths. +END + +sub wrap-lines( :$text, :$line-width ) { + my $output; + my $space-left = $line-width; + for $text.words -> $word { + if ($word.chars + 1) > $space-left { + $output ~= "\n$word "; + $space-left = $line-width - ($word.chars + 1); + } + else { + $output ~= "$word "; + $space-left -= ($word.chars + 1); + } + } + return $output; +} + +# Output the wrapped paragraph. +multi MAIN( Int :$line-width! ) { + say wrap-lines( text => $paragraph, :$line-width ); +} + +# Run tests against the wrapped paragraph. +multi MAIN( :$line-width, Bool :$test! ) { + use Test; + + my @lines = wrap-lines( text => $paragraph, :$line-width ).lines; + + # Prove all lines are <= the line width. + for @lines -> $line { + cmp-ok $line.chars, '<=', $line-width, "$line-width: line {++$} length is {$line.chars}"; + } + + # Combine the lines together and prove they match the original. + is( + @lines.join('').trim ~ "\n", + $paragraph, + "$line-width: paragraph put back together correctly" + ); +} + + diff --git a/challenge-019/randy-lauen/perl6/ch-3.p6 b/challenge-019/randy-lauen/perl6/ch-3.p6 new file mode 100644 index 0000000000..435b8c05e4 --- /dev/null +++ b/challenge-019/randy-lauen/perl6/ch-3.p6 @@ -0,0 +1,85 @@ +#!/usr/bin/env perl6 + +=begin SYNOPSIS + +Write a script to use NYT Books API. The API is documented here: +https://developer.nytimes.com/docs/books-product/1/overview + +Usage: + # Output the names of all NYT Best Seller Lists. + $ perl6 ch-3.p6 --api-key=KEY --lists + + # Output the books on a random NYT Best Seller List for a random date. + $ perl6 ch-3.p6 --api-key=KEY --random + + # Output the books for the given NYT Best Seller List on a random date. + $ perl6 ch-3.p6 --api-key=KEY --random --list='Hardcover Graphic Books' + +=end SYNOPSIS + +use Cro::HTTP::Client; +use URI::Encode; + +class NYTBooks { + has $.api-key; + has $!client = Cro::HTTP::Client.new( + :http('1.1'), + :base-uri('https://api.nytimes.com'), + headers => [ Accept => 'application/json' ], + ); + + method lists() { + my $body = self!get-json( "/svc/books/v3/lists/names.json?api-key=$!api-key" ); + return $body<results>; + } + + method list-books-on-date( :$list!, :$date! ) { + my $body = self!get-json( "/svc/books/v3/lists/$date/$list.json?api-key=$!api-key" ); + return $body<results><books>; + } + + method !get-json( $uri ) { + my $encoded = uri_encode( $uri ); + my $response = await $!client.get( $encoded ); + return await $response.body; + } +} + +# Output all the NYT Best Sellers lists. +multi MAIN( :$api-key!, Bool :$lists! ) { + my $api = NYTBooks.new( :$api-key ); + say $api.lists().map( { .<list_name> } ).join("\n"); +} + +# Output the books for a random date. If no list-name is given, use a random list. +multi MAIN( :$api-key!, Bool :$random!, :$list-name is copy ) { + my $api = NYTBooks.new( :$api-key ); + + # Retrieve all lists. + my $lists = $api.lists(); + + # Pick a list at random, or find the given list name. + my $list; + if ( $list-name.defined ) { + $list = $lists.first: { .<list_name> eq $list-name }; + die "Could not find list '$list-name'" unless $list; + } + else { + $list = $lists.pick(); + $list-name = $list<list_name>; + } + + # Find a random date between the newest and oldest publication of the list. + my $date = pick 1, ( Date.new($list<oldest_published_date>) .. Date.new($list<newest_published_date>) ); + + # Find the books for the date and list. + my $books = $api.list-books-on-date( :list($list-name), :$date ); + say "On $date, the '$list-name' list contained the following books:"; + + # Output info about each title. + for $books.flat -> $book { + say " $book<rank>. $book<title> by $book<author>"; + say ' ' x (4 + $book<rank>.chars), $book<description>; + } +} + |
