Skip to content

Commit

Permalink
Move all posts
Browse files Browse the repository at this point in the history
  • Loading branch information
zoffixznet committed May 7, 2016
1 parent 5b70b68 commit a962313
Show file tree
Hide file tree
Showing 18 changed files with 867 additions and 3 deletions.
Binary file added assets/pics/perl6.party.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion assets/sass/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ body, .blog-footer {

.bg {
background: $color-body;
padding-bottom: 30px;
}

pre {
Expand Down Expand Up @@ -59,7 +60,7 @@ h2:not(.blog-post-title):hover, h3:hover, h4:hover, h5:hover, h6:hover {
}
}

h2:not(.blog-post-title) { font-size: 200%; }
h2:not(.blog-post-title) { font-size: 230%; }
h3 { font-size: 180%; }
h4 { font-size: 160%; margin-top: 40px; }
h5 { font-size: 140%; margin-top: 30px; }
Expand Down
7 changes: 5 additions & 2 deletions bin/app.p6
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use lib <lib>;
use lib
# '/home/zoffix/CPANPRC/Bailador-Plugin-Static/lib',
# '/home/zoffix/CPANPRC/AssetPack',
'lib';

use experimental :cached;
use Bailador::App;
Expand Down Expand Up @@ -28,7 +31,7 @@ class Party is Bailador::App {
_ctemplate self, 'about.tt', :posts($posts.all), :active-page<about>;
}

self.get: rx{ ^ '/post/' (<[a..zA..Z0..9_-]>+) $ } => sub (Str(Match:D) $name) {
self.get: rx{ ^ '/post/' (<[a..zA..Z0..9_.-]>+) $ } => sub (Str(Match:D) $name) {
return self.response.code: 404 unless .f and .r given "post/$name.md".IO;
my ($meta, $post) = $posts.serve: "post/$name.md";
_ctemplate self, 'post.tt',
Expand Down
113 changes: 113 additions & 0 deletions post/How-to-Make-a-Perl-6-Module--Bit-Rot-Thursday.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
%% title: How to Make a Perl 6 Module (Bit Rot Thursday)
%% date: 2016-02-04

Happy [Bit Rot Thursday](http://blogs.perl.org/users/zoffix_znet/2016/01/bit-rot-thursday.html)! This week I'm taking care of fixing minor issues with packaging of my Perl 6 modules, and so, I'll talk about the general process of
releasing a Perl 6 module. Let's dive in!

## Prelude

Perl 6 is a brand new language, so there's yet no well-established module system like what Perl 5 has, but there is a work in progress. Thus, I'll first describe the process for our temporary GitHub-based system and then I'll talk about the PAUSE-based system that's being worked on.

There are some [tools and helpers available](http://doc.perl6.org/language/modules-extra) to help with the process of module development, but they are beyond the
scope of this post.

## Terms (and no conditions)

* **Ecosystem**—collection of Perl 6 modules and scripts, viewable at [modules.perl6.org](http://modules.perl6.org/) with META-data listed in the
[perl6/ecosystem repo](https://github.com/perl6/ecosystem/)
* [**panda**](https://github.com/tadzik/panda/)—a Perl 6 module installer
* [**zef**](https://github.com/ugexe/zef)—an alternative Perl 6 module installer
* [**repo**](https://en.wikipedia.org/wiki/Software_repository)—the files of a project hosted somewhere, like on GitHub
* **PR**—abbreviation for "Pull Request"; a request on GitHub to apply a change to some files in a project

## So, you want to write a Perl 6 module?

If so, awesome! Congratulations on your decision to become a member of the elite, exclusive, limited-time, offer-expires-soon team of about 130 developers who currently own the 549 modules that comprise the
[Perl 6 Ecosystem](http://modules.perl6.org/).

There are plenty of things that need to be written and if you're still having
trouble coming up with ideas for something to code, check out the
[Most Wanted list](https://github.com/perl6/perl6-most-wanted/blob/master/most-wanted/modules.md).

You can publish Perl 6 modules as well as scripts (executables).

## The Files


META6.json
README.md
.travis.yml
.gitignore
bin/baker.p6
lib/Bread/Baker.pm6
resources/recipe.txt
t/00-test-bake.t
xt/00-ensure-bread-is-tasty.t


The above shows the possible files and directories your distribution would
have. The `bin/` directory is for executables, `lib/` is for modules,
`resources/` is for additional resources, such as images or templates,
`t/` is for tests to be run by the user, and `xt/` is for your author tests
that are not run as part of the installation process. The documentation can be
included in the same file as code in POD6 format, but since the current system uses
GitHub, a README.md makes it much easier to read the docs.

Also, you are encouraged to enable [Travis](https://travis-ci.org/) testing, hence the
included `.travis.yml` file. You can use either a [simple config file](https://docs.travis-ci.com/user/languages/perl6) or [a more advanced version written by ugexe](https://github.com/ugexe/P6TCI).

Most important of all is the `META6.json` file. It's a distribution metafile
in JSON format that specifies what stuff your distro provides, as well as its
prerequisites and authorship information. You can learn what all the keys are for
in [S22 Speculation](http://design.perl6.org/S22.html#META6.json) or look at
[a sample META file](https://raw.githubusercontent.com/zoffixznet/perl6-IO-MiddleMan/master/META6.json). This is a place where many errors happen, so I encourage you to use [Test::META](http://modules.perl6.org/dist/Test::META) that will spot all the common mistakes.

Lastly, `.gitignore` is a file where you can list things for `git` to ignore and not include in your repo. For a start, you'll want to add single line `lib/.precomp` into it. This is the directory created by Rakudo to store precompiled files when you run your tests, for example, and you don't need to store it anywhere.

## Add to Ecosystem (The Now)

Currently, the authors host their modules as repos on
[GitHub](https://github.com/), so place your files there. It'll require some understanding of [how to use git](http://www.learnenough.com/git-tutorial).

Grab a link to
the **raw** view of your META file. You can get to it by clicking the `"Raw"`
button in the top, right corner of the file view on GitHub. It'll be a link
akin to `https://raw.githubusercontent.com/zoffixznet/perl6-IO-MiddleMan/master/META6.json`

<img alt="arrow.png" src="http://blogs.perl.org/users/zoffix_znet/arrow.png" width="589" height="301" class="mt-image-none" style="" />

Go to the [META.list file in perl6/ecosystem repo](https://github.com/perl6/ecosystem/blob/master/META.list). You can edit that file directly (and submit a PR) by clicking the pencil icon in top, right corner on GitHub, or fork the repo and submit a PR using other means. In that file, on a separate line, add the link to your dist's META file.

After 1–2 hours after your PR is merged, the build cron job will list your
module on [modules.perl6.org](http://modules.perl6.org). If it's still
missing, check the [build log](http://modules.perl6.org/update.log) for any
errors; you can just search the page for term `[error]`

Keep in mind that `panda` doesn't fetch a new ecosystem list on each run,
so if you want to install your freshly-added module, you need to run
`panda update` first.

## Add to Ecosystem (The Future)

Perl 5's model goes something like this: you upload stuff on PAUSE, it gets
propagated to all sorts of mirrors (CPAN), you can search for things using
[MetaCPAN](https://metacpan.org/), and you install those things from one
of the mirrors using a CPAN client, like `cpanm`. Wouldn't it be sweet for
Perl 6 folks to get in on that action?

Well, you can! Unless you're reading this after
the [world was destroyed by a nuclear catastrophe](https://www.youtube.com/watch?v=SZTKyOj8gjM), you can log in onto [PAUSE](http://pause.perl.org/) **right this second** and upload a Perl 6 dist.

Providing your dist looks proper and contains `META6.json` file, all you need
to do is choose `Perl6` as the `Target Directory` on the [dist upload page](https://pause.perl.org/pause/authenquery?ACTION=add_uri).

Now, just because you uploaded a Perl 6 dist doesn't mean it'll show up on
[MetaCPAN](https://metacpan.org/); it's the whole point of specifying
the `Perl6` target dir. There will be a Perl 6 version of the MetaCPAN hosted elsewhere. That MetaCPAN will be a modified version of the Perl 5's MetaCPAN under the hood.

Currently, that work is being done by brave pioneers like jdv79, ranguard, and
anyone else who I left out due to my ignorance. Having more Volunteers would
certainly be helpful, and if you seek fame and recognition, you should stop
by [#perl6-toolchain channel on irc.Freenode.net](irc://irc.freenode.net/#perl6-toolchain) and offer a helping hand.

Hopefully, you found this article helpful and I await your contributions to the Perl 6 Ecosystem!
176 changes: 176 additions & 0 deletions post/Perl-6-.rotor-The-King-of-List-Manipulation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
%% title: .rotor: The King of List Manipulation
%% date: 2016-01-29

Rotor. The word makes a mechanic think about brakes, an electrical engineer about motors, and a fan of [Red Letter Media YouTube channel](https://www.youtube.com/watch?v=s76vZATqLrE) about poorly executed films. But to a Perl 6 programmer, [`.rotor`](http://docs.perl6.org/routine/rotor) is a powerful tool for list operations.

## Break up into chunks

At its simplest, `.rotor` takes an integer and breaks up a list into sublists with that many elements:

say <a b c d e f g h>.rotor: 3;
# OUTPUT: ((a b c) (d e f))

We have a list of 8 elements, we called `.rotor` on it with argument `3` and we received two [Lists](http://docs.perl6.org/type/List), with 3 elements each. The last two elements of the original list we
not included, because they don't make up a complete, 3-element list. That can be rectified, however, using
the `:partial` named argument set to `True`:

say <a b c d e f g h>.rotor: 3, :partial;
# OUTPUT: ((a b c) (d e f) (g h))
say <a b c d e f g h>.rotor: 3, :partial(True);
# OUTPUT: ((a b c) (d e f) (g h))
say <a b c d e f g h>.rotor: 3, :partial(False);
# OUTPUT: ((a b c) (d e f))

Here's what we've learned so far, used as a crude means to fit a chunk of text into 10-column width:

"foobarberboorboozebazmeow".comb.rotor(10, :partial)».join».say
# OUTPUT:
# foobarberb
# oorboozeba
# zmeow

We broke up the string into individual letters with `.comb` method, then we `.rotor` them into 10-element lists,
specifying that `:partial` lists are fine too, and lastly we use a pair of hyper method calls to `.join` and `.say` each of those sublists.

## Mind The Gap

Say, you're receiving input: you get a word, its French translation, and its Spanish translation, and so on for a whole bunch of words. You want to output only a particular language, so we need to somehow skip over some items in our list. `.rotor` to the rescue!

Specifying a [Pair](http://docs.perl6.org/type/Pair) of integers as the argument makes `.rotor` break up the list into `$key` elements, with `$value` gap in between. Easier to see in the example:

say ^10 .rotor: 3 => 1, :partial;
# OUTPUT: ((0 1 2) (4 5 6) (8 9))
say ^10 .rotor: 2 => 2, :partial;
# OUTPUT: ((0 1) (4 5) (8 9))

On the first line, we have a range of integers from `0` to `9`, we're asking `.rotor` to break that up into lists
of 3 elements (including partial lists) and use a gap of `1`. And indeed, you can see the output is missing number
`3` as well as `7`. Those are the gaps we skipped. In the second example, we've increased the gap to `2`, and broke
up the list into 2-element sublists: the `2`, `3`, `6`, and `7` are the numbers that fell into gaps and were not included. Back to our exquisitely convoluted translations program:

enum <English French Spanish>;
say join " ", <Good Bon Buenos morning matin días>[French..*].rotor: 1 => 2;
# OUTPUT: Bon matin

We cheatsy-doodle with an `enum` and then use the `[LANG..*]` to toss the head of the list. The `French` in our
example is `enum`erated into integer `1`, which means `[1..*]` gets rid of the first element. Then, we use `.rotor` to make
1-element lists with a 2-element gap. This makes it skip over the words for languages we're not interested in.

Now, I'm sure some in the audence are currently throwing tomatoes at me and saying I'm going mental with my examples here... Let's look at something more real-worldly.

## Overlaps

You have a list and you want to Do Things™ based on whether the next item is the same as the current one. Typically,
this would involve a loop and a variable holding the index. You check the `index+1`, while also checking you've
not reached the upper boundary of the list. Sounds tedious. Let's use `.rotor` instead!

We've already learned above that using a Pair we can introduce gaps, but what if we make the gap negative? It actually works!

say <a a b c c c d>.rotor: 2 => -1;
# OUTPUT: ((a a) (a b) (b c) (c c) (c c) (c d))
say <a a b c c c d>.rotor(2 => -1).map: {$_[0] eq $_[1] ?? "same" !! "different"};
# OUTPUT: (same different different same same different)

On the first line, we're just printing the results from `.rotor` to see what they look like and on the second line,
we're performing the actual comparison and acting accordingly. Looking at the first result: we get 2-element lists,
where the first element is the element from the original list and the second element is the one that follows it. That
is, were we to print just the first elements of our sublists, we'd receive our original list back, minus the last element. The second elements are all just a bonus!

## All Out

A single `Int` or a `Pair` are not the only thing `.rotor` can accept. You can specify additional positional parameters that are `Int`s or `Pair`s to break up lists into sublists of different sizes, with different gaps between
them.

Say, I have a custom daemon that creates logs about users that access it. The log is in plain text, each record
follows the other. Records are multi-line and always look something like this (two records + separator shown):

IP: 198.0.1.22
Login: suser
Time: 1454017107
Resource: /report/accounting/x23gs
Input: x=42,y=32
Output: success
===================================================
IP: 198.0.1.23
Login: nanom
Time: 1454027106
Resource: /report/systems/boot
Input: mode=standard
Output: success

Each item contains a "header" with user information and resource they tried to access, as well as the "operation"
they wanted to execute. In addition, each item is separated by a double-line. I would like to print the header and
the executed operation, and I want `Resource:` to be present in both.

To parse this, we could use [Grammars](http://docs.perl6.org/language/grammars), but `.rotor` can do the trick too:

for 'report.txt'.IO.lines».indent(4).rotor( 4 => -1, 3 => 1 ) -> $head, $op {
.say for "Header:", |$head,
"Operation:", |$op, '';
}

# OUTPUT:
# Header:
# IP: 198.0.1.22
# Login: suser
# Time: 1454017107
# Resource: /report/accounting/x23gs
# Operation:
# Resource: /report/accounting/x23gs
# Input: x=42,y=32
# Output: success
#
# Header:
# IP: 198.0.1.23
# Login: nanom
# Time: 1454027106
# Resource: /report/systems/boot
# Operation:
# Resource: /report/systems/boot
# Input: mode=standard
# Output: success

We fetch lines from file `report.txt` with `'report.txt'.IO.lines`. To make output prettier, we indent each line
with 4 spaces by calling `.indent(4)` on each item using the hyper operator (`»`). Now comes `.rotor`!
We use it to break up lines into repeating chunks of 4 and 3 items: that's items for our header
and our operation. After grabbing the 4-element chunk, we use a negative gap to backtrack and include `Resource:`
line in our operation chunk as well. In the 3-element chunk, we use a positive gap, to skip over the separator line.

Afterwards, we use a `for` loop and give it two variables with `-> $head, $op`, so it loops over two items at a time.
Inside the loop, we merely print each log item onto the screen. Since `$head` and `$op` are Lists, we use the pipe
(`|`) character to [slip](http://docs.perl6.org/type/Slip) them in.

Keep in mind, the pattern you supply to `.rotor` can be dynamically generated! Here we use a sine to generate it:

say ^92 .rotor(
(0.2, 0.4 ... 3).map: (10 * *.sin).Int # pattern we supply to .rotor
).join: "\n"'

# OUTPUT:
# 0
# 1 2 3
# 4 5 6 7 8
# 9 10 11 12 13 14 15
# 16 17 18 19 20 21 22 23
# 24 25 26 27 28 29 30 31 32
# 33 34 35 36 37 38 39 40 41
# 42 43 44 45 46 47 48 49 50
# 51 52 53 54 55 56 57 58 59
# 60 61 62 63 64 65 66 67 68
# 69 70 71 72 73 74 75 76
# 77 78 79 80 81 82
# 83 84 85 86 87
# 88 89 90
# 91

So whether you're an electrician, mechanic, or anyone else, I hope you'll find `.rotor` a useful multipurpose tool.

## Update 1:

It's been pointed out to me that

"foobarberboorboozebazmeow".comb.rotor(10, :partial)».join».say

Is better written as

"foobarberboorboozebazmeow".comb(10)».say
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit a962313

Please sign in to comment.